com.hazelcast.org.apache.calcite.sql.type.ReturnTypes 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.type;
import com.hazelcast.org.apache.calcite.rel.type.RelDataType;
import com.hazelcast.org.apache.calcite.rel.type.RelDataTypeFactory;
import com.hazelcast.org.apache.calcite.rel.type.RelDataTypeField;
import com.hazelcast.org.apache.calcite.rel.type.RelDataTypeImpl;
import com.hazelcast.org.apache.calcite.rel.type.RelDataTypeSystem;
import com.hazelcast.org.apache.calcite.rel.type.RelProtoDataType;
import com.hazelcast.org.apache.calcite.sql.ExplicitOperatorBinding;
import com.hazelcast.org.apache.calcite.sql.SqlCallBinding;
import com.hazelcast.org.apache.calcite.sql.SqlCollation;
import com.hazelcast.org.apache.calcite.sql.SqlOperatorBinding;
import com.hazelcast.org.apache.calcite.sql.SqlUtil;
import com.hazelcast.org.apache.calcite.util.Glossary;
import com.hazelcast.com.google.common.base.Preconditions;
import java.util.AbstractList;
import java.util.List;
import static com.hazelcast.org.apache.calcite.util.Static.RESOURCE;
/**
* A collection of return-type inference strategies.
*/
public abstract class ReturnTypes {
private ReturnTypes() {
}
public static SqlReturnTypeInferenceChain chain(
SqlReturnTypeInference... rules) {
return new SqlReturnTypeInferenceChain(rules);
}
/** Creates a return-type inference that applies a rule then a sequence of
* transforms. */
public static SqlTypeTransformCascade cascade(SqlReturnTypeInference rule,
SqlTypeTransform... transforms) {
return new SqlTypeTransformCascade(rule, transforms);
}
public static ExplicitReturnTypeInference explicit(
RelProtoDataType protoType) {
return new ExplicitReturnTypeInference(protoType);
}
/**
* Creates an inference rule which returns a copy of a given data type.
*/
public static ExplicitReturnTypeInference explicit(RelDataType type) {
return explicit(RelDataTypeImpl.proto(type));
}
/**
* Creates an inference rule which returns a type with no precision or scale,
* such as {@code DATE}.
*/
public static ExplicitReturnTypeInference explicit(SqlTypeName typeName) {
return explicit(RelDataTypeImpl.proto(typeName, false));
}
/**
* Creates an inference rule which returns a type with precision but no scale,
* such as {@code VARCHAR(100)}.
*/
public static ExplicitReturnTypeInference explicit(SqlTypeName typeName,
int precision) {
return explicit(RelDataTypeImpl.proto(typeName, precision, false));
}
/**
* Type-inference strategy whereby the result type of a call is the type of
* the operand #0 (0-based).
*/
public static final SqlReturnTypeInference ARG0 =
new OrdinalReturnTypeInference(0);
/**
* Type-inference strategy whereby the result type of a call is VARYING the
* type of the first argument. The length returned is the same as length of
* the first argument. If any of the other operands are nullable the
* returned type will also be nullable. First Arg must be of string type.
*/
public static final SqlReturnTypeInference ARG0_NULLABLE_VARYING =
cascade(ARG0, SqlTypeTransforms.TO_NULLABLE,
SqlTypeTransforms.TO_VARYING);
/**
* Type-inference strategy whereby the result type of a call is the type of
* the operand #0 (0-based). If any of the other operands are nullable the
* returned type will also be nullable.
*/
public static final SqlReturnTypeInference ARG0_NULLABLE =
cascade(ARG0, SqlTypeTransforms.TO_NULLABLE);
/**
* Type-inference strategy whereby the result type of a call is the type of
* the operand #0 (0-based), with nulls always allowed.
*/
public static final SqlReturnTypeInference ARG0_FORCE_NULLABLE =
cascade(ARG0, SqlTypeTransforms.FORCE_NULLABLE);
public static final SqlReturnTypeInference ARG0_INTERVAL =
new MatchReturnTypeInference(0,
SqlTypeFamily.DATETIME_INTERVAL.getTypeNames());
public static final SqlReturnTypeInference ARG0_INTERVAL_NULLABLE =
cascade(ARG0_INTERVAL, SqlTypeTransforms.TO_NULLABLE);
/**
* Type-inference strategy whereby the result type of a call is the type of
* the operand #0 (0-based), and nullable if the call occurs within a
* "GROUP BY ()" query. E.g. in "select sum(1) as s from empty", s may be
* null.
*/
public static final SqlReturnTypeInference ARG0_NULLABLE_IF_EMPTY =
new OrdinalReturnTypeInference(0) {
@Override public RelDataType
inferReturnType(SqlOperatorBinding opBinding) {
final RelDataType type = super.inferReturnType(opBinding);
if (opBinding.getGroupCount() == 0 || opBinding.hasFilter()) {
return opBinding.getTypeFactory()
.createTypeWithNullability(type, true);
} else {
return type;
}
}
};
/**
* Type-inference strategy whereby the result type of a call is the type of
* the operand #1 (0-based).
*/
public static final SqlReturnTypeInference ARG1 =
new OrdinalReturnTypeInference(1);
/**
* Type-inference strategy whereby the result type of a call is the type of
* the operand #1 (0-based). If any of the other operands are nullable the
* returned type will also be nullable.
*/
public static final SqlReturnTypeInference ARG1_NULLABLE =
cascade(ARG1, SqlTypeTransforms.TO_NULLABLE);
/**
* Type-inference strategy whereby the result type of a call is the type of
* operand #2 (0-based).
*/
public static final SqlReturnTypeInference ARG2 =
new OrdinalReturnTypeInference(2);
/**
* Type-inference strategy whereby the result type of a call is the type of
* operand #2 (0-based). If any of the other operands are nullable the
* returned type will also be nullable.
*/
public static final SqlReturnTypeInference ARG2_NULLABLE =
cascade(ARG2, SqlTypeTransforms.TO_NULLABLE);
/**
* Type-inference strategy whereby the result type of a call is Boolean.
*/
public static final SqlReturnTypeInference BOOLEAN =
explicit(SqlTypeName.BOOLEAN);
/**
* Type-inference strategy whereby the result type of a call is Boolean,
* with nulls allowed if any of the operands allow nulls.
*/
public static final SqlReturnTypeInference BOOLEAN_NULLABLE =
cascade(BOOLEAN, SqlTypeTransforms.TO_NULLABLE);
/**
* Type-inference strategy with similar effect to {@link #BOOLEAN_NULLABLE},
* which is more efficient, but can only be used if all arguments are
* BOOLEAN.
*/
public static final SqlReturnTypeInference BOOLEAN_NULLABLE_OPTIMIZED =
opBinding -> {
// Equivalent to
// cascade(ARG0, SqlTypeTransforms.TO_NULLABLE);
// but implemented by hand because used in AND, which is a very common
// operator.
final int n = opBinding.getOperandCount();
RelDataType type1 = null;
for (int i = 0; i < n; i++) {
type1 = opBinding.getOperandType(i);
if (type1.isNullable()) {
break;
}
}
return type1;
};
/**
* Type-inference strategy whereby the result type of a call is a nullable
* Boolean.
*/
public static final SqlReturnTypeInference BOOLEAN_FORCE_NULLABLE =
cascade(BOOLEAN, SqlTypeTransforms.FORCE_NULLABLE);
/**
* Type-inference strategy whereby the result type of a call is Boolean
* not null.
*/
public static final SqlReturnTypeInference BOOLEAN_NOT_NULL =
cascade(BOOLEAN, SqlTypeTransforms.TO_NOT_NULLABLE);
/**
* Type-inference strategy whereby the result type of a call is Date.
*/
public static final SqlReturnTypeInference DATE =
explicit(SqlTypeName.DATE);
/**
* Type-inference strategy whereby the result type of a call is nullable
* Date.
*/
public static final SqlReturnTypeInference DATE_NULLABLE =
cascade(DATE, SqlTypeTransforms.TO_NULLABLE);
/**
* Type-inference strategy whereby the result type of a call is Time(0).
*/
public static final SqlReturnTypeInference TIME =
explicit(SqlTypeName.TIME, 0);
/**
* Type-inference strategy whereby the result type of a call is nullable
* Time(0).
*/
public static final SqlReturnTypeInference TIME_NULLABLE =
cascade(TIME, SqlTypeTransforms.TO_NULLABLE);
/**
* Type-inference strategy whereby the result type of a call is Double.
*/
public static final SqlReturnTypeInference DOUBLE =
explicit(SqlTypeName.DOUBLE);
/**
* Type-inference strategy whereby the result type of a call is Double with
* nulls allowed if any of the operands allow nulls.
*/
public static final SqlReturnTypeInference DOUBLE_NULLABLE =
cascade(DOUBLE, SqlTypeTransforms.TO_NULLABLE);
/**
* Type-inference strategy whereby the result type of a call is a Char.
*/
public static final SqlReturnTypeInference CHAR =
explicit(SqlTypeName.CHAR);
/**
* Type-inference strategy whereby the result type of a call is an Integer.
*/
public static final SqlReturnTypeInference INTEGER =
explicit(SqlTypeName.INTEGER);
/**
* Type-inference strategy whereby the result type of a call is an Integer
* with nulls allowed if any of the operands allow nulls.
*/
public static final SqlReturnTypeInference INTEGER_NULLABLE =
cascade(INTEGER, SqlTypeTransforms.TO_NULLABLE);
/**
* Type-inference strategy whereby the result type of a call is a Bigint
*/
public static final SqlReturnTypeInference BIGINT =
explicit(SqlTypeName.BIGINT);
/**
* Type-inference strategy whereby the result type of a call is a nullable
* Bigint
*/
public static final SqlReturnTypeInference BIGINT_FORCE_NULLABLE =
cascade(BIGINT, SqlTypeTransforms.FORCE_NULLABLE);
/**
* Type-inference strategy whereby the result type of a call is an Bigint
* with nulls allowed if any of the operands allow nulls.
*/
public static final SqlReturnTypeInference BIGINT_NULLABLE =
cascade(BIGINT, SqlTypeTransforms.TO_NULLABLE);
/**
* Type-inference strategy that always returns "VARCHAR(4)".
*/
public static final SqlReturnTypeInference VARCHAR_4 =
explicit(SqlTypeName.VARCHAR, 4);
/**
* Type-inference strategy that always returns "VARCHAR(4)" with nulls
* allowed if any of the operands allow nulls.
*/
public static final SqlReturnTypeInference VARCHAR_4_NULLABLE =
cascade(VARCHAR_4, SqlTypeTransforms.TO_NULLABLE);
/**
* Type-inference strategy that always returns "VARCHAR(2000)".
*/
public static final SqlReturnTypeInference VARCHAR_2000 =
explicit(SqlTypeName.VARCHAR, 2000);
/**
* Type-inference strategy that always returns "VARCHAR(2000)" with nulls
* allowed if any of the operands allow nulls.
*/
public static final SqlReturnTypeInference VARCHAR_2000_NULLABLE =
cascade(VARCHAR_2000, SqlTypeTransforms.TO_NULLABLE);
/**
* Type-inference strategy for Histogram agg support
*/
public static final SqlReturnTypeInference HISTOGRAM =
explicit(SqlTypeName.VARBINARY, 8);
/**
* Type-inference strategy that always returns "CURSOR".
*/
public static final SqlReturnTypeInference CURSOR =
explicit(SqlTypeName.CURSOR);
/**
* Type-inference strategy that always returns "COLUMN_LIST".
*/
public static final SqlReturnTypeInference COLUMN_LIST =
explicit(SqlTypeName.COLUMN_LIST);
/**
* Type-inference strategy whereby the result type of a call is using its
* operands biggest type, using the SQL:1999 rules described in "Data types
* of results of aggregations". These rules are used in union, except,
* intersect, case and other places.
*
* @see Glossary#SQL99 SQL:1999 Part 2 Section 9.3
*/
public static final SqlReturnTypeInference LEAST_RESTRICTIVE =
opBinding -> opBinding.getTypeFactory().leastRestrictive(
opBinding.collectOperandTypes());
/**
* Returns the same type as the multiset carries. The multiset type returned
* is the least restrictive of the call's multiset operands
*/
public static final SqlReturnTypeInference MULTISET = opBinding -> {
ExplicitOperatorBinding newBinding =
new ExplicitOperatorBinding(
opBinding,
new AbstractList() {
// CHECKSTYLE: IGNORE 12
public RelDataType get(int index) {
RelDataType type =
opBinding.getOperandType(index)
.getComponentType();
assert type != null;
return type;
}
public int size() {
return opBinding.getOperandCount();
}
});
RelDataType biggestElementType =
LEAST_RESTRICTIVE.inferReturnType(newBinding);
return opBinding.getTypeFactory().createMultisetType(
biggestElementType,
-1);
};
/**
* Returns a multiset type.
*
* For example, given INTEGER
, returns
* INTEGER MULTISET
.
*/
public static final SqlReturnTypeInference TO_MULTISET =
cascade(ARG0, SqlTypeTransforms.TO_MULTISET);
/**
* Returns the element type of a multiset
*/
public static final SqlReturnTypeInference MULTISET_ELEMENT_NULLABLE =
cascade(MULTISET, SqlTypeTransforms.TO_MULTISET_ELEMENT_TYPE);
/**
* Same as {@link #MULTISET} but returns with nullability if any of the
* operands is nullable.
*/
public static final SqlReturnTypeInference MULTISET_NULLABLE =
cascade(MULTISET, SqlTypeTransforms.TO_NULLABLE);
/**
* Returns the type of the only column of a multiset.
*
*
For example, given RECORD(x INTEGER) MULTISET
, returns
* INTEGER MULTISET
.
*/
public static final SqlReturnTypeInference MULTISET_PROJECT_ONLY =
cascade(MULTISET, SqlTypeTransforms.ONLY_COLUMN);
/**
* Type-inference strategy whereby the result type of a call is
* {@link #ARG0_INTERVAL_NULLABLE} and {@link #LEAST_RESTRICTIVE}. These rules
* are used for integer division.
*/
public static final SqlReturnTypeInference INTEGER_QUOTIENT_NULLABLE =
chain(ARG0_INTERVAL_NULLABLE, LEAST_RESTRICTIVE);
/**
* Type-inference strategy for a call where the first argument is a decimal.
* The result type of a call is a decimal with a scale of 0, and the same
* precision and nullability as the first argument.
*/
public static final SqlReturnTypeInference DECIMAL_SCALE0 = opBinding -> {
RelDataType type1 = opBinding.getOperandType(0);
if (SqlTypeUtil.isDecimal(type1)) {
if (type1.getScale() == 0) {
return type1;
} else {
int p = type1.getPrecision();
RelDataType ret;
ret =
opBinding.getTypeFactory().createSqlType(
SqlTypeName.DECIMAL,
p,
0);
if (type1.isNullable()) {
ret =
opBinding.getTypeFactory()
.createTypeWithNullability(ret, true);
}
return ret;
}
}
return null;
};
/**
* Type-inference strategy whereby the result type of a call is
* {@link #DECIMAL_SCALE0} with a fallback to {@link #ARG0} This rule
* is used for floor, ceiling.
*/
public static final SqlReturnTypeInference ARG0_OR_EXACT_NO_SCALE =
chain(DECIMAL_SCALE0, ARG0);
/**
* Type-inference strategy whereby the result type of a call is the decimal
* product of two exact numeric operands where at least one of the operands
* is a decimal.
*/
public static final SqlReturnTypeInference DECIMAL_PRODUCT = opBinding -> {
RelDataTypeFactory typeFactory = opBinding.getTypeFactory();
RelDataType type1 = opBinding.getOperandType(0);
RelDataType type2 = opBinding.getOperandType(1);
return typeFactory.getTypeSystem().deriveDecimalMultiplyType(typeFactory, type1, type2);
};
/**
* Same as {@link #DECIMAL_PRODUCT} but returns with nullability if any of
* the operands is nullable by using
* {@link com.hazelcast.org.apache.calcite.sql.type.SqlTypeTransforms#TO_NULLABLE}
*/
public static final SqlReturnTypeInference DECIMAL_PRODUCT_NULLABLE =
cascade(DECIMAL_PRODUCT, SqlTypeTransforms.TO_NULLABLE);
/**
* Type-inference strategy whereby the result type of a call is
* {@link #DECIMAL_PRODUCT_NULLABLE} with a fallback to
* {@link #ARG0_INTERVAL_NULLABLE}
* and {@link #LEAST_RESTRICTIVE}.
* These rules are used for multiplication.
*/
public static final SqlReturnTypeInference PRODUCT_NULLABLE =
chain(DECIMAL_PRODUCT_NULLABLE, ARG0_INTERVAL_NULLABLE,
LEAST_RESTRICTIVE);
/**
* Type-inference strategy whereby the result type of a call is the decimal
* quotient of two exact numeric operands where at least one of the operands
* is a decimal.
*/
public static final SqlReturnTypeInference DECIMAL_QUOTIENT = opBinding -> {
RelDataTypeFactory typeFactory = opBinding.getTypeFactory();
RelDataType type1 = opBinding.getOperandType(0);
RelDataType type2 = opBinding.getOperandType(1);
return typeFactory.getTypeSystem().deriveDecimalDivideType(typeFactory, type1, type2);
};
/**
* Same as {@link #DECIMAL_QUOTIENT} but returns with nullability if any of
* the operands is nullable by using
* {@link com.hazelcast.org.apache.calcite.sql.type.SqlTypeTransforms#TO_NULLABLE}
*/
public static final SqlReturnTypeInference DECIMAL_QUOTIENT_NULLABLE =
cascade(DECIMAL_QUOTIENT, SqlTypeTransforms.TO_NULLABLE);
/**
* Type-inference strategy whereby the result type of a call is
* {@link #DECIMAL_QUOTIENT_NULLABLE} with a fallback to
* {@link #ARG0_INTERVAL_NULLABLE} and {@link #LEAST_RESTRICTIVE}. These rules
* are used for division.
*/
public static final SqlReturnTypeInference QUOTIENT_NULLABLE =
chain(DECIMAL_QUOTIENT_NULLABLE, ARG0_INTERVAL_NULLABLE,
LEAST_RESTRICTIVE);
/**
* Type-inference strategy whereby the result type of a call is the decimal
* sum of two exact numeric operands where at least one of the operands is a
* decimal.
*/
public static final SqlReturnTypeInference DECIMAL_SUM = opBinding -> {
RelDataTypeFactory typeFactory = opBinding.getTypeFactory();
RelDataType type1 = opBinding.getOperandType(0);
RelDataType type2 = opBinding.getOperandType(1);
return typeFactory.getTypeSystem().deriveDecimalPlusType(typeFactory, type1, type2);
};
/**
* Same as {@link #DECIMAL_SUM} but returns with nullability if any
* of the operands is nullable by using
* {@link com.hazelcast.org.apache.calcite.sql.type.SqlTypeTransforms#TO_NULLABLE}.
*/
public static final SqlReturnTypeInference DECIMAL_SUM_NULLABLE =
cascade(DECIMAL_SUM, SqlTypeTransforms.TO_NULLABLE);
/**
* Type-inference strategy whereby the result type of a call is
* {@link #DECIMAL_SUM_NULLABLE} with a fallback to {@link #LEAST_RESTRICTIVE}
* These rules are used for addition and subtraction.
*/
public static final SqlReturnTypeInference NULLABLE_SUM =
new SqlReturnTypeInferenceChain(DECIMAL_SUM_NULLABLE, LEAST_RESTRICTIVE);
public static final SqlReturnTypeInference DECIMAL_MOD = opBinding -> {
RelDataTypeFactory typeFactory = opBinding.getTypeFactory();
RelDataType type1 = opBinding.getOperandType(0);
RelDataType type2 = opBinding.getOperandType(1);
return typeFactory.getTypeSystem().deriveDecimalModType(typeFactory, type1, type2);
};
/**
* Type-inference strategy whereby the result type of a call is the decimal
* modulus of two exact numeric operands where at least one of the operands is a
* decimal.
*/
public static final SqlReturnTypeInference DECIMAL_MOD_NULLABLE =
cascade(DECIMAL_MOD, SqlTypeTransforms.TO_NULLABLE);
/**
* Type-inference strategy whereby the result type of a call is
* {@link #DECIMAL_MOD_NULLABLE} with a fallback to {@link #ARG1_NULLABLE}
* These rules are used for modulus.
*/
public static final SqlReturnTypeInference NULLABLE_MOD =
chain(DECIMAL_MOD_NULLABLE, ARG1_NULLABLE);
/**
* Type-inference strategy whereby the result type of a call is
*
*
* - the same type as the input types but with the combined length of the
* two first types
* - if types are of char type the type with the highest coercibility will
* be used
* - result is varying if either input is; otherwise fixed
*
*
* Pre-requisites:
*
*
* - input types must be of the same string type
*
- types must be comparable without casting
*
*/
public static final SqlReturnTypeInference DYADIC_STRING_SUM_PRECISION =
opBinding -> {
final RelDataType argType0 = opBinding.getOperandType(0);
final RelDataType argType1 = opBinding.getOperandType(1);
final boolean containsAnyType =
(argType0.getSqlTypeName() == SqlTypeName.ANY)
|| (argType1.getSqlTypeName() == SqlTypeName.ANY);
final boolean containsNullType =
(argType0.getSqlTypeName() == SqlTypeName.NULL)
|| (argType1.getSqlTypeName() == SqlTypeName.NULL);
if (!containsAnyType
&& !containsNullType
&& !(SqlTypeUtil.inCharOrBinaryFamilies(argType0)
&& SqlTypeUtil.inCharOrBinaryFamilies(argType1))) {
Preconditions.checkArgument(
SqlTypeUtil.sameNamedType(argType0, argType1));
}
SqlCollation pickedCollation = null;
if (!containsAnyType
&& !containsNullType
&& SqlTypeUtil.inCharFamily(argType0)) {
if (!SqlTypeUtil.isCharTypeComparable(
opBinding.collectOperandTypes().subList(0, 2))) {
throw opBinding.newError(
RESOURCE.typeNotComparable(
argType0.getFullTypeString(),
argType1.getFullTypeString()));
}
pickedCollation =
SqlCollation.getCoercibilityDyadicOperator(
argType0.getCollation(), argType1.getCollation());
assert null != pickedCollation;
}
// Determine whether result is variable-length
SqlTypeName typeName =
argType0.getSqlTypeName();
if (SqlTypeUtil.isBoundedVariableWidth(argType1)) {
typeName = argType1.getSqlTypeName();
}
RelDataType ret;
int typePrecision;
final long x =
(long) argType0.getPrecision() + (long) argType1.getPrecision();
final RelDataTypeFactory typeFactory = opBinding.getTypeFactory();
final RelDataTypeSystem typeSystem = typeFactory.getTypeSystem();
if (argType0.getPrecision() == RelDataType.PRECISION_NOT_SPECIFIED
|| argType1.getPrecision() == RelDataType.PRECISION_NOT_SPECIFIED
|| x > typeSystem.getMaxPrecision(typeName)) {
typePrecision = RelDataType.PRECISION_NOT_SPECIFIED;
} else {
typePrecision = (int) x;
}
ret = typeFactory.createSqlType(typeName, typePrecision);
if (null != pickedCollation) {
RelDataType pickedType;
if (argType0.getCollation().equals(pickedCollation)) {
pickedType = argType0;
} else if (argType1.getCollation().equals(pickedCollation)) {
pickedType = argType1;
} else {
throw new AssertionError("should never come here");
}
ret =
typeFactory.createTypeWithCharsetAndCollation(ret,
pickedType.getCharset(), pickedType.getCollation());
}
if (ret.getSqlTypeName() == SqlTypeName.NULL) {
ret = typeFactory.createTypeWithNullability(
typeFactory.createSqlType(SqlTypeName.VARCHAR), true);
}
return ret;
};
/**
* Type-inference strategy for String concatenation.
* Result is varying if either input is; otherwise fixed.
* For example,
*
* concat(cast('a' as varchar(2)), cast('b' as varchar(3)),cast('c' as varchar(2)))
* returns varchar(7).
*
* concat(cast('a' as varchar), cast('b' as varchar(2), cast('c' as varchar(2))))
* returns varchar.
*
* concat(cast('a' as varchar(65535)), cast('b' as varchar(2)), cast('c' as varchar(2)))
* returns varchar.
*/
public static final SqlReturnTypeInference MULTIVALENT_STRING_SUM_PRECISION =
opBinding -> {
boolean hasPrecisionNotSpecifiedOperand = false;
boolean precisionOverflow = false;
int typePrecision;
long amount = 0;
List operandTypes = opBinding.collectOperandTypes();
final RelDataTypeFactory typeFactory = opBinding.getTypeFactory();
final RelDataTypeSystem typeSystem = typeFactory.getTypeSystem();
for (RelDataType operandType: operandTypes) {
int operandPrecision = operandType.getPrecision();
amount = (long) operandPrecision + amount;
if (operandPrecision == RelDataType.PRECISION_NOT_SPECIFIED) {
hasPrecisionNotSpecifiedOperand = true;
break;
}
if (amount > typeSystem.getMaxPrecision(SqlTypeName.VARCHAR)) {
precisionOverflow = true;
break;
}
}
if (hasPrecisionNotSpecifiedOperand || precisionOverflow) {
typePrecision = RelDataType.PRECISION_NOT_SPECIFIED;
} else {
typePrecision = (int) amount;
}
return opBinding.getTypeFactory()
.createSqlType(SqlTypeName.VARCHAR, typePrecision);
};
/**
* Same as {@link #MULTIVALENT_STRING_SUM_PRECISION} and using
* {@link com.hazelcast.org.apache.calcite.sql.type.SqlTypeTransforms#TO_NULLABLE}.
*/
public static final SqlReturnTypeInference MULTIVALENT_STRING_SUM_PRECISION_NULLABLE =
cascade(MULTIVALENT_STRING_SUM_PRECISION, SqlTypeTransforms.TO_NULLABLE);
/**
* Same as {@link #DYADIC_STRING_SUM_PRECISION} and using
* {@link com.hazelcast.org.apache.calcite.sql.type.SqlTypeTransforms#TO_NULLABLE},
* {@link com.hazelcast.org.apache.calcite.sql.type.SqlTypeTransforms#TO_VARYING}.
*/
public static final SqlReturnTypeInference DYADIC_STRING_SUM_PRECISION_NULLABLE_VARYING =
cascade(DYADIC_STRING_SUM_PRECISION, SqlTypeTransforms.TO_NULLABLE,
SqlTypeTransforms.TO_VARYING);
/**
* Same as {@link #DYADIC_STRING_SUM_PRECISION} and using
* {@link com.hazelcast.org.apache.calcite.sql.type.SqlTypeTransforms#TO_NULLABLE}
*/
public static final SqlReturnTypeInference DYADIC_STRING_SUM_PRECISION_NULLABLE =
cascade(DYADIC_STRING_SUM_PRECISION, SqlTypeTransforms.TO_NULLABLE);
/**
* Type-inference strategy where the expression is assumed to be registered
* as a {@link com.hazelcast.org.apache.calcite.sql.validate.SqlValidatorNamespace}, and
* therefore the result type of the call is the type of that namespace.
*/
public static final SqlReturnTypeInference SCOPE = opBinding -> {
SqlCallBinding callBinding = (SqlCallBinding) opBinding;
return callBinding.getValidator().getNamespace(
callBinding.getCall()).getRowType();
};
/**
* Returns a multiset of column #0 of a multiset. For example, given
* RECORD(x INTEGER, y DATE) MULTISET
, returns INTEGER
* MULTISET
.
*/
public static final SqlReturnTypeInference MULTISET_PROJECT0 = opBinding -> {
assert opBinding.getOperandCount() == 1;
final RelDataType recordMultisetType =
opBinding.getOperandType(0);
RelDataType multisetType =
recordMultisetType.getComponentType();
assert multisetType != null : "expected a multiset type: "
+ recordMultisetType;
final List fields =
multisetType.getFieldList();
assert fields.size() > 0;
final RelDataType firstColType = fields.get(0).getType();
return opBinding.getTypeFactory().createMultisetType(
firstColType,
-1);
};
/**
* Returns a multiset of the first column of a multiset. For example, given
* INTEGER MULTISET
, returns RECORD(x INTEGER)
* MULTISET
.
*/
public static final SqlReturnTypeInference MULTISET_RECORD = opBinding -> {
assert opBinding.getOperandCount() == 1;
final RelDataType multisetType = opBinding.getOperandType(0);
RelDataType componentType = multisetType.getComponentType();
assert componentType != null : "expected a multiset type: "
+ multisetType;
final RelDataTypeFactory typeFactory = opBinding.getTypeFactory();
final RelDataType type = typeFactory.builder()
.add(SqlUtil.deriveAliasFromOrdinal(0), componentType).build();
return typeFactory.createMultisetType(type, -1);
};
/**
* Returns the field type of a structured type which has only one field. For
* example, given {@code RECORD(x INTEGER)} returns {@code INTEGER}.
*/
public static final SqlReturnTypeInference RECORD_TO_SCALAR = opBinding -> {
assert opBinding.getOperandCount() == 1;
final RelDataType recordType = opBinding.getOperandType(0);
boolean isStruct = recordType.isStruct();
int fieldCount = recordType.getFieldCount();
assert isStruct && (fieldCount == 1);
RelDataTypeField fieldType = recordType.getFieldList().get(0);
assert fieldType != null
: "expected a record type with one field: "
+ recordType;
final RelDataType firstColType = fieldType.getType();
return opBinding.getTypeFactory().createTypeWithNullability(
firstColType,
true);
};
/**
* Type-inference strategy for SUM aggregate function inferred from the
* operand type, and nullable if the call occurs within a "GROUP BY ()"
* query. E.g. in "select sum(x) as s from empty", s may be null. Also,
* with the default implementation of RelDataTypeSystem, s has the same
* type name as x.
*/
public static final SqlReturnTypeInference AGG_SUM = opBinding -> {
final RelDataTypeFactory typeFactory = opBinding.getTypeFactory();
final RelDataType type = typeFactory.getTypeSystem()
.deriveSumType(typeFactory, opBinding.getOperandType(0));
if (opBinding.getGroupCount() == 0 || opBinding.hasFilter()) {
return typeFactory.createTypeWithNullability(type, true);
} else {
return type;
}
};
/**
* Type-inference strategy for $SUM0 aggregate function inferred from the
* operand type. By default the inferred type is identical to the operand
* type. E.g. in "select $sum0(x) as s from empty", s has the same type as
* x.
*/
public static final SqlReturnTypeInference AGG_SUM_EMPTY_IS_ZERO =
opBinding -> {
final RelDataTypeFactory typeFactory = opBinding.getTypeFactory();
final RelDataType sumType = typeFactory.getTypeSystem()
.deriveSumType(typeFactory, opBinding.getOperandType(0));
// SUM0 should not return null.
return typeFactory.createTypeWithNullability(sumType, false);
};
/**
* Type-inference strategy for the {@code CUME_DIST} and {@code PERCENT_RANK}
* aggregate functions.
*/
public static final SqlReturnTypeInference FRACTIONAL_RANK = opBinding -> {
final RelDataTypeFactory typeFactory = opBinding.getTypeFactory();
return typeFactory.getTypeSystem().deriveFractionalRankType(typeFactory);
};
/**
* Type-inference strategy for the {@code NTILE}, {@code RANK},
* {@code DENSE_RANK}, and {@code ROW_NUMBER} aggregate functions.
*/
public static final SqlReturnTypeInference RANK = opBinding -> {
final RelDataTypeFactory typeFactory = opBinding.getTypeFactory();
return typeFactory.getTypeSystem().deriveRankType(typeFactory);
};
public static final SqlReturnTypeInference AVG_AGG_FUNCTION = opBinding -> {
final RelDataTypeFactory typeFactory = opBinding.getTypeFactory();
final RelDataType relDataType =
typeFactory.getTypeSystem().deriveAvgAggType(typeFactory,
opBinding.getOperandType(0));
if (opBinding.getGroupCount() == 0 || opBinding.hasFilter()) {
return typeFactory.createTypeWithNullability(relDataType, true);
} else {
return relDataType;
}
};
public static final SqlReturnTypeInference COVAR_REGR_FUNCTION = opBinding -> {
final RelDataTypeFactory typeFactory = opBinding.getTypeFactory();
final RelDataType relDataType =
typeFactory.getTypeSystem().deriveCovarType(typeFactory,
opBinding.getOperandType(0), opBinding.getOperandType(1));
if (opBinding.getGroupCount() == 0 || opBinding.hasFilter()) {
return typeFactory.createTypeWithNullability(relDataType, true);
} else {
return relDataType;
}
};
}