com.hazelcast.org.apache.calcite.sql.SqlRowTypeNameSpec Maven / Gradle / Ivy
/*
* 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 com.hazelcast.org.apache.calcite.sql;
import com.hazelcast.org.apache.calcite.rel.type.RelDataType;
import com.hazelcast.org.apache.calcite.rel.type.RelDataTypeFactory;
import com.hazelcast.org.apache.calcite.sql.parser.SqlParserPos;
import com.hazelcast.org.apache.calcite.sql.type.SqlTypeName;
import com.hazelcast.org.apache.calcite.sql.validate.SqlValidator;
import com.hazelcast.org.apache.calcite.util.Litmus;
import com.hazelcast.org.apache.calcite.util.Pair;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* A sql type name specification of row type.
*
* The grammar definition in SQL-2011 IWD 9075-2:201?(E)
* 6.1 <data type> is as following:
*
* <row type> ::=
* ROW <row type body>
* <row type body> ::=
* <left paren> <field definition>
* [ { <comma> <field definition> }... ]
* <right paren>
*
* <field definition> ::=
* <field name> <data type>
*
*
* As a extended syntax to the standard SQL, each field type can have a
* [ NULL | NOT NULL ] suffix specification, i.e.
* Row(f0 int null, f1 varchar not null). The default is NOT NULL(not nullable).
*/
public class SqlRowTypeNameSpec extends SqlTypeNameSpec {
private final List fieldNames;
private final List fieldTypes;
/**
* Creates a row type specification.
*
* @param pos The parser position
* @param fieldNames The field names
* @param fieldTypes The field data types
*/
public SqlRowTypeNameSpec(
SqlParserPos pos,
List fieldNames,
List fieldTypes) {
super(new SqlIdentifier(SqlTypeName.ROW.getName(), pos), pos);
Objects.requireNonNull(fieldNames);
Objects.requireNonNull(fieldTypes);
assert fieldNames.size() > 0; // there must be at least one field.
this.fieldNames = fieldNames;
this.fieldTypes = fieldTypes;
}
public List getFieldNames() {
return fieldNames;
}
public List getFieldTypes() {
return fieldTypes;
}
public int getArity() {
return fieldNames.size();
}
@Override public void unparse(SqlWriter writer, int leftPrec, int rightPrec) {
writer.print(getTypeName().getSimple());
SqlWriter.Frame frame = writer.startList(SqlWriter.FrameTypeEnum.FUN_CALL, "(", ")");
for (Pair p : Pair.zip(this.fieldNames, this.fieldTypes)) {
writer.sep(",", false);
p.left.unparse(writer, 0, 0);
p.right.unparse(writer, leftPrec, rightPrec);
if (p.right.getNullable() != null && p.right.getNullable()) {
// Row fields default is not nullable.
writer.print("NULL");
}
}
writer.endList(frame);
}
@Override public boolean equalsDeep(SqlTypeNameSpec node, Litmus litmus) {
if (!(node instanceof SqlRowTypeNameSpec)) {
return litmus.fail("{} != {}", this, node);
}
SqlRowTypeNameSpec that = (SqlRowTypeNameSpec) node;
if (this.fieldNames.size() != that.fieldNames.size()) {
return litmus.fail("{} != {}", this, node);
}
for (int i = 0; i < fieldNames.size(); i++) {
if (!this.fieldNames.get(i).equalsDeep(that.fieldNames.get(i), litmus)) {
return litmus.fail("{} != {}", this, node);
}
}
if (this.fieldTypes.size() != that.fieldTypes.size()) {
return litmus.fail("{} != {}", this, node);
}
for (int i = 0; i < fieldTypes.size(); i++) {
if (!this.fieldTypes.get(i).equals(that.fieldTypes.get(i))) {
return litmus.fail("{} != {}", this, node);
}
}
return litmus.succeed();
}
@Override public RelDataType deriveType(SqlValidator sqlValidator) {
final RelDataTypeFactory typeFactory = sqlValidator.getTypeFactory();
return typeFactory.createStructType(
fieldTypes.stream()
.map(dt -> dt.deriveType(sqlValidator))
.collect(Collectors.toList()),
fieldNames.stream()
.map(SqlIdentifier::toString)
.collect(Collectors.toList()));
}
}