Package railo.runtime.type

Source Code of railo.runtime.type.QueryImpl

package railo.runtime.type;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.Reader;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URL;
import java.nio.charset.Charset;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.NClob;
import java.sql.PreparedStatement;
import java.sql.Ref;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.RowId;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.SQLXML;
import java.sql.Statement;
import java.sql.Time;
import java.sql.Timestamp;
import java.sql.Types;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TimeZone;

import railo.commons.db.DBUtil;
import railo.commons.io.IOUtil;
import railo.commons.lang.StringUtil;
import railo.commons.sql.SQLUtil;
import railo.loader.engine.CFMLEngineFactory;
import railo.runtime.PageContext;
import railo.runtime.config.NullSupportHelper;
import railo.runtime.converter.ScriptConverter;
import railo.runtime.db.CFTypes;
import railo.runtime.db.DataSourceUtil;
import railo.runtime.db.DatasourceConnection;
import railo.runtime.db.DatasourceConnectionImpl;
import railo.runtime.db.SQL;
import railo.runtime.db.SQLCaster;
import railo.runtime.db.SQLItem;
import railo.runtime.dump.DumpData;
import railo.runtime.dump.DumpProperties;
import railo.runtime.engine.ThreadLocalPageContext;
import railo.runtime.exp.ApplicationException;
import railo.runtime.exp.DatabaseException;
import railo.runtime.exp.ExpressionException;
import railo.runtime.exp.PageException;
import railo.runtime.exp.PageRuntimeException;
import railo.runtime.interpreter.CFMLExpressionInterpreter;
import railo.runtime.op.Caster;
import railo.runtime.op.Decision;
import railo.runtime.op.Duplicator;
import railo.runtime.op.ThreadLocalDuplication;
import railo.runtime.op.date.DateCaster;
import railo.runtime.query.caster.Cast;
import railo.runtime.type.comparator.NumberSortRegisterComparator;
import railo.runtime.type.comparator.SortRegister;
import railo.runtime.type.comparator.SortRegisterComparator;
import railo.runtime.type.dt.DateTime;
import railo.runtime.type.dt.DateTimeImpl;
import railo.runtime.type.it.CollectionIterator;
import railo.runtime.type.it.EntryIterator;
import railo.runtime.type.it.ForEachQueryIterator;
import railo.runtime.type.it.KeyIterator;
import railo.runtime.type.it.StringIterator;
import railo.runtime.type.sql.BlobImpl;
import railo.runtime.type.sql.ClobImpl;
import railo.runtime.type.util.ArrayUtil;
import railo.runtime.type.util.CollectionUtil;
import railo.runtime.type.util.KeyConstants;
import railo.runtime.type.util.ListUtil;
import railo.runtime.type.util.MemberUtil;
import railo.runtime.type.util.QueryUtil;

/**
* implementation of the query interface
*/
/**
*
*/
public class QueryImpl implements Query,Objects {

  private static final long serialVersionUID = 1035795427320192551L; // do not chnage


  /**
   * @return the template
   */
  public String getTemplate() {
    return template;
  }

  public static final Collection.Key GENERATED_KEYS = KeyImpl.intern("GENERATED_KEYS");
  public static final Collection.Key GENERATEDKEYS = KeyImpl.intern("GENERATEDKEYS");
 
 
 
  //private static int count=0;
  private QueryColumnImpl[] columns;
  private Collection.Key[] columnNames;
  private SQL sql;
  private ArrayInt arrCurrentRow=new ArrayInt();
  private int recordcount=0;
  private int columncount;
  private long exeTime=0;
    private boolean isCached=false;
    private String name;
  private int updateCount;
    private QueryImpl generatedKeys;
  private String template;
 
 
  @Override
  public int executionTime() {
    return (int) exeTime;
  }

  /**
   * create a QueryImpl from a SQL Resultset
     * @param result SQL Resultset
   * @param maxrow
   * @param name
   * @throws PageException
     */
    public QueryImpl(ResultSet result, int maxrow, String name, TimeZone tz) throws PageException {
      this.name=name;
        //Stopwatch stopwatch=new Stopwatch();
    //stopwatch.start();
    long start=System.nanoTime();
      try {
            fillResult(null,result,maxrow,false,false,tz);
        } catch (SQLException e) {
            throw new DatabaseException(e,null);
        } catch (IOException e) {
            throw Caster.toPageException(e);
        }
    exeTime=System.nanoTime()-start;
    }
   
