001    package railo.runtime.type;
002    
003    import java.io.ByteArrayInputStream;
004    import java.io.IOException;
005    import java.io.InputStream;
006    import java.io.ObjectInput;
007    import java.io.ObjectOutput;
008    import java.io.Reader;
009    import java.io.StringReader;
010    import java.io.UnsupportedEncodingException;
011    import java.math.BigDecimal;
012    import java.net.URL;
013    import java.sql.Blob;
014    import java.sql.Clob;
015    import java.sql.NClob;
016    import java.sql.PreparedStatement;
017    import java.sql.Ref;
018    import java.sql.ResultSet;
019    import java.sql.ResultSetMetaData;
020    import java.sql.RowId;
021    import java.sql.SQLException;
022    import java.sql.SQLWarning;
023    import java.sql.SQLXML;
024    import java.sql.Statement;
025    import java.sql.Time;
026    import java.sql.Timestamp;
027    import java.sql.Types;
028    import java.util.Arrays;
029    import java.util.Calendar;
030    import java.util.Comparator;
031    import java.util.HashMap;
032    import java.util.HashSet;
033    import java.util.Iterator;
034    import java.util.Map;
035    import java.util.Map.Entry;
036    import java.util.Set;
037    import java.util.TimeZone;
038    
039    import railo.commons.db.DBUtil;
040    import railo.commons.io.IOUtil;
041    import railo.commons.lang.StringUtil;
042    import railo.commons.sql.SQLUtil;
043    import railo.loader.engine.CFMLEngineFactory;
044    import railo.runtime.PageContext;
045    import railo.runtime.config.NullSupportHelper;
046    import railo.runtime.converter.ScriptConverter;
047    import railo.runtime.db.CFTypes;
048    import railo.runtime.db.DataSourceUtil;
049    import railo.runtime.db.DatasourceConnection;
050    import railo.runtime.db.DatasourceConnectionImpl;
051    import railo.runtime.db.SQL;
052    import railo.runtime.db.SQLCaster;
053    import railo.runtime.db.SQLItem;
054    import railo.runtime.dump.DumpData;
055    import railo.runtime.dump.DumpProperties;
056    import railo.runtime.engine.ThreadLocalPageContext;
057    import railo.runtime.exp.ApplicationException;
058    import railo.runtime.exp.DatabaseException;
059    import railo.runtime.exp.ExpressionException;
060    import railo.runtime.exp.PageException;
061    import railo.runtime.exp.PageRuntimeException;
062    import railo.runtime.interpreter.CFMLExpressionInterpreter;
063    import railo.runtime.op.Caster;
064    import railo.runtime.op.Decision;
065    import railo.runtime.op.Duplicator;
066    import railo.runtime.op.ThreadLocalDuplication;
067    import railo.runtime.op.date.DateCaster;
068    import railo.runtime.query.caster.Cast;
069    import railo.runtime.type.comparator.NumberSortRegisterComparator;
070    import railo.runtime.type.comparator.SortRegister;
071    import railo.runtime.type.comparator.SortRegisterComparator;
072    import railo.runtime.type.dt.DateTime;
073    import railo.runtime.type.dt.DateTimeImpl;
074    import railo.runtime.type.it.CollectionIterator;
075    import railo.runtime.type.it.EntryIterator;
076    import railo.runtime.type.it.ForEachQueryIterator;
077    import railo.runtime.type.it.KeyIterator;
078    import railo.runtime.type.it.StringIterator;
079    import railo.runtime.type.sql.BlobImpl;
080    import railo.runtime.type.sql.ClobImpl;
081    import railo.runtime.type.util.ArrayUtil;
082    import railo.runtime.type.util.CollectionUtil;
083    import railo.runtime.type.util.KeyConstants;
084    import railo.runtime.type.util.ListUtil;
085    import railo.runtime.type.util.MemberUtil;
086    import railo.runtime.type.util.QueryUtil;
087    
088    /**
089     * implementation of the query interface
090     */
091    /**
092     * 
093     */
094    public class QueryImpl implements Query,Objects {
095    
096            private static final long serialVersionUID = 1035795427320192551L;
097    
098    
099            /**
100             * @return the template
101             */
102            public String getTemplate() {
103                    return template;
104            }
105    
106            public static final Collection.Key GENERATED_KEYS = KeyImpl.intern("GENERATED_KEYS");
107            public static final Collection.Key GENERATEDKEYS = KeyImpl.intern("GENERATEDKEYS");
108            public static final Collection.Key ID = KeyImpl.intern("ID");
109            
110            
111            
112            //private static int count=0;
113            private QueryColumnImpl[] columns;
114            private Collection.Key[] columnNames;
115            private SQL sql;
116            private ArrayInt arrCurrentRow=new ArrayInt();
117            private int recordcount=0;
118            private int columncount;
119            private long exeTime=0;
120        private boolean isCached=false;
121        private String name;
122            private int updateCount;
123        private QueryImpl generatedKeys;
124            private String template;
125            
126            
127            @Override
128            public int executionTime() {
129                    return (int) exeTime;
130            }
131    
132            /**
133             * create a QueryImpl from a SQL Resultset
134         * @param result SQL Resultset
135             * @param maxrow
136             * @param name 
137             * @throws PageException
138         */
139        public QueryImpl(ResultSet result, int maxrow, String name, TimeZone tz) throws PageException {
140            this.name=name;
141            //Stopwatch stopwatch=new Stopwatch();
142                    //stopwatch.start();
143                    long start=System.nanoTime();
144            try {
145                fillResult(null,result,maxrow,false,false,tz);
146            } catch (SQLException e) {
147                throw new DatabaseException(e,null);
148            } catch (IOException e) {
149                throw Caster.toPageException(e);
150            }
151                    exeTime=System.nanoTime()-start;
152        }
153        
154        /**
155         * Constructor of the class
156         * only for internal usage (cloning/deserialize)
157         */
158        public QueryImpl() {
159        }
160        
161        
162        public QueryImpl(ResultSet result, String name,TimeZone tz) throws PageException {
163                    this.name=name;
164            
165                    try {   
166                        fillResult(null,result,-1,true,false,tz);
167                    } 
168                    catch (SQLException e) {
169                            throw new DatabaseException(e,null);
170                    } 
171                    catch (Exception e) {
172                        throw Caster.toPageException(e);
173                    } 
174            }
175            
176            /**
177             * constructor of the class, to generate a resultset from a sql query
178             * @param dc Connection to a database
179             * @param name 
180             * @param sql sql to execute
181             * @param maxrow maxrow for the resultset
182             * @throws PageException
183             */     
184        public QueryImpl(PageContext pc, DatasourceConnection dc,SQL sql,int maxrow, int fetchsize,int timeout, String name) throws PageException {
185            this(pc,dc, sql, maxrow, fetchsize, timeout, name,null,false,true);
186        }
187        
188    
189        public QueryImpl(PageContext pc, DatasourceConnection dc,SQL sql,int maxrow, int fetchsize,int timeout, String name,String template) throws PageException {
190            this(pc,dc, sql, maxrow, fetchsize, timeout, name,template,false,true);
191        }
192        
193            public QueryImpl(PageContext pc, DatasourceConnection dc,SQL sql,int maxrow, int fetchsize,int timeout, String name,String template,boolean createUpdateData, boolean allowToCachePreperadeStatement) throws PageException {
194                    this.name=name;
195                    this.template=template;
196            this.sql=sql;
197                    TimeZone tz = ThreadLocalPageContext.getTimeZone(pc);
198            //ResultSet result=null;
199                    Statement stat=null;
200                    // check SQL Restrictions
201                    if(dc.getDatasource().hasSQLRestriction()) {
202                            QueryUtil.checkSQLRestriction(dc,sql);
203            }
204                    // check if datasource support Generated Keys
205                    boolean createGeneratedKeys=createUpdateData;
206            if(createUpdateData){
207                    DatasourceConnectionImpl dci=(DatasourceConnectionImpl) dc;
208                    if(!dci.supportsGetGeneratedKeys())createGeneratedKeys=false;
209            }
210    
211            
212                    //Stopwatch stopwatch=new Stopwatch();
213            long start=System.nanoTime();
214                    //stopwatch.start();
215                    boolean hasResult=false;
216                    //boolean closeStatement=true;
217                    try {   
218                            SQLItem[] items=sql.getItems();
219                            if(items.length==0) {
220                            stat=dc.getConnection().createStatement();
221                            setAttributes(stat,maxrow,fetchsize,timeout);
222                         // some driver do not support second argument
223                            //hasResult=createGeneratedKeys?stat.execute(sql.getSQLString(),Statement.RETURN_GENERATED_KEYS):stat.execute(sql.getSQLString());
224                            hasResult=QueryUtil.execute(pc,stat,createGeneratedKeys,sql);
225                    }
226                    else {
227                            // some driver do not support second argument
228                            PreparedStatement preStat = dc.getPreparedStatement(sql, createGeneratedKeys,allowToCachePreperadeStatement);
229                            //closeStatement=false;
230                            stat=preStat;
231                        setAttributes(preStat,maxrow,fetchsize,timeout);
232                        setItems(ThreadLocalPageContext.getTimeZone(pc),preStat,items);
233                            hasResult=QueryUtil.execute(pc,preStat);    
234                    }
235                            int uc;
236                            ResultSet res;
237                            do {
238                                    if(hasResult) {
239                                            res=stat.getResultSet();
240                                            if(fillResult(dc,res, maxrow, true,createGeneratedKeys,tz))break;
241                                    }
242                                    else if((uc=setUpdateCount(stat))!=-1){
243                                            if(uc>0 && createGeneratedKeys)setGeneratedKeys(dc, stat,tz);
244                                    }
245                                    else break;
246                                    try{
247                                            hasResult=stat.getMoreResults(Statement.CLOSE_CURRENT_RESULT);
248                                    }
249                                    catch(Throwable t){
250                                            break;
251                                    }
252                            }
253                            while(true);
254                    } 
255                    catch (SQLException e) {
256                            throw new DatabaseException(e,sql,dc);
257                    } 
258                    catch (Throwable e) {
259                            throw Caster.toPageException(e);
260                    }
261            finally {
262                    //if(closeStatement)
263                            DBUtil.closeEL(stat);
264            }  
265                    exeTime=System.nanoTime()-start;
266    
267                    if(columncount==0) {
268                            if(columnNames==null) columnNames=new Collection.Key[0];
269                            if(columns==null) columns=new QueryColumnImpl[0];
270                    }
271            }
272            
273            private int setUpdateCount(Statement stat)  {
274                    try{
275                            int uc=stat.getUpdateCount();
276                            if(uc>-1){
277                                    updateCount+=uc;
278                                    return uc;
279                            }
280                    }
281                    catch(Throwable t){}
282                    return -1;
283            }
284            
285            private boolean setGeneratedKeys(DatasourceConnection dc,Statement stat, TimeZone tz)  {
286                    try{
287                            ResultSet rs = stat.getGeneratedKeys();
288                            setGeneratedKeys(dc, rs,tz);
289                            return true;
290                    }
291                    catch(Throwable t) {t.printStackTrace();
292                            return false;
293                    }
294            }
295            
296            private void setGeneratedKeys(DatasourceConnection dc,ResultSet rs, TimeZone tz) throws PageException  {
297                    generatedKeys=new QueryImpl(rs,"",tz);
298                    
299                    // ACF compatibility action 
300                    if(generatedKeys.getColumnCount()==1 && DataSourceUtil.isMSSQL(dc)) {
301                            generatedKeys.renameEL(GENERATED_KEYS,KeyConstants._IDENTITYCOL);
302                            generatedKeys.renameEL(GENERATEDKEYS,KeyConstants._IDENTITYCOL);
303                            generatedKeys.renameEL(ID,KeyConstants._IDENTITYCOL);
304                    }
305            }
306            
307            /*private void setUpdateData(Statement stat, boolean createGeneratedKeys, boolean createUpdateCount)  {
308                    
309                    // update Count
310                    if(createUpdateCount){
311                            try{
312                                    updateCount=stat.getUpdateCount();
313                            }
314                            catch(Throwable t){
315                                    t.printStackTrace();
316                            }
317                    }
318                    // generated keys
319                    if(createGeneratedKeys){
320                            try{
321                                    ResultSet rs = stat.getGeneratedKeys();
322                                    generatedKeys=new QueryImpl(rs,"");
323                            }
324                            catch(Throwable t){
325                                    t.printStackTrace();
326                            }
327                    }
328            }*/
329    
330    
331            private void setItems(TimeZone tz,PreparedStatement preStat, SQLItem[] items) throws DatabaseException, PageException, SQLException {
332                    for(int i=0;i<items.length;i++) {
333                SQLCaster.setValue(tz,preStat,i+1,items[i]);
334            }
335            }
336    
337            public int getUpdateCount() {
338                    return updateCount;
339            }
340            public Query getGeneratedKeys() {
341                    return generatedKeys;
342            }
343    
344            private void setAttributes(Statement stat,int maxrow, int fetchsize,int timeout) throws SQLException {
345                    if(maxrow>-1) stat.setMaxRows(maxrow);
346            if(fetchsize>0)stat.setFetchSize(fetchsize);
347            if(timeout>0)stat.setQueryTimeout(timeout);
348            }
349    
350        private boolean fillResult(DatasourceConnection dc, ResultSet result, int maxrow, boolean closeResult,boolean createGeneratedKeys, TimeZone tz) throws SQLException, IOException, PageException {
351            if(result==null) return false;
352            recordcount=0;
353                    ResultSetMetaData meta = result.getMetaData();
354                    columncount=meta.getColumnCount();
355                    
356            // set header arrays
357                    Collection.Key[] tmpColumnNames = new Collection.Key[columncount];
358                    int count=0;
359                    Collection.Key key;
360                    String columnName;
361                    for(int i=0;i<columncount;i++) {
362                            columnName=QueryUtil.getColumnName(meta,i+1);
363                            if(StringUtil.isEmpty(columnName))columnName="column_"+i;
364                            key=KeyImpl.init(columnName);
365                            int index=getIndexFrom(tmpColumnNames,key,0,i);
366                            if(index==-1) {
367                                    tmpColumnNames[i]=key;
368                                    count++;
369                            }
370                    }
371                    
372    
373                    columncount=count;
374                    columnNames=new Collection.Key[columncount];
375                    columns=new QueryColumnImpl[columncount];
376                    Cast[] casts = new Cast[columncount];
377                    
378            // get all used ints
379                    int[] usedColumns=new int[columncount];
380                    count=0;
381                    for(int i=0;i<tmpColumnNames.length;i++) {
382                            if(tmpColumnNames[i]!=null) {
383                                    usedColumns[count++]=i;
384                            }
385                    }       
386                                            
387            // set used column names
388                    int[] types=new int[columns.length];
389                    for(int i=0;i<usedColumns.length;i++) {
390                columnNames[i]=tmpColumnNames[usedColumns[i]];
391                columns[i]=new QueryColumnImpl(this,columnNames[i],types[i]=meta.getColumnType(usedColumns[i]+1));
392                
393                if(types[i]==Types.TIMESTAMP)       casts[i]=Cast.TIMESTAMP;
394                else if(types[i]==Types.TIME)       casts[i]=Cast.TIME;
395                else if(types[i]==Types.DATE)       casts[i]=Cast.DATE;
396                else if(types[i]==Types.CLOB)       casts[i]=Cast.CLOB;
397                else if(types[i]==Types.BLOB)       casts[i]=Cast.BLOB;
398                else if(types[i]==Types.BIT)        casts[i]=Cast.BIT;
399                else if(types[i]==Types.ARRAY)      casts[i]=Cast.ARRAY;
400                //else if(types[i]==Types.TINYINT)  casts[i]=Cast.ARRAY;
401                
402                else if(types[i]==CFTypes.OPAQUE){
403                    if(SQLUtil.isOracle(result.getStatement().getConnection()))
404                            casts[i]=Cast.ORACLE_OPAQUE;
405                    else 
406                            casts[i]=Cast.OTHER;
407                                    
408                }
409                else casts[i]=Cast.OTHER;
410                    }
411                    
412                    if(createGeneratedKeys && columncount==1 && columnNames[0].equals(GENERATED_KEYS) && dc!=null && DataSourceUtil.isMSSQLDriver(dc)) {
413                            columncount=0;
414                            columnNames=null;
415                            columns=null;
416                            setGeneratedKeys(dc, result,tz);
417                            return false;
418                    }
419                    
420    
421            // fill data
422                    //Object o;
423                    while(result.next()) {
424                            if(maxrow>-1 && recordcount>=maxrow) {
425                                    break;
426                            }
427                            for(int i=0;i<usedColumns.length;i++) {
428                                columns[i].add(casts[i].toCFType(tz,types[i], result, usedColumns[i]+1));
429                            }
430                            ++recordcount;
431                    }
432                    if(closeResult)result.close();
433                    return true;
434            }
435    
436        private Object toBytes(Blob blob) throws IOException, SQLException {
437                    return IOUtil.toBytes((blob).getBinaryStream());
438            }
439    
440            private static Object toString(Clob clob) throws IOException, SQLException {
441                    return IOUtil.toString(clob.getCharacterStream());
442            }
443    
444        private static int getIndexFrom(Collection.Key[] tmpColumnNames, Collection.Key key, int from, int to) {
445                    for(int i=from;i<to;i++) {
446                            if(tmpColumnNames[i]!=null && tmpColumnNames[i].equalsIgnoreCase(key))return i;
447                    }
448                    return -1;
449            }
450    
451            /**
452             * constructor of the class, to generate a empty resultset (no database execution)
453             * @param strColumns columns for the resultset
454             * @param rowNumber count of rows to generate (empty fields)
455             * @param name 
456             * @deprecated use instead <code>QueryImpl(Collection.Key[] columnKeys, int rowNumber,String name)</code>
457             */
458            public QueryImpl(String[] strColumns, int rowNumber,String name) {
459            this.name=name;
460            columncount=strColumns.length;
461                    recordcount=rowNumber;
462                    columnNames=new Collection.Key[columncount];
463                    columns=new QueryColumnImpl[columncount];
464                    for(int i=0;i<strColumns.length;i++) {
465                            columnNames[i]=KeyImpl.init(strColumns[i].trim());
466                            columns[i]=new QueryColumnImpl(this,columnNames[i],Types.OTHER,recordcount);
467                    }
468            }
469    
470            /**
471             * constructor of the class, to generate a empty resultset (no database execution)
472             * @param strColumns columns for the resultset
473             * @param rowNumber count of rows to generate (empty fields)
474             * @param name 
475             */
476            public QueryImpl(Collection.Key[] columnKeys, int rowNumber,String name) throws DatabaseException {
477                    this.name=name;
478            columncount=columnKeys.length;
479                    recordcount=rowNumber;
480                    columnNames=new Collection.Key[columncount];
481                    columns=new QueryColumnImpl[columncount];
482                    for(int i=0;i<columnKeys.length;i++) {
483                            columnNames[i]=columnKeys[i];
484                            columns[i]=new QueryColumnImpl(this,columnNames[i],Types.OTHER,recordcount);
485                    }
486                    validateColumnNames(columnNames);
487            }
488            
489            /**
490             * constructor of the class, to generate a empty resultset (no database execution)
491             * @param strColumns columns for the resultset
492             * @param strTypes array of the types
493             * @param rowNumber count of rows to generate (empty fields)
494             * @param name 
495             * @throws DatabaseException 
496             */
497            public QueryImpl(String[] strColumns, String[] strTypes, int rowNumber, String name) throws DatabaseException {
498            this.name=name;
499            columncount=strColumns.length;
500                    if(strTypes.length!=columncount) throw new DatabaseException("columns and types has not the same count",null,null,null);
501                    recordcount=rowNumber;
502                    columnNames=new Collection.Key[columncount];
503                    columns=new QueryColumnImpl[columncount];
504                    for(int i=0;i<strColumns.length;i++) {
505                            columnNames[i]=KeyImpl.init(strColumns[i].trim());
506                            columns[i]=new QueryColumnImpl(this,columnNames[i],SQLCaster.toIntType(strTypes[i]),recordcount);
507                    }
508            }
509            
510            /**
511             * constructor of the class, to generate a empty resultset (no database execution)
512             * @param strColumns columns for the resultset
513             * @param strTypes array of the types
514             * @param rowNumber count of rows to generate (empty fields)
515             * @param name 
516             * @throws DatabaseException 
517             */
518            public QueryImpl(Collection.Key[] columnNames, String[] strTypes, int rowNumber, String name) throws DatabaseException {
519            this.name=name;
520            this.columnNames=columnNames;
521            columncount=columnNames.length;
522                    if(strTypes.length!=columncount) throw new DatabaseException("columns and types has not the same count",null,null,null);
523                    recordcount=rowNumber;
524                    columns=new QueryColumnImpl[columncount];
525                    for(int i=0;i<columnNames.length;i++) {
526                            columns[i]=new QueryColumnImpl(this,columnNames[i],SQLCaster.toIntType(strTypes[i]),recordcount);
527                    }
528                    validateColumnNames(columnNames);
529            }
530            
531            /**
532             * constructor of the class, to generate a empty resultset (no database execution)
533             * @param arrColumns columns for the resultset
534             * @param rowNumber count of rows to generate (empty fields)
535             * @param name 
536             * @throws DatabaseException 
537             */
538            public QueryImpl(Array arrColumns, int rowNumber, String name) throws DatabaseException {
539            this.name=name;
540            columncount=arrColumns.size();
541                    recordcount=rowNumber;
542                    columnNames=new Collection.Key[columncount];
543                    columns=new QueryColumnImpl[columncount];
544                    for(int i=0;i<columncount;i++) {
545                            columnNames[i]=KeyImpl.init(arrColumns.get(i+1,"").toString().trim());
546                            columns[i]=new QueryColumnImpl(this,columnNames[i],Types.OTHER,recordcount);
547                    }
548                    validateColumnNames(columnNames);
549            }
550    
551            /**
552             * constructor of the class, to generate a empty resultset (no database execution)
553             * @param arrColumns columns for the resultset
554             * @param arrTypes type of the columns
555             * @param rowNumber count of rows to generate (empty fields)
556             * @param name 
557             * @throws PageException
558             */
559            public QueryImpl(Array arrColumns, Array arrTypes, int rowNumber, String name) throws PageException {
560            this.name=name;
561            columncount=arrColumns.size();
562                    if(arrTypes.size()!=columncount) throw new DatabaseException("columns and types has not the same count",null,null,null);
563                    recordcount=rowNumber;
564                    columnNames=new Collection.Key[columncount];
565                    columns=new QueryColumnImpl[columncount];
566                    for(int i=0;i<columncount;i++) {
567                            columnNames[i]=KeyImpl.init(arrColumns.get(i+1,"").toString().trim());
568                            columns[i]=new QueryColumnImpl(this,columnNames[i],SQLCaster.toIntType(Caster.toString(arrTypes.get(i+1,""))),recordcount);
569                    }
570                    validateColumnNames(columnNames);
571            }
572    
573            /**
574             * constructor of the class
575             * @param columnNames columns definition as String Array
576             * @param arrColumns values
577             * @param name 
578             * @throws DatabaseException
579             */
580    
581            public QueryImpl(String[] strColumnNames, Array[] arrColumns, String name) throws DatabaseException {
582                    this(_toKeys(strColumnNames),arrColumns,name);          
583            }       
584            
585            private static void validateColumnNames(Key[] columnNames) throws DatabaseException {
586                    Set<String> testMap=new HashSet<String>();
587                    for(int i=0     ;i<columnNames.length;i++) {
588                            
589                            // Only allow column names that are valid variable name
590                            //if(!Decision.isSimpleVariableName(columnNames[i]))
591                            //      throw new DatabaseException("invalid column name ["+columnNames[i]+"] for query", "column names must start with a letter and can be followed by letters numbers and underscores [_]. RegExp:[a-zA-Z][a-zA-Z0-9_]*",null,null,null);
592                            
593                            if(testMap.contains(columnNames[i].getLowerString()))
594                                    throw new DatabaseException("invalid parameter for query, ambiguous column name "+columnNames[i],"columnNames: "+ListUtil.arrayToListTrim( _toStringKeys(columnNames),","),null,null,null);
595                            testMap.add(columnNames[i].getLowerString());
596                    }
597            }
598            
599    
600            private static Collection.Key[] _toKeys(String[] strColumnNames) {
601                    Collection.Key[] columnNames=new Collection.Key[strColumnNames.length];
602                    for(int i=0     ;i<columnNames.length;i++) {
603                            columnNames[i]=KeyImpl.init(strColumnNames[i].trim());
604                    }
605                    return columnNames;
606            }
607            private static String[] _toStringKeys(Collection.Key[] columnNames) {
608                    String[] strColumnNames=new String[columnNames.length];
609                    for(int i=0     ;i<strColumnNames.length;i++) {
610                            strColumnNames[i]=columnNames[i].getString();
611                    }
612                    return strColumnNames;
613            }
614            
615            /*public QueryImpl(Collection.Key[] columnNames, QueryColumn[] columns, String name,long exeTime, boolean isCached,SQL sql) throws DatabaseException {
616                    this.columnNames=columnNames;
617                    this.columns=columns;
618                    this.exeTime=exeTime;
619                    this.isCached=isCached;
620                    this.name=name;
621                    this.columncount=columnNames.length;
622                    this.recordcount=columns.length==0?0:columns[0].size();
623                    this.sql=sql;
624                    
625            }*/
626    
627            public QueryImpl(Collection.Key[] columnNames, Array[] arrColumns, String name) throws DatabaseException {
628            this.name=name;
629            
630            if(columnNames.length!=arrColumns.length)
631                            throw new DatabaseException("invalid parameter for query, not the same count from names and columns","names:"+columnNames.length+";columns:"+arrColumns.length,null,null,null);
632                    int len=0;
633                    columns=new QueryColumnImpl[arrColumns.length];
634                    if(arrColumns.length>0) {
635                    // test columns
636                            len=arrColumns[0].size();
637                            for(int i=0;i<arrColumns.length;i++) {
638                                    if(arrColumns[i].size()!=len)
639                                            throw new DatabaseException("invalid parameter for query, all columns must have the same size","column[1]:"+len+"<>column["+(i+1)+"]:"+arrColumns[i].size(),null,null,null);
640                                    //columns[i]=new QueryColumnTypeFlex(arrColumns[i]);
641                                    columns[i]=new QueryColumnImpl(this,columnNames[i],arrColumns[i],Types.OTHER);
642                            }
643                    // test keys
644                            validateColumnNames(columnNames);
645                    }
646                    
647                    columncount=columns.length;
648                    recordcount=len;
649                    this.columnNames=columnNames;
650            }
651            
652        /**
653         * constructor of the class
654         * @param columnList
655         * @param data
656         * @param name 
657         * @throws DatabaseException 
658         */
659        public QueryImpl(String[] strColumnList, Object[][] data,String name) throws DatabaseException {
660            
661            this(toCollKeyArr(strColumnList),data.length,name);
662            
663            for(int iRow=0;iRow<data.length;iRow++) {
664                Object[] row=data[iRow];
665                for(int iCol=0;iCol<row.length;iCol++) {
666                    //print.ln(columnList[iCol]+":"+iRow+"="+row[iCol]);
667                    setAtEL(columnNames[iCol],iRow+1,row[iCol]);
668                }
669            }
670        }
671    
672        private static Collection.Key[] toCollKeyArr(String[] strColumnList) {
673            Collection.Key[] columnList=new Collection.Key[strColumnList.length];
674                    for(int i=0     ;i<columnList.length;i++) {
675                            columnList[i]=KeyImpl.init(strColumnList[i].trim());
676                    }
677                    return columnList;
678            }
679    
680            @Override
681            public int size() {
682                    return columncount;
683            }
684    
685            @Override
686            public Collection.Key[] keys() {
687                    return columnNames;
688            }
689    
690            @Override
691            public Object removeEL(Collection.Key key) {
692                    return setEL(key,null);
693            }
694    
695            @Override
696            public Object remove(Collection.Key key) throws PageException {
697                    return set(key,null);
698            }
699    
700            @Override
701            public void clear() {
702                    for(int i=0;i<columns.length;i++) {
703                columns[i].clear();
704            }
705            recordcount=0;
706            }
707    
708            @Override
709            public Object get(String key, Object defaultValue) {
710                    return getAt(key,
711                                    arrCurrentRow.get(getPid(), 1),
712                                    defaultValue);
713            }
714    
715            //private static int pidc=0;
716            private int getPid() {
717                    
718                    PageContext pc = ThreadLocalPageContext.get();
719                    if(pc==null) {
720                            pc=CFMLEngineFactory.getInstance().getThreadPageContext();
721                            if(pc==null)throw new RuntimeException("cannot get pid for current thread");
722                    }
723                    return pc.getId();
724            }
725    
726            @Override
727            public Object get(Collection.Key key, Object defaultValue) {
728                    return getAt(key,
729                                    arrCurrentRow.get(getPid(), 1),
730                                    defaultValue);
731            }
732    
733            @Override
734            public Object get(String key) throws PageException {
735                    return getAt(key,
736                                    arrCurrentRow.get(getPid(), 1)
737                                    );
738            }
739    
740            @Override
741            public Object get(Collection.Key key) throws PageException {
742                    return getAt(key,
743                                    arrCurrentRow.get(getPid(), 1)
744                                    );
745            }
746    
747            @Override
748            public Object getAt(String key, int row, Object defaultValue) {
749                    return getAt(KeyImpl.init(key), row, defaultValue);
750            }
751    
752            public Object getAt(Collection.Key key, int row, Object defaultValue) {
753                    int index=getIndexFromKey(key);
754                    if(index!=-1) {
755                            return columns[index].get(row,defaultValue);
756                    }
757                    if(key.getString().length()>0) {
758                    char c=key.lowerCharAt(0);
759                    if(c=='r') {
760                        if(key.equals(KeyConstants._RECORDCOUNT)) return new Double(getRecordcount());
761                    }
762                    else if(c=='c') {
763                        if(key.equals(KeyConstants._CURRENTROW)) return new Double(row);
764                        else if(key.equals(KeyConstants._COLUMNLIST)) return getColumnlist(true);
765                    }
766                    }
767            return defaultValue;
768            }
769            
770            @Override
771            public Object getAt(String key, int row) throws PageException {
772                    return getAt(KeyImpl.init(key), row);
773            }
774    
775            @Override
776            public Object getAt(Collection.Key key, int row) throws PageException {
777                    int index=getIndexFromKey(key);
778                    if(index!=-1) {
779                            if(NullSupportHelper.full()) return columns[index].get(row, null);
780                            Object v = columns[index].get(row, null);
781                            return v==null?"":v;
782                    }
783            if(key.getString().length()>0) {
784                    char c=key.lowerCharAt(0);
785                    if(c=='r') {
786                        if(key.equals(KeyConstants._RECORDCOUNT)) return new Double(getRecordcount());
787                            }
788                    else if(c=='c') {
789                                if(key.equals(KeyConstants._CURRENTROW)) return new Double(row);
790                                else if(key.equals(KeyConstants._COLUMNLIST)) return getColumnlist(true);
791                            }
792            }
793                    throw new DatabaseException("column ["+key+"] not found in query, columns are ["+getColumnlist(false)+"]",null,sql,null);
794            }
795    
796        @Override
797        public synchronized int removeRow(int row) throws PageException {
798            //disconnectCache();
799            
800            for(int i=0;i<columns.length;i++) {
801                columns[i].removeRow(row);
802            }
803            return --recordcount;
804        }
805    
806        @Override
807        public int removeRowEL(int row) {
808            //disconnectCache();
809            
810            try {
811                return removeRow(row);
812            } catch (PageException e) {
813                return recordcount;
814            }
815        }
816        
817        @Override
818        public QueryColumn removeColumn(String key) throws DatabaseException {
819            return removeColumn(KeyImpl.init(key));
820        }
821    
822            @Override
823            public QueryColumn removeColumn(Collection.Key key) throws DatabaseException {
824                    //disconnectCache();
825            
826            QueryColumn removed = removeColumnEL(key);
827            if(removed==null) {
828                if(key.equals(KeyConstants._RECORDCOUNT) || 
829                            key.equals(KeyConstants._CURRENTROW) || 
830                            key.equals(KeyConstants._COLUMNLIST))
831                    throw new DatabaseException("can't remove "+key+" this is not a row","existing rows are ["+getColumnlist(false)+"]",null,null,null);
832                throw new DatabaseException("can't remove row ["+key+"], this row doesn't exist",
833                        "existing rows are ["+getColumnlist(false)+"]",null,null,null);
834            }
835            return removed;
836            }
837    
838        @Override
839        public synchronized QueryColumn removeColumnEL(String key) {
840            return removeColumnEL(KeyImpl.init(key));
841        }
842    
843            public QueryColumn removeColumnEL(Collection.Key key) {
844                    //disconnectCache();
845            
846            int index=getIndexFromKey(key);
847            if(index!=-1) {
848                int current=0;
849                QueryColumn removed=null;
850                Collection.Key[] newColumnNames=new Collection.Key[columnNames.length-1];
851                QueryColumnImpl[] newColumns=new QueryColumnImpl[columns.length-1];
852                for(int i=0;i<columns.length;i++) {
853                    if(i==index) {
854                        removed=columns[i];
855                    }
856                    else {
857                        newColumnNames[current]=columnNames[i];
858                        newColumns[current++]=columns[i];
859                    }
860                }
861                columnNames=newColumnNames;
862                columns=newColumns;
863                columncount--;
864                return removed;
865            }
866            return null;
867            }
868    
869            @Override
870            public Object setEL(String key, Object value) { 
871                    return setEL(KeyImpl.init(key),value);  
872            }
873    
874            @Override
875            public Object setEL(Collection.Key key, Object value) {
876                    return setAtEL(key,
877                                    arrCurrentRow.get(getPid(), 1),
878                                    value);
879            }
880            
881            @Override
882            public Object set(String key, Object value) throws PageException {
883                    return set(KeyImpl.init(key),value);
884            }
885    
886            @Override
887            public Object set(Collection.Key key, Object value) throws PageException {
888                    return setAt(key,
889                                    arrCurrentRow.get(getPid(), 1),
890                                    value);
891            }
892        
893        @Override
894        public Object setAt(String key,int row, Object value) throws PageException {
895            return setAt(KeyImpl.init(key), row, value);
896        }
897    
898        public Object setAt(Collection.Key key, int row, Object value) throws PageException {
899                    int index=getIndexFromKey(key);
900            if(index!=-1) {
901                return columns[index].set(row,value);
902            }
903            throw new DatabaseException("column ["+key+"] does not exist","columns are ["+getColumnlist(false)+"]",null,sql,null);
904            }
905        
906        @Override
907        public Object setAtEL(String key,int row, Object value) {
908            return setAtEL(KeyImpl.init(key), row, value);
909        }
910    
911            public Object setAtEL(Collection.Key key, int row, Object value) {
912                    int index=getIndexFromKey(key);
913            if(index!=-1) {
914                return columns[index].setEL(row,value);
915            }
916            return null;
917            }
918    
919            @Override
920            public boolean next() {
921                    return next(getPid());
922            }
923    
924            @Override
925            public boolean next(int pid) {
926                    if(recordcount>=(arrCurrentRow.set(pid,arrCurrentRow.get(pid,0)+1))) {
927                            return true;
928                    }
929                    arrCurrentRow.set(pid,0);
930                    return false;
931            }
932    
933            @Override
934            public void reset() {
935                    reset(getPid());
936            }
937            
938            public void reset(int pid) {
939                    arrCurrentRow.set(pid,0);
940            }
941    
942            @Override
943            public int getRecordcount() {
944                    return recordcount;
945            }
946            
947            @Override
948            public int getCurrentrow(int pid) {
949                    return arrCurrentRow.get(pid,1);
950            }
951    
952    
953            /**
954             * return a string list of all columns
955             * @return string list
956             */
957            public String getColumnlist(boolean upperCase) {
958                    
959                    StringBuffer sb=new StringBuffer();
960                    for(int i=0;i<columnNames.length;i++) {
961                            if(i>0)sb.append(',');
962                            sb.append(upperCase?columnNames[i].getUpperString():columnNames[i].getString());
963                    }
964                    return sb.toString();
965            }
966            public String getColumnlist() {
967                    return getColumnlist(true);
968            }
969    
970            public boolean go(int index) {
971                    return go(index,getPid());
972            }
973            
974            public boolean go(int index, int pid) {
975                    if(index>0 && index<=recordcount) {
976                            arrCurrentRow.set(pid, index);
977                            return true;
978                    }
979                    arrCurrentRow.set(pid, 0);
980                    return false;
981            }
982    
983            @Override
984            public boolean isEmpty() {
985                    return recordcount+columncount==0;
986            }
987    
988            @Override
989            public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp) {
990                    return QueryUtil.toDumpData(this, pageContext, maxlevel, dp);
991            }
992            
993            /**
994             * sorts a query by a column
995             * @param column colun to sort
996             * @throws PageException
997             */
998            public void sort(String column) throws PageException {
999                    sort(column,Query.ORDER_ASC);
1000            }
1001    
1002            @Override
1003            public void sort(Collection.Key column) throws PageException {
1004                    sort(column,Query.ORDER_ASC);
1005            }
1006    
1007            /**
1008             * sorts a query by a column 
1009             * @param strColumn column to sort
1010             * @param order sort type (Query.ORDER_ASC or Query.ORDER_DESC)
1011             * @throws PageException
1012             */
1013            public synchronized void sort(String strColumn, int order) throws PageException {
1014                    //disconnectCache();
1015            sort(getColumn(strColumn),order);
1016            }
1017            
1018            @Override
1019            public synchronized void sort(Collection.Key keyColumn, int order) throws PageException {
1020                    //disconnectCache();
1021            sort(getColumn(keyColumn),order);
1022            }
1023            
1024            private void sort(QueryColumn column, int order) throws PageException {
1025            int type = column.getType();
1026                    
1027                    SortRegister[] arr= ArrayUtil.toSortRegisterArray(column);
1028                    
1029                    Arrays.sort(arr,
1030                    (
1031                                    type==Types.BIGINT || 
1032                                    type==Types.BIT || 
1033                                    type==Types.INTEGER || 
1034                                    type==Types.SMALLINT || 
1035                                    type==Types.TINYINT     ||
1036                            type==Types.DECIMAL || 
1037                            type==Types.DOUBLE || 
1038                            type==Types.NUMERIC || 
1039                            type==Types.REAL)?
1040                    
1041                    (Comparator)new NumberSortRegisterComparator(order==ORDER_ASC):(Comparator)new SortRegisterComparator(order==ORDER_ASC,true)
1042                    );
1043                    
1044                    for(int i=0;i<columns.length;i++) {
1045                            column=columns[i];
1046                            int len=column.size();
1047                            QueryColumnImpl newCol=new QueryColumnImpl(this,columnNames[i],columns[i].getType(),len);
1048                            for(int y=1;y<=len;y++) {
1049                                    newCol.set(y,column.get(arr[y-1].getOldPosition()+1,null));
1050                            }
1051                            columns[i]=newCol;
1052                    }
1053            }
1054    
1055            @Override
1056             public synchronized boolean addRow(int count) {                
1057             //disconnectCache();
1058                
1059             for(int i=0;i<columns.length;i++) {
1060                     QueryColumnPro column = columns[i];
1061                            column.addRow(count);
1062                     }
1063                     recordcount+=count;
1064                     return true;
1065             }
1066             
1067             @Override
1068            public boolean addColumn(String columnName, Array content) throws DatabaseException {
1069                    return addColumn(columnName,content,Types.OTHER);
1070             }
1071    
1072            public boolean addColumn(Collection.Key columnName, Array content) throws PageException {
1073                    return addColumn(columnName,content,Types.OTHER);
1074            }
1075            
1076        @Override
1077        public synchronized boolean addColumn(String columnName, Array content, int type) throws DatabaseException {
1078                    return addColumn(KeyImpl.init(columnName.trim()), content, type);
1079        }
1080    
1081            @Override
1082            public boolean addColumn(Collection.Key columnName, Array content, int type) throws DatabaseException {
1083                    //disconnectCache();
1084            // TODO Meta type
1085                    content=(Array) Duplicator.duplicate(content,false);
1086                    
1087                    if(getIndexFromKey(columnName)!=-1)
1088                            throw new DatabaseException("column name ["+columnName.getString()+"] already exist",null,sql,null);
1089                    if(content.size()!=getRecordcount()) {
1090                            //throw new DatabaseException("array for the new column has not the same size like the query (arrayLen!=query.recordcount)");
1091                            if(content.size()>getRecordcount()) addRow(content.size()-getRecordcount());
1092                            else content.setEL(getRecordcount(),"");
1093                    }
1094                    QueryColumnImpl[] newColumns=new QueryColumnImpl[columns.length+1];
1095                    Collection.Key[] newColumnNames=new Collection.Key[columns.length+1];
1096                    boolean logUsage=false;
1097                    for(int i=0;i<columns.length;i++) {
1098                            newColumns[i]=columns[i];
1099                            newColumnNames[i]=columnNames[i];
1100                            if(!logUsage && columns[i] instanceof DebugQueryColumn) logUsage=true;
1101                    }
1102                    newColumns[columns.length]=new QueryColumnImpl(this,columnName,content,type);
1103                    newColumnNames[columns.length]=columnName;
1104                    columns=newColumns;
1105                    columnNames=newColumnNames;
1106                    
1107                    columncount++;
1108                    
1109                    if(logUsage)enableShowQueryUsage();
1110                    
1111                    return true;
1112            }
1113            
1114    
1115            /* *
1116             * if this query is still connected with cache (same query also in cache)
1117         * it will disconnetd from cache (clone object and add clone to cache)
1118             */
1119            //protected void disconnectCache() {}
1120    
1121            
1122            @Override
1123        public Object clone() {
1124            return cloneQuery(true);
1125        }
1126        
1127        @Override
1128        public Collection duplicate(boolean deepCopy) {
1129            return cloneQuery(true);
1130        }
1131        
1132    
1133            
1134        
1135        /**
1136         * @return clones the query object
1137         */
1138        public QueryImpl cloneQuery(boolean deepCopy) {
1139            QueryImpl newResult=new QueryImpl();
1140            ThreadLocalDuplication.set(this, newResult);
1141            try{
1142                    if(columnNames!=null){
1143                            newResult.columnNames=new Collection.Key[columnNames.length];
1144                            newResult.columns=new QueryColumnImpl[columnNames.length];
1145                            for(int i=0;i<columnNames.length;i++) {
1146                                    newResult.columnNames[i]=columnNames[i];
1147                                    newResult.columns[i]=columns[i].cloneColumnImpl(deepCopy);
1148                            }
1149                    }
1150                    newResult.sql=sql;
1151                    newResult.template=template;
1152                    newResult.recordcount=recordcount;
1153                    newResult.columncount=columncount;
1154                    newResult.isCached=isCached;
1155                    newResult.name=name;
1156                    newResult.exeTime=exeTime;
1157                    newResult.updateCount=updateCount;
1158                    if(generatedKeys!=null)newResult.generatedKeys=generatedKeys.cloneQuery(false);
1159                    return newResult;
1160            }
1161            finally {
1162                    // ThreadLocalDuplication.remove(this); removed "remove" to catch sisters and brothers
1163            }
1164        }
1165    
1166            @Override
1167            public synchronized int[] getTypes() {
1168                    int[] types=new int[columns.length];
1169                    for(int i=0;i<columns.length;i++) {
1170                        types[i]=columns[i].getType();
1171                    }
1172                    return types;
1173            }
1174            
1175            @Override
1176            public synchronized Map<Collection.Key,String> getTypesAsMap() {
1177                    
1178                    Map<Collection.Key,String> map=new HashMap<Collection.Key,String>();
1179                    for(int i=0;i<columns.length;i++) {
1180                            map.put(columnNames[i],columns[i].getTypeAsString());
1181                    }
1182                    return map;
1183            }
1184    
1185            @Override
1186            public QueryColumn getColumn(String key) throws DatabaseException {
1187                    return getColumn(KeyImpl.init(key.trim()));
1188            }
1189    
1190            @Override
1191            public QueryColumn getColumn(Collection.Key key) throws DatabaseException {
1192                    int index=getIndexFromKey(key);
1193                    if(index!=-1) return columns[index];
1194            
1195                    if(key.getString().length()>0) {
1196                    char c=key.lowerCharAt(0);
1197                    if(c=='r') {
1198                        if(key.equals(KeyConstants._RECORDCOUNT)) return new QueryColumnRef(this,key,Types.INTEGER);
1199                    }
1200                    if(c=='c') {
1201                        if(key.equals(KeyConstants._CURRENTROW)) return new QueryColumnRef(this,key,Types.INTEGER);
1202                        else if(key.equals(KeyConstants._COLUMNLIST)) return new QueryColumnRef(this,key,Types.INTEGER);
1203                    }
1204                    }
1205            throw new DatabaseException("key ["+key.getString()+"] not found in query, columns are ["+getColumnlist(false)+"]",null,sql,null);
1206            }
1207            
1208    
1209            private void renameEL(Collection.Key src, Collection.Key trg) {
1210                    int index=getIndexFromKey(src);
1211                    if(index!=-1){
1212                            columnNames[index]=trg;
1213                            columns[index].setKey(trg);
1214                    }
1215            }
1216            
1217            public synchronized void rename(Collection.Key columnName,Collection.Key newColumnName) throws ExpressionException {
1218                    int index=getIndexFromKey(columnName);
1219                    if(index==-1) throw new ExpressionException("invalid column name definitions");
1220                    columnNames[index]=newColumnName;
1221                    columns[index].setKey(newColumnName);
1222            }
1223            
1224    
1225            @Override
1226            public QueryColumn getColumn(String key, QueryColumn defaultValue) {
1227                    return getColumn(KeyImpl.init(key.trim()),defaultValue);
1228            }
1229    
1230            @Override
1231            public QueryColumn getColumn(Collection.Key key, QueryColumn defaultValue) {
1232            int index=getIndexFromKey(key);
1233                    if(index!=-1) return columns[index];
1234            if(key.length()>0) {
1235                    char c=key.lowerCharAt(0);
1236                    if(c=='r') {
1237                        if(key.equals(KeyConstants._RECORDCOUNT)) return new QueryColumnRef(this,key,Types.INTEGER);
1238                    }
1239                    if(c=='c') {
1240                        if(key.equals(KeyConstants._CURRENTROW)) return new QueryColumnRef(this,key,Types.INTEGER);
1241                        else if(key.equals(KeyConstants._COLUMNLIST)) return new QueryColumnRef(this,key,Types.INTEGER);
1242                    }
1243            }
1244            return defaultValue;
1245            }
1246            
1247            @Override
1248            public String toString() {
1249                    Collection.Key[] keys=keys();
1250                    
1251                    StringBuffer sb=new StringBuffer();
1252    
1253                    sb.append("Query\n");
1254                    sb.append("---------------------------------------------------\n");
1255                    
1256                    if(sql!=null) {
1257                            sb.append(sql+"\n");
1258                            sb.append("---------------------------------------------------\n");
1259                    }
1260    
1261                    if(exeTime>0)        {
1262                            sb.append("Execution Time (ns): "+exeTime+"\n");
1263                            sb.append("---------------------------------------------------\n");
1264                    }
1265                    
1266                    sb.append("Recordcount: "+getRecordcount()+"\n");
1267                    sb.append("---------------------------------------------------\n");
1268                    String trenner="";
1269                    for(int i=0;i<keys.length;i++) {
1270                            trenner+="+---------------------";
1271                    }
1272                    trenner+="+\n";
1273                    sb.append(trenner);
1274            
1275            // Header
1276                    for(int i=0;i<keys.length;i++) {
1277                            sb.append(getToStringField(keys[i].getString()));
1278                    }
1279                    sb.append("|\n");
1280                    sb.append(trenner);
1281                    sb.append(trenner);
1282                    
1283            // body
1284                    for(int i=0;i<recordcount;i++) {
1285                            for(int y=0;y<keys.length;y++) {
1286                                    try {
1287                                            Object o=getAt(keys[y],i+1);
1288                                            if(o instanceof String)sb.append(getToStringField(o.toString()));
1289                                            else if(o instanceof Number) sb.append(getToStringField(Caster.toString(((Number)o).doubleValue())));
1290                                            else if(o instanceof Clob) sb.append(getToStringField(Caster.toString(o)));                                                     
1291                                            else sb.append(getToStringField(o.toString()));
1292                                    } catch (PageException e) {
1293                                            sb.append(getToStringField("[empty]"));
1294                                    }
1295                            }
1296                            sb.append("|\n");
1297                            sb.append(trenner);
1298                    }
1299                    return sb.toString();
1300            }
1301    
1302            private String getToStringField(String str) {
1303                    if(str==null) return "|                    ";
1304                    else if(str.length()<21) {
1305                            String s="|"+str;
1306                            for(int i=str.length();i<21;i++)s+=" ";
1307                            return s;
1308                    }
1309                    else if(str.length()==21) return "|"+str;
1310                    else  return "|"+str.substring(0,18)+"...";
1311            }
1312            
1313            /**
1314             * 
1315             * @param type
1316             * @return return String represetation of a Type from int type
1317             */
1318            public static String getColumTypeName(int type) {
1319                    switch(type) {
1320                            case Types.ARRAY: return "OBJECT";
1321                            case Types.BIGINT: return "BIGINT";
1322                            case Types.BINARY: return "BINARY";
1323                            case Types.BIT: return "BIT";
1324                            case Types.BLOB: return "OBJECT";
1325                            case Types.BOOLEAN: return "BOOLEAN";
1326                            case Types.CHAR: return "CHAR";
1327                            case Types.NCHAR: return "NCHAR";
1328                            case Types.CLOB: return "OBJECT";
1329                            case Types.NCLOB: return "OBJECT";
1330                            case Types.DATALINK: return "OBJECT";
1331                            case Types.DATE: return "DATE";
1332                            case Types.DECIMAL: return "DECIMAL";
1333                            case Types.DISTINCT: return "OBJECT";
1334                            case Types.DOUBLE: return "DOUBLE";
1335                            case Types.FLOAT: return "DOUBLE";
1336                            case Types.INTEGER: return "INTEGER";
1337                            case Types.JAVA_OBJECT: return "OBJECT";
1338                            case Types.LONGVARBINARY: return "LONGVARBINARY";
1339                            case Types.LONGVARCHAR: return "LONGVARCHAR";
1340                            case Types.NULL: return "OBJECT";
1341                            case Types.NUMERIC: return "NUMERIC";
1342                            case Types.OTHER: return "OBJECT";
1343                            case Types.REAL: return "REAL";
1344                            case Types.REF: return "OBJECT";
1345                            case Types.SMALLINT: return "SMALLINT";
1346                            case Types.STRUCT: return "OBJECT";
1347                            case Types.TIME: return "TIME";
1348                            case Types.TIMESTAMP: return "TIMESTAMP";
1349                            case Types.TINYINT: return "TINYINT";
1350                            case Types.VARBINARY: return "VARBINARY";
1351                            case Types.NVARCHAR: return "NVARCHAR";
1352                            case Types.SQLXML: return "SQLXML";
1353                            case Types.VARCHAR: return "VARCHAR";
1354                            default : return "VARCHAR";
1355                    }
1356            }
1357    
1358            private int getIndexFromKey(String key) {
1359                    String lc = StringUtil.toLowerCase(key);
1360                    for(int i=0;i<columnNames.length;i++) {
1361                            if(columnNames[i].getLowerString().equals(lc)) return i;
1362                    }
1363                    return -1;
1364            }
1365            
1366            private int getIndexFromKey(Collection.Key key) {
1367                    
1368                    for(int i=0;i<columnNames.length;i++) {
1369                            if(columnNames[i].equalsIgnoreCase(key)) return i;
1370                    }
1371                    return -1;
1372            }
1373            
1374            @Override
1375            public void setExecutionTime(long exeTime) {
1376                    this.exeTime=exeTime;
1377            }
1378    
1379        /**
1380         * @param maxrows
1381         * @return has cutted or not
1382         */
1383        public synchronized boolean cutRowsTo(int maxrows) {
1384            //disconnectCache();
1385            
1386            if(maxrows>-1 && maxrows<getRecordcount()) {
1387                             for(int i=0;i<columns.length;i++) {
1388                                    QueryColumn column = columns[i];
1389                                    column.cutRowsTo(maxrows);
1390                             }
1391                             recordcount=maxrows;
1392                             return true;
1393            }
1394            return false;
1395        }
1396    
1397        @Override
1398        public void setCached(boolean isCached) {
1399            this.isCached=isCached; 
1400        }
1401    
1402        @Override
1403        public boolean isCached() {
1404            return isCached;
1405        }
1406    
1407    
1408    
1409        @Override
1410        public int addRow() {
1411                    addRow(1);
1412                    return getRecordcount();
1413        }
1414    
1415    
1416        public Key getColumnName(int columnIndex) {
1417            Key[] keys = keys();
1418                    if(columnIndex<1 || columnIndex>keys.length) return null;
1419                    return keys[columnIndex-1];
1420        }
1421    
1422        @Override
1423        public int getColumnIndex(String coulmnName) {
1424            Collection.Key[] keys = keys();
1425                    for(int i=0;i<keys.length;i++) {
1426                            if(keys[i].getString().equalsIgnoreCase(coulmnName)) return i+1;
1427                    }
1428                    return -1;
1429        }
1430    
1431    
1432    
1433        @Override
1434        public String[] getColumns() {
1435            return getColumnNamesAsString();
1436        }
1437        
1438        @Override
1439        public Collection.Key[] getColumnNames() {
1440            Collection.Key[] keys = keys();
1441            Collection.Key[] rtn=new Collection.Key[keys.length];
1442                    System.arraycopy(keys,0,rtn,0,keys.length);
1443                    return rtn;
1444        }
1445        
1446        public void setColumnNames(Collection.Key[] trg) throws PageException {
1447            columncount=trg.length;
1448            Collection.Key[] src = keys();
1449            
1450            // target < source
1451            if(trg.length<src.length){
1452                    this.columnNames=new Collection.Key[trg.length];
1453                    QueryColumnImpl[] tmp=new QueryColumnImpl[trg.length];
1454                    for(int i=0;i<trg.length;i++){
1455                            this.columnNames[i]=trg[i];
1456                            tmp[i]=this.columns[i];
1457                            tmp[i].setKey(trg[i]);
1458                    }
1459                    this.columns=tmp;
1460                    return;
1461            }
1462            
1463            if(trg.length>src.length){
1464                    int recordcount=getRecordcount();
1465                    for(int i=src.length;i<trg.length;i++){
1466                            
1467                            Array arr=new ArrayImpl();
1468                            for(int r=1;r<=recordcount;r++){
1469                                    arr.setE(i,"");
1470                            }
1471                            addColumn(trg[i], arr);
1472                    }
1473                    src = keys();
1474            }
1475            
1476                    for(int i=0;i<trg.length;i++){
1477                            this.columnNames[i]=trg[i];
1478                            this.columns[i].setKey(trg[i]);
1479            }
1480        }
1481        
1482    
1483    
1484            @Override
1485            public String[] getColumnNamesAsString() {
1486                    return CollectionUtil.keysAsString(this);
1487            }
1488            
1489            public int getColumnCount() {
1490                    return columncount;
1491            }
1492    
1493        @Override
1494        public String getData(int row, int col) throws IndexOutOfBoundsException {
1495            Collection.Key[] keys = keys();
1496                    if(col<1 || col>keys.length) {
1497                            new IndexOutOfBoundsException("invalid column index to retrieve Data from query, valid index goes from 1 to "+keys.length);
1498                    }
1499                    
1500                    Object o=getAt(keys[col-1],row,NullSupportHelper.NULL());
1501                    if(o==NullSupportHelper.NULL())
1502                            throw new IndexOutOfBoundsException("invalid row index to retrieve Data from query, valid index goes from 1 to "+getRecordcount());
1503                    return Caster.toString( o,NullSupportHelper.full()?null:"");
1504        }
1505    
1506    
1507    
1508        @Override
1509        public String getName() {
1510            return this.name;
1511        }
1512    
1513    
1514    
1515        @Override
1516        public int getRowCount() {
1517            return getRecordcount();
1518        }
1519    
1520    
1521    
1522        @Override
1523        public void setData(int row, int col, String value) throws IndexOutOfBoundsException {
1524            Collection.Key[] keys = keys();
1525                    if(col<1 || col>keys.length) {
1526                            new IndexOutOfBoundsException("invalid column index to retrieve Data from query, valid index goes from 1 to "+keys.length);
1527                    }
1528                    try {
1529                            setAt(keys[col-1],row,value);
1530                    } 
1531                    catch (PageException e) {
1532                            throw new IndexOutOfBoundsException("invalid row index to retrieve Data from query, valid index goes from 1 to "+getRecordcount());
1533                    }
1534        }
1535    
1536        @Override
1537        public boolean containsKey(String key) {
1538            return getColumn(key,null)!=null;
1539        }   
1540    
1541            @Override
1542            public boolean containsKey(Collection.Key key) {
1543            return getColumn(key,null)!=null;
1544            }
1545            
1546        @Override
1547        public String castToString() throws ExpressionException {
1548            throw new ExpressionException("Can't cast Complex Object Type Query to String",
1549              "Use Built-In-Function \"serialize(Query):String\" to create a String from Query");
1550        }
1551    
1552            @Override
1553            public String castToString(String defaultValue) {
1554                    return defaultValue;
1555            }
1556    
1557    
1558        @Override
1559        public boolean castToBooleanValue() throws ExpressionException {
1560            throw new ExpressionException("Can't cast Complex Object Type Query to a boolean value");
1561        }
1562        
1563        @Override
1564        public Boolean castToBoolean(Boolean defaultValue) {
1565            return defaultValue;
1566        }
1567    
1568    
1569        @Override
1570        public double castToDoubleValue() throws ExpressionException {
1571            throw new ExpressionException("Can't cast Complex Object Type Query to a number value");
1572        }
1573        
1574        @Override
1575        public double castToDoubleValue(double defaultValue) {
1576            return defaultValue;
1577        }
1578    
1579    
1580        @Override
1581        public DateTime castToDateTime() throws ExpressionException {
1582            throw new ExpressionException("Can't cast Complex Object Type Query to a Date");
1583        }
1584        
1585        @Override
1586        public DateTime castToDateTime(DateTime defaultValue) {
1587            return defaultValue;
1588        }
1589    
1590            @Override
1591            public int compareTo(boolean b) throws ExpressionException {
1592                    throw new ExpressionException("can't compare Complex Object Type Query with a boolean value");
1593            }
1594    
1595            @Override
1596            public int compareTo(DateTime dt) throws PageException {
1597                    throw new ExpressionException("can't compare Complex Object Type Query with a DateTime Object");
1598            }
1599    
1600            @Override
1601            public int compareTo(double d) throws PageException {
1602                    throw new ExpressionException("can't compare Complex Object Type Query with a numeric value");
1603            }
1604    
1605            @Override
1606            public int compareTo(String str) throws PageException {
1607                    throw new ExpressionException("can't compare Complex Object Type Query with a String");
1608            }
1609    
1610        public synchronized Array getMetaDataSimple() {
1611            Array cols=new ArrayImpl();
1612            Struct column;
1613            for(int i=0;i<columns.length;i++) {
1614                    column=new StructImpl();
1615                    column.setEL(KeyConstants._name,columnNames[i].getString());
1616                    column.setEL("isCaseSensitive",Boolean.FALSE);
1617                    column.setEL("typeName",columns[i].getTypeAsString());
1618                    cols.appendEL(column);
1619            }
1620            return cols;
1621        }
1622    
1623        /*public synchronized Struct _getMetaData() {
1624            
1625            Struct cols=new StructImpl();
1626            for(int i=0;i<columns.length;i++) {
1627                cols.setEL(columnNames[i],columns[i].getTypeAsString());
1628            }
1629            
1630            Struct sct=new StructImpl();
1631            sct.setEL(KeyConstants._NAME,getName());
1632            sct.setEL(KeyConstants._COLUMNS,cols);
1633            sct.setEL(KeyConstants._SQL,sql==null?"":sql.toString());
1634            sct.setEL(KeyConstants._executionTime,new Double(exeTime));
1635            sct.setEL(KeyConstants._RECORDCOUNT,new Double(getRowCount()));
1636            sct.setEL(KeyConstants._cached,Caster.toBoolean(isCached()));
1637            return sct;
1638            
1639        }*/
1640    
1641            /**
1642             * @return the sql
1643             */
1644            public SQL getSql() {
1645                    return sql;
1646            }
1647    
1648            /**
1649             * @param sql the sql to set
1650             */
1651            public void setSql(SQL sql) {
1652                    this.sql = sql;
1653            }
1654    
1655    
1656            @Override
1657            public Object getObject(String columnName) throws SQLException {
1658                    int currentrow;
1659                    if((currentrow=arrCurrentRow.get(getPid(),0))==0) return null;
1660                    return getAt(columnName,currentrow,null);
1661            }
1662            
1663            @Override
1664            public Object getObject(int columnIndex) throws SQLException {
1665                    if(columnIndex>0 && columnIndex<=columncount) return  getObject(this.columnNames[columnIndex-1].getString());
1666                    return null;
1667            }
1668            
1669            @Override
1670            public String getString(int columnIndex) throws SQLException {
1671                    Object rtn = getObject(columnIndex);
1672                    if(rtn==null)return null;
1673                    if(Decision.isCastableToString(rtn)) return Caster.toString(rtn,null);
1674                    throw new SQLException("can't cast value to string");
1675            }
1676            
1677            @Override
1678            public String getString(String columnName) throws SQLException {
1679                    Object rtn = getObject(columnName);
1680                    if(rtn==null)return null;
1681                    if(Decision.isCastableToString(rtn)) return Caster.toString(rtn,null);
1682                    throw new SQLException("can't cast value to string");
1683            }
1684            
1685            @Override
1686            public boolean getBoolean(int columnIndex) throws SQLException {
1687                    Object rtn = getObject(columnIndex);
1688                    if(rtn==null)return false;
1689                    if(Decision.isCastableToBoolean(rtn)) return Caster.toBooleanValue(rtn,false);
1690                    throw new SQLException("can't cast value to boolean");
1691            }
1692            
1693            @Override
1694            public boolean getBoolean(String columnName) throws SQLException {
1695                    Object rtn = getObject(columnName);
1696                    if(rtn==null)return false;
1697                    if(Decision.isCastableToBoolean(rtn)) return Caster.toBooleanValue(rtn,false);
1698                    throw new SQLException("can't cast value to boolean");
1699            }
1700            
1701            
1702            // ---------------------------------------
1703    
1704            @Override
1705            public Object call(PageContext pc, Key methodName, Object[] arguments) throws PageException {
1706                    return MemberUtil.call(pc, this, methodName, arguments, railo.commons.lang.CFTypes.TYPE_QUERY, "query");
1707                    //return Reflector.callMethod(this,methodName,arguments);
1708            }
1709    
1710            @Override
1711            public Object callWithNamedValues(PageContext pc, Key methodName, Struct args) throws PageException {   
1712                    return MemberUtil.callWithNamedValues(pc, this, methodName, args,railo.commons.lang.CFTypes.TYPE_QUERY, "query");
1713            }
1714    
1715            @Override
1716            public Object get(PageContext pc, Key key, Object defaultValue) {
1717                    return getAt(key,arrCurrentRow.get(
1718                                    pc.getId(),1),defaultValue);
1719            }
1720    
1721            @Override
1722            public Object get(PageContext pc, Key key) throws PageException {
1723                    return getAt(key,arrCurrentRow.get(pc.getId(),1));
1724            }
1725    
1726            public boolean isInitalized() {
1727                    return true;
1728            }
1729    
1730            @Override
1731            public Object set(PageContext pc, Key propertyName, Object value) throws PageException {
1732                    return setAt(propertyName,arrCurrentRow.get(pc.getId(),1),value);
1733            }
1734    
1735            @Override
1736            public Object setEL(PageContext pc, Key propertyName, Object value) {
1737                    return setAtEL(propertyName,arrCurrentRow.get(pc.getId(),1),value);
1738            }
1739            
1740            @Override
1741            public boolean wasNull() {
1742                    throw new PageRuntimeException(new ApplicationException("method [wasNull] is not supported"));
1743            }
1744    
1745            @Override
1746            public boolean absolute(int row) throws SQLException {
1747                    if(recordcount==0) {
1748                            if(row!=0) throw new SQLException("invalid row ["+row+"], query is Empty");
1749                            return false;
1750                    }
1751                    //row=row%recordcount;
1752                    
1753                    if(row>0) arrCurrentRow.set(getPid(),row);
1754                    else arrCurrentRow.set(getPid(),(recordcount+1)+row);
1755                    return true;
1756            }
1757    
1758            @Override
1759            public void afterLast() throws SQLException {
1760                    arrCurrentRow.set(getPid(),recordcount+1);
1761            }
1762    
1763            @Override
1764            public void beforeFirst() throws SQLException {
1765                    arrCurrentRow.set(getPid(),0);
1766            }
1767    
1768            @Override
1769            public void cancelRowUpdates() throws SQLException {
1770                    // ignored
1771            }
1772    
1773            @Override
1774            public void clearWarnings() throws SQLException {
1775                    // ignored
1776            }
1777    
1778            @Override
1779            public void close() throws SQLException {
1780                    // ignored
1781            }
1782    
1783            @Override
1784            public void deleteRow() throws SQLException {
1785                    try {
1786                            removeRow(arrCurrentRow.get(getPid()));
1787                    } catch (Exception e) {
1788                            throw new SQLException(e.getMessage());
1789                    }
1790            }
1791    
1792            @Override
1793            public int findColumn(String columnName) throws SQLException {
1794                    int index= getColumnIndex(columnName);
1795                    if(index==-1) throw new SQLException("invald column definitions ["+columnName+"]");
1796                    return index;
1797            }
1798    
1799            @Override
1800            public boolean first() throws SQLException {
1801                    return absolute(1);
1802            }
1803    
1804            public java.sql.Array getArray(int i) throws SQLException {
1805                    throw new SQLException("method is not implemented");
1806            }
1807    
1808            public java.sql.Array getArray(String colName) throws SQLException {
1809                    throw new SQLException("method is not implemented");
1810            }
1811    
1812            @Override
1813            public InputStream getAsciiStream(int columnIndex) throws SQLException {
1814                    String res = getString(columnIndex);
1815                    if(res==null)return null;
1816                    return new ByteArrayInputStream(res.getBytes());
1817            }
1818    
1819            @Override
1820            public InputStream getAsciiStream(String columnName) throws SQLException {
1821                    String res = getString(columnName);
1822                    if(res==null)return null;
1823                    return new ByteArrayInputStream(res.getBytes());
1824            }
1825    
1826            @Override
1827            public BigDecimal getBigDecimal(int columnIndex) throws SQLException {
1828                    return new BigDecimal(getDouble(columnIndex));
1829            }
1830    
1831            @Override
1832            public BigDecimal getBigDecimal(String columnName) throws SQLException {
1833                    return new BigDecimal(getDouble(columnName));
1834            }
1835    
1836            @Override
1837            public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException {
1838                    return new BigDecimal(getDouble(columnIndex));
1839            }
1840    
1841            @Override
1842            public BigDecimal getBigDecimal(String columnName, int scale) throws SQLException {
1843                    return new BigDecimal(getDouble(columnName));
1844            }
1845    
1846            @Override
1847            public InputStream getBinaryStream(int columnIndex) throws SQLException {
1848                    Object obj = getObject(columnIndex);
1849                    if(obj==null)return null;
1850                    try {
1851                            return Caster.toInputStream(obj);
1852                    } catch (Exception e) {
1853                            throw new SQLException(e.getMessage());
1854                    }
1855            }
1856    
1857            @Override
1858            public InputStream getBinaryStream(String columnName) throws SQLException {
1859                    Object obj = getObject(columnName);
1860                    if(obj==null)return null;
1861                    try {
1862                            return Caster.toInputStream(obj);
1863                    } catch (Exception e) {
1864                            throw new SQLException(e.getMessage());
1865                    }
1866            }
1867    
1868            @Override
1869            public Blob getBlob(int i) throws SQLException {
1870                    byte[] bytes = getBytes(i);
1871                    if(bytes==null) return null;
1872                    try {
1873                            return BlobImpl.toBlob(bytes);
1874                    } 
1875                    catch (PageException e) {
1876                            throw new SQLException(e.getMessage());
1877                    }
1878            }
1879    
1880            @Override
1881            public Blob getBlob(String colName) throws SQLException {
1882                    byte[] bytes = getBytes(colName);
1883                    if(bytes==null) return null;
1884                    try {
1885                            return BlobImpl.toBlob(bytes);
1886                    } catch (PageException e) {
1887                            throw new SQLException(e.getMessage());
1888                    }
1889            }
1890    
1891            @Override
1892            public byte getByte(int columnIndex) throws SQLException {
1893                    Object obj = getObject(columnIndex);
1894                    if(obj==null) return (byte)0;
1895                    try {
1896                            return Caster.toByteValue(obj);
1897                    } catch (PageException e) {
1898                            throw new SQLException(e.getMessage());
1899                    }
1900            }
1901    
1902            @Override
1903            public byte getByte(String columnName) throws SQLException {
1904                    Object obj = getObject(columnName);
1905                    if(obj==null) return (byte)0;
1906                    try {
1907                            return Caster.toByteValue(obj);
1908                    } catch (PageException e) {
1909                            throw new SQLException(e.getMessage());
1910                    }
1911            }
1912    
1913            @Override
1914            public byte[] getBytes(int columnIndex) throws SQLException {
1915                    Object obj = getObject(columnIndex);
1916                    if(obj==null) return null;
1917                    try {
1918                            return Caster.toBytes(obj);
1919                    } catch (Exception e) {
1920                            throw new SQLException(e.getMessage());
1921                    }
1922            }
1923    
1924            @Override
1925            public byte[] getBytes(String columnName) throws SQLException {
1926                    Object obj = getObject(columnName);
1927                    if(obj==null) return null;
1928                    try {
1929                            return Caster.toBytes(obj);
1930                    } catch (Exception e) {
1931                            throw new SQLException(e.getMessage());
1932                    }
1933            }
1934    
1935            @Override
1936            public Reader getCharacterStream(int columnIndex) throws SQLException {
1937                    String str=getString(columnIndex);
1938                    if(str==null) return null;
1939                    return new StringReader(str);
1940            }
1941    
1942            @Override
1943            public Reader getCharacterStream(String columnName) throws SQLException {
1944                    String str=getString(columnName);
1945                    if(str==null) return null;
1946                    return new StringReader(str);
1947            }
1948    
1949            @Override
1950            public Clob getClob(int i) throws SQLException {
1951                    String str=getString(i);
1952                    if(str==null) return null;
1953                    return ClobImpl.toClob(str);
1954            }
1955    
1956            @Override
1957            public Clob getClob(String colName) throws SQLException {
1958                    String str=getString(colName);
1959                    if(str==null) return null;
1960                    return ClobImpl.toClob(str);
1961            }
1962    
1963            @Override
1964            public int getConcurrency() throws SQLException {
1965                    return 0;
1966            }
1967    
1968            @Override
1969            public String getCursorName() throws SQLException {
1970                    return null;
1971            }
1972    
1973            @Override
1974            public java.sql.Date getDate(int columnIndex) throws SQLException {
1975                    Object obj=getObject(columnIndex);
1976                    if(obj==null) return null;
1977                    try {
1978                            return new java.sql.Date(Caster.toDate(obj, false, null).getTime());
1979                    } catch (PageException e) {
1980                            throw new SQLException(e.getMessage());
1981                    }
1982            }
1983    
1984            @Override
1985            public java.sql.Date getDate(String columnName) throws SQLException {
1986                    Object obj=getObject(columnName);
1987                    if(obj==null) return null;
1988                    try {
1989                            return new java.sql.Date(Caster.toDate(obj, false, null).getTime());
1990                    } catch (PageException e) {
1991                            throw new SQLException(e.getMessage());
1992                    }
1993            }
1994    
1995            @Override
1996            public java.sql.Date getDate(int columnIndex, Calendar cal)throws SQLException {
1997                    return getDate(columnIndex); // TODO impl
1998            }
1999    
2000            @Override
2001            public java.sql.Date getDate(String columnName, Calendar cal) throws SQLException {
2002                    return getDate(columnName);// TODO impl
2003            }
2004    
2005            @Override
2006            public double getDouble(int columnIndex) throws SQLException {
2007                    Object obj=getObject(columnIndex);
2008                    if(obj==null) return 0;
2009                    try {
2010                            return Caster.toDoubleValue(obj);
2011                    } catch (PageException e) {
2012                            throw new SQLException(e.getMessage());
2013                    }
2014            }
2015    
2016            @Override
2017            public double getDouble(String columnName) throws SQLException {
2018                    Object obj=getObject(columnName);
2019                    if(obj==null) return 0;
2020                    try {
2021                            return Caster.toDoubleValue(obj);
2022                    } catch (PageException e) {
2023                            throw new SQLException(e.getMessage());
2024                    }
2025            }
2026    
2027            @Override
2028            public int getFetchDirection() throws SQLException {
2029                    return 1000;
2030            }
2031    
2032            @Override
2033            public int getFetchSize() throws SQLException {
2034                    return 0;
2035            }
2036    
2037            @Override
2038            public float getFloat(int columnIndex) throws SQLException {
2039                    Object obj=getObject(columnIndex);
2040                    if(obj==null) return 0;
2041                    try {
2042                            return Caster.toFloatValue(obj);
2043                    } catch (PageException e) {
2044                            throw new SQLException(e.getMessage());
2045                    }
2046            }
2047    
2048            @Override
2049            public float getFloat(String columnName) throws SQLException {
2050                    Object obj=getObject(columnName);
2051                    if(obj==null) return 0;
2052                    try {
2053                            return Caster.toFloatValue(obj);
2054                    } catch (PageException e) {
2055                            throw new SQLException(e.getMessage());
2056                    }
2057            }
2058    
2059            @Override
2060            public int getInt(int columnIndex) throws SQLException {
2061                    Object obj=getObject(columnIndex);
2062                    if(obj==null) return 0;
2063                    try {
2064                            return Caster.toIntValue(obj);
2065                    } catch (PageException e) {
2066                            throw new SQLException(e.getMessage());
2067                    }
2068            }
2069    
2070            @Override
2071            public int getInt(String columnName) throws SQLException {
2072                    Object obj=getObject(columnName);
2073                    if(obj==null) return 0;
2074                    try {
2075                            return Caster.toIntValue(obj);
2076                    } catch (PageException e) {
2077                            throw new SQLException(e.getMessage());
2078                    }
2079            }
2080    
2081            @Override
2082            public long getLong(int columnIndex) throws SQLException {
2083                    Object obj=getObject(columnIndex);
2084                    if(obj==null) return 0;
2085                    try {
2086                            return Caster.toLongValue(obj);
2087                    } catch (PageException e) {
2088                            throw new SQLException(e.getMessage());
2089                    }
2090            }
2091    
2092            @Override
2093            public long getLong(String columnName) throws SQLException {
2094                    Object obj=getObject(columnName);
2095                    if(obj==null) return 0;
2096                    try {
2097                            return Caster.toLongValue(obj);
2098                    } catch (PageException e) {
2099                            throw new SQLException(e.getMessage());
2100                    }
2101            }
2102    
2103            @Override
2104            public Object getObject(int i, Map map) throws SQLException {
2105                    throw new SQLException("method is not implemented");
2106            }
2107    
2108            @Override
2109            public Object getObject(String colName, Map map) throws SQLException {
2110                    throw new SQLException("method is not implemented");
2111            }
2112    
2113            // used only with java 7, do not set @Override
2114            public <T> T getObject(int columnIndex, Class<T> type) throws SQLException {
2115                    return (T) QueryUtil.getObject(this,columnIndex, type);
2116            }
2117    
2118            // used only with java 7, do not set @Override
2119            public <T> T getObject(String columnLabel, Class<T> type) throws SQLException {
2120                    return (T) QueryUtil.getObject(this,columnLabel, type);
2121            }
2122    
2123            @Override
2124            public Ref getRef(int i) throws SQLException {
2125                    throw new SQLException("method is not implemented");
2126            }
2127    
2128            @Override
2129            public Ref getRef(String colName) throws SQLException {
2130                    throw new SQLException("method is not implemented");
2131            }
2132    
2133            @Override
2134            public int getRow() throws SQLException {
2135                    return arrCurrentRow.get(getPid(),0);
2136            }
2137    
2138            @Override
2139            public short getShort(int columnIndex) throws SQLException {
2140                    Object obj=getObject(columnIndex);
2141                    if(obj==null) return 0;
2142                    try {
2143                            return Caster.toShortValue(obj);
2144                    } catch (PageException e) {
2145                            throw new SQLException(e.getMessage());
2146                    }
2147            }
2148    
2149            @Override
2150            public short getShort(String columnName) throws SQLException {
2151                    Object obj=getObject(columnName);
2152                    if(obj==null) return 0;
2153                    try {
2154                            return Caster.toShortValue(obj);
2155                    } catch (PageException e) {
2156                            throw new SQLException(e.getMessage());
2157                    }
2158            }
2159    
2160            public Statement getStatement() throws SQLException {
2161                    throw new SQLException("method is not implemented");
2162            }
2163    
2164            @Override
2165            public Time getTime(int columnIndex) throws SQLException {
2166                    Object obj=getObject(columnIndex);
2167                    if(obj==null) return null;
2168                    try {
2169                            return new Time(DateCaster.toTime(null, obj).getTime());
2170                    } catch (PageException e) {
2171                            throw new SQLException(e.getMessage());
2172                    }
2173            }
2174    
2175            @Override
2176            public Time getTime(String columnName) throws SQLException {
2177                    Object obj=getObject(columnName);
2178                    if(obj==null) return null;
2179                    try {
2180                            return new Time(DateCaster.toTime(null, obj).getTime());
2181                    } catch (PageException e) {
2182                            throw new SQLException(e.getMessage());
2183                    }
2184            }
2185    
2186            @Override
2187            public Time getTime(int columnIndex, Calendar cal) throws SQLException {
2188                    return getTime(columnIndex);// TODO impl
2189            }
2190    
2191            @Override
2192            public Time getTime(String columnName, Calendar cal) throws SQLException {
2193                    return getTime(columnName);// TODO impl
2194            }
2195    
2196            @Override
2197            public Timestamp getTimestamp(int columnIndex) throws SQLException {
2198                    Object obj=getObject(columnIndex);
2199                    if(obj==null) return null;
2200                    try {
2201                            return new Timestamp(DateCaster.toTime(null, obj).getTime());
2202                    } catch (PageException e) {
2203                            throw new SQLException(e.getMessage());
2204                    }
2205            }
2206    
2207            @Override
2208            public Timestamp getTimestamp(String columnName) throws SQLException {
2209                    Object obj=getObject(columnName);
2210                    if(obj==null) return null;
2211                    try {
2212                            return new Timestamp(DateCaster.toTime(null, obj).getTime());
2213                    } catch (PageException e) {
2214                            throw new SQLException(e.getMessage());
2215                    }
2216            }
2217    
2218            @Override
2219            public Timestamp getTimestamp(int columnIndex, Calendar cal) throws SQLException {
2220                    return getTimestamp(columnIndex);// TODO impl
2221            }
2222    
2223            @Override
2224            public Timestamp getTimestamp(String columnName, Calendar cal) throws SQLException {
2225                    return getTimestamp(columnName);// TODO impl
2226            }
2227    
2228            @Override
2229            public int getType() throws SQLException {
2230                    return 0;
2231            }
2232    
2233            @Override
2234            public URL getURL(int columnIndex) throws SQLException {
2235                    throw new SQLException("method is not implemented");
2236            }
2237    
2238            @Override
2239            public URL getURL(String columnName) throws SQLException {
2240                    throw new SQLException("method is not implemented");
2241            }
2242    
2243            @Override
2244            public InputStream getUnicodeStream(int columnIndex) throws SQLException {
2245                    String str=getString(columnIndex);
2246                    if(str==null) return null;
2247                    try {
2248                            return new ByteArrayInputStream(str.getBytes("UTF-8"));
2249                    } 
2250                    catch (UnsupportedEncodingException e) {
2251                            throw new SQLException(e.getMessage());
2252                    }
2253            }
2254    
2255            @Override
2256            public InputStream getUnicodeStream(String columnName) throws SQLException {
2257                    String str=getString(columnName);
2258                    if(str==null) return null;
2259                    try {
2260                            return new ByteArrayInputStream(str.getBytes("UTF-8"));
2261                    } 
2262                    catch (UnsupportedEncodingException e) {
2263                            throw new SQLException(e.getMessage());
2264                    }
2265            }
2266    
2267            @Override
2268            public SQLWarning getWarnings() throws SQLException {
2269                    throw new SQLException("method is not implemented");
2270            }
2271    
2272            @Override
2273            public void insertRow() throws SQLException {
2274                    throw new SQLException("method is not implemented");
2275            }
2276    
2277            @Override
2278            public boolean isAfterLast() throws SQLException {
2279                    return getCurrentrow(ThreadLocalPageContext.get().getId())>recordcount;
2280            }
2281    
2282            @Override
2283            public boolean isBeforeFirst() throws SQLException {
2284                    return arrCurrentRow.get(getPid(),0)==0;
2285            }
2286    
2287            @Override
2288            public boolean isFirst() throws SQLException {
2289                    return arrCurrentRow.get(getPid(),0)==1;
2290            }
2291    
2292            public boolean isLast() throws SQLException {
2293                    return arrCurrentRow.get(getPid(),0)==recordcount;
2294            }
2295    
2296            public boolean last() throws SQLException {
2297                    return absolute(recordcount);
2298            }
2299    
2300            public void moveToCurrentRow() throws SQLException {
2301                    // ignore
2302            }
2303    
2304            public void moveToInsertRow() throws SQLException {
2305                    // ignore
2306            }
2307    
2308    
2309            public boolean previous() {
2310                    return previous(getPid());
2311            }
2312            
2313            public boolean previous(int pid) {
2314                    if(0<(arrCurrentRow.set(pid,arrCurrentRow.get(pid,0)-1))) {
2315                            return true;
2316                    }
2317                    arrCurrentRow.set(pid,0);
2318                    return false;
2319            }
2320    
2321            public void refreshRow() throws SQLException {
2322                    // ignore
2323                    
2324            }
2325    
2326            @Override
2327            public boolean relative(int rows) throws SQLException {
2328                    return absolute(getRow()+rows);
2329            }
2330    
2331            @Override
2332            public boolean rowDeleted() throws SQLException {
2333                    return false;
2334            }
2335    
2336            @Override
2337            public boolean rowInserted() throws SQLException {
2338                    return false;
2339            }
2340    
2341            @Override
2342            public boolean rowUpdated() throws SQLException {
2343                    return false;
2344            }
2345    
2346            public void setFetchDirection(int direction) throws SQLException {
2347                    // ignore
2348            }
2349    
2350            public void setFetchSize(int rows) throws SQLException {
2351                    // ignore
2352            }
2353    
2354            @Override
2355            public void updateArray(int columnIndex, java.sql.Array x)throws SQLException {
2356                    updateObject(columnIndex, x.getArray());
2357            }
2358    
2359            @Override
2360            public void updateArray(String columnName, java.sql.Array x)throws SQLException {
2361                    updateObject(columnName, x.getArray());
2362            }
2363    
2364            @Override
2365            public void updateAsciiStream(int columnIndex, InputStream x, int length)throws SQLException {
2366                    updateBinaryStream(columnIndex, x, length);
2367            }
2368    
2369            @Override
2370            public void updateAsciiStream(String columnName, InputStream x, int length)throws SQLException {
2371                    updateBinaryStream(columnName, x, length);
2372            }
2373    
2374            @Override
2375            public void updateBigDecimal(int columnIndex, BigDecimal x)throws SQLException {
2376                    updateObject(columnIndex, x.toString());
2377            }
2378    
2379            @Override
2380            public void updateBigDecimal(String columnName, BigDecimal x) throws SQLException {
2381                    updateObject(columnName, x.toString());
2382            }
2383    
2384            @Override
2385            public void updateBinaryStream(int columnIndex, InputStream x, int length) throws SQLException {
2386                    try {
2387                            updateObject(columnIndex, IOUtil.toBytesMax(x, length));
2388                    } catch (IOException e) {
2389                            throw new SQLException(e.getMessage());
2390                    }
2391            }
2392    
2393            @Override
2394            public void updateBinaryStream(String columnName, InputStream x, int length) throws SQLException {
2395                    try {
2396                            updateObject(columnName, IOUtil.toBytesMax(x, length));
2397                    } catch (IOException e) {
2398                            throw new SQLException(e.getMessage());
2399                    }
2400            }
2401    
2402            @Override
2403            public void updateBlob(int columnIndex, Blob x) throws SQLException {
2404                    try {
2405                            updateObject(columnIndex, toBytes(x));
2406                    } catch (IOException e) {
2407                            throw new SQLException(e.getMessage());
2408                    }
2409            }
2410    
2411            @Override
2412            public void updateBlob(String columnName, Blob x) throws SQLException {
2413                    try {
2414                            updateObject(columnName, toBytes(x));
2415                    } catch (IOException e) {
2416                            throw new SQLException(e.getMessage());
2417                    }
2418            }
2419    
2420            @Override
2421            public void updateBoolean(int columnIndex, boolean x) throws SQLException {
2422                    updateObject(columnIndex, Caster.toBoolean(x));
2423            }
2424    
2425            @Override
2426            public void updateBoolean(String columnName, boolean x) throws SQLException {
2427                    updateObject(columnName, Caster.toBoolean(x));
2428            }
2429    
2430            @Override
2431            public void updateByte(int columnIndex, byte x) throws SQLException {
2432                    updateObject(columnIndex, new Byte(x));
2433            }
2434    
2435            @Override
2436            public void updateByte(String columnName, byte x) throws SQLException {
2437                    updateObject(columnName, new Byte(x));
2438            }
2439    
2440            @Override
2441            public void updateBytes(int columnIndex, byte[] x) throws SQLException {
2442                    updateObject(columnIndex, x);
2443            }
2444    
2445            @Override
2446            public void updateBytes(String columnName, byte[] x) throws SQLException {
2447                    updateObject(columnName, x);
2448            }
2449    
2450            @Override
2451            public void updateCharacterStream(int columnIndex, Reader reader, int length)throws SQLException {
2452                    try {
2453                            updateObject(columnIndex, IOUtil.toString(reader));
2454                    } catch (Exception e) {
2455                            throw new SQLException(e.getMessage());
2456                    }
2457            }
2458    
2459            @Override
2460            public void updateCharacterStream(String columnName, Reader reader,int length) throws SQLException {
2461                    try {
2462                            updateObject(columnName, IOUtil.toString(reader));
2463                    } catch (Exception e) {
2464                            throw new SQLException(e.getMessage());
2465                    }
2466            }
2467    
2468            @Override
2469            public void updateClob(int columnIndex, Clob x) throws SQLException {
2470                    try {
2471                            updateObject(columnIndex, toString(x));
2472                    } catch (IOException e) {
2473                            throw new SQLException(e.getMessage());
2474                    }
2475            }
2476    
2477            @Override
2478            public void updateClob(String columnName, Clob x) throws SQLException {
2479                    try {
2480                            updateObject(columnName, toString(x));
2481                    } catch (IOException e) {
2482                            throw new SQLException(e.getMessage());
2483                    }
2484            }
2485    
2486            @Override
2487            public void updateDate(int columnIndex, java.sql.Date x)throws SQLException {
2488                    updateObject(columnIndex, Caster.toDate(x, false, null, null));
2489            }
2490    
2491            @Override
2492            public void updateDate(String columnName, java.sql.Date x)throws SQLException {
2493                    updateObject(columnName, Caster.toDate(x, false, null, null));
2494            }
2495    
2496            @Override
2497            public void updateDouble(int columnIndex, double x) throws SQLException {
2498                    updateObject(columnIndex, Caster.toDouble(x));
2499            }
2500    
2501            @Override
2502            public void updateDouble(String columnName, double x) throws SQLException {
2503                    updateObject(columnName, Caster.toDouble(x));
2504            }
2505    
2506            @Override
2507            public void updateFloat(int columnIndex, float x) throws SQLException {
2508                    updateObject(columnIndex, Caster.toDouble(x));
2509            }
2510    
2511            @Override
2512            public void updateFloat(String columnName, float x) throws SQLException {
2513                    updateObject(columnName, Caster.toDouble(x));
2514            }
2515    
2516            @Override
2517            public void updateInt(int columnIndex, int x) throws SQLException {
2518                    updateObject(columnIndex, Caster.toDouble(x));
2519            }
2520    
2521            @Override
2522            public void updateInt(String columnName, int x) throws SQLException {
2523                    updateObject(columnName, Caster.toDouble(x));
2524            }
2525    
2526            @Override
2527            public void updateLong(int columnIndex, long x) throws SQLException {
2528                    updateObject(columnIndex, Caster.toDouble(x));
2529            }
2530    
2531            @Override
2532            public void updateLong(String columnName, long x) throws SQLException {
2533                    updateObject(columnName, Caster.toDouble(x));
2534            }
2535    
2536            @Override
2537            public void updateNull(int columnIndex) throws SQLException {
2538                    updateObject(columnIndex, null);
2539            }
2540    
2541            @Override
2542            public void updateNull(String columnName) throws SQLException {
2543                    updateObject(columnName, null);
2544            }
2545    
2546            @Override
2547            public void updateObject(int columnIndex, Object x) throws SQLException {
2548                    try {
2549                            set(getColumnName(columnIndex), x);
2550                    } catch (PageException e) {
2551                            throw new SQLException(e.getMessage());
2552                    }
2553            }
2554    
2555            @Override
2556            public void updateObject(String columnName, Object x) throws SQLException {
2557                    try {
2558                            set(KeyImpl.init(columnName), x);
2559                    } catch (PageException e) {
2560                            throw new SQLException(e.getMessage());
2561                    }
2562            }
2563    
2564            @Override
2565            public void updateObject(int columnIndex, Object x, int scale)throws SQLException {
2566                    updateObject(columnIndex, x);
2567            }
2568    
2569            @Override
2570            public void updateObject(String columnName, Object x, int scale)throws SQLException {
2571                    updateObject(columnName, x);
2572            }
2573    
2574            @Override
2575            public void updateRef(int columnIndex, Ref x) throws SQLException {
2576                    updateObject(columnIndex, x.getObject());
2577            }
2578    
2579            @Override
2580            public void updateRef(String columnName, Ref x) throws SQLException {
2581                    updateObject(columnName, x.getObject());
2582            }
2583    
2584            public void updateRow() throws SQLException {
2585                    throw new SQLException("method is not implemented");
2586            }
2587    
2588            @Override
2589            public void updateShort(int columnIndex, short x) throws SQLException {
2590                    updateObject(columnIndex, Caster.toDouble(x));
2591            }
2592    
2593            @Override
2594            public void updateShort(String columnName, short x) throws SQLException {
2595                    updateObject(columnName, Caster.toDouble(x));
2596            }
2597    
2598            @Override
2599            public void updateString(int columnIndex, String x) throws SQLException {
2600                    updateObject(columnIndex, x);
2601            }
2602    
2603            @Override
2604            public void updateString(String columnName, String x) throws SQLException {
2605                    updateObject(columnName, x);
2606            }
2607    
2608            @Override
2609            public void updateTime(int columnIndex, Time x) throws SQLException {
2610                    updateObject(columnIndex, new DateTimeImpl(x.getTime(),false));
2611            }
2612    
2613            @Override
2614            public void updateTime(String columnName, Time x) throws SQLException {
2615                    updateObject(columnName, new DateTimeImpl(x.getTime(),false));
2616            }
2617    
2618            @Override
2619            public void updateTimestamp(int columnIndex, Timestamp x) throws SQLException {
2620                    updateObject(columnIndex, new DateTimeImpl(x.getTime(),false));
2621            }
2622    
2623            @Override
2624            public void updateTimestamp(String columnName, Timestamp x) throws SQLException {
2625                    updateObject(columnName, new DateTimeImpl(x.getTime(),false));
2626            }
2627    
2628            @Override
2629            public ResultSetMetaData getMetaData() throws SQLException {
2630                    throw new SQLException("method is not implemented");
2631            }
2632    
2633            @Override
2634            public Iterator<Collection.Key> keyIterator() {
2635                    return new KeyIterator(keys());
2636            }
2637        
2638            @Override
2639            public Iterator<String> keysAsStringIterator() {
2640            return new StringIterator(keys());
2641        }
2642            
2643            @Override
2644            public Iterator<Entry<Key, Object>> entryIterator() {
2645                    return new EntryIterator(this, keys());
2646            }
2647            
2648            public Iterator<Object> valueIterator() {
2649                    return new CollectionIterator(keys(),this);
2650            }
2651    
2652            public void readExternal(ObjectInput in) throws IOException {
2653                    try {
2654                            QueryImpl other=(QueryImpl) new CFMLExpressionInterpreter().interpret(ThreadLocalPageContext.get(),in.readUTF());
2655                            this.arrCurrentRow=other.arrCurrentRow;
2656                            this.columncount=other.columncount;
2657                            this.columnNames=other.columnNames;
2658                            this.columns=other.columns;
2659                            this.exeTime=other.exeTime;
2660                            this.generatedKeys=other.generatedKeys;
2661                            this.isCached=other.isCached;
2662                            this.name=other.name;
2663                            this.recordcount=other.recordcount;
2664                            this.sql=other.sql;
2665                            this.updateCount=other.updateCount;
2666                            
2667                    } catch (PageException e) {
2668                            throw new IOException(e.getMessage());
2669                    }
2670            }
2671    
2672            public void writeExternal(ObjectOutput out) {
2673                    try {
2674                            out.writeUTF(new ScriptConverter().serialize(this));
2675                    } 
2676                    catch (Throwable t) {}
2677            }
2678    
2679            public int getHoldability() throws SQLException {
2680                    throw notSupported();
2681            }
2682    
2683            public boolean isClosed() throws SQLException {
2684                    return false;
2685            }
2686    
2687            public void updateNString(int columnIndex, String nString)throws SQLException {
2688                    updateString(columnIndex, nString);
2689            }
2690    
2691            public void updateNString(String columnLabel, String nString)throws SQLException {
2692                    updateString(columnLabel, nString);
2693            }
2694    
2695            
2696    
2697            public String getNString(int columnIndex) throws SQLException {
2698                    return getString(columnIndex);
2699            }
2700    
2701            public String getNString(String columnLabel) throws SQLException {
2702                    return getString(columnLabel);
2703            }
2704    
2705            public Reader getNCharacterStream(int columnIndex) throws SQLException {
2706                    return getCharacterStream(columnIndex);
2707            }
2708    
2709            public Reader getNCharacterStream(String columnLabel) throws SQLException {
2710                    return getCharacterStream(columnLabel);
2711            }
2712    
2713            public void updateNCharacterStream(int columnIndex, Reader x, long length)throws SQLException {
2714                    updateCharacterStream(columnIndex, x, length);
2715            }
2716    
2717            public void updateNCharacterStream(String columnLabel, Reader reader,long length) throws SQLException {
2718                    throw notSupported();
2719            }
2720    
2721            public void updateAsciiStream(int columnIndex, InputStream x, long length)throws SQLException {
2722                    throw notSupported();
2723            }
2724    
2725            public void updateBinaryStream(int columnIndex, InputStream x, long length)throws SQLException {
2726                    throw notSupported();
2727            }
2728    
2729            public void updateCharacterStream(int columnIndex, Reader x, long length) throws SQLException {
2730                    throw notSupported();
2731            }
2732    
2733            public void updateAsciiStream(String columnLabel, InputStream x, long length)throws SQLException {
2734                    throw notSupported();
2735            }
2736    
2737            public void updateBinaryStream(String columnLabel, InputStream x,long length) throws SQLException {
2738                    throw notSupported();
2739            }
2740    
2741            public void updateCharacterStream(String columnLabel, Reader reader,long length) throws SQLException {
2742                    throw notSupported();
2743            }
2744    
2745            public void updateBlob(int columnIndex, InputStream inputStream, long length) throws SQLException {
2746                    throw notSupported();
2747            }
2748    
2749            public void updateBlob(String columnLabel, InputStream inputStream,long length) throws SQLException {
2750                    throw notSupported();
2751            }
2752    
2753            public void updateClob(int columnIndex, Reader reader, long length) throws SQLException {
2754                    throw notSupported();
2755            }
2756    
2757            public void updateClob(String columnLabel, Reader reader, long length) throws SQLException {
2758                    throw notSupported();
2759            }
2760    
2761            public void updateNClob(int columnIndex, Reader reader, long length) throws SQLException {
2762                    updateClob(columnIndex, reader, length);
2763            }
2764    
2765            public void updateNClob(String columnLabel, Reader reader, long length) throws SQLException {
2766                    updateClob(columnLabel, reader,length);
2767            }
2768    
2769            public void updateNCharacterStream(int columnIndex, Reader x) throws SQLException {
2770                    updateCharacterStream(columnIndex, x);
2771            }
2772    
2773            public void updateNCharacterStream(String columnLabel, Reader reader)throws SQLException {
2774                    throw notSupported();
2775            }
2776    
2777            public void updateAsciiStream(int columnIndex, InputStream x)throws SQLException {
2778                    throw notSupported();
2779            }
2780    
2781            public void updateBinaryStream(int columnIndex, InputStream x)throws SQLException {
2782                    throw notSupported();
2783            }
2784    
2785            public void updateCharacterStream(int columnIndex, Reader x) throws SQLException {
2786                    throw notSupported();
2787            }
2788    
2789            public void updateAsciiStream(String columnLabel, InputStream x) throws SQLException {
2790                    throw notSupported();
2791            }
2792    
2793            public void updateBinaryStream(String columnLabel, InputStream x) throws SQLException {
2794                    throw notSupported();
2795            }
2796    
2797            public void updateCharacterStream(String columnLabel, Reader reader) throws SQLException {
2798                    throw notSupported();
2799            }
2800    
2801            public void updateBlob(int columnIndex, InputStream inputStream) throws SQLException {
2802                    throw notSupported();
2803            }
2804    
2805            public void updateBlob(String columnLabel, InputStream inputStream) throws SQLException {
2806                    throw notSupported();
2807            }
2808    
2809            public void updateClob(int columnIndex, Reader reader) throws SQLException {
2810                    throw notSupported();
2811            }
2812    
2813            public void updateClob(String columnLabel, Reader reader) throws SQLException {
2814                    throw notSupported();
2815            }
2816    
2817            public void updateNClob(int columnIndex, Reader reader) throws SQLException {
2818                    updateClob(columnIndex, reader);
2819            }
2820    
2821            public void updateNClob(String columnLabel, Reader reader) throws SQLException {
2822                    updateClob(columnLabel, reader);
2823            }
2824    
2825            public <T> T unwrap(Class<T> iface) throws SQLException {
2826                    throw notSupported();
2827            }
2828    
2829            public boolean isWrapperFor(Class<?> iface) throws SQLException {
2830                    throw notSupported();
2831            }
2832            
2833    
2834            
2835            //JDK6: uncomment this for compiling with JDK6 
2836             
2837            public void updateNClob(int columnIndex, NClob nClob) throws SQLException {
2838                    throw notSupported();
2839            }
2840    
2841            public void updateNClob(String columnLabel, NClob nClob) throws SQLException {
2842                    throw notSupported();
2843            }
2844    
2845            public NClob getNClob(int columnIndex) throws SQLException {
2846                    throw notSupported();
2847            }
2848    
2849            public NClob getNClob(String columnLabel) throws SQLException {
2850                    throw notSupported();
2851            }
2852    
2853            public SQLXML getSQLXML(int columnIndex) throws SQLException {
2854                    throw notSupported();
2855            }
2856    
2857            public SQLXML getSQLXML(String columnLabel) throws SQLException {
2858                    throw notSupported();
2859            }
2860    
2861            public void updateSQLXML(int columnIndex, SQLXML xmlObject) throws SQLException {
2862                    throw notSupported();
2863            }
2864    
2865            public void updateSQLXML(String columnLabel, SQLXML xmlObject) throws SQLException {
2866                    throw notSupported();
2867            }
2868            
2869            public RowId getRowId(int columnIndex) throws SQLException {
2870                    throw notSupported();
2871            }
2872    
2873            public RowId getRowId(String columnLabel) throws SQLException {
2874                    throw notSupported();
2875            }
2876    
2877            public void updateRowId(int columnIndex, RowId x) throws SQLException {
2878                    throw notSupported();
2879            }
2880    
2881            public void updateRowId(String columnLabel, RowId x) throws SQLException {
2882                    throw notSupported();
2883            }
2884            
2885            public void removeRows(int index, int count) throws PageException {
2886                    QueryUtil.removeRows(this,index,count);
2887            }
2888            
2889    
2890            private SQLException notSupported() {
2891                    return new SQLException("this feature is not supported");
2892            }
2893    
2894            public synchronized void enableShowQueryUsage() {
2895                    if(columns!=null)for(int i=0;i<columns.length;i++){
2896                            columns[i]=columns[i]._toDebugColumn();
2897                    }
2898            }
2899    
2900            @Override
2901            public long getExecutionTime() {
2902                    return exeTime;
2903            }
2904            
2905            public static QueryImpl cloneQuery(Query qry,boolean deepCopy) {
2906            QueryImpl newResult=new QueryImpl();
2907            ThreadLocalDuplication.set(qry, newResult);
2908            try{
2909                    newResult.columnNames=qry.getColumnNames();
2910                    newResult.columns=new QueryColumnImpl[newResult.columnNames.length];
2911                    QueryColumn col;
2912                    for(int i=0;i<newResult.columnNames.length;i++) {
2913                            col =  qry.getColumn(newResult.columnNames[i],null);
2914                            newResult.columns[i]=QueryUtil.duplicate2QueryColumnImpl(newResult,col,deepCopy);
2915                    }
2916                    
2917                            
2918                        newResult.sql=qry.getSql();
2919                    newResult.template=qry.getTemplate();
2920                    newResult.recordcount=qry.getRecordcount();
2921                    newResult.columncount=newResult.columnNames.length;
2922                    newResult.isCached=qry.isCached();
2923                    newResult.name=qry.getName();
2924                    newResult.exeTime=qry.getExecutionTime();
2925                    newResult.updateCount=qry.getUpdateCount();
2926                    if(qry.getGeneratedKeys()!=null)newResult.generatedKeys=((QueryImpl)qry.getGeneratedKeys()).cloneQuery(false);
2927                    return newResult;
2928            }
2929            finally {
2930                    // ThreadLocalDuplication.remove(qry); removed "remove" to catch sisters and brothers
2931            }
2932        }
2933            
2934            @Override
2935            public java.util.Iterator getIterator() {
2936                    return new ForEachQueryIterator(this, ThreadLocalPageContext.get().getId());
2937        }
2938            
2939            @Override
2940            public boolean equals(Object obj){
2941                    if(!(obj instanceof Collection)) return false;
2942                    return CollectionUtil.equals(this,(Collection)obj);
2943            }
2944            
2945            @Override
2946            public int hashCode() {
2947                    return CollectionUtil.hashCode(this);
2948            }
2949    }