blob: da87c5166ce42760e1e4f4225a8d8ffa972e941e [file] [log] [blame]
/*
* 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.type;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypePrecedenceList;
import org.apache.calcite.util.Glossary;
import org.apache.calcite.util.ImmutableNullableList;
import org.apache.calcite.util.Util;
import com.google.common.collect.ImmutableMap;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
/**
* SqlTypeExplicitPrecedenceList implements the
* {@link RelDataTypePrecedenceList} interface via an explicit list of
* {@link SqlTypeName} entries.
*/
public class SqlTypeExplicitPrecedenceList
implements RelDataTypePrecedenceList {
//~ Static fields/initializers ---------------------------------------------
private static final List<SqlTypeName> NUMERIC_TYPES =
ImmutableNullableList.of(
SqlTypeName.TINYINT,
SqlTypeName.SMALLINT,
SqlTypeName.INTEGER,
SqlTypeName.BIGINT,
SqlTypeName.DECIMAL,
SqlTypeName.REAL,
SqlTypeName.FLOAT,
SqlTypeName.DOUBLE);
/**
* Map from SqlTypeName to corresponding precedence list.
*
* @see Glossary#SQL2003 SQL:2003 Part 2 Section 9.5
*/
private static final Map<SqlTypeName, SqlTypeExplicitPrecedenceList>
TYPE_NAME_TO_PRECEDENCE_LIST =
ImmutableMap.<SqlTypeName, SqlTypeExplicitPrecedenceList>builder()
.put(SqlTypeName.BOOLEAN, list(SqlTypeName.BOOLEAN))
.put(SqlTypeName.TINYINT, numeric(SqlTypeName.TINYINT))
.put(SqlTypeName.SMALLINT, numeric(SqlTypeName.SMALLINT))
.put(SqlTypeName.INTEGER, numeric(SqlTypeName.INTEGER))
.put(SqlTypeName.BIGINT, numeric(SqlTypeName.BIGINT))
.put(SqlTypeName.DECIMAL, numeric(SqlTypeName.DECIMAL))
.put(SqlTypeName.REAL, numeric(SqlTypeName.REAL))
.put(
SqlTypeName.FLOAT, list(
SqlTypeName.FLOAT, SqlTypeName.REAL,
SqlTypeName.DOUBLE, SqlTypeName.DECIMAL))
.put(
SqlTypeName.DOUBLE, list(
SqlTypeName.FLOAT, SqlTypeName.REAL,
SqlTypeName.DOUBLE, SqlTypeName.DECIMAL))
.put(SqlTypeName.CHAR, list(SqlTypeName.CHAR, SqlTypeName.VARCHAR))
.put(SqlTypeName.VARCHAR, list(SqlTypeName.VARCHAR))
.put(SqlTypeName.BINARY,
list(SqlTypeName.BINARY, SqlTypeName.VARBINARY))
.put(SqlTypeName.VARBINARY, list(SqlTypeName.VARBINARY))
.put(SqlTypeName.DATE, list(SqlTypeName.DATE))
.put(SqlTypeName.TIME, list(SqlTypeName.TIME))
.put(SqlTypeName.TIMESTAMP,
list(SqlTypeName.TIMESTAMP, SqlTypeName.DATE, SqlTypeName.TIME))
.put(SqlTypeName.INTERVAL_YEAR,
list(SqlTypeName.YEAR_INTERVAL_TYPES))
.put(SqlTypeName.INTERVAL_YEAR_MONTH,
list(SqlTypeName.YEAR_INTERVAL_TYPES))
.put(SqlTypeName.INTERVAL_MONTH,
list(SqlTypeName.YEAR_INTERVAL_TYPES))
.put(SqlTypeName.INTERVAL_DAY,
list(SqlTypeName.DAY_INTERVAL_TYPES))
.put(SqlTypeName.INTERVAL_DAY_HOUR,
list(SqlTypeName.DAY_INTERVAL_TYPES))
.put(SqlTypeName.INTERVAL_DAY_MINUTE,
list(SqlTypeName.DAY_INTERVAL_TYPES))
.put(SqlTypeName.INTERVAL_DAY_SECOND,
list(SqlTypeName.DAY_INTERVAL_TYPES))
.put(SqlTypeName.INTERVAL_HOUR,
list(SqlTypeName.DAY_INTERVAL_TYPES))
.put(SqlTypeName.INTERVAL_HOUR_MINUTE,
list(SqlTypeName.DAY_INTERVAL_TYPES))
.put(SqlTypeName.INTERVAL_HOUR_SECOND,
list(SqlTypeName.DAY_INTERVAL_TYPES))
.put(SqlTypeName.INTERVAL_MINUTE,
list(SqlTypeName.DAY_INTERVAL_TYPES))
.put(SqlTypeName.INTERVAL_MINUTE_SECOND,
list(SqlTypeName.DAY_INTERVAL_TYPES))
.put(SqlTypeName.INTERVAL_SECOND,
list(SqlTypeName.DAY_INTERVAL_TYPES))
.build();
//~ Instance fields --------------------------------------------------------
private final List<SqlTypeName> typeNames;
//~ Constructors -----------------------------------------------------------
public SqlTypeExplicitPrecedenceList(Iterable<SqlTypeName> typeNames) {
this.typeNames = ImmutableNullableList.copyOf(typeNames);
}
//~ Methods ----------------------------------------------------------------
private static SqlTypeExplicitPrecedenceList list(SqlTypeName... typeNames) {
return list(Arrays.asList(typeNames));
}
private static SqlTypeExplicitPrecedenceList list(Iterable<SqlTypeName> typeNames) {
return new SqlTypeExplicitPrecedenceList(typeNames);
}
private static SqlTypeExplicitPrecedenceList numeric(SqlTypeName typeName) {
int i = getListPosition(typeName, NUMERIC_TYPES);
return new SqlTypeExplicitPrecedenceList(
Util.skip(NUMERIC_TYPES, i));
}
// implement RelDataTypePrecedenceList
@Override public boolean containsType(RelDataType type) {
SqlTypeName typeName = type.getSqlTypeName();
return typeName != null && typeNames.contains(typeName);
}
// implement RelDataTypePrecedenceList
@Override public int compareTypePrecedence(RelDataType type1, RelDataType type2) {
assert containsType(type1) : type1;
assert containsType(type2) : type2;
int p1 =
getListPosition(
type1.getSqlTypeName(),
typeNames);
int p2 =
getListPosition(
type2.getSqlTypeName(),
typeNames);
return p2 - p1;
}
private static int getListPosition(SqlTypeName type, List<SqlTypeName> list) {
int i = list.indexOf(type);
assert i != -1;
return i;
}
static @Nullable RelDataTypePrecedenceList getListForType(RelDataType type) {
SqlTypeName typeName = type.getSqlTypeName();
if (typeName == null) {
return null;
}
return TYPE_NAME_TO_PRECEDENCE_LIST.get(typeName);
}
}