Search in sources :

Example 1 with SqlCollation

use of org.apache.calcite.sql.SqlCollation in project calcite by apache.

the class SqlTypeFactoryImpl method leastRestrictiveSqlType.

private RelDataType leastRestrictiveSqlType(List<RelDataType> types) {
    RelDataType resultType = null;
    int nullCount = 0;
    int nullableCount = 0;
    int javaCount = 0;
    int anyCount = 0;
    for (RelDataType type : types) {
        final SqlTypeName typeName = type.getSqlTypeName();
        if (typeName == null) {
            return null;
        }
        if (typeName == SqlTypeName.ANY) {
            anyCount++;
        }
        if (type.isNullable()) {
            ++nullableCount;
        }
        if (typeName == SqlTypeName.NULL) {
            ++nullCount;
        }
        if (isJavaType(type)) {
            ++javaCount;
        }
    }
    // if any of the inputs are ANY, the output is ANY
    if (anyCount > 0) {
        return createTypeWithNullability(createSqlType(SqlTypeName.ANY), nullCount > 0 || nullableCount > 0);
    }
    for (int i = 0; i < types.size(); ++i) {
        RelDataType type = types.get(i);
        RelDataTypeFamily family = type.getFamily();
        final SqlTypeName typeName = type.getSqlTypeName();
        if (typeName == SqlTypeName.NULL) {
            continue;
        }
        // Except if all types are either NULL or Java types.
        if (isJavaType(type) && javaCount + nullCount < types.size()) {
            final RelDataType originalType = type;
            type = typeName.allowsPrecScale(true, true) ? createSqlType(typeName, type.getPrecision(), type.getScale()) : typeName.allowsPrecScale(true, false) ? createSqlType(typeName, type.getPrecision()) : createSqlType(typeName);
            type = createTypeWithNullability(type, originalType.isNullable());
        }
        if (resultType == null) {
            resultType = type;
            if (resultType.getSqlTypeName() == SqlTypeName.ROW) {
                return leastRestrictiveStructuredType(types);
            }
        }
        RelDataTypeFamily resultFamily = resultType.getFamily();
        SqlTypeName resultTypeName = resultType.getSqlTypeName();
        if (resultFamily != family) {
            return null;
        }
        if (SqlTypeUtil.inCharOrBinaryFamilies(type)) {
            Charset charset1 = type.getCharset();
            Charset charset2 = resultType.getCharset();
            SqlCollation collation1 = type.getCollation();
            SqlCollation collation2 = resultType.getCollation();
            // TODO:  refine collation combination rules
            final int precision = SqlTypeUtil.maxPrecision(resultType.getPrecision(), type.getPrecision());
            // width.  Otherwise, result is fixed width.
            if (SqlTypeUtil.isLob(resultType)) {
                resultType = createSqlType(resultType.getSqlTypeName());
            } else if (SqlTypeUtil.isLob(type)) {
                resultType = createSqlType(type.getSqlTypeName());
            } else if (SqlTypeUtil.isBoundedVariableWidth(resultType)) {
                resultType = createSqlType(resultType.getSqlTypeName(), precision);
            } else {
                // this catch-all case covers type variable, and both fixed
                SqlTypeName newTypeName = type.getSqlTypeName();
                if (shouldRaggedFixedLengthValueUnionBeVariable()) {
                    if (resultType.getPrecision() != type.getPrecision()) {
                        if (newTypeName == SqlTypeName.CHAR) {
                            newTypeName = SqlTypeName.VARCHAR;
                        } else if (newTypeName == SqlTypeName.BINARY) {
                            newTypeName = SqlTypeName.VARBINARY;
                        }
                    }
                }
                resultType = createSqlType(newTypeName, precision);
            }
            Charset charset = null;
            SqlCollation collation = null;
            if ((charset1 != null) || (charset2 != null)) {
                if (charset1 == null) {
                    charset = charset2;
                    collation = collation2;
                } else if (charset2 == null) {
                    charset = charset1;
                    collation = collation1;
                } else if (charset1.equals(charset2)) {
                    charset = charset1;
                    collation = collation1;
                } else if (charset1.contains(charset2)) {
                    charset = charset1;
                    collation = collation1;
                } else {
                    charset = charset2;
                    collation = collation2;
                }
            }
            if (charset != null) {
                resultType = createTypeWithCharsetAndCollation(resultType, charset, collation);
            }
        } else if (SqlTypeUtil.isExactNumeric(type)) {
            if (SqlTypeUtil.isExactNumeric(resultType)) {
                // interval + datetime = datetime
                if (types.size() > (i + 1)) {
                    RelDataType type1 = types.get(i + 1);
                    if (SqlTypeUtil.isDatetime(type1)) {
                        resultType = type1;
                        return createTypeWithNullability(resultType, nullCount > 0 || nullableCount > 0);
                    }
                }
                if (!type.equals(resultType)) {
                    if (!typeName.allowsPrec() && !resultTypeName.allowsPrec()) {
                        // use the bigger primitive
                        if (type.getPrecision() > resultType.getPrecision()) {
                            resultType = type;
                        }
                    } else {
                        // Let the result type have precision (p), scale (s)
                        // and number of whole digits (d) as follows: d =
                        // max(p1 - s1, p2 - s2) s <= max(s1, s2) p = s + d
                        int p1 = resultType.getPrecision();
                        int p2 = type.getPrecision();
                        int s1 = resultType.getScale();
                        int s2 = type.getScale();
                        final int maxPrecision = typeSystem.getMaxNumericPrecision();
                        final int maxScale = typeSystem.getMaxNumericScale();
                        int dout = Math.max(p1 - s1, p2 - s2);
                        dout = Math.min(dout, maxPrecision);
                        int scale = Math.max(s1, s2);
                        scale = Math.min(scale, maxPrecision - dout);
                        scale = Math.min(scale, maxScale);
                        int precision = dout + scale;
                        assert precision <= maxPrecision;
                        assert precision > 0 || (resultType.getSqlTypeName() == SqlTypeName.DECIMAL && precision == 0 && scale == 0);
                        resultType = createSqlType(SqlTypeName.DECIMAL, precision, scale);
                    }
                }
            } else if (SqlTypeUtil.isApproximateNumeric(resultType)) {
                // TODO:  only promote when required
                if (SqlTypeUtil.isDecimal(type)) {
                    // Only promote to double for decimal types
                    resultType = createDoublePrecisionType();
                }
            } else {
                return null;
            }
        } else if (SqlTypeUtil.isApproximateNumeric(type)) {
            if (SqlTypeUtil.isApproximateNumeric(resultType)) {
                if (type.getPrecision() > resultType.getPrecision()) {
                    resultType = type;
                }
            } else if (SqlTypeUtil.isExactNumeric(resultType)) {
                if (SqlTypeUtil.isDecimal(resultType)) {
                    resultType = createDoublePrecisionType();
                } else {
                    resultType = type;
                }
            } else {
                return null;
            }
        } else if (SqlTypeUtil.isInterval(type)) {
            // interval + datetime = datetime
            if (types.size() > (i + 1)) {
                RelDataType type1 = types.get(i + 1);
                if (SqlTypeUtil.isDatetime(type1)) {
                    resultType = type1;
                    return createTypeWithNullability(resultType, nullCount > 0 || nullableCount > 0);
                }
            }
            if (!type.equals(resultType)) {
                // TODO jvs 4-June-2005:  This shouldn't be necessary;
                // move logic into IntervalSqlType.combine
                Object type1 = resultType;
                resultType = ((IntervalSqlType) resultType).combine(this, (IntervalSqlType) type);
                resultType = ((IntervalSqlType) resultType).combine(this, (IntervalSqlType) type1);
            }
        } else if (SqlTypeUtil.isDatetime(type)) {
            // datetime +/- interval (or integer) = datetime
            if (types.size() > (i + 1)) {
                RelDataType type1 = types.get(i + 1);
                if (SqlTypeUtil.isInterval(type1) || SqlTypeUtil.isIntType(type1)) {
                    resultType = type;
                    return createTypeWithNullability(resultType, nullCount > 0 || nullableCount > 0);
                }
            }
        } else {
            // leastRestrictiveByCast handle it
            return null;
        }
    }
    if (resultType != null && nullableCount > 0) {
        resultType = createTypeWithNullability(resultType, true);
    }
    return resultType;
}
Also used : RelDataTypeFamily(org.apache.calcite.rel.type.RelDataTypeFamily) SqlCollation(org.apache.calcite.sql.SqlCollation) Charset(java.nio.charset.Charset) RelDataType(org.apache.calcite.rel.type.RelDataType)

