package railo.runtime.type;
import java.io.Serializable;
import java.sql.Types;
import java.util.Date;
import railo.runtime.op.Caster;
import railo.runtime.op.Decision;
/**
* Helper class for the QueryColumnImpl
*/
public final class QueryColumnUtil implements Serializable {
private static final long serialVersionUID = 4654833724194716718L;
/**
* reset the type of the column
*/
protected static void resetType(QueryColumnImpl column) {
column.type=Types.OTHER;
}
/**
* redefine type of value
* @param value
* @return redefined type of the value
*/
protected static Object reDefineType(QueryColumnImpl column,Object value) {
column.typeChecked=false;
if(value==null || column.type==Types.OTHER)return value;
if(value instanceof String && ((String)value).isEmpty()) return null;
switch(column.type) {
// Numeric Values
case Types.DOUBLE: return reDefineDouble(column,value);
case Types.BIGINT: return reDefineDecimal(column,value);
case Types.NUMERIC: return reDefineDouble(column,value);
case Types.INTEGER: return reDefineInteger(column,value);
case Types.TINYINT: return reDefineTinyInt(column,value);
case Types.FLOAT: return reDefineFloat(column,value);
case Types.DECIMAL: return reDefineDecimal(column,value);
case Types.REAL: return reDefineFloat(column,value);
case Types.SMALLINT:return reDefineShort(column,value);
// DateTime Values
case Types.TIMESTAMP: return reDefineDateTime(column,value);
case Types.DATE: return reDefineDateTime(column,value);
case Types.TIME: return reDefineDateTime(column,value);
// Char
case Types.CHAR: return reDefineString(column,value);
case Types.VARCHAR: return reDefineString(column,value);
case Types.LONGVARCHAR: return reDefineString(column,value);
case Types.CLOB: return reDefineClob(column,value);
// Boolean
case Types.BOOLEAN: return reDefineBoolean(column,value);
case Types.BIT: return reDefineBoolean(column,value);
// Binary
case Types.BINARY: return reDefineBinary(column,value);
case Types.VARBINARY: return reDefineBinary(column,value);
case Types.LONGVARBINARY: return reDefineBinary(column,value);
case Types.BLOB: return reDefineBlob(column,value);
// Others
case Types.ARRAY: return reDefineOther(column,value);
case Types.DATALINK: return reDefineOther(column,value);
case Types.DISTINCT: return reDefineOther(column,value);
case Types.JAVA_OBJECT: return reDefineOther(column,value);
case Types.NULL: return reDefineOther(column,value);
case Types.STRUCT: return reDefineOther(column,value);
case Types.REF: return reDefineOther(column,value);
default: return value;
}
}
private static Object reDefineBoolean(QueryColumnImpl column,Object value) {
if(Decision.isCastableToBoolean(value))
return value;
resetType(column);
return value;
}
private static Object reDefineDouble(QueryColumnImpl column,Object value) {
if(Decision.isCastableToNumeric(value))
return value;
resetType(column);
return value;
}
private static Object reDefineFloat(QueryColumnImpl column,Object value) {
if(Decision.isCastableToNumeric(value))
return value;
resetType(column);
return value;
}
private static Object reDefineInteger(QueryColumnImpl column,Object value) {
if(Decision.isCastableToNumeric(value))
return value;
resetType(column);
return value;
}
private static Object reDefineShort(QueryColumnImpl column, Object value) {
double dbl = Caster.toDoubleValue(value,Double.NaN);
if(Decision.isValid(dbl)) {
short sht=(short)dbl;
if(sht==dbl)return value;
column.type=Types.DOUBLE;
return value;
}
resetType(column);
return value;
}
private static Object reDefineTinyInt(QueryColumnImpl column,Object value) {
if(Decision.isCastableToNumeric(value))
return value;
resetType(column);
return value;
}
private static Object reDefineDecimal(QueryColumnImpl column,Object value) {
if(Decision.isCastableToNumeric(value))
return value;
resetType(column);
return value;
}
private static Object reDefineDateTime(QueryColumnImpl column, Object value) {
if(Decision.isDateSimple(value,true))
return value;
resetType(column);
return value;
}
private static Object reDefineString(QueryColumnImpl column, Object value) {
if(Decision.isCastableToString(value))
return value;
resetType(column);
return value;
}
private static Object reDefineClob(QueryColumnImpl column, Object value) {
if(Decision.isCastableToString(value))
return value;
resetType(column);
return value;
}
private static Object reDefineBinary(QueryColumnImpl column, Object value) {
if(Decision.isCastableToBinary(value,false))
return value;
resetType(column);
return value;
}
private static Object reDefineBlob(QueryColumnImpl column,Object value) {
if(Decision.isCastableToBinary(value,false))
return value;
resetType(column);
return value;
}
private static Object reDefineOther(QueryColumnImpl column,Object value) {
resetType(column);
return value;
}
/**
* reorganize type of a column
* @param reorganize
*/
protected static void reOrganizeType(QueryColumnImpl column) {
if((column.type==Types.OTHER) && !column.typeChecked) {
column.typeChecked=true;
if(column.size()>0) {
checkOther(column,column.data[0]);
// get Type
for(int i=1;i<column.size();i++) {
switch(column.type) {
case Types.NULL:checkOther(column,column.data[i]);break;
case Types.TIMESTAMP:checkDate(column,column.data[i]);break;
//case Types.DATE:checkDate(column.data[i]);break;
case Types.BOOLEAN:checkBoolean(column,column.data[i]);break;
case Types.DOUBLE:checkDouble(column,column.data[i]);break;
case Types.VARCHAR:checkBasic(column,column.data[i]);break;
default:break;
}
}
}
}
}
private static void checkOther(QueryColumnImpl column, Object value) {
// NULL
if(value==null) {
column.type=Types.NULL;
return;
}
// DateTime
if(Decision.isDateSimple(value,false)) {
column.type=Types.TIMESTAMP;
return;
}
// Boolean
if(Decision.isBoolean(value)) {
column.type=Types.BOOLEAN;
return;
}
// Double
if(Decision.isNumeric(value)) {
column.type=Types.DOUBLE;
return;
}
// String
String str = Caster.toString(value,null);
if(str!=null) {
column.type=Types.VARCHAR;
return;
}
}
private static void checkDate(QueryColumnImpl column,Object value) {
// NULL
if(value==null) return;
// DateTime
if(Decision.isDateSimple(value,false)) {
column.type=Types.TIMESTAMP;
return;
}
// String
String str = Caster.toString(value,null);
if(str!=null) {
column.type=Types.VARCHAR;
return;
}
// Other
column.type=Types.OTHER;
return;
}
private static void checkBoolean(QueryColumnImpl column, Object value) {
// NULL
if(value==null) return;
// Boolean
if(Decision.isBoolean(value)) {
column.type=Types.BOOLEAN;
return;
}
// Double
if(Decision.isNumeric(value)) {
column.type=Types.DOUBLE;
return;
}
// String
String str = Caster.toString(value,null);
if(str!=null) {
column.type=Types.VARCHAR;
return;
}
// Other
column.type=Types.OTHER;
return;
}
private static void checkDouble(QueryColumnImpl column,Object value) {
// NULL
if(value==null) return;
// Double
if(Decision.isNumeric(value)) {
column.type=Types.DOUBLE;
return;
}
// String
String str = Caster.toString(value,null);
if(str!=null) {
column.type=Types.VARCHAR;
return;
}
// Other
column.type=Types.OTHER;
return;
}
private static void checkBasic(QueryColumnImpl column,Object value) {
// NULL
if(value==null) return;
// Date
if(value instanceof Date || value instanceof Number) return;
// String
String str = Caster.toString(value,null);
if(str!=null) {
return;
}
// OTHER
column.type=Types.OTHER;
return;
}
}