    /**
     * Constructor of the class
     * only for internal usage (cloning/deserialize)
     */
    public QueryImpl() {
    }
   
   
    public QueryImpl(ResultSet result, String name,TimeZone tz) throws PageException {
    this.name=name;
       
    try
        fillResult(null,result,-1,true,false,tz);
    }
    catch (SQLException e) {
      throw new DatabaseException(e,null);
    }
    catch (Exception e) {
        throw Caster.toPageException(e);
    }
  }
 
  /**
   * constructor of the class, to generate a resultset from a sql query
   * @param dc Connection to a database
   * @param name
   * @param sql sql to execute
   * @param maxrow maxrow for the resultset
   * @throws PageException
   */ 
    public QueryImpl(PageContext pc, DatasourceConnection dc,SQL sql,int maxrow, int fetchsize,int timeout, String name) throws PageException {
      this(pc,dc, sql, maxrow, fetchsize, timeout, name,null,false,true);
    }
   

    public QueryImpl(PageContext pc, DatasourceConnection dc,SQL sql,int maxrow, int fetchsize,int timeout, String name,String template) throws PageException {
      this(pc,dc, sql, maxrow, fetchsize, timeout, name,template,false,true);
    }
   
  public QueryImpl(PageContext pc, DatasourceConnection dc,SQL sql,int maxrow, int fetchsize,int timeout, String name,String template,boolean createUpdateData, boolean allowToCachePreperadeStatement) throws PageException {
    this.name=name;
    this.template=template;
        this.sql=sql;
    TimeZone tz = ThreadLocalPageContext.getTimeZone(pc);
        //ResultSet result=null;
    Statement stat=null;
    // check SQL Restrictions
    if(dc.getDatasource().hasSQLRestriction()) {
      QueryUtil.checkSQLRestriction(dc,sql);
        }
    // check if datasource support Generated Keys
    boolean createGeneratedKeys=createUpdateData;
        if(createUpdateData){
          DatasourceConnectionImpl dci=(DatasourceConnectionImpl) dc;
          if(!dci.supportsGetGeneratedKeys())createGeneratedKeys=false;
        }

       
    //Stopwatch stopwatch=new Stopwatch();
        long start=System.nanoTime();
    //stopwatch.start();
    boolean hasResult=false;
    //boolean closeStatement=true;
    try
      SQLItem[] items=sql.getItems();
      if(items.length==0) {
          stat=dc.getConnection().createStatement();
            setAttributes(stat,maxrow,fetchsize,timeout);
         // some driver do not support second argument
            //hasResult=createGeneratedKeys?stat.execute(sql.getSQLString(),Statement.RETURN_GENERATED_KEYS):stat.execute(sql.getSQLString());
            hasResult=QueryUtil.execute(pc,stat,createGeneratedKeys,sql);
          }
          else {
            // some driver do not support second argument
            PreparedStatement preStat = dc.getPreparedStatement(sql, createGeneratedKeys,allowToCachePreperadeStatement);
            //closeStatement=false;
            stat=preStat;
              setAttributes(preStat,maxrow,fetchsize,timeout);
              setItems(ThreadLocalPageContext.getTimeZone(pc),preStat,items);
            hasResult=QueryUtil.execute(pc,preStat);   
          }
      int uc;
      ResultSet res;
      do {
        if(hasResult) {
          res=stat.getResultSet();
          if(fillResult(dc,res, maxrow, true,createGeneratedKeys,tz))break;
        }
        else if((uc=setUpdateCount(stat))!=-1){
          if(uc>0 && createGeneratedKeys)setGeneratedKeys(dc, stat,tz);
        }
        else break;
        try{
          hasResult=stat.getMoreResults(Statement.CLOSE_CURRENT_RESULT);
        }
        catch(Throwable t){
          break;
        }
      }
      while(true);
    }
    catch (SQLException e) {
      throw new DatabaseException(e,sql,dc);
    }
    catch (Throwable e) {
      throw Caster.toPageException(e);
    }
        finally {
          //if(closeStatement)
            DBUtil.closeEL(stat);
       
    exeTime=System.nanoTime()-start;

    if(columncount==0) {
      if(columnNames==null) columnNames=new Collection.Key[0];
      if(columns==null) columns=new QueryColumnImpl[0];
    }
  }
 
  private int setUpdateCount(Statement stat)  {
    try{
      int uc=stat.getUpdateCount();
      if(uc>-1){
        updateCount+=uc;
        return uc;
      }
    }
    catch(Throwable t){}
    return -1;
  }
 
  private boolean setGeneratedKeys(DatasourceConnection dc,Statement stat, TimeZone tz)  {
    try{
      ResultSet rs = stat.getGeneratedKeys();
      setGeneratedKeys(dc, rs,tz);
      return true;
    }
    catch(Throwable t) {t.printStackTrace();
      return false;
    }
  }
 
  private void setGeneratedKeys(DatasourceConnection dc,ResultSet rs, TimeZone tz) throws PageException  {
    generatedKeys=new QueryImpl(rs,"",tz);
   
    // ACF compatibility action
    if(generatedKeys.getColumnCount()==1 && DataSourceUtil.isMSSQL(dc)) {
      generatedKeys.renameEL(GENERATED_KEYS,KeyConstants._IDENTITYCOL);
      generatedKeys.renameEL(GENERATEDKEYS,KeyConstants._IDENTITYCOL);
      generatedKeys.renameEL(KeyConstants._ID,KeyConstants._IDENTITYCOL);
    }
  }
 
  /*private void setUpdateData(Statement stat, boolean createGeneratedKeys, boolean createUpdateCount)  {
   
    // update Count
    if(createUpdateCount){
      try{
        updateCount=stat.getUpdateCount();
      }
      catch(Throwable t){
        t.printStackTrace();
      }
    }
    // generated keys
    if(createGeneratedKeys){
      try{
        ResultSet rs = stat.getGeneratedKeys();
        generatedKeys=new QueryImpl(rs,"");
      }
      catch(Throwable t){
        t.printStackTrace();
      }
    }
  }*/


  private void setItems(TimeZone tz,PreparedStatement preStat, SQLItem[] items) throws DatabaseException, PageException, SQLException {
    for(int i=0;i<items.length;i++) {
            SQLCaster.setValue(tz,preStat,i+1,items[i]);
        }
  }

  public int getUpdateCount() {
    return updateCount;
  }
  public Query getGeneratedKeys() {
    return generatedKeys;
  }

  private void setAttributes(Statement stat,int maxrow, int fetchsize,int timeout) throws SQLException {
    if(maxrow>-1) stat.setMaxRows(maxrow);
        if(fetchsize>0)stat.setFetchSize(fetchsize);
        if(timeout>0)stat.setQueryTimeout(timeout);
  }

    private boolean fillResult(DatasourceConnection dc, ResultSet result, int maxrow, boolean closeResult,boolean createGeneratedKeys, TimeZone tz) throws SQLException, IOException, PageException {
      if(result==null) return false;
      try {
        recordcount=0;
      ResultSetMetaData meta = result.getMetaData();
      columncount=meta.getColumnCount();
     
    // set header arrays
      Collection.Key[] tmpColumnNames = new Collection.Key[columncount];
      int count=0;
      Collection.Key key;
      String columnName;
      for(int i=0;i<columncount;i++) {
        columnName=QueryUtil.getColumnName(meta,i+1);
        if(StringUtil.isEmpty(columnName))columnName="column_"+i;
        key=KeyImpl.init(columnName);
        int index=getIndexFrom(tmpColumnNames,key,0,i);
        if(index==-1) {
          tmpColumnNames[i]=key;
          count++;
        }
      }
     
 
      columncount=count;
      columnNames=new Collection.Key[columncount];
      columns=new QueryColumnImpl[columncount];
      Cast[] casts = new Cast[columncount];
     
    // get all used ints
      int[] usedColumns=new int[columncount];
      count=0;
      for(int i=0;i<tmpColumnNames.length;i++) {
        if(tmpColumnNames[i]!=null) {
          usedColumns[count++]=i;
        }
      } 
           
    // set used column names
      int[] types=new int[columns.length];
      for(int i=0;i<usedColumns.length;i++) {
              columnNames[i]=tmpColumnNames[usedColumns[i]];
              columns[i]=new QueryColumnImpl(this,columnNames[i],types[i]=meta.getColumnType(usedColumns[i]+1));
             
              if(types[i]==Types.TIMESTAMPcasts[i]=Cast.TIMESTAMP;
              else if(types[i]==Types.TIMEcasts[i]=Cast.TIME;
              else if(types[i]==Types.DATEcasts[i]=Cast.DATE;
              else if(types[i]==Types.CLOBcasts[i]=Cast.CLOB;
              else if(types[i]==Types.BLOBcasts[i]=Cast.BLOB;
              else if(types[i]==Types.BITcasts[i]=Cast.BIT;
              else if(types[i]==Types.ARRAYcasts[i]=Cast.ARRAY;
              else if(types[i]==Types.BIGINTcasts[i]=Cast.BIGINT;
              //else if(types[i]==Types.TINYINT)  casts[i]=Cast.ARRAY;
             
              else if(types[i]==CFTypes.OPAQUE){
                if(SQLUtil.isOracle(result.getStatement().getConnection()))
                  casts[i]=Cast.ORACLE_OPAQUE;
                else
                  casts[i]=Cast.OTHER;
         
              }
              else casts[i]=Cast.OTHER;
      }
     
      if(createGeneratedKeys && columncount==1 && columnNames[0].equals(GENERATED_KEYS) && dc!=null && DataSourceUtil.isMSSQLDriver(dc)) {
        columncount=0;
        columnNames=null;
        columns=null;
        setGeneratedKeys(dc, result,tz);
        return false;
      }
     
 
    // fill data
      //Object o;
      while(result.next()) {
        if(maxrow>-1 && recordcount>=maxrow) {
          break;
        }
        for(int i=0;i<usedColumns.length;i++) {
            columns[i].add(casts[i].toCFType(tz,types[i], result, usedColumns[i]+1));
        }
        ++recordcount;
      }
      }
      finally {
        if(closeResult)IOUtil.closeEL(result);
      }
   
    return true;
  }

    private Object toBytes(Blob blob) throws IOException, SQLException {
    return IOUtil.toBytes((blob).getBinaryStream());
  }

  private static Object toString(Clob clob) throws IOException, SQLException {
    return IOUtil.toString(clob.getCharacterStream());
  }

    private static int getIndexFrom(Collection.Key[] tmpColumnNames, Collection.Key key, int from, int to) {
    for(int i=from;i<to;i++) {
      if(tmpColumnNames[i]!=null && tmpColumnNames[i].equalsIgnoreCase(key))return i;
    }
    return -1;
  }

  /**
   * constructor of the class, to generate a empty resultset (no database execution)
   * @param strColumns columns for the resultset
   * @param rowNumber count of rows to generate (empty fields)
   * @param name
   * @deprecated use instead <code>QueryImpl(Collection.Key[] columnKeys, int rowNumber,String name)</code>
   */
  public QueryImpl(String[] strColumns, int rowNumber,String name) {
        this.name=name;
        columncount=strColumns.length;
    recordcount=rowNumber;
    columnNames=new Collection.Key[columncount];
    columns=new QueryColumnImpl[columncount];
    for(int i=0;i<strColumns.length;i++) {
      columnNames[i]=KeyImpl.init(strColumns[i].trim());
      columns[i]=new QueryColumnImpl(this,columnNames[i],Types.OTHER,recordcount);
    }
  }

  /**
   * constructor of the class, to generate a empty resultset (no database execution)
   * @param strColumns columns for the resultset
   * @param rowNumber count of rows to generate (empty fields)
   * @param name
   */
  public QueryImpl(Collection.Key[] columnKeys, int rowNumber,String name) throws DatabaseException {
    this.name=name;
        columncount=columnKeys.length;
    recordcount=rowNumber;
    columnNames=new Collection.Key[columncount];
    columns=new QueryColumnImpl[columncount];
    for(int i=0;i<columnKeys.length;i++) {
      columnNames[i]=columnKeys[i];
      columns[i]=new QueryColumnImpl(this,columnNames[i],Types.OTHER,recordcount);
    }
    validateColumnNames(columnNames);
  }
 
  /**
   * constructor of the class, to generate a empty resultset (no database execution)
   * @param strColumns columns for the resultset
   * @param strTypes array of the types
   * @param rowNumber count of rows to generate (empty fields)
   * @param name
   * @throws DatabaseException
   */
  public QueryImpl(String[] strColumns, String[] strTypes, int rowNumber, String name) throws DatabaseException {
        this.name=name;
        columncount=strColumns.length;
    if(strTypes.length!=columncount) throw new DatabaseException("columns and types has not the same count",null,null,null);
    recordcount=rowNumber;
    columnNames=new Collection.Key[columncount];
    columns=new QueryColumnImpl[columncount];
    for(int i=0;i<strColumns.length;i++) {
      columnNames[i]=KeyImpl.init(strColumns[i].trim());
      columns[i]=new QueryColumnImpl(this,columnNames[i],SQLCaster.toIntType(strTypes[i]),recordcount);
    }
  }
 
  /**
   * constructor of the class, to generate a empty resultset (no database execution)
   * @param strColumns columns for the resultset
   * @param strTypes array of the types
   * @param rowNumber count of rows to generate (empty fields)
   * @param name
   * @throws DatabaseException
   */
  public QueryImpl(Collection.Key[] columnNames, String[] strTypes, int rowNumber, String name) throws DatabaseException {
        this.name=name;
        this.columnNames=columnNames;
        columncount=columnNames.length;
    if(strTypes.length!=columncount) throw new DatabaseException("columns and types has not the same count",null,null,null);
    recordcount=rowNumber;
    columns=new QueryColumnImpl[columncount];
    for(int i=0;i<columnNames.length;i++) {
      columns[i]=new QueryColumnImpl(this,columnNames[i],SQLCaster.toIntType(strTypes[i]),recordcount);
    }
    validateColumnNames(columnNames);
  }
 
  /**
   * constructor of the class, to generate a empty resultset (no database execution)
   * @param arrColumns columns for the resultset
   * @param rowNumber count of rows to generate (empty fields)
   * @param name
   * @throws DatabaseException
   */
  public QueryImpl(Array arrColumns, int rowNumber, String name) throws DatabaseException {
        this.name=name;
        columncount=arrColumns.size();
    recordcount=rowNumber;
    columnNames=new Collection.Key[columncount];
    columns=new QueryColumnImpl[columncount];
    for(int i=0;i<columncount;i++) {
      columnNames[i]=KeyImpl.init(arrColumns.get(i+1,"").toString().trim());
      columns[i]=new QueryColumnImpl(this,columnNames[i],Types.OTHER,recordcount);
    }
    validateColumnNames(columnNames);
  }

  /**
   * constructor of the class, to generate a empty resultset (no database execution)
   * @param arrColumns columns for the resultset
   * @param arrTypes type of the columns
   * @param rowNumber count of rows to generate (empty fields)
   * @param name
   * @throws PageException
   */
  public QueryImpl(Array arrColumns, Array arrTypes, int rowNumber, String name) throws PageException {
        this.name=name;
        columncount=arrColumns.size();
    if(arrTypes.size()!=columncount) throw new DatabaseException("columns and types has not the same count",null,null,null);
    recordcount=rowNumber;
    columnNames=new Collection.Key[columncount];
    columns=new QueryColumnImpl[columncount];
    for(int i=0;i<columncount;i++) {
      columnNames[i]=KeyImpl.init(arrColumns.get(i+1,"").toString().trim());
      columns[i]=new QueryColumnImpl(this,columnNames[i],SQLCaster.toIntType(Caster.toString(arrTypes.get(i+1,""))),recordcount);
    }
    validateColumnNames(columnNames);
  }

  /**
   * constructor of the class
   * @param columnNames columns definition as String Array
   * @param arrColumns values
   * @param name
   * @throws DatabaseException
   */

  public QueryImpl(String[] strColumnNames, Array[] arrColumns, String name) throws DatabaseException {
    this(_toKeys(strColumnNames),arrColumns,name);   
 
 
  private static void validateColumnNames(Key[] columnNames) throws DatabaseException {
    Set<String> testMap=new HashSet<String>();
    for(int i=;i<columnNames.length;i++) {
     
      // Only allow column names that are valid variable name
      //if(!Decision.isSimpleVariableName(columnNames[i]))
      //  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);
     
      if(testMap.contains(columnNames[i].getLowerString()))
        throw new DatabaseException("invalid parameter for query, ambiguous column name "+columnNames[i],"columnNames: "+ListUtil.arrayToListTrim( _toStringKeys(columnNames),","),null,null);
      testMap.add(columnNames[i].getLowerString());
    }
  }
 

  private static Collection.Key[] _toKeys(String[] strColumnNames) {
    Collection.Key[] columnNames=new Collection.Key[strColumnNames.length];
    for(int i=;i<columnNames.length;i++) {
      columnNames[i]=KeyImpl.init(strColumnNames[i].trim());
    }
    return columnNames;
  }
  private static String[] _toStringKeys(Collection.Key[] columnNames) {
    String[] strColumnNames=new String[columnNames.length];
    for(int i=;i<strColumnNames.length;i++) {
      strColumnNames[i]=columnNames[i].getString();
    }
    return strColumnNames;
  }
 
  /*public QueryImpl(Collection.Key[] columnNames, QueryColumn[] columns, String name,long exeTime, boolean isCached,SQL sql) throws DatabaseException {
    this.columnNames=columnNames;
    this.columns=columns;
    this.exeTime=exeTime;
    this.isCached=isCached;
    this.name=name;
    this.columncount=columnNames.length;
    this.recordcount=columns.length==0?0:columns[0].size();
    this.sql=sql;
   
  }*/

  public QueryImpl(Collection.Key[] columnNames, Array[] arrColumns, String name) throws DatabaseException {
        this.name=name;
       
        if(columnNames.length!=arrColumns.length)
      throw new DatabaseException("invalid parameter for query, not the same count from names and columns","names:"+columnNames.length+";columns:"+arrColumns.length,null,null);
    int len=0;
    columns=new QueryColumnImpl[arrColumns.length];
    if(arrColumns.length>0) {
    // test columns
      len=arrColumns[0].size();
      for(int i=0;i<arrColumns.length;i++) {
        if(arrColumns[i].size()!=len)
          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);
        //columns[i]=new QueryColumnTypeFlex(arrColumns[i]);
        columns[i]=new QueryColumnImpl(this,columnNames[i],arrColumns[i],Types.OTHER);
      }
    // test keys
      validateColumnNames(columnNames);
    }
   
    columncount=columns.length;
    recordcount=len;
    this.columnNames=columnNames;
  }
 
    /**
     * constructor of the class
     * @param columnList
     * @param data
     * @param name
     * @throws DatabaseException
     */
    public QueryImpl(String[] strColumnList, Object[][] data,String name) throws DatabaseException {
     
        this(toCollKeyArr(strColumnList),data.length,name);
       
        for(int iRow=0;iRow<data.length;iRow++) {
            Object[] row=data[iRow];
            for(int iCol=0;iCol<row.length;iCol++) {
                //print.ln(columnList[iCol]+":"+iRow+"="+row[iCol]);
                setAtEL(columnNames[iCol],iRow+1,row[iCol]);
            }
        }
    }

    private static Collection.Key[] toCollKeyArr(String[] strColumnList) {
      Collection.Key[] columnList=new Collection.Key[strColumnList.length];
    for(int i=;i<columnList.length;i++) {
      columnList[i]=KeyImpl.init(strColumnList[i].trim());
    }
    return columnList;
  }

  @Override
  public int size() {
    return columncount;
  }

  @Override
  public Collection.Key[] keys() {
    return columnNames;
  }

  @Override
  public Object removeEL(Collection.Key key) {
    return setEL(key,null);
  }

  @Override
  public Object remove(Collection.Key key) throws PageException {
    return set(key,null);
  }

  @Override
  public void clear() {
    for(int i=0;i<columns.length;i++) {
      columns[i].clear();
        }
        recordcount=0;
  }

  @Override
  public Object get(String key, Object defaultValue) {
    return getAt(key,
        arrCurrentRow.get(getPid(), 1),
        defaultValue);
  }

  //private static int pidc=0;
  private int getPid() {
   
    PageContext pc = ThreadLocalPageContext.get();
    if(pc==null) {
      pc=CFMLEngineFactory.getInstance().getThreadPageContext();
      if(pc==null)throw new RuntimeException("cannot get pid for current thread");
    }
    return pc.getId();
  }

  @Override
  public Object get(Collection.Key key, Object defaultValue) {
    return getAt(key,
        arrCurrentRow.get(getPid(), 1),
        defaultValue);
  }

  @Override
  public Object get(String key) throws PageException {
    return getAt(key,
        arrCurrentRow.get(getPid(), 1)
        );
  }

  @Override
  public Object get(Collection.Key key) throws PageException {
    return getAt(key,
        arrCurrentRow.get(getPid(), 1)
        );
  }

  @Override
  public Object getAt(String key, int row, Object defaultValue) {
    return getAt(KeyImpl.init(key), row, defaultValue);
  }

  public Object getAt(Collection.Key key, int row, Object defaultValue) {
    int index=getIndexFromKey(key);
    if(index!=-1) {
      return columns[index].get(row,defaultValue);
    }
    if(key.length()>=10) {
          if(key.equals(KeyConstants._RECORDCOUNT)) return new Double(getRecordcount());
          if(key.equals(KeyConstants._CURRENTROW)) return new Double(row);
          if(key.equals(KeyConstants._COLUMNLIST)) return getColumnlist(true);
    }
        return defaultValue;
  }
 
  @Override
  public Object getAt(String key, int row) throws PageException {
    return getAt(KeyImpl.init(key), row);
  }

  @Override
  public Object getAt(Collection.Key key, int row) throws PageException {
    int index=getIndexFromKey(key);
    if(index!=-1) {
      return columns[index].get(row, NullSupportHelper.empty());
    }
    if(key.length()>=10) {
          if(key.equals(KeyConstants._RECORDCOUNT)) return new Double(getRecordcount());
          if(key.equals(KeyConstants._CURRENTROW)) return new Double(row);
      if(key.equals(KeyConstants._COLUMNLIST)) return getColumnlist(true);
        }
    throw new DatabaseException("column ["+key+"] not found in query, columns are ["+getColumnlist(false)+"]",null,sql,null);
  }
 

    @Override
    public synchronized int removeRow(int row) throws PageException {
        //disconnectCache();
       
        for(int i=0;i<columns.length;i++) {
            columns[i].removeRow(row);
        }
        return --recordcount;
    }

    @Override
    public int removeRowEL(int row) {
        //disconnectCache();
       
        try {
            return removeRow(row);
        } catch (PageException e) {
            return recordcount;
        }
    }
   
    @Override
    public QueryColumn removeColumn(String key) throws DatabaseException {
        return removeColumn(KeyImpl.init(key));
    }

  @Override
  public QueryColumn removeColumn(Collection.Key key) throws DatabaseException {
    //disconnectCache();
       
        QueryColumn removed = removeColumnEL(key);
        if(removed==null) {
            if(key.equals(KeyConstants._RECORDCOUNT) ||
                key.equals(KeyConstants._CURRENTROW) ||
                key.equals(KeyConstants._COLUMNLIST))
                throw new DatabaseException("can't remove "+key+" this is not a row","existing rows are ["+getColumnlist(false)+"]",null,null);
            throw new DatabaseException("can't remove row ["+key+"], this row doesn't exist",
                    "existing rows are ["+getColumnlist(false)+"]",null,null);
        }
        return removed;
  }

    @Override
    public synchronized QueryColumn removeColumnEL(String key) {
        return removeColumnEL(KeyImpl.init(key));
    }

  public QueryColumn removeColumnEL(Collection.Key key) {
    //disconnectCache();
       
        int index=getIndexFromKey(key);
        if(index!=-1) {
            int current=0;
            QueryColumn removed=null;
            Collection.Key[] newColumnNames=new Collection.Key[columnNames.length-1];
            QueryColumnImpl[] newColumns=new QueryColumnImpl[columns.length-1];
            for(int i=0;i<columns.length;i++) {
                if(i==index) {
                    removed=columns[i];
                }
                else {
                    newColumnNames[current]=columnNames[i];
                    newColumns[current++]=columns[i];
                }
            }
            columnNames=newColumnNames;
            columns=newColumns;
            columncount--;
            return removed;
        }
        return null;
  }

  @Override
  public Object setEL(String key, Object value) { 
    return setEL(KeyImpl.init(key),value)
  }

  @Override
  public Object setEL(Collection.Key key, Object value) {
    return setAtEL(key,
        arrCurrentRow.get(getPid(), 1),
        value);
  }
 
  @Override
  public Object set(String key, Object value) throws PageException {
    return set(KeyImpl.init(key),value);
  }

  @Override
  public Object set(Collection.Key key, Object value) throws PageException {
    return setAt(key,
        arrCurrentRow.get(getPid(), 1),
        value);
  }
   
    @Override
    public Object setAt(String key,int row, Object value) throws PageException {
      return setAt(KeyImpl.init(key), row, value);
    }

    public Object setAt(Collection.Key key, int row, Object value) throws PageException {
    int index=getIndexFromKey(key);
        if(index!=-1) {
            return columns[index].set(row,value);
        }
        throw new DatabaseException("column ["+key+"] does not exist","columns are ["+getColumnlist(false)+"]",sql,null);
  }
   
    @Override
    public Object setAtEL(String key,int row, Object value) {
        return setAtEL(KeyImpl.init(key), row, value);
    }

  public Object setAtEL(Collection.Key key, int row, Object value) {
    int index=getIndexFromKey(key);
        if(index!=-1) {
            return columns[index].setEL(row,value);
        }
        return null;
  }

  @Override
  public boolean next() {
    return next(getPid());
  }

  @Override
  public boolean next(int pid) {
    if(recordcount>=(arrCurrentRow.set(pid,arrCurrentRow.get(pid,0)+1))) {
      return true;
    }
    arrCurrentRow.set(pid,0);
    return false;
  }

  @Override
  public void reset() {
    reset(getPid());
  }
 
  public void reset(int pid) {
    arrCurrentRow.set(pid,0);
  }

  @Override
  public int getRecordcount() {
    return recordcount;
  }
 
  @Override
  public int getCurrentrow(int pid) {
    return arrCurrentRow.get(pid,1);
  }


  /**
   * return a string list of all columns
   * @return string list
   */
  public String getColumnlist(boolean upperCase) {
    //if(upperCase)upperCase=((ConfigImpl)ThreadLocalPageContext.getConfig()).getDotNotationUpperCase();
    StringBuffer sb=new StringBuffer();
    for(int i=0;i<columnNames.length;i++) {
      if(i>0)sb.append(',');
      sb.append(upperCase?columnNames[i].getUpperString():columnNames[i].getString());
    }
    return sb.toString();
  }
  public String getColumnlist() {
    return getColumnlist(true);
  }

  public boolean go(int index) {
    return go(index,getPid());
  }
 
  public boolean go(int index, int pid) {
    if(index>0 && index<=recordcount) {
      arrCurrentRow.set(pid, index);
      return true;
    }
    arrCurrentRow.set(pid, 0);
    return false;
  }

  @Override
  public boolean isEmpty() {
    return recordcount+columncount==0;
  }

  @Override
  public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp) {
    return QueryUtil.toDumpData(this, pageContext, maxlevel, dp);
  }
 
  /**
   * sorts a query by a column
   * @param column colun to sort
   * @throws PageException
   */
  public void sort(String column) throws PageException {
    sort(column,Query.ORDER_ASC);
  }

  @Override
  public void sort(Collection.Key column) throws PageException {
    sort(column,Query.ORDER_ASC);
  }

  /**
   * sorts a query by a column
   * @param strColumn column to sort
   * @param order sort type (Query.ORDER_ASC or Query.ORDER_DESC)
   * @throws PageException
   */
  public synchronized void sort(String strColumn, int order) throws PageException {
    //disconnectCache();
        sort(getColumn(strColumn),order);
  }
 
  @Override
  public synchronized void sort(Collection.Key keyColumn, int order) throws PageException {
    //disconnectCache();
        sort(getColumn(keyColumn),order);
  }
 
  private void sort(QueryColumn column, int order) throws PageException {
        int type = column.getType();
   
    SortRegister[] arr= ArrayUtil.toSortRegisterArray(column);
   
    Arrays.sort(arr,
    (
        type==Types.BIGINT ||
        type==Types.BIT ||
        type==Types.INTEGER ||
        type==Types.SMALLINT ||
        type==Types.TINYINT  ||
            type==Types.DECIMAL ||
            type==Types.DOUBLE ||
            type==Types.NUMERIC ||
            type==Types.REAL)?
   
    (Comparator)new NumberSortRegisterComparator(order==ORDER_ASC):(Comparator)new SortRegisterComparator(order==ORDER_ASC,true)
    );
   
    for(int i=0;i<columns.length;i++) {
      column=columns[i];
      int len=column.size();
      QueryColumnImpl newCol=new QueryColumnImpl(this,columnNames[i],columns[i].getType(),len);
      for(int y=1;y<=len;y++) {
        newCol.set(y,column.get(arr[y-1].getOldPosition()+1,null));
      }
      columns[i]=newCol;
    }
  }

  @Override
   public synchronized boolean addRow(int count) {   
         //disconnectCache();
           
         for(int i=0;i<columns.length;i++) {
           QueryColumnPro column = columns[i];
       column.addRow(count);
     }
     recordcount+=count;
     return true;
   }
  
   @Override
  public boolean addColumn(String columnName, Array content) throws DatabaseException {
    return addColumn(columnName,content,Types.OTHER);
   }

  public boolean addColumn(Collection.Key columnName, Array content) throws PageException {
    return addColumn(columnName,content,Types.OTHER);
  }
 
    @Override
    public synchronized boolean addColumn(String columnName, Array content, int type) throws DatabaseException {
    return addColumn(KeyImpl.init(columnName.trim()), content, type);
    }

  @Override
  public boolean addColumn(Collection.Key columnName, Array content, int type) throws DatabaseException {
    //disconnectCache();
        // TODO Meta type
    content=(Array) Duplicator.duplicate(content,false);
   
     if(getIndexFromKey(columnName)!=-1)
       throw new DatabaseException("column name ["+columnName.getString()+"] already exist",null,sql,null);
     if(content.size()!=getRecordcount()) {
       //throw new DatabaseException("array for the new column has not the same size like the query (arrayLen!=query.recordcount)");
       if(content.size()>getRecordcount()) addRow(content.size()-getRecordcount());
       else content.setEL(getRecordcount(),"");
     }
     QueryColumnImpl[] newColumns=new QueryColumnImpl[columns.length+1];
     Collection.Key[] newColumnNames=new Collection.Key[columns.length+1];
     boolean logUsage=false;
     for(int i=0;i<columns.length;i++) {
       newColumns[i]=columns[i];
       newColumnNames[i]=columnNames[i];
       if(!logUsage && columns[i] instanceof DebugQueryColumn) logUsage=true;
     }
     newColumns[columns.length]=new QueryColumnImpl(this,columnName,content,type);
     newColumnNames[columns.length]=columnName;
     columns=newColumns;
     columnNames=newColumnNames;
    
     columncount++;
    
     if(logUsage)enableShowQueryUsage();
    
    return true;
  }
 

  /* *
   * if this query is still connected with cache (same query also in cache)
     * it will disconnetd from cache (clone object and add clone to cache)
   */
  //protected void disconnectCache() {}

 
  @Override
    public Object clone() {
        return cloneQuery(true);
    }
   
    @Override
    public Collection duplicate(boolean deepCopy) {
        return cloneQuery(true);
    }
   

 
   
    /**
     * @return clones the query object
     */
    public QueryImpl cloneQuery(boolean deepCopy) {
        QueryImpl newResult=new QueryImpl();
        ThreadLocalDuplication.set(this, newResult);
        try{
          if(columnNames!=null){
            newResult.columnNames=new Collection.Key[columnNames.length];
            newResult.columns=new QueryColumnImpl[columnNames.length];
            for(int i=0;i<columnNames.length;i++) {
              newResult.columnNames[i]=columnNames[i];
              newResult.columns[i]=columns[i].cloneColumnImpl(deepCopy);
            }
          }
          newResult.sql=sql;
          newResult.template=template;
          newResult.recordcount=recordcount;
          newResult.columncount=columncount;
          newResult.isCached=isCached;
          newResult.name=name;
          newResult.exeTime=exeTime;
          newResult.updateCount=updateCount;
          if(generatedKeys!=null)newResult.generatedKeys=generatedKeys.cloneQuery(false);
          return newResult;
        }
        finally {
          // ThreadLocalDuplication.remove(this); removed "remove" to catch sisters and brothers
        }
    }

  @Override
  public synchronized int[] getTypes() {
    int[] types=new int[columns.length];
    for(int i=0;i<columns.length;i++) {
        types[i]=columns[i].getType();
    }
    return types;
  }
 
  @Override
  public synchronized Map<Collection.Key,String> getTypesAsMap() {
   
    Map<Collection.Key,String> map=new HashMap<Collection.Key,String>();
    for(int i=0;i<columns.length;i++) {
      map.put(columnNames[i],columns[i].getTypeAsString());
    }
    return map;
  }

  @Override
  public QueryColumn getColumn(String key) throws DatabaseException {
    return getColumn(KeyImpl.init(key.trim()));
  }

  @Override
  public QueryColumn getColumn(Collection.Key key) throws DatabaseException {
    int index=getIndexFromKey(key);
    if(index!=-1) return columns[index];
       
    if(key.length()>=10) {
          if(key.equals(KeyConstants._RECORDCOUNT)) return new QueryColumnRef(this,key,Types.INTEGER);
          if(key.equals(KeyConstants._CURRENTROW)) return new QueryColumnRef(this,key,Types.INTEGER);
          if(key.equals(KeyConstants._COLUMNLIST)) return new QueryColumnRef(this,key,Types.INTEGER);
    }
        throw new DatabaseException("key ["+key.getString()+"] not found in query, columns are ["+getColumnlist(false)+"]",null,sql,null);
  }
 

  private void renameEL(Collection.Key src, Collection.Key trg) {
    int index=getIndexFromKey(src);
    if(index!=-1){
      columnNames[index]=trg;
      columns[index].setKey(trg);
    }
  }
 
  public synchronized void rename(Collection.Key columnName,Collection.Key newColumnName) throws ExpressionException {
    int index=getIndexFromKey(columnName);
    if(index==-1) throw new ExpressionException("invalid column name definitions");
    columnNames[index]=newColumnName;
    columns[index].setKey(newColumnName);
  }
 

  @Override
  public QueryColumn getColumn(String key, QueryColumn defaultValue) {
    return getColumn(KeyImpl.init(key.trim()),defaultValue);
  }

  @Override
  public QueryColumn getColumn(Collection.Key key, QueryColumn defaultValue) {
        int index=getIndexFromKey(key);
    if(index!=-1) return columns[index];
        if(key.length()>=10) {
          if(key.equals(KeyConstants._RECORDCOUNT)) return new QueryColumnRef(this,key,Types.INTEGER);
          if(key.equals(KeyConstants._CURRENTROW)) return new QueryColumnRef(this,key,Types.INTEGER);
          if(key.equals(KeyConstants._COLUMNLIST)) return new QueryColumnRef(this,key,Types.INTEGER);
        }
        return defaultValue;
  }
 
  @Override
  public String toString() {
    Collection.Key[] keys=keys();
   
    StringBuffer sb=new StringBuffer();

    sb.append("Query\n");
    sb.append("---------------------------------------------------\n");
   
    if(sql!=null) {
      sb.append(sql+"\n");
      sb.append("---------------------------------------------------\n");
    }

    if(exeTime>0)  {
      sb.append("Execution Time (ns): "+exeTime+"\n");
      sb.append("---------------------------------------------------\n");
    }
   
    sb.append("Recordcount: "+getRecordcount()+"\n");
    sb.append("---------------------------------------------------\n");
    String trenner="";
    for(int i=0;i<keys.length;i++) {
      trenner+="+---------------------";
    }
    trenner+="+\n";
    sb.append(trenner);
 
  // Header
    for(int i=0;i<keys.length;i++) {
      sb.append(getToStringField(keys[i].getString()));
    }
    sb.append("|\n");
    sb.append(trenner);
    sb.append(trenner);
   
  // body
    for(int i=0;i<recordcount;i++) {
      for(int y=0;y<keys.length;y++) {
        try {
          Object o=getAt(keys[y],i+1);
          if(o instanceof String)sb.append(getToStringField(o.toString()));
          else if(o instanceof Number) sb.append(getToStringField(Caster.toString(((Number)o))));
          else if(o instanceof Clob) sb.append(getToStringField(Caster.toString(o)));             
          else sb.append(getToStringField(o.toString()));
        } catch (PageException e) {
          sb.append(getToStringField("[empty]"));
        }
      }
      sb.append("|\n");
      sb.append(trenner);
    }
    return sb.toString();
  }

  private String getToStringField(String str) {
    if(str==null) return "|                    ";
    else if(str.length()<21) {
      String s="|"+str;
      for(int i=str.length();i<21;i++)s+=" ";
      return s;
    }
    else if(str.length()==21) return "|"+str;
    else  return "|"+str.substring(0,18)+"...";
  }
 
  /**
   *
   * @param type
   * @return return String represetation of a Type from int type
   */
  public static String getColumTypeName(int type) {
    switch(type) {
      case Types.ARRAY: return "OBJECT";
      case Types.BIGINT: return "BIGINT";
      case Types.BINARY: return "BINARY";
      case Types.BIT: return "BIT";
      case Types.BLOB: return "OBJECT";
      case Types.BOOLEAN: return "BOOLEAN";
      case Types.CHAR: return "CHAR";
      case Types.NCHAR: return "NCHAR";
      case Types.CLOB: return "OBJECT";
      case Types.NCLOB: return "OBJECT";
      case Types.DATALINK: return "OBJECT";
      case Types.DATE: return "DATE";
      case Types.DECIMAL: return "DECIMAL";
      case Types.DISTINCT: return "OBJECT";
      case Types.DOUBLE: return "DOUBLE";
      case Types.FLOAT: return "DOUBLE";
      case Types.INTEGER: return "INTEGER";
      case Types.JAVA_OBJECT: return "OBJECT";
      case Types.LONGVARBINARY: return "LONGVARBINARY";
      case Types.LONGVARCHAR: return "LONGVARCHAR";
      case Types.NULL: return "OBJECT";
      case Types.NUMERIC: return "NUMERIC";
      case Types.OTHER: return "OBJECT";
      case Types.REAL: return "REAL";
      case Types.REF: return "OBJECT";
      case Types.SMALLINT: return "SMALLINT";
      case Types.STRUCT: return "OBJECT";
      case Types.TIME: return "TIME";
      case Types.TIMESTAMP: return "TIMESTAMP";
      case Types.TINYINT: return "TINYINT";
      case Types.VARBINARY: return "VARBINARY";
      case Types.NVARCHAR: return "NVARCHAR";
      case Types.SQLXML: return "SQLXML";
      case Types.VARCHAR: return "VARCHAR";
      default : return "VARCHAR";
    }
  }

  private int getIndexFromKey(String key) {
    String lc = StringUtil.toLowerCase(key);
    for(int i=0;i<columnNames.length;i++) {
      if(columnNames[i].getLowerString().equals(lc)) return i;
    }
    return -1;
  }
 
  private int getIndexFromKey(Collection.Key key) {
   
    for(int i=0;i<columnNames.length;i++) {
      if(columnNames[i].equalsIgnoreCase(key)) return i;
    }
    return -1;
  }
 
  @Override
  public void setExecutionTime(long exeTime) {
    this.exeTime=exeTime;
  }

    /**
     * @param maxrows
     * @return has cutted or not
     */
    public synchronized boolean cutRowsTo(int maxrows) {
        //disconnectCache();
       
        if(maxrows>-1 && maxrows<getRecordcount()) {
       for(int i=0;i<columns.length;i++) {
         QueryColumn column = columns[i];
         column.cutRowsTo(maxrows);
       }
       recordcount=maxrows;
       return true;
        }
        return false;
    }

    @Override
    public void setCached(boolean isCached) {
        this.isCached=isCached;
    }

    @Override
    public boolean isCached() {
        return isCached;
    }



    @Override
    public int addRow() {
    addRow(1);
    return getRecordcount();
    }


    public Key getColumnName(int columnIndex) {
      Key[] keys = keys();
    if(columnIndex<1 || columnIndex>keys.length) return null;
    return keys[columnIndex-1];
    }

    @Override
    public int getColumnIndex(String coulmnName) {
        Collection.Key[] keys = keys();
    for(int i=0;i<keys.length;i++) {
      if(keys[i].getString().equalsIgnoreCase(coulmnName)) return i+1;
    }
    return -1;
    }



    @Override
    public String[] getColumns() {
        return getColumnNamesAsString();
    }
   
    @Override
    public Collection.Key[] getColumnNames() {
      Collection.Key[] keys = keys();
      Collection.Key[] rtn=new Collection.Key[keys.length];
    System.arraycopy(keys,0,rtn,0,keys.length);
    return rtn;
    }
   
    public void setColumnNames(Collection.Key[] trg) throws PageException {
      columncount=trg.length;
      Collection.Key[] src = keys();
     
      // target < source
      if(trg.length<src.length){
        this.columnNames=new Collection.Key[trg.length];
        QueryColumnImpl[] tmp=new QueryColumnImpl[trg.length];
        for(int i=0;i<trg.length;i++){
          this.columnNames[i]=trg[i];
          tmp[i]=this.columns[i];
          tmp[i].setKey(trg[i]);
          }
        this.columns=tmp;
        return;
      }
     
      if(trg.length>src.length){
        int recordcount=getRecordcount();
        for(int i=src.length;i<trg.length;i++){
         
          Array arr=new ArrayImpl();
          for(int r=1;r<=recordcount;r++){
            arr.setE(i,"");
          }
          addColumn(trg[i], arr);
        }
        src = keys();
      }
     
    for(int i=0;i<trg.length;i++){
      this.columnNames[i]=trg[i];
      this.columns[i].setKey(trg[i]);
      }
    }
   


  @Override
  public String[] getColumnNamesAsString() {
    return CollectionUtil.keysAsString(this);
  }
 
  public int getColumnCount() {
    return columncount;
  }

    @Override
    public String getData(int row, int col) throws IndexOutOfBoundsException {
        Collection.Key[] keys = keys();
    if(col<1 || col>keys.length) {
      new IndexOutOfBoundsException("invalid column index to retrieve Data from query, valid index goes from 1 to "+keys.length);
    }
   
    Object o=getAt(keys[col-1],row,NullSupportHelper.NULL());
    if(o==NullSupportHelper.NULL())
      throw new IndexOutOfBoundsException("invalid row index to retrieve Data from query, valid index goes from 1 to "+getRecordcount());
    return Caster.toString( o,NullSupportHelper.full()?null:"");
    }



    @Override
    public String getName() {
        return this.name;
    }



    @Override
    public int getRowCount() {
        return getRecordcount();
    }



    @Override
    public void setData(int row, int col, String value) throws IndexOutOfBoundsException {
        Collection.Key[] keys = keys();
    if(col<1 || col>keys.length) {
      new IndexOutOfBoundsException("invalid column index to retrieve Data from query, valid index goes from 1 to "+keys.length);
    }
    try {
      setAt(keys[col-1],row,value);
    }
    catch (PageException e) {
      throw new IndexOutOfBoundsException("invalid row index to retrieve Data from query, valid index goes from 1 to "+getRecordcount());
    }
    }

    @Override
    public boolean containsKey(String key) {
        return getColumn(key,null)!=null;
   

  @Override
  public boolean containsKey(Collection.Key key) {
        return getColumn(key,null)!=null;
  }
 
    @Override
    public String castToString() throws ExpressionException {
        throw new ExpressionException("Can't cast Complex Object Type Query to String",
          "Use Built-In-Function \"serialize(Query):String\" to create a String from Query");
    }

  @Override
  public String castToString(String defaultValue) {
    return defaultValue;
  }


    @Override
    public boolean castToBooleanValue() throws ExpressionException {
        throw new ExpressionException("Can't cast Complex Object Type Query to a boolean value");
    }
   
    @Override
    public Boolean castToBoolean(Boolean defaultValue) {
        return defaultValue;
    }


    @Override
    public double castToDoubleValue() throws ExpressionException {
        throw new ExpressionException("Can't cast Complex Object Type Query to a number value");
    }
   
    @Override
    public double castToDoubleValue(double defaultValue) {
        return defaultValue;
    }


    @Override
    public DateTime castToDateTime() throws ExpressionException {
        throw new ExpressionException("Can't cast Complex Object Type Query to a Date");
    }
   
    @Override
    public DateTime castToDateTime(DateTime defaultValue) {
        return defaultValue;
    }

  @Override
  public int compareTo(boolean b) throws ExpressionException {
    throw new ExpressionException("can't compare Complex Object Type Query with a boolean value");
  }

  @Override
  public int compareTo(DateTime dt) throws PageException {
    throw new ExpressionException("can't compare Complex Object Type Query with a DateTime Object");
  }

  @Override
  public int compareTo(double d) throws PageException {
    throw new ExpressionException("can't compare Complex Object Type Query with a numeric value");
  }

  @Override
  public int compareTo(String str) throws PageException {
    throw new ExpressionException("can't compare Complex Object Type Query with a String");
  }

    public synchronized Array getMetaDataSimple() {
      Array cols=new ArrayImpl();
      Struct column;
        for(int i=0;i<columns.length;i++) {
          column=new StructImpl();
          column.setEL(KeyConstants._name,columnNames[i].getString());
          column.setEL("isCaseSensitive",Boolean.FALSE);
          column.setEL("typeName",columns[i].getTypeAsString());
          cols.appendEL(column);
        }
        return cols;
    }

  /**
   * @return the sql
   */
  public SQL getSql() {
    return sql;
  }

  /**
   * @param sql the sql to set
   */
  public void setSql(SQL sql) {
    this.sql = sql;
  }


  @Override
  public Object getObject(String columnName) throws SQLException {
    int currentrow;
    if((currentrow=arrCurrentRow.get(getPid(),0))==0) return null;
    return getAt(columnName,currentrow,null);
  }
 
  @Override
  public Object getObject(int columnIndex) throws SQLException {
    if(columnIndex>0 && columnIndex<=columncount) return  getObject(this.columnNames[columnIndex-1].getString());
    return null;
  }
 
  @Override
  public String getString(int columnIndex) throws SQLException {
    Object rtn = getObject(columnIndex);
    if(rtn==null)return null;
    if(Decision.isCastableToString(rtn)) return Caster.toString(rtn,null);
    throw new SQLException("can't cast value to string");
  }
 
  @Override
  public String getString(String columnName) throws SQLException {
    Object rtn = getObject(columnName);
    if(rtn==null)return null;
    if(Decision.isCastableToString(rtn)) return Caster.toString(rtn,null);
    throw new SQLException("can't cast value to string");
  }
 
  @Override
  public boolean getBoolean(int columnIndex) throws SQLException {
    Object rtn = getObject(columnIndex);
    if(rtn==null)return false;
    if(Decision.isCastableToBoolean(rtn)) return Caster.toBooleanValue(rtn,false);
    throw new SQLException("can't cast value to boolean");
  }
 
  @Override
  public boolean getBoolean(String columnName) throws SQLException {
    Object rtn = getObject(columnName);
    if(rtn==null)return false;
    if(Decision.isCastableToBoolean(rtn)) return Caster.toBooleanValue(rtn,false);
    throw new SQLException("can't cast value to boolean");
  }
 
 
  // ---------------------------------------

  @Override
  public Object call(PageContext pc, Key methodName, Object[] arguments) throws PageException {
    return MemberUtil.call(pc, this, methodName, arguments, railo.commons.lang.CFTypes.TYPE_QUERY, "query");
    //return Reflector.callMethod(this,methodName,arguments);
  }

  @Override
  public Object callWithNamedValues(PageContext pc, Key methodName, Struct args) throws PageException
    return MemberUtil.callWithNamedValues(pc, this, methodName, args,railo.commons.lang.CFTypes.TYPE_QUERY, "query");
  }

  @Override
  public Object get(PageContext pc, Key key, Object defaultValue) {
    return getAt(key,arrCurrentRow.get(
        pc.getId(),1),defaultValue);
  }

  @Override
  public Object get(PageContext pc, Key key) throws PageException {
    return getAt(key,arrCurrentRow.get(pc.getId(),1));
  }

  public boolean isInitalized() {
    return true;
  }

  @Override
  public Object set(PageContext pc, Key propertyName, Object value) throws PageException {
    return setAt(propertyName,arrCurrentRow.get(pc.getId(),1),value);
  }

  @Override
  public Object setEL(PageContext pc, Key propertyName, Object value) {
    return setAtEL(propertyName,arrCurrentRow.get(pc.getId(),1),value);
  }
 
  @Override
  public boolean wasNull() {
    throw new PageRuntimeException(new ApplicationException("method [wasNull] is not supported"));
  }

  @Override
  public boolean absolute(int row) throws SQLException {
    if(recordcount==0) {
      if(row!=0) throw new SQLException("invalid row ["+row+"], query is Empty");
      return false;
    }
    //row=row%recordcount;
   
    if(row>0) arrCurrentRow.set(getPid(),row);
    else arrCurrentRow.set(getPid(),(recordcount+1)+row);
    return true;
  }

  @Override
  public void afterLast() throws SQLException {
    arrCurrentRow.set(getPid(),recordcount+1);
  }

  @Override
  public void beforeFirst() throws SQLException {
    arrCurrentRow.set(getPid(),0);
  }

  @Override
  public void cancelRowUpdates() throws SQLException {
    // ignored
  }

  @Override
  public void clearWarnings() throws SQLException {
    // ignored
  }

  @Override
  public void close() throws SQLException {
    // ignored
  }

  @Override
  public void deleteRow() throws SQLException {
    try {
      removeRow(arrCurrentRow.get(getPid()));
    } catch (Exception e) {
      throw new SQLException(e.getMessage());
    }
  }

  @Override
  public int findColumn(String columnName) throws SQLException {
    int index= getColumnIndex(columnName);
    if(index==-1) throw new SQLException("invald column definitions ["+columnName+"]");
    return index;
  }

  @Override
  public boolean first() throws SQLException {
    return absolute(1);
  }

  public java.sql.Array getArray(int i) throws SQLException {
    throw new SQLException("method is not implemented");
  }

  public java.sql.Array getArray(String colName) throws SQLException {
    throw new SQLException("method is not implemented");
  }

  @Override
  public InputStream getAsciiStream(int columnIndex) throws SQLException {
    String res = getString(columnIndex);
    if(res==null)return null;
    return new ByteArrayInputStream(res.getBytes());
  }

  @Override
  public InputStream getAsciiStream(String columnName) throws SQLException {
    String res = getString(columnName);
    if(res==null)return null;
    return new ByteArrayInputStream(res.getBytes());
  }

  @Override
  public BigDecimal getBigDecimal(int columnIndex) throws SQLException {
    return new BigDecimal(getDouble(columnIndex));
  }

  @Override
  public BigDecimal getBigDecimal(String columnName) throws SQLException {
    return new BigDecimal(getDouble(columnName));
  }

  @Override
  public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException {
    return new BigDecimal(getDouble(columnIndex));
  }

  @Override
  public BigDecimal getBigDecimal(String columnName, int scale) throws SQLException {
    return new BigDecimal(getDouble(columnName));
  }

  @Override
  public InputStream getBinaryStream(int columnIndex) throws SQLException {
    Object obj = getObject(columnIndex);
    if(obj==null)return null;
    try {
      return Caster.toInputStream(obj,(Charset)null);
    } catch (Exception e) {
      throw new SQLException(e.getMessage());
    }
  }

  @Override
  public InputStream getBinaryStream(String columnName) throws SQLException {
    Object obj = getObject(columnName);
    if(obj==null)return null;
    try {
      return Caster.toInputStream(obj,(Charset)null);
    } catch (Exception e) {
      throw new SQLException(e.getMessage());
    }
  }

  @Override
  public Blob getBlob(int i) throws SQLException {
    byte[] bytes = getBytes(i);
    if(bytes==null) return null;
    try {
      return BlobImpl.toBlob(bytes);
    }
    catch (PageException e) {
      throw new SQLException(e.getMessage());
    }
  }

  @Override
  public Blob getBlob(String colName) throws SQLException {
    byte[] bytes = getBytes(colName);
    if(bytes==null) return null;
    try {
      return BlobImpl.toBlob(bytes);
    } catch (PageException e) {
      throw new SQLException(e.getMessage());
    }
  }

  @Override
  public byte getByte(int columnIndex) throws SQLException {
    Object obj = getObject(columnIndex);
    if(obj==null) return (byte)0;
    try {
      return Caster.toByteValue(obj);
    } catch (PageException e) {
      throw new SQLException(e.getMessage());
    }
  }

  @Override
  public byte getByte(String columnName) throws SQLException {
    Object obj = getObject(columnName);
    if(obj==null) return (byte)0;
    try {
      return Caster.toByteValue(obj);
    } catch (PageException e) {
      throw new SQLException(e.getMessage());
    }
  }

  @Override
  public byte[] getBytes(int columnIndex) throws SQLException {
    Object obj = getObject(columnIndex);
    if(obj==null) return null;
    try {
      return Caster.toBytes(obj,(Charset)null);
    } catch (Exception e) {
      throw new SQLException(e.getMessage());
    }
  }

  @Override
  public byte[] getBytes(String columnName) throws SQLException {
    Object obj = getObject(columnName);
    if(obj==null) return null;
    try {
      return Caster.toBytes(obj,(Charset)null);
    } catch (Exception e) {
      throw new SQLException(e.getMessage());
    }
  }

  @Override
  public Reader getCharacterStream(int columnIndex) throws SQLException {
    String str=getString(columnIndex);
    if(str==null) return null;
    return new StringReader(str);
  }

  @Override
  public Reader getCharacterStream(String columnName) throws SQLException {
    String str=getString(columnName);
    if(str==null) return null;
    return new StringReader(str);
  }

  @Override
  public Clob getClob(int i) throws SQLException {
    String str=getString(i);
    if(str==null) return null;
    return ClobImpl.toClob(str);
  }

  @Override
  public Clob getClob(String colName) throws SQLException {
    String str=getString(colName);
    if(str==null) return null;
    return ClobImpl.toClob(str);
  }

  @Override
  public int getConcurrency() throws SQLException {
    return 0;
  }

  @Override
  public String getCursorName() throws SQLException {
    return null;
  }

  @Override
  public java.sql.Date getDate(int columnIndex) throws SQLException {
    Object obj=getObject(columnIndex);
    if(obj==null) return null;
    try {
      return new java.sql.Date(Caster.toDate(obj, false, null).getTime());
    } catch (PageException e) {
      throw new SQLException(e.getMessage());
    }
  }

  @Override
  public java.sql.Date getDate(String columnName) throws SQLException {
    Object obj=getObject(columnName);
    if(obj==null) return null;
    try {
      return new java.sql.Date(Caster.toDate(obj, false, null).getTime());
    } catch (PageException e) {
      throw new SQLException(e.getMessage());
    }
  }

  @Override
  public java.sql.Date getDate(int columnIndex, Calendar cal)throws SQLException {
    return getDate(columnIndex); // TODO impl
  }

  @Override
  public java.sql.Date getDate(String columnName, Calendar cal) throws SQLException {
    return getDate(columnName);// TODO impl
  }

  @Override
  public double getDouble(int columnIndex) throws SQLException {
    Object obj=getObject(columnIndex);
    if(obj==null) return 0;
    try {
      return Caster.toDoubleValue(obj);
    } catch (PageException e) {
      throw new SQLException(e.getMessage());
    }
  }

  @Override
  public double getDouble(String columnName) throws SQLException {
    Object obj=getObject(columnName);
    if(obj==null) return 0;
    try {
      return Caster.toDoubleValue(obj);
    } catch (PageException e) {
      throw new SQLException(e.getMessage());
    }
  }

  @Override
  public int getFetchDirection() throws SQLException {
    return 1000;
  }

  @Override
  public int getFetchSize() throws SQLException {
    return 0;
  }

  @Override
  public float getFloat(int columnIndex) throws SQLException {
    Object obj=getObject(columnIndex);
    if(obj==null) return 0;
    try {
      return Caster.toFloatValue(obj);
    } catch (PageException e) {
      throw new SQLException(e.getMessage());
    }
  }

  @Override
  public float getFloat(String columnName) throws SQLException {
    Object obj=getObject(columnName);
    if(obj==null) return 0;
    try {
      return Caster.toFloatValue(obj);
    } catch (PageException e) {
      throw new SQLException(e.getMessage());
    }
  }

  @Override
  public int getInt(int columnIndex) throws SQLException {
    Object obj=getObject(columnIndex);
    if(obj==null) return 0;
    try {
      return Caster.toIntValue(obj);
    } catch (PageException e) {
      throw new SQLException(e.getMessage());
    }
  }

  @Override
  public int getInt(String columnName) throws SQLException {
    Object obj=getObject(columnName);
    if(obj==null) return 0;
    try {
      return Caster.toIntValue(obj);
    } catch (PageException e) {
      throw new SQLException(e.getMessage());
    }
  }

  @Override
  public long getLong(int columnIndex) throws SQLException {
    Object obj=getObject(columnIndex);
    if(obj==null) return 0;
    try {
      return Caster.toLongValue(obj);
    } catch (PageException e) {
      throw new SQLException(e.getMessage());
    }
  }

  @Override
  public long getLong(String columnName) throws SQLException {
    Object obj=getObject(columnName);
    if(obj==null) return 0;
    try {
      return Caster.toLongValue(obj);
    } catch (PageException e) {
      throw new SQLException(e.getMessage());
    }
  }

  @Override
  public Object getObject(int i, Map map) throws SQLException {
    throw new SQLException("method is not implemented");
  }

  @Override
  public Object getObject(String colName, Map map) throws SQLException {
    throw new SQLException("method is not implemented");
  }

  // used only with java 7, do not set @Override
  public <T> T getObject(int columnIndex, Class<T> type) throws SQLException {
    return (T) QueryUtil.getObject(this,columnIndex, type);
  }

  // used only with java 7, do not set @Override
  public <T> T getObject(String columnLabel, Class<T> type) throws SQLException {
    return (T) QueryUtil.getObject(this,columnLabel, type);
  }

  @Override
  public Ref getRef(int i) throws SQLException {
    throw new SQLException("method is not implemented");
  }

  @Override
  public Ref getRef(String colName) throws SQLException {
    throw new SQLException("method is not implemented");
  }

  @Override
  public int getRow() throws SQLException {
    return arrCurrentRow.get(getPid(),0);
  }

  @Override
  public short getShort(int columnIndex) throws SQLException {
    Object obj=getObject(columnIndex);
    if(obj==null) return 0;
    try {
      return Caster.toShortValue(obj);
    } catch (PageException e) {
      throw new SQLException(e.getMessage());
    }
  }

  @Override
  public short getShort(String columnName) throws SQLException {
    Object obj=getObject(columnName);
    if(obj==null) return 0;
    try {
      return Caster.toShortValue(obj);
    } catch (PageException e) {
      throw new SQLException(e.getMessage());
    }
  }

  public Statement getStatement() throws SQLException {
    throw new SQLException("method is not implemented");
  }

  @Override
  public Time getTime(int columnIndex) throws SQLException {
    Object obj=getObject(columnIndex);
    if(obj==null) return null;
    try {
      return new Time(DateCaster.toTime(null, obj).getTime());
    } catch (PageException e) {
      throw new SQLException(e.getMessage());
    }
  }

  @Override
  public Time getTime(String columnName) throws SQLException {
    Object obj=getObject(columnName);
    if(obj==null) return null;
    try {
      return new Time(DateCaster.toTime(null, obj).getTime());
    } catch (PageException e) {
      throw new SQLException(e.getMessage());
    }
  }

  @Override
  public Time getTime(int columnIndex, Calendar cal) throws SQLException {
    return getTime(columnIndex);// TODO impl
  }

  @Override
  public Time getTime(String columnName, Calendar cal) throws SQLException {
    return getTime(columnName);// TODO impl
  }

  @Override
  public Timestamp getTimestamp(int columnIndex) throws SQLException {
    Object obj=getObject(columnIndex);
    if(obj==null) return null;
    try {
      return new Timestamp(DateCaster.toTime(null, obj).getTime());
    } catch (PageException e) {
      throw new SQLException(e.getMessage());
    }
  }

  @Override
  public Timestamp getTimestamp(String columnName) throws SQLException {
    Object obj=getObject(columnName);
    if(obj==null) return null;
    try {
      return new Timestamp(DateCaster.toTime(null, obj).getTime());
    } catch (PageException e) {
      throw new SQLException(e.getMessage());
    }
  }

  @Override
  public Timestamp getTimestamp(int columnIndex, Calendar cal) throws SQLException {
    return getTimestamp(columnIndex);// TODO impl
  }

  @Override
  public Timestamp getTimestamp(String columnName, Calendar cal) throws SQLException {
    return getTimestamp(columnName);// TODO impl
  }

  @Override
  public int getType() throws SQLException {
    return 0;
  }

  @Override
  public URL getURL(int columnIndex) throws SQLException {
    throw new SQLException("method is not implemented");
  }

  @Override
  public URL getURL(String columnName) throws SQLException {
    throw new SQLException("method is not implemented");
  }

  @Override
  public InputStream getUnicodeStream(int columnIndex) throws SQLException {
    String str=getString(columnIndex);
    if(str==null) return null;
    try {
      return new ByteArrayInputStream(str.getBytes("UTF-8"));
    }
    catch (UnsupportedEncodingException e) {
      throw new SQLException(e.getMessage());
    }
  }

  @Override
  public InputStream getUnicodeStream(String columnName) throws SQLException {
    String str=getString(columnName);
    if(str==null) return null;
    try {
      return new ByteArrayInputStream(str.getBytes("UTF-8"));
    }
    catch (UnsupportedEncodingException e) {
      throw new SQLException(e.getMessage());
    }
  }

  @Override
  public SQLWarning getWarnings() throws SQLException {
    throw new SQLException("method is not implemented");
  }

  @Override
  public void insertRow() throws SQLException {
    throw new SQLException("method is not implemented");
  }

  @Override
  public boolean isAfterLast() throws SQLException {
    return getCurrentrow(ThreadLocalPageContext.get().getId())>recordcount;
  }

  @Override
  public boolean isBeforeFirst() throws SQLException {
    return arrCurrentRow.get(getPid(),0)==0;
  }

  @Override
  public boolean isFirst() throws SQLException {
    return arrCurrentRow.get(getPid(),0)==1;
  }

  public boolean isLast() throws SQLException {
    return arrCurrentRow.get(getPid(),0)==recordcount;
  }

  public boolean last() throws SQLException {
    return absolute(recordcount);
  }

  public void moveToCurrentRow() throws SQLException {
    // ignore
  }

  public void moveToInsertRow() throws SQLException {
    // ignore
  }


  public boolean previous() {
    return previous(getPid());
  }
 
  public boolean previous(int pid) {
    if(0<(arrCurrentRow.set(pid,arrCurrentRow.get(pid,0)-1))) {
      return true;
    }
    arrCurrentRow.set(pid,0);
    return false;
  }

  public void refreshRow() throws SQLException {
    // ignore
   
  }

  @Override
  public boolean relative(int rows) throws SQLException {
    return absolute(getRow()+rows);
  }

  @Override
  public boolean rowDeleted() throws SQLException {
    return false;
  }

  @Override
  public boolean rowInserted() throws SQLException {
    return false;
  }

  @Override
  public boolean rowUpdated() throws SQLException {
    return false;
  }

  public void setFetchDirection(int direction) throws SQLException {
    // ignore
  }

  public void setFetchSize(int rows) throws SQLException {
    // ignore
  }

  @Override
  public void updateArray(int columnIndex, java.sql.Array x)throws SQLException {
    updateObject(columnIndex, x.getArray());
  }

  @Override
  public void updateArray(String columnName, java.sql.Array x)throws SQLException {
    updateObject(columnName, x.getArray());
  }

  @Override
  public void updateAsciiStream(int columnIndex, InputStream x, int length)throws SQLException {
    updateBinaryStream(columnIndex, x, length);
  }

  @Override
  public void updateAsciiStream(String columnName, InputStream x, int length)throws SQLException {
    updateBinaryStream(columnName, x, length);
  }

  @Override
  public void updateBigDecimal(int columnIndex, BigDecimal x)throws SQLException {
    updateObject(columnIndex, x.toString());
  }

  @Override
  public void updateBigDecimal(String columnName, BigDecimal x) throws SQLException {
    updateObject(columnName, x.toString());
  }

  @Override
  public void updateBinaryStream(int columnIndex, InputStream x, int length) throws SQLException {
    try {
      updateObject(columnIndex, IOUtil.toBytesMax(x, length));
    } catch (IOException e) {
      throw new SQLException(e.getMessage());
    }
  }

  @Override
  public void updateBinaryStream(String columnName, InputStream x, int length) throws SQLException {
    try {
      updateObject(columnName, IOUtil.toBytesMax(x, length));
    } catch (IOException e) {
      throw new SQLException(e.getMessage());
    }
  }

  @Override
  public void updateBlob(int columnIndex, Blob x) throws SQLException {
    try {
      updateObject(columnIndex, toBytes(x));
    } catch (IOException e) {
      throw new SQLException(e.getMessage());
    }
  }

  @Override
  public void updateBlob(String columnName, Blob x) throws SQLException {
    try {
      updateObject(columnName, toBytes(x));
    } catch (IOException e) {
      throw new SQLException(e.getMessage());
    }
  }

  @Override
  public void updateBoolean(int columnIndex, boolean x) throws SQLException {
    updateObject(columnIndex, Caster.toBoolean(x));
  }

  @Override
  public void updateBoolean(String columnName, boolean x) throws SQLException {
    updateObject(columnName, Caster.toBoolean(x));
  }

  @Override
  public void updateByte(int columnIndex, byte x) throws SQLException {
    updateObject(columnIndex, new Byte(x));
  }

  @Override
  public void updateByte(String columnName, byte x) throws SQLException {
    updateObject(columnName, new Byte(x));
  }

  @Override
  public void updateBytes(int columnIndex, byte[] x) throws SQLException {
    updateObject(columnIndex, x);
  }

  @Override
  public void updateBytes(String columnName, byte[] x) throws SQLException {
    updateObject(columnName, x);
  }

  @Override
  public void updateCharacterStream(int columnIndex, Reader reader, int length)throws SQLException {
    try {
      updateObject(columnIndex, IOUtil.toString(reader));
    } catch (Exception e) {
      throw new SQLException(e.getMessage());
    }
  }

  @Override
  public void updateCharacterStream(String columnName, Reader reader,int length) throws SQLException {
    try {
      updateObject(columnName, IOUtil.toString(reader));
    } catch (Exception e) {
      throw new SQLException(e.getMessage());
    }
  }

  @Override
  public void updateClob(int columnIndex, Clob x) throws SQLException {
    try {
      updateObject(columnIndex, toString(x));
    } catch (IOException e) {
      throw new SQLException(e.getMessage());
    }
  }

  @Override
  public void updateClob(String columnName, Clob x) throws SQLException {
    try {
      updateObject(columnName, toString(x));
    } catch (IOException e) {
      throw new SQLException(e.getMessage());
    }
  }

  @Override
  public void updateDate(int columnIndex, java.sql.Date x)throws SQLException {
    updateObject(columnIndex, Caster.toDate(x, false, null, null));
  }

  @Override
  public void updateDate(String columnName, java.sql.Date x)throws SQLException {
    updateObject(columnName, Caster.toDate(x, false, null, null));
  }

  @Override
  public void updateDouble(int columnIndex, double x) throws SQLException {
    updateObject(columnIndex, Caster.toDouble(x));
  }

  @Override
  public void updateDouble(String columnName, double x) throws SQLException {
    updateObject(columnName, Caster.toDouble(x));
  }

  @Override
  public void updateFloat(int columnIndex, float x) throws SQLException {
    updateObject(columnIndex, Caster.toDouble(x));
  }

  @Override
  public void updateFloat(String columnName, float x) throws SQLException {
    updateObject(columnName, Caster.toDouble(x));
  }

  @Override
  public void updateInt(int columnIndex, int x) throws SQLException {
    updateObject(columnIndex, Caster.toDouble(x));
  }

  @Override
  public void updateInt(String columnName, int x) throws SQLException {
    updateObject(columnName, Caster.toDouble(x));
  }

  @Override
  public void updateLong(int columnIndex, long x) throws SQLException {
    updateObject(columnIndex, Caster.toDouble(x));
  }

  @Override
  public void updateLong(String columnName, long x) throws SQLException {
    updateObject(columnName, Caster.toDouble(x));
  }

  @Override
  public void updateNull(int columnIndex) throws SQLException {
    updateObject(columnIndex, null);
  }

  @Override
  public void updateNull(String columnName) throws SQLException {
    updateObject(columnName, null);
  }

  @Override
  public void updateObject(int columnIndex, Object x) throws SQLException {
    try {
      set(getColumnName(columnIndex), x);
    } catch (PageException e) {
      throw new SQLException(e.getMessage());
    }
  }

  @Override
  public void updateObject(String columnName, Object x) throws SQLException {
    try {
      set(KeyImpl.init(columnName), x);
    } catch (PageException e) {
      throw new SQLException(e.getMessage());
    }
  }

  @Override
  public void updateObject(int columnIndex, Object x, int scale)throws SQLException {
    updateObject(columnIndex, x);
  }

  @Override
  public void updateObject(String columnName, Object x, int scale)throws SQLException {
    updateObject(columnName, x);
  }

  @Override
  public void updateRef(int columnIndex, Ref x) throws SQLException {
    updateObject(columnIndex, x.getObject());
  }

  @Override
  public void updateRef(String columnName, Ref x) throws SQLException {
    updateObject(columnName, x.getObject());
  }

  public void updateRow() throws SQLException {
    throw new SQLException("method is not implemented");
  }

  @Override
  public void updateShort(int columnIndex, short x) throws SQLException {
    updateObject(columnIndex, Caster.toDouble(x));
  }

  @Override
  public void updateShort(String columnName, short x) throws SQLException {
    updateObject(columnName, Caster.toDouble(x));
  }

  @Override
  public void updateString(int columnIndex, String x) throws SQLException {
    updateObject(columnIndex, x);
  }

  @Override
  public void updateString(String columnName, String x) throws SQLException {
    updateObject(columnName, x);
  }

  @Override
  public void updateTime(int columnIndex, Time x) throws SQLException {
    updateObject(columnIndex, new DateTimeImpl(x.getTime(),false));
  }

  @Override
  public void updateTime(String columnName, Time x) throws SQLException {
    updateObject(columnName, new DateTimeImpl(x.getTime(),false));
  }

  @Override
  public void updateTimestamp(int columnIndex, Timestamp x) throws SQLException {
    updateObject(columnIndex, new DateTimeImpl(x.getTime(),false));
  }

  @Override
  public void updateTimestamp(String columnName, Timestamp x) throws SQLException {
    updateObject(columnName, new DateTimeImpl(x.getTime(),false));
  }

  @Override
  public ResultSetMetaData getMetaData() throws SQLException {
    throw new SQLException("method is not implemented");
  }

  @Override
  public Iterator<Collection.Key> keyIterator() {
    return new KeyIterator(keys());
  }
   
  @Override
  public Iterator<String> keysAsStringIterator() {
      return new StringIterator(keys());
    }
 
  @Override
  public Iterator<Entry<Key, Object>> entryIterator() {
    return new EntryIterator(this, keys());
  }
 
  public Iterator<Object> valueIterator() {
    return new CollectionIterator(keys(),this);
  }

  public void readExternal(ObjectInput in) throws IOException {
    try {
      QueryImpl other=(QueryImpl) new CFMLExpressionInterpreter().interpret(ThreadLocalPageContext.get(),in.readUTF());
      this.arrCurrentRow=other.arrCurrentRow;
      this.columncount=other.columncount;
      this.columnNames=other.columnNames;
      this.columns=other.columns;
      this.exeTime=other.exeTime;
      this.generatedKeys=other.generatedKeys;
      this.isCached=other.isCached;
      this.name=other.name;
      this.recordcount=other.recordcount;
      this.sql=other.sql;
      this.updateCount=other.updateCount;
     
    } catch (PageException e) {
      throw new IOException(e.getMessage());
    }
  }

  public void writeExternal(ObjectOutput out) {
    try {
      out.writeUTF(new ScriptConverter().serialize(this));
    }
    catch (Throwable t) {}
  }

  public int getHoldability() throws SQLException {
    throw notSupported();
  }

  public boolean isClosed() throws SQLException {
    return false;
  }

  public void updateNString(int columnIndex, String nString)throws SQLException {
    updateString(columnIndex, nString);
  }

  public void updateNString(String columnLabel, String nString)throws SQLException {
    updateString(columnLabel, nString);
  }

 

  public String getNString(int columnIndex) throws SQLException {
    return getString(columnIndex);
  }

  public String getNString(String columnLabel) throws SQLException {
    return getString(columnLabel);
  }

  public Reader getNCharacterStream(int columnIndex) throws SQLException {
    return getCharacterStream(columnIndex);
  }

  public Reader getNCharacterStream(String columnLabel) throws SQLException {
    return getCharacterStream(columnLabel);
  }

  public void updateNCharacterStream(int columnIndex, Reader x, long length)throws SQLException {
    updateCharacterStream(columnIndex, x, length);
  }

  public void updateNCharacterStream(String columnLabel, Reader reader,long length) throws SQLException {
    throw notSupported();
  }

  public void updateAsciiStream(int columnIndex, InputStream x, long length)throws SQLException {
    throw notSupported();
  }

  public void updateBinaryStream(int columnIndex, InputStream x, long length)throws SQLException {
    throw notSupported();
  }

  public void updateCharacterStream(int columnIndex, Reader x, long length) throws SQLException {
    throw notSupported();
  }

  public void updateAsciiStream(String columnLabel, InputStream x, long length)throws SQLException {
    throw notSupported();
  }

  public void updateBinaryStream(String columnLabel, InputStream x,long length) throws SQLException {
    throw notSupported();
  }

  public void updateCharacterStream(String columnLabel, Reader reader,long length) throws SQLException {
    throw notSupported();
  }

  public void updateBlob(int columnIndex, InputStream inputStream, long length) throws SQLException {
    throw notSupported();
  }

  public void updateBlob(String columnLabel, InputStream inputStream,long length) throws SQLException {
    throw notSupported();
  }

  public void updateClob(int columnIndex, Reader reader, long length) throws SQLException {
    throw notSupported();
  }

  public void updateClob(String columnLabel, Reader reader, long length) throws SQLException {
    throw notSupported();
  }

  public void updateNClob(int columnIndex, Reader reader, long length) throws SQLException {
    updateClob(columnIndex, reader, length);
  }

  public void updateNClob(String columnLabel, Reader reader, long length) throws SQLException {
    updateClob(columnLabel, reader,length);
  }

  public void updateNCharacterStream(int columnIndex, Reader x) throws SQLException {
    updateCharacterStream(columnIndex, x);
  }

  public void updateNCharacterStream(String columnLabel, Reader reader)throws SQLException {
    throw notSupported();
  }

  public void updateAsciiStream(int columnIndex, InputStream x)throws SQLException {
    throw notSupported();
  }

  public void updateBinaryStream(int columnIndex, InputStream x)throws SQLException {
    throw notSupported();
  }

  public void updateCharacterStream(int columnIndex, Reader x) throws SQLException {
    throw notSupported();
  }

  public void updateAsciiStream(String columnLabel, InputStream x) throws SQLException {
    throw notSupported();
  }

  public void updateBinaryStream(String columnLabel, InputStream x) throws SQLException {
    throw notSupported();
  }

  public void updateCharacterStream(String columnLabel, Reader reader) throws SQLException {
    throw notSupported();
  }

  public void updateBlob(int columnIndex, InputStream inputStream) throws SQLException {
    throw notSupported();
  }

  public void updateBlob(String columnLabel, InputStream inputStream) throws SQLException {
    throw notSupported();
  }

  public void updateClob(int columnIndex, Reader reader) throws SQLException {
    throw notSupported();
  }

  public void updateClob(String columnLabel, Reader reader) throws SQLException {
    throw notSupported();
  }

  public void updateNClob(int columnIndex, Reader reader) throws SQLException {
    updateClob(columnIndex, reader);
  }

  public void updateNClob(String columnLabel, Reader reader) throws SQLException {
    updateClob(columnLabel, reader);
  }

  public <T> T unwrap(Class<T> iface) throws SQLException {
    throw notSupported();
  }

  public boolean isWrapperFor(Class<?> iface) throws SQLException {
    throw notSupported();
  }
 

 
  //JDK6: uncomment this for compiling with JDK6
  
  public void updateNClob(int columnIndex, NClob nClob) throws SQLException {
    throw notSupported();
  }

  public void updateNClob(String columnLabel, NClob nClob) throws SQLException {
    throw notSupported();
  }

  public NClob getNClob(int columnIndex) throws SQLException {
    throw notSupported();
  }

  public NClob getNClob(String columnLabel) throws SQLException {
    throw notSupported();
  }

  public SQLXML getSQLXML(int columnIndex) throws SQLException {
    throw notSupported();
  }

  public SQLXML getSQLXML(String columnLabel) throws SQLException {
    throw notSupported();
  }

  public void updateSQLXML(int columnIndex, SQLXML xmlObject) throws SQLException {
    throw notSupported();
  }

  public void updateSQLXML(String columnLabel, SQLXML xmlObject) throws SQLException {
    throw notSupported();
  }
 
  public RowId getRowId(int columnIndex) throws SQLException {
    throw notSupported();
  }

  public RowId getRowId(String columnLabel) throws SQLException {
    throw notSupported();
  }

  public void updateRowId(int columnIndex, RowId x) throws SQLException {
    throw notSupported();
  }

  public void updateRowId(String columnLabel, RowId x) throws SQLException {
    throw notSupported();
  }
 
  public void removeRows(int index, int count) throws PageException {
    QueryUtil.removeRows(this,index,count);
  }
 

  private SQLException notSupported() {
    return new SQLException("this feature is not supported");
  }

  public synchronized void enableShowQueryUsage() {
    if(columns!=null)for(int i=0;i<columns.length;i++){
      columns[i]=columns[i]._toDebugColumn();
    }
  }

  @Override
  public long getExecutionTime() {
    return exeTime;
  }
 
  public static QueryImpl cloneQuery(Query qry,boolean deepCopy) {
        QueryImpl newResult=new QueryImpl();
        ThreadLocalDuplication.set(qry, newResult);
        try{
          newResult.columnNames=qry.getColumnNames();
          newResult.columns=new QueryColumnImpl[newResult.columnNames.length];
          QueryColumn col;
          for(int i=0;i<newResult.columnNames.length;i++) {
            col =  qry.getColumn(newResult.columnNames[i],null);
            newResult.columns[i]=QueryUtil.duplicate2QueryColumnImpl(newResult,col,deepCopy);
          }
         
           
        newResult.sql=qry.getSql();
          newResult.template=qry.getTemplate();
          newResult.recordcount=qry.getRecordcount();
          newResult.columncount=newResult.columnNames.length;
          newResult.isCached=qry.isCached();
          newResult.name=qry.getName();
          newResult.exeTime=qry.getExecutionTime();
          newResult.updateCount=qry.getUpdateCount();
          if(qry.getGeneratedKeys()!=null)newResult.generatedKeys=((QueryImpl)qry.getGeneratedKeys()).cloneQuery(false);
          return newResult;
        }
        finally {
          // ThreadLocalDuplication.remove(qry); removed "remove" to catch sisters and brothers
        }
    }
 
  @Override
  public java.util.Iterator getIterator() {
    return new ForEachQueryIterator(this, ThreadLocalPageContext.get().getId());
    }
 
  @Override
  public boolean equals(Object obj){
    if(!(obj instanceof Collection)) return false;
    return CollectionUtil.equals(this,(Collection)obj);
  }
 
  /*@Override
  public int hashCode() {
    return CollectionUtil.hashCode(this);
  }*/
}
TOP

Related Classes of railo.runtime.type.QueryImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.