All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hazelcast.org.apache.calcite.sql.type.SqlTypeName 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.avatica.util.TimeUnit;
import com.hazelcast.org.apache.calcite.sql.SqlLiteral;
import com.hazelcast.org.apache.calcite.sql.parser.SqlParserPos;
import com.hazelcast.org.apache.calcite.util.DateString;
import com.hazelcast.org.apache.calcite.util.TimeString;
import com.hazelcast.org.apache.calcite.util.TimestampString;
import com.hazelcast.org.apache.calcite.util.Util;

import com.hazelcast.com.google.common.collect.ImmutableList;
import com.hazelcast.com.google.common.collect.ImmutableMap;
import com.hazelcast.com.google.common.collect.Iterables;
import com.hazelcast.com.google.common.collect.Sets;

import com.hazelcast.org.checkerframework.checker.nullness.qual.Nullable;

import java.math.BigDecimal;
import java.sql.Types;
import java.util.Arrays;
import java.util.Calendar;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Enumeration of the type names which can be used to construct a SQL type.
 * Rationale for this class's existence (instead of just using the standard
 * java.sql.Type ordinals):
 *
 * 
    *
  • {@link java.sql.Types} does not include all SQL2003 data-types; *
  • SqlTypeName provides a type-safe enumeration; *
  • SqlTypeName provides a place to hang extra information such as whether * the type carries precision and scale. *
