Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions core/src/main/codegen/templates/Parser.jj
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ import org.apache.calcite.sql.SqlKind;
import org.apache.calcite.sql.SqlLiteral;
import org.apache.calcite.sql.SqlMatchRecognize;
import org.apache.calcite.sql.SqlMerge;
import org.apache.calcite.sql.SqlMapTypeNameSpec;
import org.apache.calcite.sql.SqlNode;
import org.apache.calcite.sql.SqlNodeList;
import org.apache.calcite.sql.SqlNumericLiteral;
Expand Down Expand Up @@ -5689,6 +5690,9 @@ SqlTypeNameSpec TypeName() :
typeNameSpec = SqlTypeName(s)
|
typeNameSpec = RowTypeName()
|
LOOKAHEAD(2)
typeNameSpec = MapTypeName()
|
typeName = CompoundIdentifier() {
typeNameSpec = new SqlUserDefinedTypeNameSpec(typeName, s.end(this));
Expand Down Expand Up @@ -5962,6 +5966,23 @@ SqlTypeNameSpec RowTypeName() :
}
}

SqlTypeNameSpec MapTypeName() :
{
SqlDataTypeSpec keyType = null;
SqlDataTypeSpec valType = null;
}
{
<MAP>
<LT>
keyType = DataType()
<COMMA>
valType = DataType()
<GT>
{
return new SqlMapTypeNameSpec(keyType, valType, getPos());
}
}

/**
* Parse character types: char, varchar.
*/
Expand Down
94 changes: 94 additions & 0 deletions core/src/main/java/org/apache/calcite/sql/SqlMapTypeNameSpec.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to you under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.calcite.sql;

import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.sql.parser.SqlParserPos;
import org.apache.calcite.sql.type.SqlTypeName;
import org.apache.calcite.sql.validate.SqlValidator;
import org.apache.calcite.util.Litmus;

/**
* Parse SQL MAP type, i.e. MAP&lt;INT NOT NULL, TIMESTAMP NULL&gt;, the key and value can specify a
* suffix to indicate if the type is nullable, default is not null.
*
* <p>MAP type does not belong to standard SQL.
*/
public class SqlMapTypeNameSpec extends SqlTypeNameSpec {

private final SqlDataTypeSpec keyType;
private final SqlDataTypeSpec valType;

/**
* Creates a {@code SqlMapTypeNameSpec}.
*
* @param keyType key type
* @param valType value type
* @param pos the parser position
*/
public SqlMapTypeNameSpec(SqlDataTypeSpec keyType, SqlDataTypeSpec valType, SqlParserPos pos) {
super(new SqlIdentifier(SqlTypeName.MAP.getName(), pos), pos);
this.keyType = keyType;
this.valType = valType;
}

public SqlDataTypeSpec getKeyType() {
return keyType;
}

public SqlDataTypeSpec getValType() {
return valType;
}

@Override public RelDataType deriveType(SqlValidator validator) {
return validator
.getTypeFactory()
.createMapType(keyType.deriveType(validator), valType.deriveType(validator));
}

@Override public void unparse(SqlWriter writer, int leftPrec, int rightPrec) {
writer.keyword("MAP");
SqlWriter.Frame frame = writer.startList(SqlWriter.FrameTypeEnum.FUN_CALL, "<", ">");
writer.sep(","); // configures the writer
keyType.unparse(writer, leftPrec, rightPrec);
// Default is not null.
if (Boolean.TRUE.equals(keyType.getNullable())) {
writer.keyword("NULL");
}
writer.sep(",");
valType.unparse(writer, leftPrec, rightPrec);
// Default is not null.
if (Boolean.TRUE.equals(valType.getNullable())) {
writer.keyword("NULL");
}
writer.endList(frame);
}

@Override public boolean equalsDeep(SqlTypeNameSpec spec, Litmus litmus) {
if (!(spec instanceof SqlMapTypeNameSpec)) {
return litmus.fail("{} != {}", this, spec);
}
SqlMapTypeNameSpec that = (SqlMapTypeNameSpec) spec;
if (!this.keyType.equalsDeep(that.keyType, litmus)) {
return litmus.fail("{} != {}", this, spec);
}
if (!this.valType.equalsDeep(that.valType, litmus)) {
return litmus.fail("{} != {}", this, spec);
}
return litmus.succeed();
}
}
20 changes: 20 additions & 0 deletions core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -7127,6 +7127,26 @@ void testGroupExpressionEquivalenceParams() {
.fails("Unknown identifier 'MYUDT'");
}

