001/** 002 * 003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. 004 * 005 * This library is free software; you can redistribute it and/or 006 * modify it under the terms of the GNU Lesser General Public 007 * License as published by the Free Software Foundation; either 008 * version 2.1 of the License, or (at your option) any later version. 009 * 010 * This library is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013 * Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public 016 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 017 * 018 **/ 019package lucee.runtime.type; 020 021import java.io.Serializable; 022import java.sql.Types; 023import java.util.Date; 024 025import lucee.runtime.op.Caster; 026import lucee.runtime.op.Decision; 027 028 029/** 030 * Helper class for the QueryColumnImpl 031 */ 032public final class QueryColumnUtil implements Serializable { 033 034 private static final long serialVersionUID = 4654833724194716718L; 035 036 /** 037 * reset the type of the column 038 */ 039 protected static void resetType(QueryColumnImpl column) { 040 column.type=Types.OTHER; 041 } 042 043 /** 044 * redefine type of value 045 * @param value 046 * @return redefined type of the value 047 */ 048 protected static Object reDefineType(QueryColumnImpl column,Object value) { 049 column.typeChecked=false; 050 if(value==null || column.type==Types.OTHER)return value; 051 if(value instanceof String && ((String)value).isEmpty()) return null; 052 053 switch(column.type) { 054 055 // Numeric Values 056 case Types.DOUBLE: return reDefineDouble(column,value); 057 case Types.BIGINT: return reDefineDecimal(column,value); 058 case Types.NUMERIC: return reDefineDouble(column,value); 059 case Types.INTEGER: return reDefineInteger(column,value); 060 case Types.TINYINT: return reDefineTinyInt(column,value); 061 case Types.FLOAT: return reDefineFloat(column,value); 062 case Types.DECIMAL: return reDefineDecimal(column,value); 063 case Types.REAL: return reDefineFloat(column,value); 064 case Types.SMALLINT:return reDefineShort(column,value); 065 066 // DateTime Values 067 case Types.TIMESTAMP: return reDefineDateTime(column,value); 068 case Types.DATE: return reDefineDateTime(column,value); 069 case Types.TIME: return reDefineDateTime(column,value); 070 071 // Char 072 case Types.CHAR: return reDefineString(column,value); 073 case Types.VARCHAR: return reDefineString(column,value); 074 case Types.LONGVARCHAR: return reDefineString(column,value); 075 case Types.CLOB: return reDefineClob(column,value); 076 077 // Boolean 078 case Types.BOOLEAN: return reDefineBoolean(column,value); 079 case Types.BIT: return reDefineBoolean(column,value); 080 081 // Binary 082 case Types.BINARY: return reDefineBinary(column,value); 083 case Types.VARBINARY: return reDefineBinary(column,value); 084 case Types.LONGVARBINARY: return reDefineBinary(column,value); 085 case Types.BLOB: return reDefineBlob(column,value); 086 087 // Others 088 case Types.ARRAY: return reDefineOther(column,value); 089 case Types.DATALINK: return reDefineOther(column,value); 090 case Types.DISTINCT: return reDefineOther(column,value); 091 case Types.JAVA_OBJECT: return reDefineOther(column,value); 092 case Types.NULL: return reDefineOther(column,value); 093 case Types.STRUCT: return reDefineOther(column,value); 094 case Types.REF: return reDefineOther(column,value); 095 default: return value; 096 } 097 098 } 099 100 private static Object reDefineBoolean(QueryColumnImpl column,Object value) { 101 if(Decision.isCastableToBoolean(value)) 102 return value; 103 104 resetType(column); 105 return value; 106 } 107 108 private static Object reDefineDouble(QueryColumnImpl column,Object value) { 109 if(Decision.isCastableToNumeric(value)) 110 return value; 111 112 resetType(column); 113 return value; 114 } 115 116 private static Object reDefineFloat(QueryColumnImpl column,Object value) { 117 if(Decision.isCastableToNumeric(value)) 118 return value; 119 resetType(column); 120 return value; 121 } 122 123 private static Object reDefineInteger(QueryColumnImpl column,Object value) { 124 if(Decision.isCastableToNumeric(value)) 125 return value; 126 resetType(column); 127 return value; 128 } 129 130 private static Object reDefineShort(QueryColumnImpl column, Object value) { 131 132 double dbl = Caster.toDoubleValue(value,true,Double.NaN); 133 if(Decision.isValid(dbl)) { 134 short sht=(short)dbl; 135 if(sht==dbl)return value; 136 137 column.type=Types.DOUBLE; 138 return value; 139 } 140 resetType(column); 141 return value; 142 } 143 144 private static Object reDefineTinyInt(QueryColumnImpl column,Object value) { 145 if(Decision.isCastableToNumeric(value)) 146 return value; 147 resetType(column); 148 return value; 149 } 150 151 private static Object reDefineDecimal(QueryColumnImpl column,Object value) { 152 if(Decision.isCastableToNumeric(value)) 153 return value; 154 resetType(column); 155 return value; 156 } 157 158 private static Object reDefineDateTime(QueryColumnImpl column, Object value) { 159 if(Decision.isDateSimple(value,true)) 160 return value; 161 resetType(column); 162 return value; 163 } 164 165 private static Object reDefineString(QueryColumnImpl column, Object value) { 166 if(Decision.isCastableToString(value)) 167 return value; 168 resetType(column); 169 return value; 170 } 171 172 private static Object reDefineClob(QueryColumnImpl column, Object value) { 173 if(Decision.isCastableToString(value)) 174 return value; 175 resetType(column); 176 return value; 177 } 178 179 private static Object reDefineBinary(QueryColumnImpl column, Object value) { 180 if(Decision.isCastableToBinary(value,false)) 181 return value; 182 183 resetType(column); 184 return value; 185 186 187 } 188 189 private static Object reDefineBlob(QueryColumnImpl column,Object value) { 190 if(Decision.isCastableToBinary(value,false)) 191 return value; 192 resetType(column); 193 return value; 194 195 196 } 197 198 private static Object reDefineOther(QueryColumnImpl column,Object value) { 199 resetType(column); 200 return value; 201 } 202 203 204 /** 205 * reorganize type of a column 206 * @param reorganize 207 */ 208 protected static void reOrganizeType(QueryColumnImpl column) { 209 if((column.type==Types.OTHER) && !column.typeChecked) { 210 column.typeChecked=true; 211 if(column.size()>0) { 212 checkOther(column,column.data[0]); 213 214 // get Type 215 for(int i=1;i<column.size();i++) { 216 switch(column.type) { 217 case Types.NULL:checkOther(column,column.data[i]);break; 218 case Types.TIMESTAMP:checkDate(column,column.data[i]);break; 219 //case Types.DATE:checkDate(column.data[i]);break; 220 case Types.BOOLEAN:checkBoolean(column,column.data[i]);break; 221 case Types.DOUBLE:checkDouble(column,column.data[i]);break; 222 case Types.VARCHAR:checkBasic(column,column.data[i]);break; 223 default:break; 224 } 225 } 226 } 227 } 228 } 229 230 231 232 233 private static void checkOther(QueryColumnImpl column, Object value) { 234 // NULL 235 if(value==null) { 236 column.type=Types.NULL; 237 return; 238 } 239 // DateTime 240 if(Decision.isDateSimple(value,false)) { 241 column.type=Types.TIMESTAMP; 242 return; 243 } 244 // Boolean 245 if(Decision.isBoolean(value)) { 246 column.type=Types.BOOLEAN; 247 return; 248 } 249 // Double 250 if(Decision.isNumeric(value)) { 251 column.type=Types.DOUBLE; 252 return; 253 } 254 // String 255 String str = Caster.toString(value,null); 256 if(str!=null) { 257 column.type=Types.VARCHAR; 258 return; 259 } 260 } 261 262 private static void checkDate(QueryColumnImpl column,Object value) { 263 // NULL 264 if(value==null) return; 265 // DateTime 266 if(Decision.isDateSimple(value,false)) { 267 column.type=Types.TIMESTAMP; 268 return; 269 } 270 // String 271 String str = Caster.toString(value,null); 272 if(str!=null) { 273 column.type=Types.VARCHAR; 274 return; 275 } 276 // Other 277 column.type=Types.OTHER; 278 return; 279 } 280 281 private static void checkBoolean(QueryColumnImpl column, Object value) { 282 // NULL 283 if(value==null) return; 284 // Boolean 285 if(Decision.isBoolean(value)) { 286 column.type=Types.BOOLEAN; 287 return; 288 } 289 // Double 290 if(Decision.isNumeric(value)) { 291 column.type=Types.DOUBLE; 292 return; 293 } 294 // String 295 String str = Caster.toString(value,null); 296 if(str!=null) { 297 column.type=Types.VARCHAR; 298 return; 299 } 300 // Other 301 column.type=Types.OTHER; 302 return; 303 } 304 private static void checkDouble(QueryColumnImpl column,Object value) { 305 // NULL 306 if(value==null) return; 307 // Double 308 if(Decision.isNumeric(value)) { 309 column.type=Types.DOUBLE; 310 return; 311 } 312 // String 313 String str = Caster.toString(value,null); 314 if(str!=null) { 315 column.type=Types.VARCHAR; 316 return; 317 } 318 // Other 319 column.type=Types.OTHER; 320 return; 321 } 322 323 private static void checkBasic(QueryColumnImpl column,Object value) { 324 // NULL 325 if(value==null) return; 326 // Date 327 if(value instanceof Date || value instanceof Number) return; 328 // String 329 String str = Caster.toString(value,null); 330 if(str!=null) { 331 return; 332 } 333 // OTHER 334 column.type=Types.OTHER; 335 return; 336 } 337}