You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by jh...@apache.org on 2016/05/31 17:28:51 UTC
[2/2] calcite git commit: [CALCITE-1250] UNNEST applied to MAP data
type (Johannes Schulte)
[CALCITE-1250] UNNEST applied to MAP data type (Johannes Schulte)
Implicit column names are KEY and VALUE.
Make UNNEST work with multiple arguments of different types.
Close apache/calcite#235
Project: http://git-wip-us.apache.org/repos/asf/calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/d757201f
Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/d757201f
Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/d757201f
Branch: refs/heads/master
Commit: d757201f155bd0c900725b3ce2776899668fce4d
Parents: 2f937c1
Author: baunz <jo...@gmail.com>
Authored: Thu May 19 23:02:34 2016 +0200
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue May 31 00:01:23 2016 -0700
----------------------------------------------------------------------
.../adapter/enumerable/EnumerableUncollect.java | 27 +++++--
.../org/apache/calcite/rel/core/Uncollect.java | 20 +++--
.../apache/calcite/runtime/SqlFunctions.java | 80 ++++++++++++++------
.../apache/calcite/sql/SqlUnnestOperator.java | 26 +++++--
.../apache/calcite/sql/type/OperandTypes.java | 3 +
.../org/apache/calcite/util/BuiltInMethod.java | 36 ++++-----
.../java/org/apache/calcite/test/JdbcTest.java | 45 +++++++++++
.../apache/calcite/test/SqlValidatorTest.java | 5 ++
8 files changed, 184 insertions(+), 58 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/calcite/blob/d757201f/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableUncollect.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableUncollect.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableUncollect.java
index 0dfa57f..def8e24 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableUncollect.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableUncollect.java
@@ -25,6 +25,8 @@ import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.core.Uncollect;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeField;
+import org.apache.calcite.runtime.SqlFunctions.FlatProductInputType;
+import org.apache.calcite.sql.type.MapSqlType;
import org.apache.calcite.util.BuiltInMethod;
import org.apache.calcite.util.IntList;
@@ -87,20 +89,33 @@ public class EnumerableUncollect extends Uncollect implements EnumerableRel {
final Expression child_ =
builder.append(
"child", result.block);
+
final List<Integer> fieldCounts = new ArrayList<>();
+ final List<FlatProductInputType> inputTypes = new ArrayList<>();
+
for (RelDataTypeField field : child.getRowType().getFieldList()) {
final RelDataType type = field.getType();
- final RelDataType elementType = type.getComponentType();
- if (elementType.isStruct()) {
- fieldCounts.add(elementType.getFieldCount());
+ if (type instanceof MapSqlType) {
+ fieldCounts.add(2);
+ inputTypes.add(FlatProductInputType.MAP);
} else {
- fieldCounts.add(-1);
+ final RelDataType elementType = type.getComponentType();
+ if (elementType.isStruct()) {
+ fieldCounts.add(elementType.getFieldCount());
+ inputTypes.add(FlatProductInputType.LIST);
+ } else {
+ fieldCounts.add(-1);
+ inputTypes.add(FlatProductInputType.SCALAR);
+ }
}
}
+
final Expression lambda =
Expressions.call(BuiltInMethod.FLAT_PRODUCT.method,
Expressions.constant(IntList.toArray(fieldCounts)),
- Expressions.constant(withOrdinality));
+ Expressions.constant(withOrdinality),
+ Expressions.constant(
+ inputTypes.toArray(new FlatProductInputType[inputTypes.size()])));
builder.add(
Expressions.return_(null,
Expressions.call(child_,
@@ -108,6 +123,8 @@ public class EnumerableUncollect extends Uncollect implements EnumerableRel {
lambda)));
return implementor.result(physType, builder.toBlock());
}
+
}
+
// End EnumerableUncollect.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/d757201f/core/src/main/java/org/apache/calcite/rel/core/Uncollect.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/core/Uncollect.java b/core/src/main/java/org/apache/calcite/rel/core/Uncollect.java
index 2d46929..d391f93 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/Uncollect.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/Uncollect.java
@@ -28,6 +28,7 @@ import org.apache.calcite.rel.type.RelDataTypeFactory;
import org.apache.calcite.rel.type.RelDataTypeField;
import org.apache.calcite.sql.SqlUnnestOperator;
import org.apache.calcite.sql.SqlUtil;
+import org.apache.calcite.sql.type.MapSqlType;
import org.apache.calcite.sql.type.SqlTypeName;
import java.util.List;
@@ -125,14 +126,19 @@ public class Uncollect extends SingleRel {
final RelDataTypeFactory.FieldInfoBuilder builder =
rel.getCluster().getTypeFactory().builder();
for (RelDataTypeField field : fields) {
- RelDataType ret = field.getType().getComponentType();
- assert null != ret;
- if (ret.isStruct()) {
- builder.addAll(ret.getFieldList());
+ if (field.getType() instanceof MapSqlType) {
+ builder.add(SqlUnnestOperator.MAP_KEY_COLUMN_NAME, field.getType().getKeyType());
+ builder.add(SqlUnnestOperator.MAP_VALUE_COLUMN_NAME, field.getType().getValueType());
} else {
- // Element type is not a record. It may be a scalar type, say
- // "INTEGER". Wrap it in a struct type.
- builder.add(SqlUtil.deriveAliasFromOrdinal(field.getIndex()), ret);
+ RelDataType ret = field.getType().getComponentType();
+ assert null != ret;
+ if (ret.isStruct()) {
+ builder.addAll(ret.getFieldList());
+ } else {
+ // Element type is not a record. It may be a scalar type, say
+ // "INTEGER". Wrap it in a struct type.
+ builder.add(SqlUtil.deriveAliasFromOrdinal(field.getIndex()), ret);
+ }
}
}
if (withOrdinality) {
http://git-wip-us.apache.org/repos/asf/calcite/blob/d757201f/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
----------------------------------------------------------------------
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 7e2d84d..e8da557 100644
--- a/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
+++ b/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
@@ -29,6 +29,7 @@ import org.apache.calcite.linq4j.function.Deterministic;
import org.apache.calcite.linq4j.function.Function1;
import org.apache.calcite.linq4j.function.NonDeterministic;
import org.apache.calcite.linq4j.tree.Primitive;
+import org.apache.calcite.runtime.FlatLists.ComparableList;
import java.math.BigDecimal;
import java.math.BigInteger;
@@ -42,6 +43,7 @@ import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.TimeZone;
import java.util.concurrent.atomic.AtomicLong;
import java.util.regex.Pattern;
@@ -1489,52 +1491,78 @@ public class SqlFunctions {
}
}
- public static <E extends Comparable>
- Function1<Object, Enumerable<FlatLists.ComparableList<E>>>
- flatProduct(final int[] fieldCounts, final boolean withOrdinality) {
+ public static Function1<Object, Enumerable<ComparableList<Comparable>>>
+ flatProduct(final int[] fieldCounts, final boolean withOrdinality,
+ final FlatProductInputType[] inputTypes) {
if (fieldCounts.length == 1) {
- if (!withOrdinality) {
+ if (!withOrdinality && inputTypes[0] == FlatProductInputType.SCALAR) {
//noinspection unchecked
return (Function1) LIST_AS_ENUMERABLE;
} else {
- return new Function1<Object, Enumerable<FlatLists.ComparableList<E>>>() {
- public Enumerable<FlatLists.ComparableList<E>> apply(Object row) {
- return p2(new Object[] {row}, fieldCounts, true);
+ return new Function1<Object, Enumerable<ComparableList<Comparable>>>() {
+ public Enumerable<ComparableList<Comparable>> apply(Object row) {
+ return p2(new Object[] { row }, fieldCounts, withOrdinality,
+ inputTypes);
}
};
}
}
- return new Function1<Object, Enumerable<FlatLists.ComparableList<E>>>() {
- public Enumerable<FlatLists.ComparableList<E>> apply(Object lists) {
- return p2((Object[]) lists, fieldCounts, withOrdinality);
+ return new Function1<Object, Enumerable<FlatLists.ComparableList<Comparable>>>() {
+ public Enumerable<FlatLists.ComparableList<Comparable>> apply(Object lists) {
+ return p2((Object[]) lists, fieldCounts, withOrdinality,
+ inputTypes);
}
};
}
- private static <E extends Comparable>
- Enumerable<FlatLists.ComparableList<E>> p2(Object[] lists, int[] fieldCounts,
- boolean withOrdinality) {
- final List<Enumerator<List<E>>> enumerators = new ArrayList<>();
+ private static Enumerable<FlatLists.ComparableList<Comparable>>
+ p2(Object[] lists, int[] fieldCounts, boolean withOrdinality,
+ FlatProductInputType[] inputTypes) {
+ final List<Enumerator<List<Comparable>>> enumerators = new ArrayList<>();
int totalFieldCount = 0;
for (int i = 0; i < lists.length; i++) {
int fieldCount = fieldCounts[i];
- if (fieldCount < 0) {
- ++totalFieldCount;
- @SuppressWarnings("unchecked")
- List<E> list = (List<E>) lists[i];
+ FlatProductInputType inputType = inputTypes[i];
+ Object inputObject = lists[i];
+ switch (inputType) {
+ case SCALAR:
+ @SuppressWarnings("unchecked") List<Comparable> list =
+ (List<Comparable>) inputObject;
enumerators.add(
Linq4j.transform(
Linq4j.enumerator(list),
- new Function1<E, List<E>>() {
- public List<E> apply(E a0) {
+ new Function1<Comparable, List<Comparable>>() {
+ public List<Comparable> apply(Comparable a0) {
return FlatLists.of(a0);
}
}));
+ break;
+ case LIST:
+ @SuppressWarnings("unchecked") List<List<Comparable>> listList =
+ (List<List<Comparable>>) inputObject;
+ enumerators.add(Linq4j.enumerator(listList));
+ break;
+ case MAP:
+ @SuppressWarnings("unchecked") Map<Comparable, Comparable> map =
+ (Map<Comparable, Comparable>) inputObject;
+ Enumerator<Entry<Comparable, Comparable>> enumerator =
+ Linq4j.enumerator(map.entrySet());
+
+ Enumerator<List<Comparable>> transformed = Linq4j.transform(enumerator,
+ new Function1<Entry<Comparable, Comparable>, List<Comparable>>() {
+ public List<Comparable> apply(Entry<Comparable, Comparable> entry) {
+ return FlatLists.<Comparable>of(entry.getKey(), entry.getValue());
+ }
+ });
+ enumerators.add(transformed);
+ break;
+ default:
+ break;
+ }
+ if (fieldCount < 0) {
+ ++totalFieldCount;
} else {
totalFieldCount += fieldCount;
- @SuppressWarnings("unchecked")
- List<List<E>> list = (List<List<E>>) lists[i];
- enumerators.add(Linq4j.enumerator(list));
}
}
if (withOrdinality) {
@@ -1592,6 +1620,12 @@ public class SqlFunctions {
return FlatLists.ofComparable(list);
}
}
+
+ /** Type of argument passed into {@link #flatProduct}. */
+ public enum FlatProductInputType {
+ SCALAR, LIST, MAP
+ }
+
}
// End SqlFunctions.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/d757201f/core/src/main/java/org/apache/calcite/sql/SqlUnnestOperator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlUnnestOperator.java b/core/src/main/java/org/apache/calcite/sql/SqlUnnestOperator.java
index b3d0a1b..7d32fe6 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlUnnestOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlUnnestOperator.java
@@ -16,15 +16,18 @@
*/
package org.apache.calcite.sql;
+
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeFactory;
import org.apache.calcite.sql.type.ArraySqlType;
+import org.apache.calcite.sql.type.MapSqlType;
import org.apache.calcite.sql.type.MultisetSqlType;
import org.apache.calcite.sql.type.OperandTypes;
import org.apache.calcite.sql.type.SqlOperandCountRanges;
import org.apache.calcite.sql.type.SqlTypeName;
import org.apache.calcite.util.Util;
+
/**
* The <code>UNNEST</code> operator.
*/
@@ -36,6 +39,10 @@ public class SqlUnnestOperator extends SqlFunctionalOperator {
public static final String ORDINALITY_COLUMN_NAME = "ORDINALITY";
+ public static final String MAP_KEY_COLUMN_NAME = "KEY";
+
+ public static final String MAP_VALUE_COLUMN_NAME = "VALUE";
+
//~ Constructors -----------------------------------------------------------
public SqlUnnestOperator(boolean withOrdinality) {
@@ -47,7 +54,7 @@ public class SqlUnnestOperator extends SqlFunctionalOperator {
null,
null,
OperandTypes.repeat(SqlOperandCountRanges.from(1),
- OperandTypes.SCALAR_OR_RECORD_COLLECTION));
+ OperandTypes.SCALAR_OR_RECORD_COLLECTION_OR_MAP));
this.withOrdinality = withOrdinality;
}
@@ -61,12 +68,18 @@ public class SqlUnnestOperator extends SqlFunctionalOperator {
if (type.isStruct()) {
type = type.getFieldList().get(0).getType();
}
- assert type instanceof ArraySqlType || type instanceof MultisetSqlType;
- if (type.getComponentType().isStruct()) {
- builder.addAll(type.getComponentType().getFieldList());
+ assert type instanceof ArraySqlType || type instanceof MultisetSqlType
+ || type instanceof MapSqlType;
+ if (type instanceof MapSqlType) {
+ builder.add(MAP_KEY_COLUMN_NAME, type.getKeyType());
+ builder.add(MAP_VALUE_COLUMN_NAME, type.getValueType());
} else {
- builder.add(SqlUtil.deriveAliasFromOrdinal(operand),
- type.getComponentType());
+ if (type.getComponentType().isStruct()) {
+ builder.addAll(type.getComponentType().getFieldList());
+ } else {
+ builder.add(SqlUtil.deriveAliasFromOrdinal(operand),
+ type.getComponentType());
+ }
}
}
if (withOrdinality) {
@@ -86,6 +99,7 @@ public class SqlUnnestOperator extends SqlFunctionalOperator {
public boolean argumentMustBeScalar(int ordinal) {
return false;
}
+
}
// End SqlUnnestOperator.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/d757201f/core/src/main/java/org/apache/calcite/sql/type/OperandTypes.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/type/OperandTypes.java b/core/src/main/java/org/apache/calcite/sql/type/OperandTypes.java
index 1d43ba0..f101ee9 100644
--- a/core/src/main/java/org/apache/calcite/sql/type/OperandTypes.java
+++ b/core/src/main/java/org/apache/calcite/sql/type/OperandTypes.java
@@ -529,6 +529,9 @@ public abstract class OperandTypes {
public static final SqlSingleOperandTypeChecker SCALAR_OR_RECORD_COLLECTION =
OperandTypes.or(COLLECTION, RECORD_COLLECTION);
+ public static final SqlSingleOperandTypeChecker SCALAR_OR_RECORD_COLLECTION_OR_MAP =
+ OperandTypes.or(COLLECTION_OR_MAP, RECORD_COLLECTION);
+
public static final SqlOperandTypeChecker MULTISET_MULTISET =
new MultisetOperandTypeChecker();
http://git-wip-us.apache.org/repos/asf/calcite/blob/d757201f/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java b/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
index 53f7880..6a17843 100644
--- a/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
+++ b/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
@@ -43,9 +43,24 @@ import org.apache.calcite.linq4j.function.Predicate2;
import org.apache.calcite.linq4j.tree.FunctionExpression;
import org.apache.calcite.linq4j.tree.Primitive;
import org.apache.calcite.linq4j.tree.Types;
+import org.apache.calcite.rel.metadata.BuiltInMetadata.Collation;
+import org.apache.calcite.rel.metadata.BuiltInMetadata.ColumnOrigin;
+import org.apache.calcite.rel.metadata.BuiltInMetadata.ColumnUniqueness;
+import org.apache.calcite.rel.metadata.BuiltInMetadata.CumulativeCost;
+import org.apache.calcite.rel.metadata.BuiltInMetadata.DistinctRowCount;
+import org.apache.calcite.rel.metadata.BuiltInMetadata.Distribution;
+import org.apache.calcite.rel.metadata.BuiltInMetadata.ExplainVisibility;
+import org.apache.calcite.rel.metadata.BuiltInMetadata.MaxRowCount;
import org.apache.calcite.rel.metadata.BuiltInMetadata.Memory;
+import org.apache.calcite.rel.metadata.BuiltInMetadata.NonCumulativeCost;
import org.apache.calcite.rel.metadata.BuiltInMetadata.Parallelism;
+import org.apache.calcite.rel.metadata.BuiltInMetadata.PercentageOriginalRows;
+import org.apache.calcite.rel.metadata.BuiltInMetadata.PopulationSize;
+import org.apache.calcite.rel.metadata.BuiltInMetadata.Predicates;
+import org.apache.calcite.rel.metadata.BuiltInMetadata.RowCount;
+import org.apache.calcite.rel.metadata.BuiltInMetadata.Selectivity;
import org.apache.calcite.rel.metadata.BuiltInMetadata.Size;
+import org.apache.calcite.rel.metadata.BuiltInMetadata.UniqueKeys;
import org.apache.calcite.rel.metadata.Metadata;
import org.apache.calcite.rex.RexNode;
import org.apache.calcite.runtime.ArrayBindable;
@@ -56,6 +71,7 @@ import org.apache.calcite.runtime.FlatLists;
import org.apache.calcite.runtime.ResultSetEnumerable;
import org.apache.calcite.runtime.SortedMultiMap;
import org.apache.calcite.runtime.SqlFunctions;
+import org.apache.calcite.runtime.SqlFunctions.FlatProductInputType;
import org.apache.calcite.runtime.Utilities;
import org.apache.calcite.schema.FilterableTable;
import org.apache.calcite.schema.ModifiableTable;
@@ -85,23 +101,8 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.TimeZone;
-import javax.sql.DataSource;
-import static org.apache.calcite.rel.metadata.BuiltInMetadata.Collation;
-import static org.apache.calcite.rel.metadata.BuiltInMetadata.ColumnOrigin;
-import static org.apache.calcite.rel.metadata.BuiltInMetadata.ColumnUniqueness;
-import static org.apache.calcite.rel.metadata.BuiltInMetadata.CumulativeCost;
-import static org.apache.calcite.rel.metadata.BuiltInMetadata.DistinctRowCount;
-import static org.apache.calcite.rel.metadata.BuiltInMetadata.Distribution;
-import static org.apache.calcite.rel.metadata.BuiltInMetadata.ExplainVisibility;
-import static org.apache.calcite.rel.metadata.BuiltInMetadata.MaxRowCount;
-import static org.apache.calcite.rel.metadata.BuiltInMetadata.NonCumulativeCost;
-import static org.apache.calcite.rel.metadata.BuiltInMetadata.PercentageOriginalRows;
-import static org.apache.calcite.rel.metadata.BuiltInMetadata.PopulationSize;
-import static org.apache.calcite.rel.metadata.BuiltInMetadata.Predicates;
-import static org.apache.calcite.rel.metadata.BuiltInMetadata.RowCount;
-import static org.apache.calcite.rel.metadata.BuiltInMetadata.Selectivity;
-import static org.apache.calcite.rel.metadata.BuiltInMetadata.UniqueKeys;
+import javax.sql.DataSource;
/**
* Built-in methods.
@@ -177,7 +178,8 @@ public enum BuiltInMethod {
FUNCTION1_APPLY(Function1.class, "apply", Object.class),
ARRAYS_AS_LIST(Arrays.class, "asList", Object[].class),
ARRAY(SqlFunctions.class, "array", Object[].class),
- FLAT_PRODUCT(SqlFunctions.class, "flatProduct", int[].class, boolean.class),
+ FLAT_PRODUCT(SqlFunctions.class, "flatProduct", int[].class, boolean.class,
+ FlatProductInputType[].class),
LIST_N(FlatLists.class, "copyOf", Comparable[].class),
LIST2(FlatLists.class, "of", Object.class, Object.class),
LIST3(FlatLists.class, "of", Object.class, Object.class, Object.class),
http://git-wip-us.apache.org/repos/asf/calcite/blob/d757201f/core/src/test/java/org/apache/calcite/test/JdbcTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/JdbcTest.java b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
index 06a6854..bab74d6 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
@@ -52,6 +52,7 @@ import org.apache.calcite.rel.core.TableModify;
import org.apache.calcite.rel.logical.LogicalTableModify;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeFactory;
+import org.apache.calcite.runtime.FlatLists;
import org.apache.calcite.runtime.Hook;
import org.apache.calcite.runtime.SqlFunctions;
import org.apache.calcite.schema.ModifiableTable;
@@ -2286,6 +2287,50 @@ public class JdbcTest {
"name=Sales; EI=150; D=10; N=Sebastian; S=7000.0; C=null; I=2; O=5");
}
+ /** Test case for
+ * <a href="https://issues.apache.org/jira/browse/CALCITE-1250">[CALCITE-1250]
+ * UNNEST applied to MAP data type</a>. */
+ @Test public void testUnnestItemsInMap() throws SQLException {
+ Connection connection = DriverManager.getConnection("jdbc:calcite:");
+ final String sql = "select * from unnest(MAP['a', 1, 'b', 2]) as um(k, v)";
+ ResultSet resultSet = connection.createStatement().executeQuery(sql);
+ final String expected = "K=a; V=1\n"
+ + "K=b; V=2\n";
+ assertThat(CalciteAssert.toString(resultSet), is(expected));
+ connection.close();
+ }
+
+ @Test public void testUnnestItemsInMapWithOrdinality() throws SQLException {
+ Connection connection = DriverManager.getConnection("jdbc:calcite:");
+ final String sql = "select *\n"
+ + "from unnest(MAP['a', 1, 'b', 2]) with ordinality as um(k, v, i)";
+ ResultSet resultSet = connection.createStatement().executeQuery(sql);
+ final String expected = "K=a; V=1; I=1\n"
+ + "K=b; V=2; I=2\n";
+ assertThat(CalciteAssert.toString(resultSet), is(expected));
+ connection.close();
+ }
+
+ @Test public void testUnnestItemsInMapWithNoAliasAndAdditionalArgument()
+ throws SQLException {
+ Connection connection = DriverManager.getConnection("jdbc:calcite:");
+ final String sql =
+ "select * from unnest(MAP['a', 1, 'b', 2], array[5, 6, 7])";
+ ResultSet resultSet = connection.createStatement().executeQuery(sql);
+
+ List<String> map = FlatLists.of("KEY=a; VALUE=1", "KEY=b; VALUE=2");
+ List<String> array = FlatLists.of(" EXPR$1=5", " EXPR$1=6", " EXPR$1=7");
+
+ final StringBuilder b = new StringBuilder();
+ for (List<String> row : Linq4j.product(FlatLists.of(map, array))) {
+ b.append(row.get(0)).append(";").append(row.get(1)).append("\n");
+ }
+ final String expected = b.toString();
+
+ assertThat(CalciteAssert.toString(resultSet), is(expected));
+ connection.close();
+ }
+
private CalciteAssert.AssertQuery withFoodMartQuery(int id)
throws IOException {
final FoodmartTest.FoodMartQuerySet set =
http://git-wip-us.apache.org/repos/asf/calcite/blob/d757201f/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
index 4a29961..c05dab3 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
@@ -6700,6 +6700,11 @@ public class SqlValidatorTest extends SqlValidatorTestCase {
"Column 'ORDINALITY' not found in any table");
}
+ @Test public void unnestMapMustNameColumnsKeyAndValueWhenNotAliased() {
+ checkResultType("select * from unnest(map[1, 12, 2, 22])",
+ "RecordType(INTEGER NOT NULL KEY, INTEGER NOT NULL VALUE) NOT NULL");
+ }
+
@Test public void testCorrelationJoin() {
check("select *,"
+ " multiset(select * from emp where deptno=dept.deptno) "