/**
* com.mckoi.database.global.CastHelper 11 Oct 2001
*
* Mckoi SQL Database ( http://www.mckoi.com/database )
* Copyright (C) 2000, 2001, 2002 Diehl and Associates, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* Version 2 as published by the Free Software Foundation.
*
* 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 General Public License Version 2 for more details.
*
* You should have received a copy of the GNU General Public License
* Version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Change Log:
*
*
*/
package com.mckoi.database.global;
import java.text.SimpleDateFormat;
import java.text.ParseException;
import java.text.DateFormat;
import com.mckoi.util.BigNumber;
import java.util.Date;
/**
* Various utility methods for helping to cast a Java object to a type that
* is conformant to an SQL type.
*
* @author Tobias Downer
*/
public class CastHelper {
/**
* A couple of standard BigNumber statics.
*/
private static BigNumber BD_ZERO = BigNumber.fromLong(0);
private static BigNumber BD_ONE = BigNumber.fromLong(1);
/**
* Date, Time and Timestamp parser/formatters
*/
private static DateFormat[] date_format_sql;
private static DateFormat[] time_format_sql;
private static DateFormat[] ts_format_sql;
static {
// The SQL time/date formatters
date_format_sql = new DateFormat[1];
date_format_sql[0] = new SimpleDateFormat("yyyy-MM-dd");
time_format_sql = new DateFormat[4];
time_format_sql[0] = new SimpleDateFormat("HH:mm:ss.S z");
time_format_sql[1] = new SimpleDateFormat("HH:mm:ss.S");
time_format_sql[2] = new SimpleDateFormat("HH:mm:ss z");
time_format_sql[3] = new SimpleDateFormat("HH:mm:ss");
ts_format_sql = new DateFormat[4];
ts_format_sql[0] = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S z");
ts_format_sql[1] = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S");
ts_format_sql[2] = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
ts_format_sql[3] = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}
/**
* Converts the given object to an SQL JAVA_OBJECT type by serializing
* the object.
*/
private static Object toJavaObject(Object ob) {
try {
return ObjectTranslator.serialize(ob);
}
catch (Throwable e) {
throw new Error("Can't serialize object " + ob.getClass());
}
}
/**
* Formats the date object as a standard SQL string.
*/
private static String formatDateAsString(Date d) {
synchronized (ts_format_sql) {
// ISSUE: We have to assume the date is a time stamp because we don't
// know if the date object represents an SQL DATE, TIMESTAMP or TIME.
return ts_format_sql[1].format(d);
}
}
/**
* Returns the given string padded or truncated to the given size. If size
* is -1 then the size doesn't matter.
*/
private static String paddedString(String str, int size) {
if (size == -1) {
return str;
}
int dif = size - str.length();
if (dif > 0) {
StringBuffer buf = new StringBuffer(str);
for (int n = 0; n < dif; ++n) {
buf.append(' ');
}
return new String(buf);
}
else if (dif < 0) {
return str.substring(0, size);
}
return str;
}
/**
* Returns the given long value as a date object.
*/
private static Date toDate(long time) {
return new Date(time);
}
/**
* Converts the given string to a BigNumber. Returns 0 if the cast fails.
*/
private static BigNumber toBigNumber(String str) {
try {
return BigNumber.fromString(str);
}
catch (Throwable e) {
return BD_ZERO;
}
}
/**
* Helper that generates an appropriate error message for a date format error.
*/
private static String dateErrorString(String msg, DateFormat[] df) {
String pattern = "";
if (df[0] instanceof SimpleDateFormat) {
SimpleDateFormat sdf = (SimpleDateFormat) df[0];
pattern = "(" + sdf.toPattern() + ")";
}
return msg + pattern;
}
/**
* Parses a String as an SQL date.
*/
public static Date toDate(String str) {
synchronized(date_format_sql) {
for (int i = 0; i < date_format_sql.length; ++i) {
try {
return date_format_sql[i].parse(str);
}
catch (ParseException e) {}
}
throw new RuntimeException(
dateErrorString("Unable to parse string as a date ",
date_format_sql));
}
}
/**
* Parses a String as an SQL time.
*/
public static Date toTime(String str) {
synchronized(time_format_sql) {
for (int i = 0; i < time_format_sql.length; ++i) {
try {
return time_format_sql[i].parse(str);
}
catch (ParseException e) {}
}
throw new RuntimeException(
dateErrorString("Unable to parse string as a time ",
time_format_sql));
}
}
/**
* Parses a String as an SQL timestamp.
*/
public static Date toTimeStamp(String str) {
synchronized(ts_format_sql) {
for (int i = 0; i < ts_format_sql.length; ++i) {
try {
return ts_format_sql[i].parse(str);
}
catch (ParseException e) {}
}
throw new RuntimeException(
dateErrorString("Unable to parse string as a timestamp ",
ts_format_sql));
}
}
/**
* Casts a Java object to the SQL type specified by the given
* DataTableColumnDef object. This is used for the following engine
* functions;
* <ol>
* <li> To prepare a value for insertion into the data store. For example,
* the table column may be STRING but the value here is a BigNumber.
* <li> To cast an object to a specific type in an SQL function such as
* CAST.
* </ol>
* Given any supported object, this will return the internal database
* representation of the object as either NullObject, BigNumber, String,
* Date, Boolean or ByteLongObject.
*
* @param ob the Object to cast to the given type
* @param sql_type the enumerated sql type, eg. SQLTypes.LONGVARCHAR
* @param sql_size the size of the type. For example, CHAR(20)
* @param sql_scale the scale of the numerical type.
* @param sql_type_string 'sql_type' as a human understandable string,
* eg. "LONGVARCHAR"
*/
public static Object castObjectToSQLType(Object ob,
int sql_type, int sql_size, int sql_scale, String sql_type_string) {
// if (ob == null) {
// ob = NullObject.NULL_OBJ;
// }
// int sql_type = col_def.getSQLType();
// int sql_size = col_def.getSize();
// int sql_scale = col_def.getScale();
// String sql_type_string = col_def.getSQLTypeString();
// If the input object is a ByteLongObject and the output type is not a
// binary SQL type then we need to attempt to deserialize the object.
if (ob instanceof ByteLongObject) {
if ( sql_type != SQLTypes.JAVA_OBJECT &&
sql_type != SQLTypes.BLOB &&
sql_type != SQLTypes.BINARY &&
sql_type != SQLTypes.VARBINARY &&
sql_type != SQLTypes.LONGVARBINARY ) {
// Attempt to deserialize it
try {
ob = ObjectTranslator.deserialize((ByteLongObject) ob);
}
catch (Throwable e) {
// Couldn't deserialize so it must be a standard blob which means
// we are in error.
throw new Error("Can't cast a BLOB to " + sql_type_string);
}
}
else {
// This is a ByteLongObject that is being cast to a binary type so
// no further processing is necessary.
return ob;
}
}
// BlobRef can be BINARY, JAVA_OBJECT, VARBINARY or LONGVARBINARY
if (ob instanceof BlobRef) {
if (sql_type == SQLTypes.BINARY ||
sql_type == SQLTypes.BLOB ||
sql_type == SQLTypes.JAVA_OBJECT ||
sql_type == SQLTypes.VARBINARY ||
sql_type == SQLTypes.LONGVARBINARY) {
return ob;
}
}
// ClobRef can be VARCHAR, LONGVARCHAR, or CLOB
if (ob instanceof ClobRef) {
if (sql_type == SQLTypes.VARCHAR ||
sql_type == SQLTypes.LONGVARCHAR ||
sql_type == SQLTypes.CLOB) {
return ob;
}
}
// Cast from NULL
if (ob == null) {
switch (sql_type) {
case(SQLTypes.BIT):
// fall through
case(SQLTypes.TINYINT):
// fall through
case(SQLTypes.SMALLINT):
// fall through
case(SQLTypes.INTEGER):
// fall through
case(SQLTypes.BIGINT):
// fall through
case(SQLTypes.FLOAT):
// fall through
case(SQLTypes.REAL):
// fall through
case(SQLTypes.DOUBLE):
// fall through
case(SQLTypes.NUMERIC):
// fall through
case(SQLTypes.DECIMAL):
// fall through
case(SQLTypes.CHAR):
// fall through
case(SQLTypes.VARCHAR):
// fall through
case(SQLTypes.LONGVARCHAR):
// fall through
case(SQLTypes.CLOB):
// fall through
case(SQLTypes.DATE):
// fall through
case(SQLTypes.TIME):
// fall through
case(SQLTypes.TIMESTAMP):
// fall through
case(SQLTypes.NULL):
// fall through
case(SQLTypes.BINARY):
// fall through
case(SQLTypes.VARBINARY):
// fall through
case(SQLTypes.LONGVARBINARY):
// fall through
case(SQLTypes.BLOB):
// fall through
case(SQLTypes.JAVA_OBJECT):
// fall through
case(SQLTypes.BOOLEAN):
return null;
default:
throw new Error("Can't cast NULL to " + sql_type_string);
}
}
// Cast from a number
if (ob instanceof Number) {
Number n = (Number) ob;
switch (sql_type) {
case(SQLTypes.BIT):
return n.intValue() == 0 ? Boolean.FALSE : Boolean.TRUE;
case(SQLTypes.TINYINT):
// fall through
case(SQLTypes.SMALLINT):
// fall through
case(SQLTypes.INTEGER):
// return new BigDecimal(n.intValue());
return BigNumber.fromLong(n.intValue());
case(SQLTypes.BIGINT):
// return new BigDecimal(n.longValue());
return BigNumber.fromLong(n.longValue());
case(SQLTypes.FLOAT):
return BigNumber.fromString(Double.toString(n.doubleValue()));
case(SQLTypes.REAL):
return BigNumber.fromString(n.toString());
case(SQLTypes.DOUBLE):
return BigNumber.fromString(Double.toString(n.doubleValue()));
case(SQLTypes.NUMERIC):
// fall through
case(SQLTypes.DECIMAL):
return BigNumber.fromString(n.toString());
case(SQLTypes.CHAR):
return StringObject.fromString(paddedString(n.toString(), sql_size));
case(SQLTypes.VARCHAR):
return StringObject.fromString(n.toString());
case(SQLTypes.LONGVARCHAR):
return StringObject.fromString(n.toString());
case(SQLTypes.DATE):
return toDate(n.longValue());
case(SQLTypes.TIME):
return toDate(n.longValue());
case(SQLTypes.TIMESTAMP):
return toDate(n.longValue());
case(SQLTypes.BLOB):
// fall through
case(SQLTypes.BINARY):
// fall through
case(SQLTypes.VARBINARY):
// fall through
case(SQLTypes.LONGVARBINARY):
return new ByteLongObject(n.toString().getBytes());
case(SQLTypes.NULL):
return null;
case(SQLTypes.JAVA_OBJECT):
return toJavaObject(ob);
case(SQLTypes.BOOLEAN):
return n.intValue() == 0 ? Boolean.FALSE : Boolean.TRUE;
default:
throw new Error("Can't cast number to " + sql_type_string);
}
} // if (ob instanceof Number)
// Cast from a string
if (ob instanceof StringObject || ob instanceof String) {
String str = ob.toString();
switch (sql_type) {
case(SQLTypes.BIT):
return str.equalsIgnoreCase("true") ? Boolean.TRUE : Boolean.FALSE;
case(SQLTypes.TINYINT):
// fall through
case(SQLTypes.SMALLINT):
// fall through
case(SQLTypes.INTEGER):
// return new BigDecimal(toBigDecimal(str).intValue());
return BigNumber.fromLong(toBigNumber(str).intValue());
case(SQLTypes.BIGINT):
// return new BigDecimal(toBigDecimal(str).longValue());
return BigNumber.fromLong(toBigNumber(str).longValue());
case(SQLTypes.FLOAT):
return BigNumber.fromString(
Double.toString(toBigNumber(str).doubleValue()));
case(SQLTypes.REAL):
return toBigNumber(str);
case(SQLTypes.DOUBLE):
return BigNumber.fromString(
Double.toString(toBigNumber(str).doubleValue()));
case(SQLTypes.NUMERIC):
// fall through
case(SQLTypes.DECIMAL):
return toBigNumber(str);
case(SQLTypes.CHAR):
return StringObject.fromString(paddedString(str, sql_size));
case(SQLTypes.VARCHAR):
return StringObject.fromString(str);
case(SQLTypes.LONGVARCHAR):
return StringObject.fromString(str);
case(SQLTypes.DATE):
return toDate(str);
case(SQLTypes.TIME):
return toTime(str);
case(SQLTypes.TIMESTAMP):
return toTimeStamp(str);
case(SQLTypes.BLOB):
// fall through
case(SQLTypes.BINARY):
// fall through
case(SQLTypes.VARBINARY):
// fall through
case(SQLTypes.LONGVARBINARY):
return new ByteLongObject(str.getBytes());
case(SQLTypes.NULL):
return null;
case(SQLTypes.JAVA_OBJECT):
return toJavaObject(str);
case(SQLTypes.BOOLEAN):
return str.equalsIgnoreCase("true") ? Boolean.TRUE : Boolean.FALSE;
case(SQLTypes.CLOB):
return StringObject.fromString(str);
default:
throw new Error("Can't cast string to " + sql_type_string);
}
} // if (ob instanceof String)
// Cast from a boolean
if (ob instanceof Boolean) {
Boolean b = (Boolean) ob;
switch (sql_type) {
case(SQLTypes.BIT):
return b;
case(SQLTypes.TINYINT):
// fall through
case(SQLTypes.SMALLINT):
// fall through
case(SQLTypes.INTEGER):
// fall through
case(SQLTypes.BIGINT):
// fall through
case(SQLTypes.FLOAT):
// fall through
case(SQLTypes.REAL):
// fall through
case(SQLTypes.DOUBLE):
// fall through
case(SQLTypes.NUMERIC):
// fall through
case(SQLTypes.DECIMAL):
return b.equals(Boolean.TRUE) ? BD_ONE : BD_ZERO;
case(SQLTypes.CHAR):
return StringObject.fromString(paddedString(b.toString(), sql_size));
case(SQLTypes.VARCHAR):
return StringObject.fromString(b.toString());
case(SQLTypes.LONGVARCHAR):
return StringObject.fromString(b.toString());
case(SQLTypes.NULL):
return null;
case(SQLTypes.JAVA_OBJECT):
return toJavaObject(ob);
case(SQLTypes.BOOLEAN):
return b;
default:
throw new Error("Can't cast boolean to " + sql_type_string);
}
} // if (ob instanceof Boolean)
// Cast from a date
if (ob instanceof Date) {
Date d = (Date) ob;
switch (sql_type) {
case(SQLTypes.TINYINT):
// fall through
case(SQLTypes.SMALLINT):
// fall through
case(SQLTypes.INTEGER):
// fall through
case(SQLTypes.BIGINT):
// fall through
case(SQLTypes.FLOAT):
// fall through
case(SQLTypes.REAL):
// fall through
case(SQLTypes.DOUBLE):
// fall through
case(SQLTypes.NUMERIC):
// fall through
case(SQLTypes.DECIMAL):
return BigNumber.fromLong(d.getTime());
case(SQLTypes.CHAR):
return StringObject.fromString(paddedString(formatDateAsString(d), sql_size));
case(SQLTypes.VARCHAR):
return StringObject.fromString(formatDateAsString(d));
case(SQLTypes.LONGVARCHAR):
return StringObject.fromString(formatDateAsString(d));
case(SQLTypes.DATE):
return d;
case(SQLTypes.TIME):
return d;
case(SQLTypes.TIMESTAMP):
return d;
case(SQLTypes.NULL):
return null;
case(SQLTypes.JAVA_OBJECT):
return toJavaObject(ob);
default:
throw new Error("Can't cast date to " + sql_type_string);
}
} // if (ob instanceof Date)
// Some obscure types
if (ob instanceof byte[]) {
switch (sql_type) {
case(SQLTypes.BLOB):
// fall through
case(SQLTypes.BINARY):
// fall through
case(SQLTypes.VARBINARY):
// fall through
case(SQLTypes.LONGVARBINARY):
return new ByteLongObject((byte[]) ob);
default:
throw new Error("Can't cast byte[] to " + sql_type_string);
}
}
// Finally, the object can only be something that we can cast to a
// JAVA_OBJECT.
if (sql_type == SQLTypes.JAVA_OBJECT) {
return toJavaObject(ob);
}
throw new RuntimeException("Can't cast object " + ob.getClass() + " to " +
sql_type_string);
}
}
|