Example 2 with SqlCollation

use of org.apache.calcite.sql.SqlCollation in project calcite by apache.

the class NlsString method concat.

/**
 * Concatenates some {@link NlsString} objects. The result has the charset
 * and collation of the first element. The other elements must have matching
 * (or null) charset and collation. Concatenates all at once, not pairwise,
 * to avoid string copies.
 *
 * @param args array of {@link NlsString} to be concatenated
 */
public static NlsString concat(List<NlsString> args) {
    if (args.size() < 2) {
        return args.get(0);
    }
    String charSetName = args.get(0).charsetName;
    SqlCollation collation = args.get(0).collation;
    int length = args.get(0).value.length();
    // sum string lengths and validate
    for (int i = 1; i < args.size(); i++) {
        final NlsString arg = args.get(i);
        length += arg.value.length();
        if (!((arg.charsetName == null) || arg.charsetName.equals(charSetName))) {
            throw new IllegalArgumentException("mismatched charsets");
        }
        if (!((arg.collation == null) || arg.collation.equals(collation))) {
            throw new IllegalArgumentException("mismatched collations");
        }
    }
    StringBuilder sb = new StringBuilder(length);
    for (NlsString arg : args) {
        sb.append(arg.value);
    }
    return new NlsString(sb.toString(), charSetName, collation);
}
Also used : SqlCollation(org.apache.calcite.sql.SqlCollation)