*/ public enum SqlTypeName { BOOLEAN(PrecScale.NO_NO, false, Types.BOOLEAN, SqlTypeFamily.BOOLEAN), TINYINT(PrecScale.NO_NO, false, Types.TINYINT, SqlTypeFamily.NUMERIC), SMALLINT(PrecScale.NO_NO, false, Types.SMALLINT, SqlTypeFamily.NUMERIC), INTEGER(PrecScale.NO_NO, false, Types.INTEGER, SqlTypeFamily.NUMERIC), BIGINT(PrecScale.NO_NO, false, Types.BIGINT, SqlTypeFamily.NUMERIC), DECIMAL(PrecScale.NO_NO | PrecScale.YES_NO | PrecScale.YES_YES, false, Types.DECIMAL, SqlTypeFamily.NUMERIC), FLOAT(PrecScale.NO_NO, false, Types.FLOAT, SqlTypeFamily.NUMERIC), REAL(PrecScale.NO_NO, false, Types.REAL, SqlTypeFamily.NUMERIC), DOUBLE(PrecScale.NO_NO, false, Types.DOUBLE, SqlTypeFamily.NUMERIC), DATE(PrecScale.NO_NO, false, Types.DATE, SqlTypeFamily.DATE), TIME(PrecScale.NO_NO | PrecScale.YES_NO, false, Types.TIME, SqlTypeFamily.TIME), TIME_WITH_LOCAL_TIME_ZONE(PrecScale.NO_NO | PrecScale.YES_NO, false, Types.OTHER, SqlTypeFamily.TIME), TIMESTAMP(PrecScale.NO_NO | PrecScale.YES_NO, false, Types.TIMESTAMP, SqlTypeFamily.TIMESTAMP), TIMESTAMP_WITH_LOCAL_TIME_ZONE(PrecScale.NO_NO | PrecScale.YES_NO, false, Types.OTHER, SqlTypeFamily.TIMESTAMP), INTERVAL_YEAR(PrecScale.NO_NO, false, Types.OTHER, SqlTypeFamily.INTERVAL_YEAR_MONTH), INTERVAL_YEAR_MONTH(PrecScale.NO_NO, false, Types.OTHER, SqlTypeFamily.INTERVAL_YEAR_MONTH), INTERVAL_MONTH(PrecScale.NO_NO, false, Types.OTHER, SqlTypeFamily.INTERVAL_YEAR_MONTH), INTERVAL_DAY(PrecScale.NO_NO | PrecScale.YES_NO | PrecScale.YES_YES, false, Types.OTHER, SqlTypeFamily.INTERVAL_DAY_TIME), INTERVAL_DAY_HOUR(PrecScale.NO_NO | PrecScale.YES_NO | PrecScale.YES_YES, false, Types.OTHER, SqlTypeFamily.INTERVAL_DAY_TIME), INTERVAL_DAY_MINUTE(PrecScale.NO_NO | PrecScale.YES_NO | PrecScale.YES_YES, false, Types.OTHER, SqlTypeFamily.INTERVAL_DAY_TIME), INTERVAL_DAY_SECOND(PrecScale.NO_NO | PrecScale.YES_NO | PrecScale.YES_YES, false, Types.OTHER, SqlTypeFamily.INTERVAL_DAY_TIME), INTERVAL_HOUR(PrecScale.NO_NO | PrecScale.YES_NO | PrecScale.YES_YES, false, Types.OTHER, SqlTypeFamily.INTERVAL_DAY_TIME), INTERVAL_HOUR_MINUTE(PrecScale.NO_NO | PrecScale.YES_NO | PrecScale.YES_YES, false, Types.OTHER, SqlTypeFamily.INTERVAL_DAY_TIME), INTERVAL_HOUR_SECOND(PrecScale.NO_NO | PrecScale.YES_NO | PrecScale.YES_YES, false, Types.OTHER, SqlTypeFamily.INTERVAL_DAY_TIME), INTERVAL_MINUTE(PrecScale.NO_NO | PrecScale.YES_NO | PrecScale.YES_YES, false, Types.OTHER, SqlTypeFamily.INTERVAL_DAY_TIME), INTERVAL_MINUTE_SECOND(PrecScale.NO_NO | PrecScale.YES_NO | PrecScale.YES_YES, false, Types.OTHER, SqlTypeFamily.INTERVAL_DAY_TIME), INTERVAL_SECOND(PrecScale.NO_NO | PrecScale.YES_NO | PrecScale.YES_YES, false, Types.OTHER, SqlTypeFamily.INTERVAL_DAY_TIME), CHAR(PrecScale.NO_NO | PrecScale.YES_NO, false, Types.CHAR, SqlTypeFamily.CHARACTER), VARCHAR(PrecScale.NO_NO | PrecScale.YES_NO, false, Types.VARCHAR, SqlTypeFamily.CHARACTER), BINARY(PrecScale.NO_NO | PrecScale.YES_NO, false, Types.BINARY, SqlTypeFamily.BINARY), VARBINARY(PrecScale.NO_NO | PrecScale.YES_NO, false, Types.VARBINARY, SqlTypeFamily.BINARY), NULL(PrecScale.NO_NO, true, Types.NULL, SqlTypeFamily.NULL), UNKNOWN(PrecScale.NO_NO, true, Types.NULL, SqlTypeFamily.NULL), ANY(PrecScale.NO_NO | PrecScale.YES_NO | PrecScale.YES_YES, true, Types.JAVA_OBJECT, SqlTypeFamily.ANY), SYMBOL(PrecScale.NO_NO, true, Types.OTHER, null), MULTISET(PrecScale.NO_NO, false, Types.ARRAY, SqlTypeFamily.MULTISET), ARRAY(PrecScale.NO_NO, false, Types.ARRAY, SqlTypeFamily.ARRAY), MAP(PrecScale.NO_NO, false, Types.OTHER, SqlTypeFamily.MAP), DISTINCT(PrecScale.NO_NO, false, Types.DISTINCT, null), STRUCTURED(PrecScale.NO_NO, false, Types.STRUCT, null), ROW(PrecScale.NO_NO, false, Types.STRUCT, null), OTHER(PrecScale.NO_NO, false, Types.OTHER, null), CURSOR(PrecScale.NO_NO, false, ExtraSqlTypes.REF_CURSOR, SqlTypeFamily.CURSOR), COLUMN_LIST(PrecScale.NO_NO, false, Types.OTHER + 2, SqlTypeFamily.COLUMN_LIST), DYNAMIC_STAR(PrecScale.NO_NO | PrecScale.YES_NO | PrecScale.YES_YES, true, Types.JAVA_OBJECT, SqlTypeFamily.ANY), /** Spatial type. Though not standard, it is common to several DBs, so we * do not flag it 'special' (internal). */ GEOMETRY(PrecScale.NO_NO, false, ExtraSqlTypes.GEOMETRY, SqlTypeFamily.GEO), SARG(PrecScale.NO_NO, true, Types.OTHER, SqlTypeFamily.ANY); public static final int MAX_DATETIME_PRECISION = 3; // Minimum and default interval precisions are defined by SQL2003 // Maximum interval precisions are implementation dependent, // but must be at least the default value public static final int DEFAULT_INTERVAL_START_PRECISION = 2; public static final int DEFAULT_INTERVAL_FRACTIONAL_SECOND_PRECISION = 6; public static final int MIN_INTERVAL_START_PRECISION = 1; public static final int MIN_INTERVAL_FRACTIONAL_SECOND_PRECISION = 1; public static final int MAX_INTERVAL_START_PRECISION = 10; public static final int MAX_INTERVAL_FRACTIONAL_SECOND_PRECISION = 9; // Cached map of enum values private static final Map VALUES_MAP = Util.enumConstants(SqlTypeName.class); // categorizations used by SqlTypeFamily definitions // you probably want to use JDK 1.5 support for treating enumeration // as collection instead; this is only here to support // SqlTypeFamily.ANY public static final List ALL_TYPES = ImmutableList.of( BOOLEAN, INTEGER, VARCHAR, DATE, TIME, TIMESTAMP, NULL, DECIMAL, ANY, CHAR, BINARY, VARBINARY, TINYINT, SMALLINT, BIGINT, REAL, DOUBLE, SYMBOL, INTERVAL_YEAR, INTERVAL_YEAR_MONTH, INTERVAL_MONTH, INTERVAL_DAY, INTERVAL_DAY_HOUR, INTERVAL_DAY_MINUTE, INTERVAL_DAY_SECOND, INTERVAL_HOUR, INTERVAL_HOUR_MINUTE, INTERVAL_HOUR_SECOND, INTERVAL_MINUTE, INTERVAL_MINUTE_SECOND, INTERVAL_SECOND, TIME_WITH_LOCAL_TIME_ZONE, TIMESTAMP_WITH_LOCAL_TIME_ZONE, FLOAT, MULTISET, DISTINCT, STRUCTURED, ROW, CURSOR, COLUMN_LIST); public static final List BOOLEAN_TYPES = ImmutableList.of(BOOLEAN); public static final List BINARY_TYPES = ImmutableList.of(BINARY, VARBINARY); public static final List INT_TYPES = ImmutableList.of(TINYINT, SMALLINT, INTEGER, BIGINT); public static final List EXACT_TYPES = combine(INT_TYPES, ImmutableList.of(DECIMAL)); public static final List APPROX_TYPES = ImmutableList.of(FLOAT, REAL, DOUBLE); public static final List NUMERIC_TYPES = combine(EXACT_TYPES, APPROX_TYPES); public static final List FRACTIONAL_TYPES = combine(APPROX_TYPES, ImmutableList.of(DECIMAL)); public static final List CHAR_TYPES = ImmutableList.of(CHAR, VARCHAR); public static final List STRING_TYPES = combine(CHAR_TYPES, BINARY_TYPES); public static final List DATETIME_TYPES = ImmutableList.of(DATE, TIME, TIME_WITH_LOCAL_TIME_ZONE, TIMESTAMP, TIMESTAMP_WITH_LOCAL_TIME_ZONE); public static final Set YEAR_INTERVAL_TYPES = Sets.immutableEnumSet(SqlTypeName.INTERVAL_YEAR, SqlTypeName.INTERVAL_YEAR_MONTH, SqlTypeName.INTERVAL_MONTH); public static final Set DAY_INTERVAL_TYPES = Sets.immutableEnumSet(SqlTypeName.INTERVAL_DAY, SqlTypeName.INTERVAL_DAY_HOUR, SqlTypeName.INTERVAL_DAY_MINUTE, SqlTypeName.INTERVAL_DAY_SECOND, SqlTypeName.INTERVAL_HOUR, SqlTypeName.INTERVAL_HOUR_MINUTE, SqlTypeName.INTERVAL_HOUR_SECOND, SqlTypeName.INTERVAL_MINUTE, SqlTypeName.INTERVAL_MINUTE_SECOND, SqlTypeName.INTERVAL_SECOND); public static final Set INTERVAL_TYPES = Sets.immutableEnumSet( Iterables.concat(YEAR_INTERVAL_TYPES, DAY_INTERVAL_TYPES)); private static final Map JDBC_TYPE_TO_NAME = ImmutableMap.builder() .put(Types.TINYINT, TINYINT) .put(Types.SMALLINT, SMALLINT) .put(Types.BIGINT, BIGINT) .put(Types.INTEGER, INTEGER) .put(Types.NUMERIC, DECIMAL) // REVIEW .put(Types.DECIMAL, DECIMAL) .put(Types.FLOAT, FLOAT) .put(Types.REAL, REAL) .put(Types.DOUBLE, DOUBLE) .put(Types.CHAR, CHAR) .put(Types.VARCHAR, VARCHAR) // TODO: provide real support for these eventually .put(ExtraSqlTypes.NCHAR, CHAR) .put(ExtraSqlTypes.NVARCHAR, VARCHAR) // TODO: additional types not yet supported. See ExtraSqlTypes. // .put(Types.LONGVARCHAR, Longvarchar) // .put(Types.CLOB, Clob) // .put(Types.LONGVARBINARY, Longvarbinary) // .put(Types.BLOB, Blob) // .put(Types.LONGNVARCHAR, Longnvarchar) // .put(Types.NCLOB, Nclob) // .put(Types.ROWID, Rowid) // .put(Types.SQLXML, Sqlxml) .put(Types.BINARY, BINARY) .put(Types.VARBINARY, VARBINARY) .put(Types.DATE, DATE) .put(Types.TIME, TIME) .put(Types.TIMESTAMP, TIMESTAMP) .put(Types.BIT, BOOLEAN) .put(Types.BOOLEAN, BOOLEAN) .put(Types.DISTINCT, DISTINCT) .put(Types.STRUCT, STRUCTURED) .put(Types.ARRAY, ARRAY) .build(); /** * Bitwise-or of flags indicating allowable precision/scale combinations. */ private final int signatures; /** * Returns true if not of a "pure" standard sql type. "Inpure" types are * {@link #ANY}, {@link #NULL} and {@link #SYMBOL} */ private final boolean special; private final int jdbcOrdinal; private final @Nullable SqlTypeFamily family; SqlTypeName(int signatures, boolean special, int jdbcType, @Nullable SqlTypeFamily family) { this.signatures = signatures; this.special = special; this.jdbcOrdinal = jdbcType; this.family = family; } /** * Looks up a type name from its name. * * @return Type name, or null if not found */ public static @Nullable SqlTypeName get(String name) { if (false) { // The following code works OK, but the spurious exceptions are // annoying. try { return SqlTypeName.valueOf(name); } catch (IllegalArgumentException e) { return null; } } return VALUES_MAP.get(name); } public boolean allowsNoPrecNoScale() { return (signatures & PrecScale.NO_NO) != 0; } public boolean allowsPrecNoScale() { return (signatures & PrecScale.YES_NO) != 0; } public boolean allowsPrec() { return allowsPrecScale(true, true) || allowsPrecScale(true, false); } public boolean allowsScale() { return allowsPrecScale(true, true); } /** * Returns whether this type can be specified with a given combination of * precision and scale. For example, * *
    *
  • Varchar.allowsPrecScale(true, false) returns * true, because the VARCHAR type allows a precision parameter, as in * VARCHAR(10).
  • *
  • Varchar.allowsPrecScale(true, true) returns * true, because the VARCHAR type does not allow a precision and a * scale parameter, as in VARCHAR(10, 4).
  • *
  • allowsPrecScale(false, true) returns false * for every type.
  • *
* * @param precision Whether the precision/length field is part of the type * specification * @param scale Whether the scale field is part of the type specification * @return Whether this combination of precision/scale is valid */ public boolean allowsPrecScale( boolean precision, boolean scale) { int mask = precision ? (scale ? PrecScale.YES_YES : PrecScale.YES_NO) : (scale ? 0 : PrecScale.NO_NO); return (signatures & mask) != 0; } public boolean isSpecial() { return special; } /** Returns the ordinal from {@link java.sql.Types} corresponding to this * SqlTypeName. */ public int getJdbcOrdinal() { return jdbcOrdinal; } private static List combine( List list0, List list1) { return ImmutableList.builder() .addAll(list0) .addAll(list1) .build(); } /** Returns the default scale for this type if supported, otherwise -1 if * scale is either unsupported or must be specified explicitly. */ public int getDefaultScale() { switch (this) { case DECIMAL: return 0; case INTERVAL_YEAR: case INTERVAL_YEAR_MONTH: case INTERVAL_MONTH: 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: return DEFAULT_INTERVAL_FRACTIONAL_SECOND_PRECISION; default: return -1; } } /** * Gets the SqlTypeFamily containing this SqlTypeName. * * @return containing family, or null for none (SYMBOL, DISTINCT, STRUCTURED, ROW, OTHER) */ public @Nullable SqlTypeFamily getFamily() { return family; } /** * Gets the SqlTypeName corresponding to a JDBC type. * * @param jdbcType the JDBC type of interest * @return corresponding SqlTypeName, or null if the type is not known */ public static @Nullable SqlTypeName getNameForJdbcType(int jdbcType) { return JDBC_TYPE_TO_NAME.get(jdbcType); } /** * Returns the limit of this datatype. For example, * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Datatype limits
DatatypesignlimitbeyondprecisionscaleReturns
Integertruetruefalse-1-12147483647 (2 ^ 31 -1 = MAXINT)
Integertruetruetrue-1-12147483648 (2 ^ 31 = MAXINT + 1)
Integerfalsetruefalse-1-1-2147483648 (-2 ^ 31 = MININT)
Booleantruetruefalse-1-1TRUE
Varchartruetruefalse10-1'ZZZZZZZZZZ'
* * @param sign If true, returns upper limit, otherwise lower limit * @param limit If true, returns value at or near to overflow; otherwise * value at or near to underflow * @param beyond If true, returns the value just beyond the limit, * otherwise the value at the limit * @param precision Precision, or -1 if not applicable * @param scale Scale, or -1 if not applicable * @return Limit value */ public @Nullable Object getLimit( boolean sign, Limit limit, boolean beyond, int precision, int scale) { assert allowsPrecScale(precision != -1, scale != -1) : this; if (limit == Limit.ZERO) { if (beyond) { return null; } sign = true; } Calendar calendar; switch (this) { case BOOLEAN: switch (limit) { case ZERO: return false; case UNDERFLOW: return null; case OVERFLOW: if (beyond || !sign) { return null; } else { return true; } default: throw Util.unexpected(limit); } case TINYINT: return getNumericLimit(2, 8, sign, limit, beyond); case SMALLINT: return getNumericLimit(2, 16, sign, limit, beyond); case INTEGER: return getNumericLimit(2, 32, sign, limit, beyond); case BIGINT: return getNumericLimit(2, 64, sign, limit, beyond); case DECIMAL: BigDecimal decimal = getNumericLimit(10, precision, sign, limit, beyond); if (decimal == null) { return null; } // Decimal values must fit into 64 bits. So, the maximum value of // a DECIMAL(19, 0) is 2^63 - 1, not 10^19 - 1. switch (limit) { case OVERFLOW: final BigDecimal other = (BigDecimal) BIGINT.getLimit(sign, limit, beyond, -1, -1); if (other != null && decimal.compareTo(other) == (sign ? 1 : -1)) { decimal = other; } break; default: break; } // Apply scale. if (scale == 0) { // do nothing } else if (scale > 0) { decimal = decimal.divide(BigDecimal.TEN.pow(scale)); } else { decimal = decimal.multiply(BigDecimal.TEN.pow(-scale)); } return decimal; case CHAR: case VARCHAR: if (!sign) { return null; // this type does not have negative values } StringBuilder buf = new StringBuilder(); switch (limit) { case ZERO: break; case UNDERFLOW: if (beyond) { // There is no value between the empty string and the // smallest non-empty string. return null; } buf.append("a"); break; case OVERFLOW: for (int i = 0; i < precision; ++i) { buf.append("Z"); } if (beyond) { buf.append("Z"); } break; default: break; } return buf.toString(); case BINARY: case VARBINARY: if (!sign) { return null; // this type does not have negative values } byte[] bytes; switch (limit) { case ZERO: bytes = new byte[0]; break; case UNDERFLOW: if (beyond) { // There is no value between the empty string and the // smallest value. return null; } bytes = new byte[]{0x00}; break; case OVERFLOW: bytes = new byte[precision + (beyond ? 1 : 0)]; Arrays.fill(bytes, (byte) 0xff); break; default: throw Util.unexpected(limit); } return bytes; case DATE: calendar = Util.calendar(); switch (limit) { case ZERO: // The epoch. calendar.set(Calendar.YEAR, 1970); calendar.set(Calendar.MONTH, 0); calendar.set(Calendar.DAY_OF_MONTH, 1); break; case UNDERFLOW: return null; case OVERFLOW: if (beyond) { // It is impossible to represent an invalid year as a date // literal. SQL dates are represented as 'yyyy-mm-dd', and // 1 <= yyyy <= 9999 is valid. There is no year 0: the year // before 1AD is 1BC, so SimpleDateFormat renders the day // before 0001-01-01 (AD) as 0001-12-31 (BC), which looks // like a valid date. return null; } // "SQL:2003 6.1 Access Rules 6" says that year is // between 1 and 9999, and days/months are the valid Gregorian // calendar values for these years. if (sign) { calendar.set(Calendar.YEAR, 9999); calendar.set(Calendar.MONTH, 11); calendar.set(Calendar.DAY_OF_MONTH, 31); } else { calendar.set(Calendar.YEAR, 1); calendar.set(Calendar.MONTH, 0); calendar.set(Calendar.DAY_OF_MONTH, 1); } break; default: break; } calendar.set(Calendar.HOUR_OF_DAY, 0); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); return calendar; case TIME: if (!sign) { return null; // this type does not have negative values } if (beyond) { return null; // invalid values are impossible to represent } calendar = Util.calendar(); switch (limit) { case ZERO: // The epoch. calendar.set(Calendar.HOUR_OF_DAY, 0); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); calendar.set(Calendar.MILLISECOND, 0); break; case UNDERFLOW: return null; case OVERFLOW: calendar.set(Calendar.HOUR_OF_DAY, 23); calendar.set(Calendar.MINUTE, 59); calendar.set(Calendar.SECOND, 59); int millis = (precision >= 3) ? 999 : ((precision == 2) ? 990 : ((precision == 1) ? 900 : 0)); calendar.set(Calendar.MILLISECOND, millis); break; default: break; } return calendar; case TIMESTAMP: calendar = Util.calendar(); switch (limit) { case ZERO: // The epoch. calendar.set(Calendar.YEAR, 1970); calendar.set(Calendar.MONTH, 0); calendar.set(Calendar.DAY_OF_MONTH, 1); calendar.set(Calendar.HOUR_OF_DAY, 0); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); calendar.set(Calendar.MILLISECOND, 0); break; case UNDERFLOW: return null; case OVERFLOW: if (beyond) { // It is impossible to represent an invalid year as a date // literal. SQL dates are represented as 'yyyy-mm-dd', and // 1 <= yyyy <= 9999 is valid. There is no year 0: the year // before 1AD is 1BC, so SimpleDateFormat renders the day // before 0001-01-01 (AD) as 0001-12-31 (BC), which looks // like a valid date. return null; } // "SQL:2003 6.1 Access Rules 6" says that year is // between 1 and 9999, and days/months are the valid Gregorian // calendar values for these years. if (sign) { calendar.set(Calendar.YEAR, 9999); calendar.set(Calendar.MONTH, 11); calendar.set(Calendar.DAY_OF_MONTH, 31); calendar.set(Calendar.HOUR_OF_DAY, 23); calendar.set(Calendar.MINUTE, 59); calendar.set(Calendar.SECOND, 59); int millis = (precision >= 3) ? 999 : ((precision == 2) ? 990 : ((precision == 1) ? 900 : 0)); calendar.set(Calendar.MILLISECOND, millis); } else { calendar.set(Calendar.YEAR, 1); calendar.set(Calendar.MONTH, 0); calendar.set(Calendar.DAY_OF_MONTH, 1); calendar.set(Calendar.HOUR_OF_DAY, 0); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); calendar.set(Calendar.MILLISECOND, 0); } break; default: break; } return calendar; default: throw Util.unexpected(this); } } /** * Returns the minimum precision (or length) allowed for this type, or -1 if * precision/length are not applicable for this type. * * @return Minimum allowed precision */ public int getMinPrecision() { switch (this) { case DECIMAL: case VARCHAR: case CHAR: case VARBINARY: case BINARY: case TIME: case TIME_WITH_LOCAL_TIME_ZONE: case TIMESTAMP: case TIMESTAMP_WITH_LOCAL_TIME_ZONE: return 1; case INTERVAL_YEAR: case INTERVAL_YEAR_MONTH: case INTERVAL_MONTH: 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: return MIN_INTERVAL_START_PRECISION; default: return -1; } } /** * Returns the minimum scale (or fractional second precision in the case of * intervals) allowed for this type, or -1 if precision/length are not * applicable for this type. * * @return Minimum allowed scale */ public int getMinScale() { switch (this) { // TODO: Minimum numeric scale for decimal case INTERVAL_YEAR: case INTERVAL_YEAR_MONTH: case INTERVAL_MONTH: 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: return MIN_INTERVAL_FRACTIONAL_SECOND_PRECISION; default: return -1; } } /** Returns {@code HOUR} for {@code HOUR TO SECOND} and * {@code HOUR}, {@code SECOND} for {@code SECOND}. */ public TimeUnit getStartUnit() { switch (this) { case INTERVAL_YEAR: case INTERVAL_YEAR_MONTH: return TimeUnit.YEAR; case INTERVAL_MONTH: return TimeUnit.MONTH; case INTERVAL_DAY: case INTERVAL_DAY_HOUR: case INTERVAL_DAY_MINUTE: case INTERVAL_DAY_SECOND: return TimeUnit.DAY; case INTERVAL_HOUR: case INTERVAL_HOUR_MINUTE: case INTERVAL_HOUR_SECOND: return TimeUnit.HOUR; case INTERVAL_MINUTE: case INTERVAL_MINUTE_SECOND: return TimeUnit.MINUTE; case INTERVAL_SECOND: return TimeUnit.SECOND; default: throw new AssertionError(this); } } /** Returns {@code SECOND} for both {@code HOUR TO SECOND} and * {@code SECOND}. */ public TimeUnit getEndUnit() { switch (this) { case INTERVAL_YEAR: return TimeUnit.YEAR; case INTERVAL_YEAR_MONTH: case INTERVAL_MONTH: return TimeUnit.MONTH; case INTERVAL_DAY: return TimeUnit.DAY; case INTERVAL_DAY_HOUR: case INTERVAL_HOUR: return TimeUnit.HOUR; case INTERVAL_DAY_MINUTE: case INTERVAL_HOUR_MINUTE: case INTERVAL_MINUTE: return TimeUnit.MINUTE; case INTERVAL_DAY_SECOND: case INTERVAL_HOUR_SECOND: case INTERVAL_MINUTE_SECOND: case INTERVAL_SECOND: return TimeUnit.SECOND; default: throw new AssertionError(this); } } public boolean isYearMonth() { switch (this) { case INTERVAL_YEAR: case INTERVAL_YEAR_MONTH: case INTERVAL_MONTH: return true; default: return false; } } /** Limit. */ public enum Limit { ZERO, UNDERFLOW, OVERFLOW } private static @Nullable BigDecimal getNumericLimit( int radix, int exponent, boolean sign, Limit limit, boolean beyond) { switch (limit) { case OVERFLOW: // 2-based schemes run from -2^(N-1) to 2^(N-1)-1 e.g. -128 to +127 // 10-based schemas run from -(10^N-1) to 10^N-1 e.g. -99 to +99 final BigDecimal bigRadix = BigDecimal.valueOf(radix); if (radix == 2) { --exponent; } BigDecimal decimal = bigRadix.pow(exponent); if (sign || (radix != 2)) { decimal = decimal.subtract(BigDecimal.ONE); } if (beyond) { decimal = decimal.add(BigDecimal.ONE); } if (!sign) { decimal = decimal.negate(); } return decimal; case UNDERFLOW: return beyond ? null : (sign ? BigDecimal.ONE : BigDecimal.ONE.negate()); case ZERO: return BigDecimal.ZERO; default: throw Util.unexpected(limit); } } public SqlLiteral createLiteral(Object o, SqlParserPos pos) { switch (this) { case BOOLEAN: return SqlLiteral.createBoolean((Boolean) o, pos); case TINYINT: case SMALLINT: case INTEGER: case BIGINT: case DECIMAL: return SqlLiteral.createExactNumeric(o.toString(), pos); case VARCHAR: case CHAR: return SqlLiteral.createCharString((String) o, pos); case VARBINARY: case BINARY: return SqlLiteral.createBinaryString((byte[]) o, pos); case DATE: return SqlLiteral.createDate(o instanceof Calendar ? DateString.fromCalendarFields((Calendar) o) : (DateString) o, pos); case TIME: return SqlLiteral.createTime(o instanceof Calendar ? TimeString.fromCalendarFields((Calendar) o) : (TimeString) o, 0 /* todo */, pos); case TIMESTAMP: return SqlLiteral.createTimestamp(o instanceof Calendar ? TimestampString.fromCalendarFields((Calendar) o) : (TimestampString) o, 0 /* todo */, pos); default: throw Util.unexpected(this); } } /** Returns the name of this type. */ public String getName() { return toString(); } /** * Flags indicating precision/scale combinations. * *

Note: for intervals: * *

    *
  • precision = start (leading field) precision
  • *
  • scale = fractional second precision
  • *
*/ private interface PrecScale { int NO_NO = 1; int YES_NO = 2; int YES_YES = 4; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy