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.query;
020
021import java.io.IOException;
022import java.sql.ResultSet;
023import java.sql.SQLException;
024import java.sql.Types;
025import java.util.Iterator;
026import java.util.Map.Entry;
027
028import lucee.commons.lang.ExceptionUtil;
029import lucee.commons.sql.SQLUtil;
030import lucee.runtime.PageContext;
031import lucee.runtime.db.CFTypes;
032import lucee.runtime.dump.DumpData;
033import lucee.runtime.dump.DumpProperties;
034import lucee.runtime.engine.ThreadLocalPageContext;
035import lucee.runtime.exp.DatabaseException;
036import lucee.runtime.exp.PageException;
037import lucee.runtime.op.Caster;
038import lucee.runtime.query.caster.Cast;
039import lucee.runtime.type.Collection;
040import lucee.runtime.type.KeyImpl;
041import lucee.runtime.type.QueryColumn;
042import lucee.runtime.type.QueryImpl;
043import lucee.runtime.type.dt.DateTime;
044import lucee.runtime.type.it.EntryIterator;
045import lucee.runtime.type.scope.Undefined;
046
047public class SimpleQueryColumn implements QueryColumn {
048
049        private static final long serialVersionUID = 288731277532671308L;
050
051        private SimpleQuery qry;
052        private Key key;
053        private int type;
054        private ResultSet res;
055        private Cast cast;
056        private int index;
057        //private Object[] data;
058
059        public SimpleQueryColumn(SimpleQuery qry, ResultSet res, Collection.Key key, int type, int index) {
060                this.qry=qry;
061                this.res=res;
062                this.key=key;
063                this.index=index;
064                
065                try {
066                        switch(type){
067                        case Types.TIMESTAMP:
068                                cast=Cast.TIMESTAMP;
069                        break;
070                        case Types.TIME:
071                                cast=Cast.TIME;
072                        break;
073                        case Types.DATE:
074                                cast=Cast.DATE;
075                        break;
076                        case Types.CLOB:
077                                cast=Cast.CLOB;
078                        break;
079                        case Types.BLOB:
080                                cast=Cast.BLOB;
081                        break;
082                        case Types.BIT:
083                                cast=Cast.BIT;
084                        break;
085                        case Types.ARRAY:
086                                cast=Cast.ARRAY;
087                        break;
088                        case Types.BIGINT:
089                                cast=Cast.BIGINT;
090                        break;
091                        
092                        case CFTypes.OPAQUE:
093                                if(SQLUtil.isOracle(res.getStatement().getConnection()))
094                                cast=Cast.ORACLE_OPAQUE;
095                        else 
096                                cast=Cast.OTHER;
097                        break;
098                        default:
099                                cast=Cast.OTHER;
100                        break;
101                        }
102                }
103                catch (Exception e) {
104                        throw SimpleQuery.toRuntimeExc(e);
105                }
106        }
107
108        public Object get(Key key, Object defaultValue) {
109                int row=Caster.toIntValue(key,Integer.MIN_VALUE);
110                if(row==Integer.MIN_VALUE) {
111                        Object child=getChildElement(key,null);
112                if(child!=null) return child;
113            return defaultValue;
114        }
115            return get(row,defaultValue);
116        }
117        
118        public Object get(Key key) throws PageException {
119                int row=Caster.toIntValue(key,Integer.MIN_VALUE);
120                if(row==Integer.MIN_VALUE) {
121                        Object child=getChildElement(key,null);
122                if(child!=null) return child;
123            throw new DatabaseException("key ["+key+"] not found",null,null,null);
124        }
125            return get(row);
126        }
127        
128        
129        private Object getChildElement(Key key, Object defaultValue) {
130        PageContext pc = ThreadLocalPageContext.get();
131                // column and query has same name
132                if(key.equals(this.key)) {
133                return get(qry.getCurrentrow(pc.getId()),defaultValue);
134        }
135        // get it from undefined scope
136                if(pc!=null){
137                        Undefined undefined = pc.undefinedScope();
138                        boolean old = undefined.setAllowImplicidQueryCall(false);
139                        Object sister = undefined.get(this.key,null);
140                        undefined.setAllowImplicidQueryCall(old);
141                        if(sister!=null){
142                                try {
143                                        return pc.get(sister, key);
144                                } catch (PageException e) {
145                                        return defaultValue;
146                                }
147                        }
148                }
149        return defaultValue;
150        }
151        
152        public int size() {
153                throw SimpleQuery.notSupported();
154        }
155
156        
157        public Key[] keys() {
158                throw SimpleQuery.notSupported();
159        }
160
161        
162        public Object remove(Key key) throws PageException {
163                throw SimpleQuery.notSupported();
164        }
165
166        
167        public Object removeEL(Key key) {
168                throw SimpleQuery.notSupported();
169        }
170
171        
172        public void clear() {
173                throw SimpleQuery.notSupported();
174        }
175
176
177        
178        public Object get(String key) throws PageException {
179                return get(KeyImpl.init(key));
180        }
181        
182        public Object get(String key, Object defaultValue) {
183                return get(KeyImpl.init(key),defaultValue);
184        }
185
186        public Object set(String key, Object value) throws PageException {
187                throw SimpleQuery.notSupported();
188        }
189
190        
191        public Object set(Key key, Object value) throws PageException {
192                throw SimpleQuery.notSupported();
193        }
194
195        
196        public Object setEL(String key, Object value) {
197                throw SimpleQuery.notSupported();
198        }
199
200        
201        public Object setEL(Key key, Object value) {
202                throw SimpleQuery.notSupported();
203        }
204
205        
206        public Collection duplicate(boolean deepCopy) {
207                throw SimpleQuery.notSupported();
208        }
209
210        
211        public boolean containsKey(String key) {
212                throw SimpleQuery.notSupported();
213        }
214
215        
216        public boolean containsKey(Key key) {
217                throw SimpleQuery.notSupported();
218        }
219
220        
221        @Override
222        public DumpData toDumpData(PageContext pageContext, int maxlevel,
223                        DumpProperties properties) {
224                throw SimpleQuery.notSupported();
225        }
226
227        @Override
228        public Iterator<Collection.Key> keyIterator() {
229                throw SimpleQuery.notSupported();
230        }
231    
232    @Override
233        public Iterator<String> keysAsStringIterator() {
234        throw SimpleQuery.notSupported();
235    }
236        
237        @Override
238        public Iterator<Entry<Key, Object>> entryIterator() {
239                return new EntryIterator(this,keys());
240        }
241
242        
243        public Iterator<Object> valueIterator() {
244                throw SimpleQuery.notSupported();
245        }
246
247        
248        public String castToString() throws PageException {
249                // TODO Auto-generated method stub
250                return Caster.toString(get(key));
251        }
252
253        
254        public String castToString(String defaultValue) {
255                return Caster.toString(get(key,defaultValue),defaultValue);
256        }
257
258        
259        public boolean castToBooleanValue() throws PageException {
260                return Caster.toBoolean(get(key));
261        }
262
263        
264        public Boolean castToBoolean(Boolean defaultValue) {
265                return Caster.toBoolean(get(key,defaultValue),defaultValue);
266        }
267
268        
269        public double castToDoubleValue() throws PageException {
270                return Caster.toDoubleValue(get(key));
271        }
272
273        
274        public double castToDoubleValue(double defaultValue) {
275                return Caster.toDoubleValue(get(key,defaultValue),true,defaultValue);
276        }
277
278        
279        public DateTime castToDateTime() throws PageException {
280                return Caster.toDate(get(key), false, null);
281        }
282
283        
284        public DateTime castToDateTime(DateTime defaultValue) {
285                return Caster.toDate(get(key,defaultValue), false, null, defaultValue);
286        }
287
288        
289        public int compareTo(String str) throws PageException {
290                throw SimpleQuery.notSupported();
291        }
292
293        
294        public int compareTo(boolean b) throws PageException {
295                throw SimpleQuery.notSupported();
296        }
297
298        
299        public int compareTo(double d) throws PageException {
300                throw SimpleQuery.notSupported();
301        }
302
303        
304        public int compareTo(DateTime dt) throws PageException {
305                throw SimpleQuery.notSupported();
306        }
307
308        
309        public String getKeyAsString() {
310                return key.getString();
311        }
312
313        
314        public Key getKey() {
315                return key;
316        }
317
318        
319        public Object get(PageContext pc) throws PageException {
320                return get(key);
321        }
322
323        
324        public Object get(PageContext pc, Object defaultValue) {
325                return get(key,defaultValue);
326        }
327
328        
329        public Object set(PageContext pc, Object value) throws PageException {
330                throw SimpleQuery.notSupported();
331        }
332
333        
334        public Object setEL(PageContext pc, Object value) {
335                throw SimpleQuery.notSupported();
336        }
337
338        
339        public Object remove(PageContext pc) throws PageException {
340                throw SimpleQuery.notSupported();
341        }
342
343        
344        public Object removeEL(PageContext pc) {
345                throw SimpleQuery.notSupported();
346        }
347
348        
349        public Object touch(PageContext pc) throws PageException {
350                throw SimpleQuery.notSupported();
351        }
352
353        
354        public Object touchEL(PageContext pc) {
355                throw SimpleQuery.notSupported();
356        }
357
358        
359        public Object getParent() {
360                return qry;
361        }
362
363        
364        public Object remove(int row) throws PageException {
365                throw SimpleQuery.notSupported();
366        }
367
368        
369        public Object removeRow(int row) throws PageException {
370                throw SimpleQuery.notSupported();
371        }
372
373        
374        public Object removeEL(int row) {
375                throw SimpleQuery.notSupported();
376        }
377
378        @Override
379        public synchronized Object get(int row) throws PageException {
380                //Object sv = getStoredValue(row);
381                //if(sv!=SimpleQuery.DEFAULT_VALUE) return sv;
382                
383                try {
384                        if(row!=res.getRow()) {
385                                res.absolute(row);
386                        }
387                        return _get(row);
388                }
389                catch (Throwable t) {
390                        throw Caster.toPageException(t);
391                }
392        }
393
394        @Override
395        public synchronized Object get(int row, Object defaultValue) {
396                //Object sv = getStoredValue(row);
397                //if(sv!=SimpleQuery.DEFAULT_VALUE) return sv;
398                
399                try {
400                        if(row!=res.getRow()) {
401                                res.absolute(row);
402                        }
403                        return _get(row);
404                }
405                catch (Throwable t) {
406                        ExceptionUtil.rethrowIfNecessary(t);
407                        return defaultValue;
408                }
409        }
410        
411        /*private synchronized Object getStoredValue(int row) {
412                if(data==null) return SimpleQuery.DEFAULT_VALUE;
413                return data[row-1];
414        }
415        
416        private synchronized Object _get(int row) throws SQLException, IOException {
417                if(data==null) {
418                        data=new Object[qry.getRecordcount()];
419                        for(int i=0;i<data.length;i++){
420                                data[i]=SimpleQuery.DEFAULT_VALUE;
421                        }
422                        
423                }
424                return data[row-1]=cast.toCFType(null, type, res, index);
425        }*/
426        
427        private Object _get(int row) throws SQLException, IOException {
428                return cast.toCFType(null, type, res, index);
429        }
430
431        
432        public Object set(int row, Object value) throws PageException {
433                throw SimpleQuery.notSupported();
434        }
435
436        
437        public void add(Object value) {
438                throw SimpleQuery.notSupported();
439        }
440
441        
442        public Object setEL(int row, Object value) {
443                throw SimpleQuery.notSupported();
444        }
445
446        
447        public void addRow(int count) {
448                throw SimpleQuery.notSupported();
449        }
450
451        
452        public int getType() {
453                return type;
454        }
455
456        
457        public String getTypeAsString() {
458                return QueryImpl.getColumTypeName(type);
459        }
460
461        
462        public void cutRowsTo(int maxrows) {
463                throw SimpleQuery.notSupported();
464
465        }
466        
467        public Object clone() {
468                throw SimpleQuery.notSupported();
469        }
470
471
472        public int getIndex() {
473                return index;
474        }
475        
476        @Override
477        public java.util.Iterator<String> getIterator() {
478        return keysAsStringIterator();
479    }
480}