com.hazelcast.org.apache.calcite.sql.SqlDataTypeSpec 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 com.hazelcast.com.liance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.com.hazelcast.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.util.SqlVisitor;
import com.hazelcast.org.apache.calcite.sql.validate.SqlMonotonicity;
import com.hazelcast.org.apache.calcite.sql.validate.SqlValidator;
import com.hazelcast.org.apache.calcite.sql.validate.SqlValidatorScope;
import com.hazelcast.org.apache.calcite.util.Litmus;
import java.util.Objects;
import java.util.TimeZone;
/**
* Represents a SQL data type specification in a parse tree.
*
* A SqlDataTypeSpec
is immutable; once created, you cannot
* change any of the fields.
*
* We support the following data type expressions:
*
*
* - Complex data type expression like:
*
ROW(
* foo NUMBER(5, 2) NOT NULL,
* rec ROW(b BOOLEAN, i MyUDT NOT NULL))
* Internally we use {@link SqlRowTypeNameSpec} to specify row data type name.
*
* - Simple data type expression like CHAR, VARCHAR and DOUBLE
* with optional precision and scale;
* Internally we use {@link SqlBasicTypeNameSpec} to specify basic sql data type name.
*
* - Collection data type expression like:
*
* INT ARRAY;
* VARCHAR(20) MULTISET;
* INT ARRAY MULTISET;
* Internally we use {@link SqlCollectionTypeNameSpec} to specify collection data type name.
*
* - User defined data type expression like `My_UDT`;
* Internally we use {@link SqlUserDefinedTypeNameSpec} to specify user defined data type name.
*
*
*/
public class SqlDataTypeSpec extends SqlNode {
//~ Instance fields --------------------------------------------------------
private final SqlTypeNameSpec typeNameSpec;
private final TimeZone timeZone;
/** Whether data type allows nulls.
*
* Nullable is nullable! Null means "not specified". E.g.
* {@code CAST(x AS INTEGER)} preserves the same nullability as {@code x}.
*/
private Boolean nullable;
//~ Constructors -----------------------------------------------------------
/**
* Creates a type specification representing a type.
*
* @param typeNameSpec The type name can be basic sql type, row type,
* collections type and user defined type
*/
public SqlDataTypeSpec(
final SqlTypeNameSpec typeNameSpec,
SqlParserPos pos) {
this(typeNameSpec, null, null, pos);
}
/**
* Creates a type specification representing a type, with time zone specified.
*
* @param typeNameSpec The type name can be basic sql type, row type,
* collections type and user defined type
* @param timeZone Specified time zone
*/
public SqlDataTypeSpec(
final SqlTypeNameSpec typeNameSpec,
TimeZone timeZone,
SqlParserPos pos) {
this(typeNameSpec, timeZone, null, pos);
}
/**
* Creates a type specification representing a type, with time zone,
* nullability and base type name specified.
*
* @param typeNameSpec The type name can be basic sql type, row type,
* collections type and user defined type
* @param timeZone Specified time zone
* @param nullable The nullability
*/
public SqlDataTypeSpec(
SqlTypeNameSpec typeNameSpec,
TimeZone timeZone,
Boolean nullable,
SqlParserPos pos) {
super(pos);
this.typeNameSpec = typeNameSpec;
this.timeZone = timeZone;
this.nullable = nullable;
}
//~ Methods ----------------------------------------------------------------
public SqlNode clone(SqlParserPos pos) {
return new SqlDataTypeSpec(typeNameSpec, timeZone, pos);
}
public SqlMonotonicity getMonotonicity(SqlValidatorScope scope) {
return SqlMonotonicity.CONSTANT;
}
public SqlIdentifier getCollectionsTypeName() {
if (typeNameSpec instanceof SqlCollectionTypeNameSpec) {
return typeNameSpec.getTypeName();
}
return null;
}
public SqlIdentifier getTypeName() {
return typeNameSpec.getTypeName();
}
public SqlTypeNameSpec getTypeNameSpec() {
return typeNameSpec;
}
public TimeZone getTimeZone() {
return timeZone;
}
public Boolean getNullable() {
return nullable;
}
/** Returns a copy of this data type specification with a given
* nullability. */
public SqlDataTypeSpec withNullable(Boolean nullable) {
if (Objects.equals(nullable, this.nullable)) {
return this;
}
return new SqlDataTypeSpec(typeNameSpec, timeZone, nullable, getParserPosition());
}
/**
* Returns a new SqlDataTypeSpec corresponding to the com.hazelcast.com.onent type if the
* type spec is a collections type spec.
* Collection types are ARRAY
and MULTISET
.
*/
public SqlDataTypeSpec getComponentTypeSpec() {
assert typeNameSpec instanceof SqlCollectionTypeNameSpec;
SqlTypeNameSpec elementTypeName =
((SqlCollectionTypeNameSpec) typeNameSpec).getElementTypeName();
return new SqlDataTypeSpec(elementTypeName, timeZone, getParserPosition());
}
public void unparse(SqlWriter writer, int leftPrec, int rightPrec) {
typeNameSpec.unparse(writer, leftPrec, rightPrec);
}
public void validate(SqlValidator validator, SqlValidatorScope scope) {
validator.validateDataType(this);
}
public R accept(SqlVisitor visitor) {
return visitor.visit(this);
}
public boolean equalsDeep(SqlNode node, Litmus litmus) {
if (!(node instanceof SqlDataTypeSpec)) {
return litmus.fail("{} != {}", this, node);
}
SqlDataTypeSpec that = (SqlDataTypeSpec) node;
if (!Objects.equals(this.timeZone, that.timeZone)) {
return litmus.fail("{} != {}", this, node);
}
if (!this.typeNameSpec.equalsDeep(that.typeNameSpec, litmus)) {
return litmus.fail(null);
}
return litmus.succeed();
}
/**
* Converts this type specification to a {@link RelDataType}.
*
* Throws an error if the type is not found.
*/
public RelDataType deriveType(SqlValidator validator) {
return deriveType(validator, false);
}
/**
* Converts this type specification to a {@link RelDataType}.
*
*
Throws an error if the type is not found.
*
* @param nullable Whether the type is nullable if the type specification
* does not explicitly state
*/
public RelDataType deriveType(SqlValidator validator, boolean nullable) {
RelDataType type;
type = typeNameSpec.deriveType(validator);
// Fix-up the nullability, default is false.
final RelDataTypeFactory typeFactory = validator.getTypeFactory();
type = fixUpNullability(typeFactory, type, nullable);
return type;
}
//~ Tools ------------------------------------------------------------------
/**
* Fix up the nullability of the {@code type}.
*
* @param typeFactory Type factory
* @param type The type to coerce nullability
* @param nullable Default nullability to use if this type specification does not
* specify nullability
* @return Type with specified nullability or the default(false)
*/
private RelDataType fixUpNullability(RelDataTypeFactory typeFactory,
RelDataType type, boolean nullable) {
if (this.nullable != null) {
nullable = this.nullable;
}
return typeFactory.createTypeWithNullability(type, nullable);
}
}