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}