Interface TypeCoercion

All Known Implementing Classes:
AbstractTypeCoercion, TypeCoercionImpl

public interface TypeCoercion
Default strategies to coerce differing types that participate in operations into compatible ones.

Notes about type widening / tightest common types: Broadly, there are two cases that need to widen data types (i.e. set operations, binary comparison):

  • Case1: Look for a common data type for two or more data types, and no loss of precision is allowed. Including type inference for returned/operands type (i.e. what's the column's common data type if one row is an integer while the other row is a long?).
  • Case2: Look for a widen data type with some acceptable loss of precision (i.e. there is no common type for double and decimal because double's range is larger than decimal(with default max precision), and yet decimal is more precise than double, but in union we would cast the decimal to double).


  • Method Details

    • getTightestCommonType

      @Nullable RelDataType getTightestCommonType(@Nullable RelDataType type1, @Nullable RelDataType type2)
      Case1: type widening with no precision loss. Find the tightest common type of two types that might be used in binary expression.
      common type
    • getWiderTypeForTwo

      @Nullable RelDataType getWiderTypeForTwo(@Nullable RelDataType type1, @Nullable RelDataType type2, boolean stringPromotion)
      Case2: type widening. The main difference with getTightestCommonType(org.apache.calcite.rel.type.RelDataType, org.apache.calcite.rel.type.RelDataType) is that we allow some precision loss when widening decimal to fractional, or promote to string type.
    • getWiderTypeFor

      @Nullable RelDataType getWiderTypeFor(List<RelDataType> typeList, boolean stringPromotion)
      Similar to getWiderTypeForTwo(org.apache.calcite.rel.type.RelDataType, org.apache.calcite.rel.type.RelDataType, boolean), but can handle sequence types. getWiderTypeForTwo(org.apache.calcite.rel.type.RelDataType, org.apache.calcite.rel.type.RelDataType, boolean) doesn't satisfy the associative law, i.e. (a op b) op c may not equal to a op (b op c). This is only a problem for STRING or nested STRING in collection type like ARRAY. Excluding these types, getWiderTypeForTwo(org.apache.calcite.rel.type.RelDataType, org.apache.calcite.rel.type.RelDataType, boolean) satisfies the associative law. For instance, (DATE, INTEGER, VARCHAR) should have VARCHAR as the wider common type.
    • getWiderTypeForDecimal

      @Nullable RelDataType getWiderTypeForDecimal(@Nullable RelDataType type1, @Nullable RelDataType type2)
      Finds a wider type when one or both types are DECIMAL type.

      If the wider decimal type's precision/scale exceeds system limitation, this rule will truncate the decimal type to the max precision/scale. For DECIMAL and fractional types, returns DECIMAL type that has the higher precision of the two.

      The default implementation depends on the max precision/scale of the type system, you can override it based on the specific system requirement in RelDataTypeSystem.

    • commonTypeForBinaryComparison

      @Nullable RelDataType commonTypeForBinaryComparison(@Nullable RelDataType type1, @Nullable RelDataType type2)
      Determines common type for a comparison operator whose operands are STRING type and the other (non STRING) type.
    • rowTypeCoercion

      boolean rowTypeCoercion(@Nullable SqlValidatorScope scope, SqlNode query, int columnIndex, RelDataType targetType)
      Widen a SqlNode ith column type to target type, mainly used for set operations like UNION, INTERSECT and EXCEPT.
      scope - Scope to query
      query - SqlNode which have children nodes as columns
      columnIndex - Target column index
      targetType - Target type to cast to
    • inOperationCoercion

      boolean inOperationCoercion(SqlCallBinding binding)
      Handles type coercion for IN operation with or without sub-query.

      See TypeCoercionImpl for default strategies.

    • binaryArithmeticCoercion

      boolean binaryArithmeticCoercion(SqlCallBinding binding)
      Coerces operand of binary arithmetic expressions to Numeric type.
    • binaryComparisonCoercion

      boolean binaryComparisonCoercion(SqlCallBinding binding)
      Coerces operands in binary comparison expressions.
    • caseWhenCoercion

      boolean caseWhenCoercion(SqlCallBinding binding)
      Coerces CASE WHEN statement branches to one common type.

      Rules: Find common type for all the then operands and else operands, then try to coerce the then/else operands to the type if needed.

    • builtinFunctionCoercion

      boolean builtinFunctionCoercion(SqlCallBinding binding, List<RelDataType> operandTypes, List<SqlTypeFamily> expectedFamilies)
      Type coercion with inferred type from passed in arguments and the SqlTypeFamily defined in the checkers, e.g. the FamilyOperandTypeChecker.

      Caution that we do not cast from NUMERIC if desired type family is also SqlTypeFamily.NUMERIC.

      If the FamilyOperandTypeCheckers are subsumed in a CompositeOperandTypeChecker, check them based on their combination order. i.e. If we allow a NUMERIC_NUMERIC OR STRING_NUMERIC family combination and are with arguments (op1: VARCHAR(20), op2: BOOLEAN), try to coerce both op1 and op2 to NUMERIC if the type coercion rules allow it, or else try to coerce op2 to NUMERIC and keep op1 the type as it is.

      This is also very interrelated to the composition predicate for the checkers: if the predicate is AND, we would fail fast if the first family type coercion fails.

      binding - Call binding
      operandTypes - Types of the operands passed in
      expectedFamilies - Expected SqlTypeFamily list by user specified
    • userDefinedFunctionCoercion

      boolean userDefinedFunctionCoercion(SqlValidatorScope scope, SqlCall call, SqlFunction function)
      Non built-in functions (UDFs) type coercion, compare the types of arguments with rules:
      1. Named param: find the desired type by the passed in operand's name
      2. Non-named param: find the desired type by formal parameter ordinal

      Try to make type coercion only if the desired type is found.

    • querySourceCoercion

      boolean querySourceCoercion(@Nullable SqlValidatorScope scope, RelDataType sourceRowType, RelDataType targetRowType, SqlNode query)
      Coerces the source row expression to target type in an INSERT or UPDATE query.

      If the source and target fields in the same ordinal do not equal sans nullability, try to coerce the source field to target field type.

      scope - Source scope
      sourceRowType - Source row type
      targetRowType - Target row type
      query - The query, either an INSERT or UPDATE