Example 3 with SqlCollation

use of org.apache.calcite.sql.SqlCollation in project calcite by apache.

the class SqlTesterImpl method checkCollation.

public void checkCollation(String expression, String expectedCollationName, SqlCollation.Coercibility expectedCoercibility) {
    for (String sql : buildQueries(expression)) {
        RelDataType actualType = getColumnType(sql);
        SqlCollation collation = actualType.getCollation();
        assertEquals(expectedCollationName, collation.getCollationName());
        assertEquals(expectedCoercibility, collation.getCoercibility());
    }
}
Also used : SqlCollation(org.apache.calcite.sql.SqlCollation) RelDataType(org.apache.calcite.rel.type.RelDataType)

Example 4 with SqlCollation

use of org.apache.calcite.sql.SqlCollation in project calcite by apache.

the class SqlTypeUtil method addCharsetAndCollation.

/**
 * Adds collation and charset to a character type, returns other types
 * unchanged.
 *
 * @param type        Type
 * @param typeFactory Type factory
 * @return Type with added charset and collation, or unchanged type if it is
 * not a char type.
 */
public static RelDataType addCharsetAndCollation(RelDataType type, RelDataTypeFactory typeFactory) {
    if (!inCharFamily(type)) {
        return type;
    }
    Charset charset = type.getCharset();
    if (charset == null) {
        charset = typeFactory.getDefaultCharset();
    }
    SqlCollation collation = type.getCollation();
    if (collation == null) {
        collation = SqlCollation.IMPLICIT;
    }
    // todo: should get the implicit collation from repository
    // instead of null
    type = typeFactory.createTypeWithCharsetAndCollation(type, charset, collation);
    SqlValidatorUtil.checkCharsetAndCollateConsistentIfCharType(type);
    return type;
}
Also used : SqlCollation(org.apache.calcite.sql.SqlCollation) Charset(java.nio.charset.Charset)

Example 5 with SqlCollation

use of org.apache.calcite.sql.SqlCollation in project calcite by apache.

the class RexLiteral method fromJdbcString.

/**
 * Converts a Jdbc string into a RexLiteral. This method accepts a string,
 * as returned by the Jdbc method ResultSet.getString(), and restores the
 * string into an equivalent RexLiteral. It allows one to use Jdbc strings
 * as a common format for data.
 *
 * <p>If a null literal is provided, then a null pointer will be returned.
 *
 * @param type     data type of literal to be read
 * @param typeName type family of literal
 * @param literal  the (non-SQL encoded) string representation, as returned
 *                 by the Jdbc call to return a column as a string
 * @return a typed RexLiteral, or null
 */
