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.InputStream;
022import java.io.Reader;
023import java.math.BigDecimal;
024import java.net.URL;
025import java.sql.Array;
026import java.sql.Blob;
027import java.sql.Clob;
028import java.sql.Date;
029import java.sql.NClob;
030import java.sql.PreparedStatement;
031import java.sql.Ref;
032import java.sql.ResultSet;
033import java.sql.ResultSetMetaData;
034import java.sql.RowId;
035import java.sql.SQLException;
036import java.sql.SQLFeatureNotSupportedException;
037import java.sql.SQLWarning;
038import java.sql.SQLXML;
039import java.sql.Statement;
040import java.sql.Time;
041import java.sql.Timestamp;
042import java.sql.Types;
043import java.util.ArrayList;
044import java.util.Calendar;
045import java.util.HashMap;
046import java.util.Iterator;
047import java.util.LinkedHashMap;
048import java.util.List;
049import java.util.Map;
050import java.util.Map.Entry;
051import java.util.TimeZone;
052
053import lucee.commons.lang.ExceptionUtil;
054import lucee.commons.lang.StringUtil;
055import lucee.loader.engine.CFMLEngineFactory;
056import lucee.runtime.PageContext;
057import lucee.runtime.PageContextImpl;
058import lucee.runtime.db.DataSourceUtil;
059import lucee.runtime.db.DatasourceConnection;
060import lucee.runtime.db.SQL;
061import lucee.runtime.db.SQLCaster;
062import lucee.runtime.db.SQLItem;
063import lucee.runtime.dump.DumpData;
064import lucee.runtime.dump.DumpProperties;
065import lucee.runtime.engine.ThreadLocalPageContext;
066import lucee.runtime.exp.ApplicationException;
067import lucee.runtime.exp.DatabaseException;
068import lucee.runtime.exp.ExpressionException;
069import lucee.runtime.exp.PageException;
070import lucee.runtime.exp.PageRuntimeException;
071import lucee.runtime.op.Caster;
072import lucee.runtime.type.ArrayImpl;
073import lucee.runtime.type.ArrayInt;
074import lucee.runtime.type.Collection;
075import lucee.runtime.type.KeyImpl;
076import lucee.runtime.type.Objects;
077import lucee.runtime.type.Query;
078import lucee.runtime.type.QueryColumn;
079import lucee.runtime.type.QueryColumnRef;
080import lucee.runtime.type.QueryImpl;
081import lucee.runtime.type.Struct;
082import lucee.runtime.type.StructImpl;
083import lucee.runtime.type.dt.DateTime;
084import lucee.runtime.type.dt.TimeSpan;
085import lucee.runtime.type.it.CollectionIterator;
086import lucee.runtime.type.it.EntryIterator;
087import lucee.runtime.type.it.ForEachQueryIterator;
088import lucee.runtime.type.it.KeyIterator;
089import lucee.runtime.type.it.StringIterator;
090import lucee.runtime.type.util.KeyConstants;
091import lucee.runtime.type.util.QueryUtil;
092
093public class SimpleQuery implements Query, ResultSet, Objects {
094        
095        static final Object DEFAULT_VALUE = new Object();
096        private ResultSet res;
097        private ResultSetMetaData meta;
098        private Collection.Key[] columnNames;
099        private Map<String,SimpleQueryColumn> columns=new LinkedHashMap<String, SimpleQueryColumn>();
100        private int[] _types;
101        
102        private String name;
103        private String template;
104        private SQL sql;
105        private long exeTime;
106        private int recordcount;
107        private ArrayInt arrCurrentRow=new ArrayInt();
108        
109
110        public SimpleQuery(PageContext pc,DatasourceConnection dc,SQL sql,int maxrow, int fetchsize,TimeSpan timeout, String name,String template,TimeZone tz) throws PageException {
111                this.name=name;
112                this.template=template;
113        this.sql=sql;
114                
115        //ResultSet result=null;
116                Statement stat=null;
117                // check SQL Restrictions
118                if(dc.getDatasource().hasSQLRestriction()) {
119            QueryUtil.checkSQLRestriction(dc,sql);
120        }
121                
122                //Stopwatch stopwatch=new Stopwatch(Stopwatch.UNIT_NANO);
123                //stopwatch.start();
124                long start=System.nanoTime();
125                boolean hasResult=false;
126                try {   
127                        SQLItem[] items=sql.getItems();
128                        if(items.length==0) {
129                        stat=dc.getConnection().createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
130                        setAttributes(stat,maxrow,fetchsize,timeout);
131                     // some driver do not support second argument
132                        hasResult=stat.execute(sql.getSQLString());
133                }
134                else {
135                        // some driver do not support second argument
136                        PreparedStatement preStat = dc.getPreparedStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
137                        stat=preStat;
138                    setAttributes(preStat,maxrow,fetchsize,timeout);
139                    setItems(tz,preStat,items);
140                        hasResult=preStat.execute();    
141                }
142                        ResultSet res;
143                        
144                        do {
145                                if(hasResult) {
146                                        res=stat.getResultSet();
147                                        init(res);
148                                        break;
149                                }
150                                throw new ApplicationException("Simple queries can only be used for queries returning a resultset");
151                        }
152                        while(true);
153                } 
154                catch (SQLException e) {
155                        throw new DatabaseException(e,sql,dc);
156                } 
157                catch (Throwable e) {
158                        throw Caster.toPageException(e);
159                }
160                exeTime= System.nanoTime()-start;
161                
162                ((PageContextImpl)pc).registerLazyStatement(stat);
163        }
164        
165        private void setAttributes(Statement stat,int maxrow, int fetchsize,TimeSpan timeout) throws SQLException {
166                if(maxrow>-1) stat.setMaxRows(maxrow);
167        if(fetchsize>0)stat.setFetchSize(fetchsize);
168        if(timeout!=null && timeout.getSeconds()>0)
169                DataSourceUtil.setQueryTimeoutSilent(stat,(int)timeout.getSeconds());
170        }
171        private void setItems(TimeZone tz,PreparedStatement preStat, SQLItem[] items) throws DatabaseException, PageException, SQLException {
172                for(int i=0;i<items.length;i++) {
173            SQLCaster.setValue(tz,preStat,i+1,items[i]);
174        }
175        }
176        
177        private void init(ResultSet res) throws SQLException{
178                this.res=res;
179                this.meta=res.getMetaData();
180                
181                // init columns
182                int columncount = meta.getColumnCount();
183                List<Key> tmpKeys=new ArrayList<Key>();
184                //List<Integer> tmpTypes=new ArrayList<Integer>();
185                //int count=0;
186                Collection.Key key;
187                String columnName;
188                int type;
189                for(int i=0;i<columncount;i++) {
190                        try {
191                                columnName=meta.getColumnName(i+1);
192                                type=meta.getColumnType(i+1);
193                        } catch (SQLException e) {
194                                throw toRuntimeExc(e);
195                        }
196                        if(StringUtil.isEmpty(columnName))columnName="column_"+i;
197                        key=KeyImpl.init(columnName);
198                        int index=tmpKeys.indexOf(key);
199                        if(index==-1) {
200                                //mappings.put(key.getLowerString(), Caster.toInteger(i+1));
201                                tmpKeys.add(key);
202                                //tmpTypes.add(type);
203                                columns.put(key.getLowerString(), new SimpleQueryColumn(this,res, key,type, i+1));
204                                
205                                //count++;
206                        }
207                        
208                }
209                columnNames=tmpKeys.toArray(new Key[tmpKeys.size()]);
210                
211                res.last();
212                recordcount=res.getRow();
213                res.beforeFirst();
214                /*Iterator<Integer> it = tmpTypes.iterator();
215                types=new int[tmpTypes.size()];
216                int index=0;
217                while(it.hasNext()){
218                        types[index++]=it.next();
219                }*/
220                
221                
222        }
223
224        @Override
225        public int executionTime() {
226                return (int)exeTime;
227        }
228
229        @Override
230        
231        public int getUpdateCount() {
232                throw notSupported();
233        }
234
235        @Override
236        public int size() {
237                return columnNames.length;
238        }
239
240        @Override
241        
242        public Key[] keys() {
243                return columnNames;
244        }
245
246        @Override
247        public Object removeEL(Key key) {
248                throw notSupported();
249        }
250
251        @Override
252        public Object remove(Key key) throws PageException {
253                throw notSupported();
254        }
255
256        @Override
257        public void clear() {
258                throw notSupported();
259        }
260
261        @Override
262        
263        public Object get(Key key, Object defaultValue) {
264                int pid = getPid();
265                return getAt(key, getCurrentrow(pid),pid,defaultValue);
266        }
267
268        @Override
269        public Object get(String key, Object defaultValue) {
270                return get(KeyImpl.init(key),defaultValue);
271        }
272
273        @Override
274        public Object get(String key) throws PageException {
275                return get(KeyImpl.init(key));
276        }
277
278        @Override
279        
280        public Object get(Key key) throws PageException {
281                int pid = getPid();
282                return getAt(key, getCurrentrow(pid),pid);
283        }
284
285        public Object getAt(Key key, int row, int pid, Object defaultValue) {
286                char c=key.lowerCharAt(0);
287        if(c=='r') {
288            if(key.equals(KeyConstants._RECORDCOUNT)) return new Double(getRecordcount());
289        }
290        else if(c=='c') {
291            if(key.equals(KeyConstants._CURRENTROW)) return new Double(getCurrentrow(pid));
292            else if(key.equals(KeyConstants._COLUMNLIST)) return getColumnlist();
293        }
294        
295        SimpleQueryColumn column = columns.get(key.getLowerString());
296        if(column==null) return null;
297                try {
298                        return column.get(row,defaultValue);
299                } 
300                catch (Throwable t) {
301                        ExceptionUtil.rethrowIfNecessary(t);
302                        return defaultValue;
303                }
304        }
305
306        public Object getAt(Key key, int row,int pid) throws PageException {
307                Object res = getAt(key,row,pid,DEFAULT_VALUE);
308                if(res!=DEFAULT_VALUE) return res;
309                throw new DatabaseException("key ["+key+"] not found",null,null,null);
310        }
311
312
313        @Override
314        
315        public Object getAt(Key key, int row, Object defaultValue) {
316                return getAt(key, row,getPid(),defaultValue);
317        }
318        
319        
320        public Object getAt(Key key, int row) throws PageException {
321                Object res = getAt(key,row,getPid(),DEFAULT_VALUE);
322                if(res!=DEFAULT_VALUE) return res;
323                throw new DatabaseException("key ["+key+"] not found",null,null,null);
324        }
325
326        public Object getAt(String key, int row, Object defaultValue) {
327                return getAt(KeyImpl.init(key), row,defaultValue);
328        }
329
330        @Override
331        
332        public Object getAt(String key, int row) throws PageException {
333                return getAt(KeyImpl.init(key), row);
334        }
335
336        
337        @Override
338        
339        public synchronized int removeRow(int row) throws PageException {
340                throw notSupported();
341        }
342
343        @Override
344        
345        public int removeRowEL(int row) {
346                throw notSupported();
347        }
348
349        @Override
350        
351        public QueryColumn removeColumn(String key) throws DatabaseException {
352                throw notSupported();
353        }
354
355        @Override
356        
357        public QueryColumn removeColumn(Key key) throws DatabaseException {
358                throw notSupported();
359        }
360
361        @Override
362        
363        public synchronized QueryColumn removeColumnEL(String key) {
364                throw notSupported();
365        }
366
367        @Override
368        
369        public QueryColumn removeColumnEL(Key key) {
370                throw notSupported();
371        }
372
373        @Override
374        
375        public Object setEL(String key, Object value) {
376                throw notSupported();
377        }
378
379        @Override
380        
381        public Object setEL(Key key, Object value) {
382                throw notSupported();
383        }
384
385        @Override
386        
387        public Object set(String key, Object value) throws PageException {
388                throw notSupported();
389        }
390
391        @Override
392        
393        public Object set(Key key, Object value) throws PageException {
394                throw notSupported();
395        }
396
397        @Override
398        
399        public Object setAt(String key, int row, Object value) throws PageException {
400                throw notSupported();
401        }
402
403        @Override
404        
405        public Object setAt(Key key, int row, Object value) throws PageException {
406                throw notSupported();
407        }
408
409        @Override
410        
411        public Object setAtEL(String key, int row, Object value) {
412                throw notSupported();
413        }
414
415        @Override
416        
417        public Object setAtEL(Key key, int row, Object value) {
418                throw notSupported();
419        }
420
421        @Override
422        
423        public synchronized boolean next() {
424                return next(getPid());
425        }
426
427        @Override
428        
429        public synchronized boolean next(int pid) {
430                if(recordcount>=(arrCurrentRow.set(pid,arrCurrentRow.get(pid,0)+1))) {
431                        return true;
432                }
433                arrCurrentRow.set(pid,0);
434                return false;
435        }
436
437        @Override
438        
439        public synchronized void reset() {
440                reset(getPid());
441        }
442
443        @Override
444        
445        public synchronized void reset(int pid) {
446                arrCurrentRow.set(pid,0);
447        }
448
449        @Override
450        
451        public int getRecordcount() {
452                return recordcount;
453        }
454
455        @Override
456        
457        public synchronized int getCurrentrow(int pid) {
458                return arrCurrentRow.get(pid, 1);
459        }
460
461        public String getColumnlist(boolean upperCase) {
462                Key[] columnNames = keys();
463                StringBuffer sb=new StringBuffer();
464                for(int i=0;i<columnNames.length;i++) {
465                        if(i>0)sb.append(',');
466                        sb.append(upperCase?columnNames[i].getUpperString():columnNames[i].getString());
467                }
468                return sb.toString();
469        }
470
471        
472        public String getColumnlist() {
473                return getColumnlist(true);
474        }
475
476        public boolean go(int index) {
477                return go(index,getPid());
478        }
479        
480        public boolean go(int index, int pid) {
481                if(index>0 && index<=recordcount) {
482                        arrCurrentRow.set(pid, index);
483                        return true;
484                }
485                arrCurrentRow.set(pid, 0);
486                return false;
487        }
488        
489        
490        
491        /*public synchronized boolean go(int index) {
492                if(index==getCurrentrow()) return true;
493                try {
494                        return res.absolute(index);
495                } 
496                catch (SQLException e) {
497                        throw toRuntimeExc(e);
498                }
499        }
500        
501        public boolean go(int index, int pid) {
502                return go(index);
503        }*/
504
505        @Override
506        public boolean isEmpty() {
507                return recordcount+columnNames.length==0;
508        }
509
510        @Override
511        public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp) {
512                return QueryUtil.toDumpData(this, pageContext, maxlevel, dp);
513        }
514
515        @Override
516        
517        public void sort(String column) throws PageException {
518                throw notSupported();
519        }
520
521        @Override
522        
523        public void sort(Key column) throws PageException {
524                throw notSupported();
525        }
526
527        @Override
528        
529        public synchronized void sort(String strColumn, int order)
530                        throws PageException {
531                throw notSupported();
532        }
533
534        @Override
535        
536        public synchronized void sort(Key keyColumn, int order)
537                        throws PageException {
538                throw notSupported();
539        }
540
541        @Override
542        
543        public synchronized boolean addRow(int count) {
544                throw notSupported();
545        }
546
547        @Override
548        
549        public boolean addColumn(String columnName, lucee.runtime.type.Array content)
550                        throws DatabaseException {
551                throw notSupported();
552        }
553
554        @Override
555        
556        public boolean addColumn(Key columnName, lucee.runtime.type.Array content)
557                        throws PageException {
558                throw notSupported();
559        }
560
561        @Override
562        
563        public synchronized boolean addColumn(String columnName,
564                        lucee.runtime.type.Array content, int type)
565                        throws DatabaseException {
566                throw notSupported();
567        }
568
569        @Override
570        
571        public boolean addColumn(Key columnName, lucee.runtime.type.Array content,
572                        int type) throws DatabaseException {
573                throw notSupported();
574        }
575
576        @Override
577        
578        public Object clone() {
579                return cloneQuery(true);
580        }
581
582        @Override
583        
584        public Collection duplicate(boolean deepCopy) {
585                return cloneQuery(deepCopy);
586        }
587
588        public QueryImpl cloneQuery(boolean deepCopy) {
589                return QueryImpl.cloneQuery(this, deepCopy);
590        }
591
592        @Override
593
594        public synchronized int[] getTypes() {
595                if(_types==null) {
596                        _types=new int[columns.size()];
597                        int i=0;
598                        Iterator<Entry<String, SimpleQueryColumn>> it = columns.entrySet().iterator();
599                        while(it.hasNext()){
600                                _types[i++]=it.next().getValue().getType();
601                        }
602                }
603                return _types;
604        }
605        @Override
606        
607        public synchronized Map getTypesAsMap() {
608                Map<String,String> map=new HashMap<String,String>();
609                Iterator<SimpleQueryColumn> it = columns.values().iterator();
610                SimpleQueryColumn c;
611                while(it.hasNext()){
612                        c=it.next();
613                        map.put(c.getKeyAsString(), c.getTypeAsString());
614                }
615                return map;
616        }
617
618        @Override
619        
620        public QueryColumn getColumn(String key) throws DatabaseException {
621                return getColumn(KeyImpl.init(key));
622        }
623
624        @Override
625        
626        public QueryColumn getColumn(Key key) throws DatabaseException {
627                QueryColumn rtn = getColumn(key,null);
628                if(rtn!=null) return rtn;
629        throw new DatabaseException("key ["+key.getString()+"] not found in query, columns are ["+getColumnlist(false)+"]",null,null,null);
630        }
631
632        @Override
633        public QueryColumn getColumn(String key, QueryColumn defaultValue) {
634                return getColumn(KeyImpl.init(key),defaultValue);
635        }
636
637        @Override
638        
639        public QueryColumn getColumn(Key key, QueryColumn defaultValue) {
640                if(key.getString().length()>0) {
641                char c=key.lowerCharAt(0);
642                if(c=='r') {
643                    if(key.equals(KeyConstants._RECORDCOUNT)) return new QueryColumnRef(this,key,Types.INTEGER);
644                }
645                else if(c=='c') {
646                    if(key.equals(KeyConstants._CURRENTROW)) return new QueryColumnRef(this,key,Types.INTEGER);
647                    else if(key.equals(KeyConstants._COLUMNLIST)) return new QueryColumnRef(this,key,Types.INTEGER);
648                }
649                SimpleQueryColumn col = columns.get(key.getLowerString());
650                if(col!=null) return col;
651                
652                }
653                return defaultValue;
654        }
655
656        @Override
657        
658        public synchronized void rename(Key columnName, Key newColumnName)
659                        throws ExpressionException {
660                throw notSupported();
661                //Integer index=mappings.get(columnName);
662                //if(index==null) throw new ExpressionException("invalid column name definitions");     
663                // TODO implement
664        }
665
666        @Override
667        public String toString() {
668                return res.toString();
669        }
670
671        @Override
672        public void setExecutionTime(long exeTime) {
673                throw notSupported();
674        }
675
676        public synchronized boolean cutRowsTo(int maxrows) {
677                throw notSupported();
678        }
679
680        @Override
681        public void setCached(boolean isCached) {
682                throw notSupported();
683        }
684
685        @Override
686        public boolean isCached() {
687                return false;
688        }
689
690        @Override
691        public int addRow() {
692                throw notSupported();
693        }
694
695        public Key getColumnName(int columnIndex) {
696                Iterator<SimpleQueryColumn> it = columns.values().iterator();
697                SimpleQueryColumn c;
698                while(it.hasNext()){
699                        c = it.next();
700                        if(c.getIndex()==columnIndex) return c.getKey();
701                }
702                return null;
703        }
704
705        @Override
706        
707        public int getColumnIndex(String coulmnName) {
708                SimpleQueryColumn col = columns.get(coulmnName.toLowerCase());
709                if(col==null) return -1;
710                return col.getIndex();
711        }
712
713        @Override
714        
715        public String[] getColumns() {
716                return getColumnNamesAsString();
717        }
718
719        @Override
720        
721        public Key[] getColumnNames() {
722                Key[] _columns=new Key[columnNames.length];
723                for(int i=0;i<columnNames.length;i++){
724                        _columns[i]=columnNames[i];
725                }
726                return _columns;
727        }
728
729        public void setColumnNames(Key[] trg) {
730                throw notSupported();
731        }
732
733        @Override
734        
735        public String[] getColumnNamesAsString() {
736                String[] _columns=new String[columnNames.length];
737                for(int i=0;i<columnNames.length;i++){
738                        _columns[i]=columnNames[i].getString();
739                }
740                return _columns;
741        }
742
743        @Override
744        
745        public synchronized String getData(int row, int col) throws IndexOutOfBoundsException {
746                try{
747                        int rowBefore=res.getRow();
748                        try{
749                                res.absolute(row);
750                                if(col<1 || col>columnNames.length) {
751                                        new IndexOutOfBoundsException("invalid column index to retrieve Data from query, valid index goes from 1 to "+columnNames.length);
752                                }
753                                return Caster.toString(get(columnNames[col]));
754                                
755                        }
756                        finally{
757                                res.absolute(rowBefore);
758                        }
759                }
760                catch(Throwable t){
761                        ExceptionUtil.rethrowIfNecessary(t);
762                        throw toRuntimeExc(t);
763                }
764        }
765
766        @Override
767        
768        public String getName() {
769                return name;
770        }
771
772        @Override
773        
774        public int getRowCount() {
775                return getRecordcount();
776        }
777
778        @Override
779        
780        public void setData(int row, int col, String value)
781                        throws IndexOutOfBoundsException {
782                throw notSupported();
783        }
784
785        @Override
786        
787        public boolean containsKey(String key) {
788                return columns.get(key.toLowerCase())!=null;
789        }
790
791        @Override
792        
793        public boolean containsKey(Key key) {
794                return containsKey(key.getString());
795        }
796
797        @Override
798        
799        public String castToString() throws ExpressionException {
800                throw notSupported();
801        }
802
803        @Override
804        
805        public String castToString(String defaultValue) {
806                throw notSupported();
807        }
808
809        @Override
810        
811        public boolean castToBooleanValue() throws ExpressionException {
812                throw notSupported();
813        }
814
815        @Override
816        
817        public Boolean castToBoolean(Boolean defaultValue) {
818                throw notSupported();
819        }
820
821        @Override
822        
823        public double castToDoubleValue() throws ExpressionException {
824                throw notSupported();
825        }
826
827        @Override
828        
829        public double castToDoubleValue(double defaultValue) {
830                throw notSupported();
831        }
832
833        @Override
834        
835        public DateTime castToDateTime() throws ExpressionException {
836                throw notSupported();
837        }
838
839        @Override
840        
841        public DateTime castToDateTime(DateTime defaultValue) {
842                throw notSupported();
843        }
844
845        @Override
846        
847        public int compareTo(boolean b) throws ExpressionException {
848                throw notSupported();
849        }
850
851        @Override
852        
853        public int compareTo(DateTime dt) throws PageException {
854                throw notSupported();
855        }
856
857        @Override
858        
859        public int compareTo(double d) throws PageException {
860                throw notSupported();
861        }
862
863        @Override
864        
865        public int compareTo(String str) throws PageException {
866                throw notSupported();
867        }
868
869        @Override
870        public synchronized lucee.runtime.type.Array getMetaDataSimple() {
871                        lucee.runtime.type.Array cols=new ArrayImpl();
872                SimpleQueryColumn sqc;
873                Struct column;
874                Iterator<SimpleQueryColumn> it = columns.values().iterator();
875                while(it.hasNext()){
876                        sqc=it.next();
877                        column=new StructImpl();
878                        column.setEL(KeyConstants._name,sqc.getKey());
879                        column.setEL("isCaseSensitive",Boolean.FALSE);
880                        column.setEL("typeName",sqc.getTypeAsString());
881                        cols.appendEL(column);
882                }
883                return cols;
884            }
885        
886        @Override
887        
888        public Object getObject(String columnName) throws SQLException {
889                return res.getObject(toIndex(columnName));
890        }
891
892        @Override
893        
894        public Object getObject(int columnIndex) throws SQLException {
895                return res.getObject(columnIndex);
896        }
897
898        @Override
899        
900        public String getString(int columnIndex) throws SQLException {
901                return res.getString(columnIndex);
902        }
903
904        @Override
905        
906        public String getString(String columnName) throws SQLException {
907                return res.getString(toIndex(columnName));
908        }
909
910        @Override
911        
912        public boolean getBoolean(int columnIndex) throws SQLException {
913                return res.getBoolean(columnIndex);
914        }
915
916        @Override
917        
918        public boolean getBoolean(String columnName) throws SQLException {
919                return res.getBoolean(toIndex(columnName));
920        }
921
922        @Override
923        
924        public Object call(PageContext pc, Key methodName, Object[] arguments)
925                        throws PageException {
926                throw notSupported();
927        }
928
929
930        @Override
931        
932        public Object callWithNamedValues(PageContext pc, Key methodName,
933                        Struct args) throws PageException {
934                throw notSupported();
935        }
936
937        @Override       
938        public Object get(PageContext pc, Key key, Object defaultValue) {
939                return getAt(key, getCurrentrow(pc.getId()), pc.getId(),defaultValue);
940        }
941
942        @Override
943        public Object get(PageContext pc, Key key) throws PageException {
944                return getAt(key, getCurrentrow(pc.getId()), pc.getId());
945        }
946
947        public boolean isInitalized() {
948                return true;
949        }
950
951        @Override
952        
953        public Object set(PageContext pc, Key propertyName, Object value)
954                        throws PageException {
955                throw notSupported();
956        }
957
958
959        @Override       
960        public Object setEL(PageContext pc, Key propertyName, Object value) {
961                throw notSupported();
962        }
963
964        @Override
965        public boolean wasNull() {
966                try {
967                        return res.wasNull();
968                } catch (SQLException e) {
969                        throw toRuntimeExc(e);
970                }
971        }
972
973        @Override
974        
975        public synchronized boolean absolute(int row) throws SQLException {
976                return res.absolute(row);
977        }
978
979        @Override
980        
981        public synchronized void afterLast() throws SQLException {
982                res.afterLast();
983        }
984
985        @Override
986        
987        public synchronized void beforeFirst() throws SQLException {
988                res.beforeFirst();
989        }
990
991        @Override
992        
993        public synchronized void cancelRowUpdates() throws SQLException {
994                res.cancelRowUpdates();
995        }
996
997        @Override
998        
999        public synchronized void clearWarnings() throws SQLException {
1000                res.clearWarnings();
1001        }
1002
1003        @Override
1004        
1005        public synchronized void close() throws SQLException {
1006                res.close();
1007        }
1008
1009        @Override
1010        
1011        public synchronized void deleteRow() throws SQLException {
1012                res.deleteRow();
1013        }
1014
1015        @Override
1016        
1017        public int findColumn(String columnName) throws SQLException {
1018                return res.findColumn(columnName);
1019        }
1020
1021        @Override
1022        
1023        public synchronized boolean first() throws SQLException {
1024                return res.first();
1025        }
1026
1027        @Override
1028        
1029        public Array getArray(int i) throws SQLException {
1030                return res.getArray(i);
1031        }
1032
1033        @Override
1034        
1035        public Array getArray(String colName) throws SQLException {
1036                return res.getArray(toIndex(colName));
1037        }
1038
1039        @Override
1040        
1041        public InputStream getAsciiStream(int columnIndex) throws SQLException {
1042                return res.getAsciiStream(columnIndex);
1043        }
1044
1045        @Override
1046        
1047        public InputStream getAsciiStream(String columnName) throws SQLException {
1048                return res.getAsciiStream(toIndex(columnName));
1049        }
1050
1051        @Override
1052        
1053        public BigDecimal getBigDecimal(int columnIndex) throws SQLException {
1054                return res.getBigDecimal(columnIndex);
1055        }
1056
1057        @Override
1058        
1059        public BigDecimal getBigDecimal(String columnName) throws SQLException {
1060                return res.getBigDecimal(toIndex(columnName));
1061        }
1062
1063        @Override
1064        
1065        public BigDecimal getBigDecimal(int columnIndex, int scale)
1066                        throws SQLException {
1067                return res.getBigDecimal(columnIndex, scale);
1068        }
1069
1070        @Override
1071        
1072        public BigDecimal getBigDecimal(String columnName, int scale)
1073                        throws SQLException {
1074                return res.getBigDecimal(toIndex(columnName), scale);
1075        }
1076
1077        @Override
1078        
1079        public InputStream getBinaryStream(int columnIndex) throws SQLException {
1080                return res.getBinaryStream(columnIndex);
1081        }
1082
1083        @Override
1084        
1085        public InputStream getBinaryStream(String columnName) throws SQLException {
1086                return res.getBinaryStream(toIndex(columnName));
1087        }
1088
1089        @Override
1090        
1091        public Blob getBlob(int i) throws SQLException {
1092                return res.getBlob(i);
1093        }
1094
1095        @Override
1096        
1097        public Blob getBlob(String colName) throws SQLException {
1098                return res.getBlob(toIndex(colName));
1099        }
1100
1101        @Override
1102        
1103        public byte getByte(int columnIndex) throws SQLException {
1104                return res.getByte(columnIndex);
1105        }
1106
1107        @Override
1108        
1109        public byte getByte(String columnName) throws SQLException {
1110                return res.getByte(toIndex(columnName));
1111        }
1112
1113        @Override
1114        
1115        public byte[] getBytes(int columnIndex) throws SQLException {
1116                return res.getBytes(columnIndex);
1117        }
1118
1119        @Override
1120        
1121        public byte[] getBytes(String columnName) throws SQLException {
1122                return res.getBytes(toIndex(columnName));
1123        }
1124
1125        @Override
1126        
1127        public Reader getCharacterStream(int columnIndex) throws SQLException {
1128                return res.getCharacterStream(columnIndex);
1129        }
1130
1131        @Override
1132        
1133        public Reader getCharacterStream(String columnName) throws SQLException {
1134                return res.getCharacterStream(toIndex(columnName));
1135        }
1136
1137        @Override
1138        
1139        public Clob getClob(int i) throws SQLException {
1140                return res.getClob(i);
1141        }
1142
1143        @Override
1144        
1145        public Clob getClob(String colName) throws SQLException {
1146                return res.getClob(toIndex(colName));
1147        }
1148
1149        @Override
1150        
1151        public int getConcurrency() throws SQLException {
1152                return res.getConcurrency();
1153        }
1154
1155        @Override
1156        
1157        public String getCursorName() throws SQLException {
1158                return res.getCursorName();
1159        }
1160
1161        @Override
1162        
1163        public Date getDate(int columnIndex) throws SQLException {
1164                return res.getDate(columnIndex);
1165        }
1166
1167        @Override
1168        
1169        public Date getDate(String columnName) throws SQLException {
1170                return res.getDate(toIndex(columnName));
1171        }
1172
1173        @Override
1174        
1175        public Date getDate(int columnIndex, Calendar cal) throws SQLException {
1176                return res.getDate(columnIndex, cal);
1177        }
1178
1179        @Override
1180        
1181        public Date getDate(String columnName, Calendar cal) throws SQLException {
1182                return res.getDate(toIndex(columnName), cal);
1183        }
1184
1185        @Override
1186        
1187        public double getDouble(int columnIndex) throws SQLException {
1188                return res.getDouble(columnIndex);
1189        }
1190
1191        @Override
1192        
1193        public double getDouble(String columnName) throws SQLException {
1194                return res.getDouble(toIndex(columnName));
1195        }
1196
1197        @Override
1198        
1199        public int getFetchDirection() throws SQLException {
1200                return res.getFetchDirection();
1201        }
1202
1203        @Override
1204        
1205        public int getFetchSize() throws SQLException {
1206                return res.getFetchSize();
1207        }
1208
1209        @Override
1210        
1211        public float getFloat(int columnIndex) throws SQLException {
1212                return res.getFloat(columnIndex);
1213        }
1214
1215        @Override
1216        
1217        public float getFloat(String columnName) throws SQLException {
1218                return res.getFloat(toIndex(columnName));
1219        }
1220
1221        @Override
1222        
1223        public int getInt(int columnIndex) throws SQLException {
1224                return res.getInt(columnIndex);
1225        }
1226
1227        @Override
1228        
1229        public int getInt(String columnName) throws SQLException {
1230                return res.getInt(toIndex(columnName));
1231        }
1232
1233        @Override
1234        
1235        public long getLong(int columnIndex) throws SQLException {
1236                return res.getLong(columnIndex);
1237        }
1238
1239        @Override
1240        
1241        public long getLong(String columnName) throws SQLException {
1242                return res.getLong(toIndex(columnName));
1243        }
1244
1245        @Override
1246        
1247        public Object getObject(int i, Map map) throws SQLException {
1248                return res.getObject(i, map);
1249        }
1250
1251        @Override
1252        
1253        public Object getObject(String colName, Map map) throws SQLException {
1254                return res.getObject(toIndex(colName), map);
1255        }
1256
1257        // used only with java 7, do not set @Override
1258        public <T> T getObject(int columnIndex, Class<T> type) throws SQLException {
1259                return (T) QueryUtil.getObject(this,columnIndex, type);
1260        }
1261
1262        // used only with java 7, do not set @Override
1263        public <T> T getObject(String columnLabel, Class<T> type) throws SQLException {
1264                return (T) QueryUtil.getObject(this,columnLabel, type);
1265        }
1266        
1267        @Override
1268        
1269        public Ref getRef(int i) throws SQLException {
1270                return res.getRef(i);
1271        }
1272
1273        @Override
1274        
1275        public Ref getRef(String colName) throws SQLException {
1276                return res.getRef(toIndex(colName));
1277        }
1278
1279        @Override
1280        
1281        public int getRow() throws SQLException {
1282                return res.getRow();
1283        }
1284
1285        @Override
1286        
1287        public short getShort(int columnIndex) throws SQLException {
1288                return res.getShort(columnIndex);
1289        }
1290
1291        @Override
1292        
1293        public short getShort(String columnName) throws SQLException {
1294                return res.getShort(toIndex(columnName));
1295        }
1296
1297        @Override
1298        
1299        public Statement getStatement() throws SQLException {
1300                return res.getStatement();
1301        }
1302
1303        @Override
1304        
1305        public Time getTime(int columnIndex) throws SQLException {
1306                return res.getTime(columnIndex);
1307        }
1308
1309        @Override
1310        
1311        public Time getTime(String columnName) throws SQLException {
1312                return res.getTime(toIndex(columnName));
1313        }
1314
1315        @Override
1316        
1317        public Time getTime(int columnIndex, Calendar cal) throws SQLException {
1318                return res.getTime(columnIndex, cal);
1319        }
1320
1321        @Override
1322        
1323        public Time getTime(String columnName, Calendar cal) throws SQLException {
1324                return res.getTime(toIndex(columnName), cal);
1325        }
1326
1327        @Override
1328        
1329        public Timestamp getTimestamp(int columnIndex) throws SQLException {
1330                return res.getTimestamp(columnIndex);
1331        }
1332
1333        @Override
1334        
1335        public Timestamp getTimestamp(String columnName) throws SQLException {
1336                return res.getTimestamp(toIndex(columnName));
1337        }
1338
1339        @Override
1340        
1341        public Timestamp getTimestamp(int columnIndex, Calendar cal)
1342                        throws SQLException {
1343                return res.getTimestamp(columnIndex, cal);
1344        }
1345
1346        @Override
1347        
1348        public Timestamp getTimestamp(String columnName, Calendar cal)
1349                        throws SQLException {
1350                return res.getTimestamp(toIndex(columnName), cal);
1351        }
1352
1353        @Override
1354        
1355        public int getType() throws SQLException {
1356                return res.getType();
1357        }
1358
1359        @Override
1360        
1361        public URL getURL(int columnIndex) throws SQLException {
1362                return res.getURL(columnIndex);
1363        }
1364
1365        @Override
1366        
1367        public URL getURL(String columnName) throws SQLException {
1368                return res.getURL(toIndex(columnName));
1369        }
1370
1371        @Override
1372        
1373        public InputStream getUnicodeStream(int columnIndex) throws SQLException {
1374                return res.getUnicodeStream(columnIndex);
1375        }
1376
1377        @Override
1378        
1379        public InputStream getUnicodeStream(String columnName) throws SQLException {
1380                return res.getUnicodeStream(toIndex(columnName));
1381        }
1382
1383        @Override
1384        
1385        public SQLWarning getWarnings() throws SQLException {
1386                return res.getWarnings();
1387        }
1388
1389        @Override
1390        
1391        public void insertRow() throws SQLException {
1392                res.insertRow();
1393        }
1394
1395        @Override
1396        
1397        public boolean isAfterLast() throws SQLException {
1398                return res.isAfterLast();
1399        }
1400
1401        @Override
1402        
1403        public boolean isBeforeFirst() throws SQLException {
1404                return res.isBeforeFirst();
1405        }
1406
1407        @Override
1408        
1409        public boolean isFirst() throws SQLException {
1410                return res.isFirst();
1411        }
1412
1413        @Override
1414        
1415        public boolean isLast() throws SQLException {
1416                return res.isLast();
1417        }
1418
1419        @Override
1420        
1421        public boolean last() throws SQLException {
1422                return res.last();
1423        }
1424
1425        @Override
1426        
1427        public void moveToCurrentRow() throws SQLException {
1428                res.moveToCurrentRow();
1429        }
1430
1431        @Override
1432        
1433        public void moveToInsertRow() throws SQLException {
1434                res.moveToInsertRow();
1435        }
1436
1437        @Override
1438        
1439        public boolean previous() {
1440                throw notSupported();
1441        }
1442
1443        @Override
1444        
1445        public boolean previous(int pid) {
1446                throw notSupported();
1447        }
1448
1449        @Override
1450        
1451        public void refreshRow() throws SQLException {
1452                res.refreshRow();
1453        }
1454
1455        @Override
1456        
1457        public boolean relative(int rows) throws SQLException {
1458                return res.relative(rows);
1459        }
1460
1461        @Override
1462        
1463        public boolean rowDeleted() throws SQLException {
1464                return res.rowDeleted();
1465        }
1466
1467        @Override
1468        
1469        public boolean rowInserted() throws SQLException {
1470                return res.rowInserted();
1471        }
1472
1473        @Override
1474        
1475        public boolean rowUpdated() throws SQLException {
1476                return res.rowUpdated();
1477        }
1478
1479        @Override
1480        
1481        public void setFetchDirection(int direction) throws SQLException {
1482                res.setFetchDirection(direction);
1483        }
1484
1485        @Override
1486        
1487        public void setFetchSize(int rows) throws SQLException {
1488                res.setFetchSize(rows);
1489        }
1490
1491        @Override
1492        
1493        public void updateArray(int columnIndex, Array x) throws SQLException {
1494                res.updateArray(columnIndex, x);
1495        }
1496
1497        @Override
1498        
1499        public void updateArray(String columnName, Array x) throws SQLException {
1500                res.updateArray(toIndex(columnName), x);
1501        }
1502
1503        @Override
1504        
1505        public void updateAsciiStream(int columnIndex, InputStream x, int length)
1506                        throws SQLException {
1507                res.updateAsciiStream(columnIndex, x, length);
1508        }
1509
1510        @Override
1511        
1512        public void updateAsciiStream(String columnName, InputStream x, int length)
1513                        throws SQLException {
1514                res.updateAsciiStream(toIndex(columnName), x, length);
1515        }
1516
1517        @Override
1518        
1519        public void updateBigDecimal(int columnIndex, BigDecimal x)
1520                        throws SQLException {
1521                res.updateBigDecimal(columnIndex, x);
1522        }
1523
1524        @Override
1525        
1526        public void updateBigDecimal(String columnName, BigDecimal x)
1527                        throws SQLException {
1528                res.updateBigDecimal(toIndex(columnName), x);
1529        }
1530
1531        @Override
1532        
1533        public void updateBinaryStream(int columnIndex, InputStream x, int length)
1534                        throws SQLException {
1535                res.updateBinaryStream(columnIndex, x, length);
1536        }
1537
1538        @Override
1539        
1540        public void updateBinaryStream(String columnName, InputStream x, int length)
1541                        throws SQLException {
1542                res.updateBinaryStream(toIndex(columnName), x, length);
1543        }
1544
1545        @Override
1546        
1547        public void updateBlob(int columnIndex, Blob x) throws SQLException {
1548                res.updateBlob(columnIndex, x);
1549        }
1550
1551        @Override
1552        
1553        public void updateBlob(String columnName, Blob x) throws SQLException {
1554                res.updateBlob(toIndex(columnName), x);
1555        }
1556
1557        @Override
1558        
1559        public void updateBoolean(int columnIndex, boolean x) throws SQLException {
1560                res.updateBoolean(columnIndex, x);
1561        }
1562
1563        @Override
1564        
1565        public void updateBoolean(String columnName, boolean x) throws SQLException {
1566                res.updateBoolean(toIndex(columnName), x);
1567        }
1568
1569        @Override
1570        
1571        public void updateByte(int columnIndex, byte x) throws SQLException {
1572                res.updateByte(columnIndex, x);
1573        }
1574
1575        @Override
1576        
1577        public void updateByte(String columnName, byte x) throws SQLException {
1578                res.updateByte(toIndex(columnName), x);
1579        }
1580
1581        @Override
1582        
1583        public void updateBytes(int columnIndex, byte[] x) throws SQLException {
1584                res.updateBytes(columnIndex, x);
1585        }
1586
1587        @Override
1588        
1589        public void updateBytes(String columnName, byte[] x) throws SQLException {
1590                res.updateBytes(toIndex(columnName), x);
1591        }
1592
1593        @Override
1594        
1595        public void updateCharacterStream(int columnIndex, Reader reader, int length)
1596                        throws SQLException {
1597                res.updateCharacterStream(columnIndex, reader, length);
1598        }
1599
1600        @Override
1601        
1602        public void updateCharacterStream(String columnName, Reader reader,
1603                        int length) throws SQLException {
1604                res.updateCharacterStream(toIndex(columnName), reader, length);
1605        }
1606
1607        @Override
1608        
1609        public void updateClob(int columnIndex, Clob x) throws SQLException {
1610                res.updateClob(columnIndex, x);
1611        }
1612
1613        @Override
1614        
1615        public void updateClob(String columnName, Clob x) throws SQLException {
1616                res.updateClob(toIndex(columnName), x);
1617        }
1618
1619        @Override
1620        
1621        public void updateDate(int columnIndex, Date x) throws SQLException {
1622                res.updateDate(columnIndex, x);
1623        }
1624
1625        @Override
1626        
1627        public void updateDate(String columnName, Date x) throws SQLException {
1628                res.updateDate(toIndex(columnName), x);
1629        }
1630
1631        @Override
1632        
1633        public void updateDouble(int columnIndex, double x) throws SQLException {
1634                res.updateDouble(columnIndex, x);
1635        }
1636
1637        @Override
1638        
1639        public void updateDouble(String columnName, double x) throws SQLException {
1640                res.updateDouble(toIndex(columnName), x);
1641        }
1642
1643        @Override
1644        
1645        public void updateFloat(int columnIndex, float x) throws SQLException {
1646                res.updateFloat(columnIndex, x);
1647        }
1648
1649        @Override
1650        
1651        public void updateFloat(String columnName, float x) throws SQLException {
1652                res.updateFloat(toIndex(columnName), x);
1653        }
1654
1655        @Override
1656        
1657        public void updateInt(int columnIndex, int x) throws SQLException {
1658                res.updateInt(columnIndex, x);
1659        }
1660
1661        @Override
1662        
1663        public void updateInt(String columnName, int x) throws SQLException {
1664                res.updateInt(toIndex(columnName), x);
1665        }
1666
1667        @Override
1668        
1669        public void updateLong(int columnIndex, long x) throws SQLException {
1670                res.updateLong(columnIndex, x);
1671        }
1672
1673        @Override
1674        
1675        public void updateLong(String columnName, long x) throws SQLException {
1676                res.updateLong(toIndex(columnName), x);
1677        }
1678
1679        @Override
1680        
1681        public void updateNull(int columnIndex) throws SQLException {
1682                res.updateNull(columnIndex);
1683        }
1684
1685        @Override
1686        
1687        public void updateNull(String columnName) throws SQLException {
1688                res.updateNull(toIndex(columnName));
1689        }
1690
1691        @Override
1692        
1693        public void updateObject(int columnIndex, Object x) throws SQLException {
1694                res.updateObject(columnIndex, x);
1695        }
1696
1697        @Override
1698        
1699        public void updateObject(String columnName, Object x) throws SQLException {
1700                res.updateObject(toIndex(columnName), x);
1701        }
1702
1703        @Override
1704        
1705        public void updateObject(int columnIndex, Object x, int scale)
1706                        throws SQLException {
1707                res.updateObject(columnIndex, x, scale);
1708        }
1709
1710        @Override
1711        
1712        public void updateObject(String columnName, Object x, int scale)
1713                        throws SQLException {
1714                res.updateObject(toIndex(columnName), x, scale);
1715        }
1716
1717        @Override
1718        
1719        public void updateRef(int columnIndex, Ref x) throws SQLException {
1720                res.updateRef(columnIndex, x);
1721        }
1722
1723        @Override
1724        
1725        public void updateRef(String columnName, Ref x) throws SQLException {
1726                res.updateRef(toIndex(columnName), x);
1727        }
1728
1729        @Override
1730        
1731        public void updateRow() throws SQLException {
1732                res.updateRow();
1733        }
1734
1735        @Override
1736        
1737        public void updateShort(int columnIndex, short x) throws SQLException {
1738                res.updateShort(columnIndex, x);
1739        }
1740
1741        @Override
1742        
1743        public void updateShort(String columnName, short x) throws SQLException {
1744                res.updateShort(toIndex(columnName), x);
1745        }
1746
1747        @Override
1748        
1749        public void updateString(int columnIndex, String x) throws SQLException {
1750                res.updateString(columnIndex, x);
1751        }
1752
1753        @Override
1754        
1755        public void updateString(String columnName, String x) throws SQLException {
1756                res.updateString(toIndex(columnName), x);
1757        }
1758
1759        @Override
1760        
1761        public void updateTime(int columnIndex, Time x) throws SQLException {
1762                res.updateTime(columnIndex, x);
1763        }
1764
1765        @Override
1766        
1767        public void updateTime(String columnName, Time x) throws SQLException {
1768                res.updateTime(toIndex(columnName), x);
1769        }
1770
1771        @Override
1772        
1773        public void updateTimestamp(int columnIndex, Timestamp x)
1774                        throws SQLException {
1775                res.updateTimestamp(columnIndex, x);
1776        }
1777
1778        @Override
1779        
1780        public void updateTimestamp(String columnName, Timestamp x)
1781                        throws SQLException {
1782                res.updateTimestamp(toIndex(columnName), x);
1783        }
1784
1785        @Override
1786        
1787        public ResultSetMetaData getMetaData() throws SQLException {
1788                return res.getMetaData();
1789        }
1790
1791          @Override
1792        public Iterator<Collection.Key> keyIterator() {
1793                return new KeyIterator(keys());
1794        }
1795    
1796    @Override
1797        public Iterator<String> keysAsStringIterator() {
1798        return new StringIterator(keys());
1799    }
1800        
1801        @Override
1802        public Iterator<Entry<Key, Object>> entryIterator() {
1803                return new EntryIterator(this,keys());
1804        }
1805        
1806        @Override
1807        public Iterator<Object> valueIterator() {
1808                return new CollectionIterator(keys(),this);
1809        }
1810        
1811        @Override
1812        
1813        public boolean equals(Object obj) {
1814                return res.equals(obj);
1815        }
1816
1817        @Override
1818        
1819        public int getHoldability() throws SQLException {
1820                return res.getHoldability();
1821        }
1822
1823        @Override
1824        
1825        public boolean isClosed() throws SQLException {
1826                return res.isClosed();
1827        }
1828
1829        @Override
1830        
1831        public void updateNString(int columnIndex, String nString)
1832                        throws SQLException {
1833                res.updateNString(columnIndex, nString);
1834        }
1835
1836        @Override
1837        
1838        public void updateNString(String columnLabel, String nString)
1839                        throws SQLException {
1840                res.updateNString(toIndex(columnLabel), nString);
1841        }
1842
1843        @Override
1844        
1845        public String getNString(int columnIndex) throws SQLException {
1846                return res.getNString(columnIndex);
1847        }
1848
1849        @Override
1850        
1851        public String getNString(String columnLabel) throws SQLException {
1852                return res.getNString(toIndex(columnLabel));
1853        }
1854
1855        @Override
1856        
1857        public Reader getNCharacterStream(int columnIndex) throws SQLException {
1858                return res.getNCharacterStream(columnIndex);
1859        }
1860
1861        @Override
1862        
1863        public Reader getNCharacterStream(String columnLabel) throws SQLException {
1864                return res.getNCharacterStream(toIndex(columnLabel));
1865        }
1866
1867        @Override
1868        
1869        public void updateNCharacterStream(int columnIndex, Reader x, long length)
1870                        throws SQLException {
1871                res.updateNCharacterStream(columnIndex, x, length);
1872        }
1873
1874        @Override
1875        
1876        public void updateNCharacterStream(String columnLabel, Reader reader,
1877                        long length) throws SQLException {
1878                res.updateNCharacterStream(toIndex(columnLabel), reader, length);
1879        }
1880
1881        @Override
1882        
1883        public void updateAsciiStream(int columnIndex, InputStream x, long length)
1884                        throws SQLException {
1885                res.updateAsciiStream(columnIndex, x, length);
1886        }
1887
1888        @Override
1889        
1890        public void updateBinaryStream(int columnIndex, InputStream x, long length)
1891                        throws SQLException {
1892                res.updateBinaryStream(columnIndex, x, length);
1893        }
1894
1895        @Override
1896        
1897        public void updateCharacterStream(int columnIndex, Reader x, long length)
1898                        throws SQLException {
1899                res.updateCharacterStream(columnIndex, x, length);
1900        }
1901
1902        @Override
1903        
1904        public void updateAsciiStream(String columnLabel, InputStream x, long length)
1905                        throws SQLException {
1906                res.updateAsciiStream(toIndex(columnLabel), x, length);
1907        }
1908
1909        @Override
1910        
1911        public void updateBinaryStream(String columnLabel, InputStream x,
1912                        long length) throws SQLException {
1913                res.updateBinaryStream(toIndex(columnLabel), x, length);
1914        }
1915
1916        @Override
1917        
1918        public void updateCharacterStream(String columnLabel, Reader reader,
1919                        long length) throws SQLException {
1920                res.updateCharacterStream(toIndex(columnLabel), reader, length);
1921        }
1922
1923        @Override
1924        
1925        public void updateBlob(int columnIndex, InputStream inputStream, long length)
1926                        throws SQLException {
1927                res.updateBlob(columnIndex, inputStream, length);
1928        }
1929
1930        @Override
1931        
1932        public void updateBlob(String columnLabel, InputStream inputStream,
1933                        long length) throws SQLException {
1934                res.updateBlob(toIndex(columnLabel), inputStream, length);
1935        }
1936
1937        @Override
1938        
1939        public void updateClob(int columnIndex, Reader reader, long length)
1940                        throws SQLException {
1941                res.updateClob(columnIndex, reader, length);
1942        }
1943
1944        @Override
1945        
1946        public void updateClob(String columnLabel, Reader reader, long length)
1947                        throws SQLException {
1948                res.updateClob(toIndex(columnLabel), reader, length);
1949        }
1950
1951        @Override
1952        
1953        public void updateNClob(int columnIndex, Reader reader, long length)
1954                        throws SQLException {
1955                res.updateNClob(columnIndex, reader, length);
1956        }
1957
1958        @Override
1959        
1960        public void updateNClob(String columnLabel, Reader reader, long length)
1961                        throws SQLException {
1962                res.updateNClob(toIndex(columnLabel), reader, length);
1963        }
1964
1965        @Override
1966        
1967        public void updateNCharacterStream(int columnIndex, Reader x)
1968                        throws SQLException {
1969                res.updateNCharacterStream(columnIndex, x);
1970        }
1971
1972        @Override
1973        
1974        public void updateNCharacterStream(String columnLabel, Reader reader)
1975                        throws SQLException {
1976                res.updateNCharacterStream(toIndex(columnLabel), reader);
1977        }
1978
1979        @Override
1980        
1981        public void updateAsciiStream(int columnIndex, InputStream x)
1982                        throws SQLException {
1983                res.updateAsciiStream(columnIndex, x);
1984        }
1985
1986        @Override
1987        
1988        public void updateBinaryStream(int columnIndex, InputStream x)
1989                        throws SQLException {
1990                res.updateBinaryStream(columnIndex, x);
1991        }
1992
1993        @Override
1994        
1995        public void updateCharacterStream(int columnIndex, Reader x)
1996                        throws SQLException {
1997                res.updateCharacterStream(columnIndex, x);
1998        }
1999
2000        @Override
2001        
2002        public void updateAsciiStream(String columnLabel, InputStream x)
2003                        throws SQLException {
2004                res.updateAsciiStream(toIndex(columnLabel), x);
2005        }
2006
2007        @Override
2008        
2009        public void updateBinaryStream(String columnLabel, InputStream x)
2010                        throws SQLException {
2011                res.updateBinaryStream(columnLabel, x);
2012        }
2013
2014        @Override
2015        
2016        public void updateCharacterStream(String columnLabel, Reader reader)
2017                        throws SQLException {
2018                res.updateCharacterStream(toIndex(columnLabel), reader);
2019        }
2020
2021        @Override
2022        
2023        public void updateBlob(int columnIndex, InputStream inputStream)
2024                        throws SQLException {
2025                res.updateBlob(columnIndex, inputStream);
2026        }
2027
2028        @Override
2029        
2030        public void updateBlob(String columnLabel, InputStream inputStream)
2031                        throws SQLException {
2032                res.updateBlob(toIndex(columnLabel), inputStream);
2033        }
2034
2035        @Override
2036        
2037        public void updateClob(int columnIndex, Reader reader) throws SQLException {
2038                res.updateClob(columnIndex, reader);
2039        }
2040
2041        @Override
2042        
2043        public void updateClob(String columnLabel, Reader reader)
2044                        throws SQLException {
2045                res.updateClob(toIndex(columnLabel), reader);
2046        }
2047
2048        @Override
2049        
2050        public void updateNClob(int columnIndex, Reader reader) throws SQLException {
2051                res.updateNClob(columnIndex, reader);
2052        }
2053
2054        @Override
2055        
2056        public void updateNClob(String columnLabel, Reader reader)
2057                        throws SQLException {
2058                res.updateNClob(toIndex(columnLabel), reader);
2059        }
2060
2061        @Override
2062        
2063        public <T> T unwrap(Class<T> iface) throws SQLException {
2064                return res.unwrap(iface);
2065        }
2066
2067        @Override
2068        
2069        public boolean isWrapperFor(Class<?> iface) throws SQLException {
2070                return res.isWrapperFor(iface);
2071        }
2072
2073        @Override
2074        
2075        public void updateNClob(int columnIndex, NClob nClob) throws SQLException {
2076                res.updateNClob(columnIndex, nClob);
2077        }
2078
2079        @Override
2080        
2081        public void updateNClob(String columnLabel, NClob nClob)
2082                        throws SQLException {
2083                res.updateNClob(toIndex(columnLabel), nClob);
2084        }
2085
2086        @Override
2087        
2088        public NClob getNClob(int columnIndex) throws SQLException {
2089                return res.getNClob(columnIndex);
2090        }
2091
2092        @Override
2093        
2094        public NClob getNClob(String columnLabel) throws SQLException {
2095                return res.getNClob(toIndex(columnLabel));
2096        }
2097
2098        @Override
2099        
2100        public SQLXML getSQLXML(int columnIndex) throws SQLException {
2101                return res.getSQLXML(columnIndex);
2102        }
2103
2104        @Override
2105        
2106        public SQLXML getSQLXML(String columnLabel) throws SQLException {
2107                return res.getSQLXML(toIndex(columnLabel));
2108        }
2109
2110        @Override
2111        
2112        public void updateSQLXML(int columnIndex, SQLXML xmlObject)
2113                        throws SQLException {
2114                res.updateSQLXML(columnIndex, xmlObject);
2115        }
2116
2117        @Override
2118        
2119        public void updateSQLXML(String columnLabel, SQLXML xmlObject)
2120                        throws SQLException {
2121                res.updateSQLXML(toIndex(columnLabel), xmlObject);
2122        }
2123
2124        @Override
2125        
2126        public RowId getRowId(int columnIndex) throws SQLException {
2127                return res.getRowId(columnIndex);
2128        }
2129
2130        @Override
2131        
2132        public RowId getRowId(String columnLabel) throws SQLException {
2133                return res.getRowId(toIndex(columnLabel));
2134        }
2135
2136        @Override
2137        
2138        public void updateRowId(int columnIndex, RowId x) throws SQLException {
2139                res.updateRowId(columnIndex, x);
2140        }
2141
2142        @Override
2143        public void updateRowId(String columnLabel, RowId x) throws SQLException {
2144                res.updateRowId(toIndex(columnLabel), x);
2145        }
2146
2147        public synchronized void enableShowQueryUsage() {
2148                throw notSupported();
2149        }
2150
2151        public static PageRuntimeException notSupported() {
2152                return toRuntimeExc(new SQLFeatureNotSupportedException("not supported"));
2153        }
2154
2155        public static PageRuntimeException toRuntimeExc(Throwable t) {
2156                return new PageRuntimeException(Caster.toPageException(t));
2157        }
2158
2159        public static PageException toPageExc(Throwable t) {
2160                return Caster.toPageException(t);
2161        }
2162
2163        private int toIndex(String columnName) throws SQLException {
2164                SimpleQueryColumn col = columns.get(columnName.toLowerCase());
2165                if(col==null) throw new SQLException("There is no column with name ["+columnName+"], available columns are ["+getColumnlist()+"]");
2166                return col.getIndex();
2167        }
2168        
2169        int getPid() {
2170                
2171                PageContext pc = ThreadLocalPageContext.get();
2172                if(pc==null) {
2173                        pc=CFMLEngineFactory.getInstance().getThreadPageContext();
2174                        if(pc==null)throw new RuntimeException("cannot get pid for current thread");
2175                }
2176                return pc.getId();
2177        }
2178
2179        @Override
2180        public Query getGeneratedKeys() {
2181                return null;
2182        }
2183
2184        @Override
2185        public SQL getSql() {
2186                return sql;
2187        }
2188
2189        @Override
2190        public String getTemplate() {
2191                return template;
2192        }
2193
2194        @Override
2195        public long getExecutionTime() {
2196                return exeTime;
2197        }
2198        
2199        @Override
2200        public java.util.Iterator getIterator() {
2201                return new ForEachQueryIterator(this, ThreadLocalPageContext.get().getId());
2202    }
2203
2204}