/**
* Copyright (C) 2009-2013 FoundationDB, LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.foundationdb.server.types.mcompat.mtypes;
import com.foundationdb.server.types.TClass;
import com.foundationdb.server.types.TInstance;
import com.foundationdb.server.types.common.types.TypesTranslator;
import com.foundationdb.server.types.value.ValueSource;
import com.foundationdb.server.types.value.ValueTarget;
import com.foundationdb.sql.types.DataTypeDescriptor;
import com.foundationdb.sql.types.TypeId;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import java.sql.Types;
public class MTypesTranslator extends TypesTranslator
{
public static final TypesTranslator INSTANCE = new MTypesTranslator();
private MTypesTranslator() {
}
@Override
public TClass typeClassForJDBCType(int jdbcType,
String schemaName, String tableName, String columnName) {
switch (jdbcType) {
case Types.BIGINT:
return MNumeric.BIGINT;
case Types.BINARY:
case Types.BIT:
return MBinary.BINARY;
case Types.CHAR:
case Types.NCHAR:
return MString.CHAR;
case Types.CLOB:
case Types.NCLOB:
case Types.LONGVARCHAR:
case Types.LONGNVARCHAR:
//case Types.SQLXML:
return MString.LONGTEXT;
case Types.DATE:
return MDateAndTime.DATE;
case Types.DECIMAL:
case Types.NUMERIC:
return MNumeric.DECIMAL;
case Types.DOUBLE:
return MApproximateNumber.DOUBLE;
case Types.FLOAT:
case Types.REAL:
return MApproximateNumber.FLOAT;
case Types.INTEGER:
return MNumeric.INT;
case Types.SMALLINT:
return MNumeric.SMALLINT;
case Types.TIME:
return MDateAndTime.TIME;
case Types.TIMESTAMP:
return MDateAndTime.DATETIME; // (Not TIMESTAMP.)
case Types.TINYINT:
return MNumeric.TINYINT;
case Types.VARBINARY:
return MBinary.VARBINARY;
case Types.VARCHAR:
case Types.NVARCHAR:
return MString.VARCHAR;
default:
return super.typeClassForJDBCType(jdbcType, schemaName, tableName, columnName);
}
}
@Override
protected TInstance typeForSQLType(TypeId typeId, DataTypeDescriptor sqlType,
int defaultCharsetId, int defaultCollationId,
String schemaName, String tableName, String columnName) {
// Handle non-standard / more-specific cases.
switch (typeId.getTypeFormatId()) {
case TypeId.FormatIds.TINYINT_TYPE_ID:
if (typeId.isUnsigned()) {
return MNumeric.TINYINT_UNSIGNED.instance(sqlType.isNullable());
}
break;
case TypeId.FormatIds.SMALLINT_TYPE_ID:
if (typeId == TypeId.YEAR_ID) {
return MDateAndTime.YEAR.instance(sqlType.isNullable());
}
else if (typeId.isUnsigned()) {
return MNumeric.SMALLINT_UNSIGNED.instance(sqlType.isNullable());
}
break;
case TypeId.FormatIds.MEDIUMINT_ID:
if (typeId.isUnsigned()) {
return MNumeric.MEDIUMINT_UNSIGNED.instance(sqlType.isNullable());
}
else {
return MNumeric.MEDIUMINT.instance(sqlType.isNullable());
}
case TypeId.FormatIds.INT_TYPE_ID:
if (typeId.isUnsigned()) {
return MNumeric.INT_UNSIGNED.instance(sqlType.isNullable());
}
break;
case TypeId.FormatIds.LONGINT_TYPE_ID:
if (typeId.isUnsigned()) {
return MNumeric.BIGINT_UNSIGNED.instance(sqlType.isNullable());
}
break;
case TypeId.FormatIds.REAL_TYPE_ID:
if (typeId.isUnsigned()) {
return MApproximateNumber.FLOAT_UNSIGNED.instance(sqlType.isNullable());
}
break;
case TypeId.FormatIds.DOUBLE_TYPE_ID:
if (typeId.isUnsigned()) {
return MApproximateNumber.DOUBLE_UNSIGNED.instance(sqlType.isNullable());
}
break;
case TypeId.FormatIds.DECIMAL_TYPE_ID:
if (typeId.isUnsigned()) {
return MNumeric.DECIMAL_UNSIGNED.instance(sqlType.getPrecision(), sqlType.getScale(), sqlType.isNullable());
}
break;
/* (This would be needed to allow timestamp in DDL to mean timestamp
and not datetime.)
case TypeId.FormatIds.TIMESTAMP_TYPE_ID:
if (typeId == TypeId.DATETIME_ID) {
return MDatetimes.DATETIME.instance(sqlType.isNullable());
}
break;
*/
case TypeId.FormatIds.CLOB_TYPE_ID:
if (typeId == TypeId.TINYTEXT_ID) {
return typeForStringType(MString.TINYTEXT, sqlType,
defaultCharsetId, defaultCollationId,
schemaName, tableName, columnName);
}
if (typeId == TypeId.TEXT_ID) {
return typeForStringType(MString.TEXT, sqlType,
defaultCharsetId, defaultCollationId,
schemaName, tableName, columnName);
}
if (typeId == TypeId.MEDIUMTEXT_ID) {
return typeForStringType(MString.MEDIUMTEXT, sqlType,
defaultCharsetId, defaultCollationId,
schemaName, tableName, columnName);
}
if (typeId == TypeId.LONGTEXT_ID) {
return typeForStringType(MString.LONGTEXT, sqlType,
defaultCharsetId, defaultCollationId,
schemaName, tableName, columnName);
}
break;
}
return super.typeForSQLType(typeId, sqlType,
defaultCharsetId, defaultCollationId,
schemaName, tableName, columnName);
}
@Override
public Class<?> jdbcClass(TInstance type) {
TClass tclass = TInstance.tClass(type);
if (tclass == MDateAndTime.DATE)
return java.sql.Date.class;
if ((tclass == MDateAndTime.TIMESTAMP) ||
(tclass == MDateAndTime.DATETIME))
return java.sql.Timestamp.class;
if ((tclass == MNumeric.DECIMAL) ||
(tclass == MNumeric.DECIMAL_UNSIGNED))
return java.math.BigDecimal.class;
if ((tclass == MApproximateNumber.DOUBLE) ||
(tclass == MApproximateNumber.DOUBLE_UNSIGNED))
return Double.class;
if ((tclass == MApproximateNumber.FLOAT) ||
(tclass == MApproximateNumber.FLOAT_UNSIGNED))
return Float.class;
if (tclass == MNumeric.TINYINT)
return Byte.class;
if ((tclass == MNumeric.TINYINT_UNSIGNED) ||
(tclass == MNumeric.SMALLINT) ||
(tclass == MDateAndTime.YEAR))
return Short.class;
if ((tclass == MNumeric.SMALLINT_UNSIGNED) ||
(tclass == MNumeric.INT) ||
(tclass == MNumeric.MEDIUMINT))
return Integer.class;
if ((tclass == MNumeric.INT_UNSIGNED) ||
(tclass == MNumeric.BIGINT))
return Long.class;
if (tclass == MNumeric.BIGINT_UNSIGNED)
return java.math.BigInteger.class;
if ((tclass == MString.CHAR) ||
(tclass == MString.VARCHAR) ||
(tclass == MString.TINYTEXT) ||
(tclass == MString.MEDIUMTEXT) ||
(tclass == MString.TEXT) ||
(tclass == MString.LONGTEXT))
return String.class;
if (tclass == MDateAndTime.TIME)
return java.sql.Time.class;
if ((tclass == MBinary.VARBINARY) ||
(tclass == MBinary.BINARY))
return byte[].class;
return super.jdbcClass(type);
}
@Override
public boolean isTypeSigned(TInstance type) {
TClass tclass = TInstance.tClass(type);
return ((tclass == MNumeric.TINYINT) ||
(tclass == MNumeric.SMALLINT) ||
(tclass == MNumeric.MEDIUMINT) ||
(tclass == MNumeric.INT) ||
(tclass == MNumeric.BIGINT) ||
(tclass == MNumeric.DECIMAL) ||
(tclass == MApproximateNumber.DOUBLE) ||
(tclass == MApproximateNumber.FLOAT));
}
@Override
public long getIntegerValue(ValueSource value) {
long base = super.getIntegerValue(value);
if (TInstance.tClass(value.getType()) == MDateAndTime.YEAR) {
base += 1900;
}
return base;
}
@Override
public void setIntegerValue(ValueTarget target, long value) {
if (TInstance.tClass(target.getType()) == MDateAndTime.YEAR) {
value -= 1900;
}
super.setIntegerValue(target, value);
}
@Override
public TClass typeClassForSystemTimestamp() {
return MDateAndTime.TIMESTAMP;
}
@Override
public long getTimestampMillisValue(ValueSource value) {
TClass tclass = TInstance.tClass(value.getType());
long[] ymdhms = null;
if (tclass == MDateAndTime.DATE) {
ymdhms = MDateAndTime.decodeDate(value.getInt32());
}
else if (tclass == MDateAndTime.TIME) {
ymdhms = MDateAndTime.decodeTime(value.getInt32());
}
else if (tclass == MDateAndTime.DATETIME) {
ymdhms = MDateAndTime.decodeDateTime(value.getInt64());
}
if (ymdhms != null) {
DateTime dt = new DateTime((int)ymdhms[0], (int)ymdhms[1], (int)ymdhms[2],
(int)ymdhms[3], (int)ymdhms[4], (int)ymdhms[5]);
return dt.getMillis();
}
else {
return value.getInt32() * 1000L;
}
}
@Override
public void setTimestampMillisValue(ValueTarget value, long millis, int nanos) {
TClass tclass = TInstance.tClass(value.getType());
if (tclass == MDateAndTime.DATE) {
value.putInt32(MDateAndTime.encodeDate(millis, DateTimeZone.getDefault().getID()));
}
else if (tclass == MDateAndTime.TIME) {
value.putInt32(MDateAndTime.encodeTime(millis, DateTimeZone.getDefault().getID()));
}
else if (tclass == MDateAndTime.DATETIME) {
value.putInt64(MDateAndTime.encodeDateTime(millis, DateTimeZone.getDefault().getID()));
}
else {
value.putInt32((int)(millis / 1000));
}
}
}