public static RexLiteral fromJdbcString(RelDataType type, SqlTypeName typeName, String literal) {
    if (literal == null) {
        return null;
    }
    switch(typeName) {
        case CHAR:
            Charset charset = type.getCharset();
            SqlCollation collation = type.getCollation();
            NlsString str = new NlsString(literal, charset.name(), collation);
            return new RexLiteral(str, type, typeName);
        case BOOLEAN:
            boolean b = ConversionUtil.toBoolean(literal);
            return new RexLiteral(b, type, typeName);
        case DECIMAL:
        case DOUBLE:
            BigDecimal d = new BigDecimal(literal);
            return new RexLiteral(d, type, typeName);
        case BINARY:
            byte[] bytes = ConversionUtil.toByteArrayFromString(literal, 16);
            return new RexLiteral(new ByteString(bytes), type, typeName);
        case NULL:
            return new RexLiteral(null, type, typeName);
        case INTERVAL_DAY:
        case INTERVAL_DAY_HOUR:
        case INTERVAL_DAY_MINUTE:
        case INTERVAL_DAY_SECOND:
        case INTERVAL_HOUR:
        case INTERVAL_HOUR_MINUTE:
        case INTERVAL_HOUR_SECOND:
        case INTERVAL_MINUTE:
        case INTERVAL_MINUTE_SECOND:
        case INTERVAL_SECOND:
            long millis = SqlParserUtil.intervalToMillis(literal, type.getIntervalQualifier());
            return new RexLiteral(BigDecimal.valueOf(millis), type, typeName);
        case INTERVAL_YEAR:
        case INTERVAL_YEAR_MONTH:
        case INTERVAL_MONTH:
            long months = SqlParserUtil.intervalToMonths(literal, type.getIntervalQualifier());
            return new RexLiteral(BigDecimal.valueOf(months), type, typeName);
        case DATE:
        case TIME:
        case TIMESTAMP:
            String format = getCalendarFormat(typeName);
            TimeZone tz = DateTimeUtils.UTC_ZONE;
            final Comparable v;
            switch(typeName) {
                case DATE:
                    final Calendar cal = DateTimeUtils.parseDateFormat(literal, new SimpleDateFormat(format, Locale.ROOT), tz);
                    if (cal == null) {
                        throw new AssertionError("fromJdbcString: invalid date/time value '" + literal + "'");
                    }
                    v = DateString.fromCalendarFields(cal);
                    break;
                default:
                    // Allow fractional seconds for times and timestamps
                    assert format != null;
                    final DateTimeUtils.PrecisionTime ts = DateTimeUtils.parsePrecisionDateTimeLiteral(literal, new SimpleDateFormat(format, Locale.ROOT), tz, -1);
                    if (ts == null) {
                        throw new AssertionError("fromJdbcString: invalid date/time value '" + literal + "'");
                    }
                    switch(typeName) {
                        case TIMESTAMP:
                            v = TimestampString.fromCalendarFields(ts.getCalendar()).withFraction(ts.getFraction());
                            break;
                        case TIME:
                            v = TimeString.fromCalendarFields(ts.getCalendar()).withFraction(ts.getFraction());
                            break;
                        default:
                            throw new AssertionError();
                    }
            }
            return new RexLiteral(v, type, typeName);
        case SYMBOL:
        // Symbols are for internal use
        default:
            throw new AssertionError("fromJdbcString: unsupported type");
    }
}
Also used : ByteString(org.apache.calcite.avatica.util.ByteString) Calendar(java.util.Calendar) Charset(java.nio.charset.Charset) TimeString(org.apache.calcite.util.TimeString) DateString(org.apache.calcite.util.DateString) NlsString(org.apache.calcite.util.NlsString) ByteString(org.apache.calcite.avatica.util.ByteString) TimestampString(org.apache.calcite.util.TimestampString) BigDecimal(java.math.BigDecimal) TimeZone(java.util.TimeZone) SqlCollation(org.apache.calcite.sql.SqlCollation) NlsString(org.apache.calcite.util.NlsString) DateTimeUtils(org.apache.calcite.avatica.util.DateTimeUtils) SimpleDateFormat(java.text.SimpleDateFormat)

Aggregations

SqlCollation (org.apache.calcite.sql.SqlCollation)7 Charset (java.nio.charset.Charset)4 NlsString (org.apache.calcite.util.NlsString)3 BigDecimal (java.math.BigDecimal)2 SimpleDateFormat (java.text.SimpleDateFormat)2 Calendar (java.util.Calendar)2 TimeZone (java.util.TimeZone)2 ByteString (org.apache.calcite.avatica.util.ByteString)2 DateTimeUtils (org.apache.calcite.avatica.util.DateTimeUtils)2 RelDataType (org.apache.calcite.rel.type.RelDataType)2 DateString (org.apache.calcite.util.DateString)2 TimeString (org.apache.calcite.util.TimeString)2 TimestampString (org.apache.calcite.util.TimestampString)2 RelDataTypeFamily (org.apache.calcite.rel.type.RelDataTypeFamily)1 SqlCharStringLiteral (org.apache.calcite.sql.SqlCharStringLiteral)1 SqlLiteral (org.apache.calcite.sql.SqlLiteral)1 SqlNode (org.apache.calcite.sql.SqlNode)1 SqlWriter (org.apache.calcite.sql.SqlWriter)1 BitString (org.apache.calcite.util.BitString)1