/**
* Test case for
* <a href="https://issues.apache.org/jira/browse/CALCITE-5570">[CALCITE-5570]
* Support nested map type for SqlDataTypeSpec</a>.
*/
@Test void testCastMapType() {
sql("select cast(\"int2IntMapType\" as map<int,int>) from COMPLEXTYPES.CTC_T1")
.withExtendedCatalog()
.columnType("(INTEGER NOT NULL, INTEGER NOT NULL) MAP NOT NULL");
sql("select cast(\"int2varcharArrayMapType\" as map<int,varchar array>) "
+ "from COMPLEXTYPES.CTC_T1")
.withExtendedCatalog()
.columnType("(INTEGER NOT NULL, VARCHAR NOT NULL ARRAY NOT NULL) MAP NOT NULL");
sql("select cast(\"varcharMultiset2IntIntMapType\" as map<varchar(5) multiset, map<int, int>>)"
+ " from COMPLEXTYPES.CTC_T1")
.withExtendedCatalog()
.columnType("(VARCHAR(5) NOT NULL MULTISET NOT NULL, "
+ "(INTEGER NOT NULL, INTEGER NOT NULL) MAP NOT NULL) MAP NOT NULL");
}

@Test void testCastAsRowType() {
sql("select cast(a as row(f0 int, f1 varchar)) from COMPLEXTYPES.CTC_T1")
.withExtendedCatalog()
Expand Down
19 changes: 19 additions & 0 deletions core/src/test/resources/sql/misc.iq
Original file line number Diff line number Diff line change
Expand Up @@ -2543,4 +2543,23 @@ select decimal'12.3' + 5.6;

!ok

# [CALCITE-5570] Support nested map type for SqlDataTypeSpec
SELECT
cast(x as map<int, int>),
cast(y as map<int, varchar array>),
cast(z as map<varchar multiset, map<int, int>>)
FROM (
SELECT
map[1, 2, 3, 4] as x,
map[1, array['a', 'b'], 2, array['c', 'd']] as y,
map[multiset['A'], map[1,2], multiset['B'], map[3, 4]] as z
);
+------------+----------------------+------------------------+
| EXPR$0 | EXPR$1 | EXPR$2 |
+------------+----------------------+------------------------+
| {1=2, 3=4} | {1=[a, b], 2=[c, d]} | {[A]={1=2}, [B]={3=4}} |
+------------+----------------------+------------------------+
(1 row)

!ok
# End misc.iq
Original file line number Diff line number Diff line change
Expand Up @@ -6079,6 +6079,20 @@ private static Matcher<SqlNode> isCharLiteral(String s) {
.ok("CAST(`A` AS ROW(`F0` VARCHAR, `F1` TIMESTAMP NULL) MULTISET)");
}

/**
* Test case for
* <a href="https://issues.apache.org/jira/browse/CALCITE-5570">[CALCITE-5570]
* Support nested map type for SqlDataTypeSpec</a>.
*/
@Test void testCastAsMapType() {
expr("cast(a as map<int, int>)")
.ok("CAST(`A` AS MAP< INTEGER, INTEGER >)");
expr("cast(a as map<int, varchar array>)")
.ok("CAST(`A` AS MAP< INTEGER, VARCHAR ARRAY >)");
expr("cast(a as map<varchar multiset, map<int, int>>)")
.ok("CAST(`A` AS MAP< VARCHAR MULTISET, MAP< INTEGER, INTEGER > >)");
}

@Test void testMapValueConstructor() {
expr("map[1, 'x', 2, 'y']")
.ok("(MAP[1, 'x', 2, 'y'])");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,12 @@ final class Fixture extends AbstractFixture {
Arrays.asList(intArrayMultisetType, varchar5ArrayType),
Arrays.asList("f0", "f1"))),
-1);
final RelDataType int2IntMapType =
typeFactory.createMapType(intType, intType);
final RelDataType int2varcharArrayMapType =
typeFactory.createMapType(intType, array(varcharType));
final RelDataType varcharMultiset2IntIntMapType =
typeFactory.createMapType(varchar5MultisetType, int2IntMapType);

Fixture(RelDataTypeFactory typeFactory) {
super(typeFactory);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,11 @@ protected MockCatalogReaderExtended(RelDataTypeFactory typeFactory,
f.varchar5MultisetArrayType);
complexTypeColumnsTable.addColumn("intArrayMultisetType", f.intArrayMultisetType);
complexTypeColumnsTable.addColumn("rowArrayMultisetType", f.rowArrayMultisetType);
complexTypeColumnsTable.addColumn("int2IntMapType", f.int2IntMapType);
complexTypeColumnsTable.addColumn("int2varcharArrayMapType",
f.int2varcharArrayMapType);
complexTypeColumnsTable.addColumn("varcharMultiset2IntIntMapType",
f.varcharMultiset2IntIntMapType);
registerTable(complexTypeColumnsTable);

MockSchema nullableRowsSchema = new MockSchema("NULLABLEROWS");
Expand Down