package railo.runtime.type.query; import java.io.InputStream; import java.io.Reader; import java.math.BigDecimal; import java.net.URL; import java.sql.Array; import java.sql.Blob; import java.sql.Clob; import java.sql.Date; 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.SQLFeatureNotSupportedException; 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.ArrayList; import java.util.Calendar; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.TimeZone; import railo.commons.lang.StringUtil; import railo.loader.engine.CFMLEngineFactory; import railo.runtime.PageContext; import railo.runtime.db.DatasourceConnection; 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.op.Caster; import railo.runtime.type.ArrayImpl; import railo.runtime.type.ArrayInt; import railo.runtime.type.Collection; import railo.runtime.type.KeyImpl; import railo.runtime.type.Objects; import railo.runtime.type.Query; import railo.runtime.type.QueryColumn; import railo.runtime.type.QueryColumnRef; import railo.runtime.type.QueryImpl; import railo.runtime.type.Struct; import railo.runtime.type.StructImpl; import railo.runtime.type.dt.DateTime; 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.util.KeyConstants; import railo.runtime.type.util.QueryUtil; public class SimpleQuery implements Query, ResultSet, Objects { static final Object DEFAULT_VALUE = new Object(); private ResultSet res; private ResultSetMetaData meta; private Collection.Key[] columnNames; private Map<String,SimpleQueryColumn> columns=new LinkedHashMap<String, SimpleQueryColumn>(); private int[] _types; private String name; private String template; private SQL sql; private long exeTime; private int recordcount; private ArrayInt arrCurrentRow=new ArrayInt(); public SimpleQuery(DatasourceConnection dc,SQL sql,int maxrow, int fetchsize,int timeout, String name,String template,TimeZone tz) throws PageException { this.name=name; this.template=template; this.sql=sql; //ResultSet result=null; Statement stat=null; // check SQL Restrictions if(dc.getDatasource().hasSQLRestriction()) { QueryUtil.checkSQLRestriction(dc,sql); } //Stopwatch stopwatch=new Stopwatch(Stopwatch.UNIT_NANO); //stopwatch.start(); long start=System.nanoTime(); boolean hasResult=false; try { SQLItem[] items=sql.getItems(); if(items.length==0) { stat=dc.getConnection().createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY); setAttributes(stat,maxrow,fetchsize,timeout); // some driver do not support second argument hasResult=stat.execute(sql.getSQLString()); } else { // some driver do not support second argument PreparedStatement preStat = dc.getPreparedStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY); stat=preStat; setAttributes(preStat,maxrow,fetchsize,timeout); setItems(tz,preStat,items); hasResult=preStat.execute(); } ResultSet res; do { if(hasResult) { res=stat.getResultSet(); init(res); break; } throw new ApplicationException("Simple queries can only be used for queries returning a resultset"); } while(true); } catch (SQLException e) { throw new DatabaseException(e,sql,dc); } catch (Throwable e) { throw Caster.toPageException(e); } exeTime= System.nanoTime()-start; } 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 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]); } } private void init(ResultSet res) throws SQLException{ this.res=res; this.meta=res.getMetaData(); // init columns int columncount = meta.getColumnCount(); List<Key> tmpKeys=new ArrayList<Key>(); //List<Integer> tmpTypes=new ArrayList<Integer>(); //int count=0; Collection.Key key; String columnName; int type; for(int i=0;i<columncount;i++) { try { columnName=meta.getColumnName(i+1); type=meta.getColumnType(i+1); } catch (SQLException e) { throw toRuntimeExc(e); } if(StringUtil.isEmpty(columnName))columnName="column_"+i; key=KeyImpl.init(columnName); int index=tmpKeys.indexOf(key); if(index==-1) { //mappings.put(key.getLowerString(), Caster.toInteger(i+1)); tmpKeys.add(key); //tmpTypes.add(type); columns.put(key.getLowerString(), new SimpleQueryColumn(this,res, key,type, i+1)); //count++; } } columnNames=tmpKeys.toArray(new Key[tmpKeys.size()]); res.last(); recordcount=res.getRow(); res.beforeFirst(); /*Iterator<Integer> it = tmpTypes.iterator(); types=new int[tmpTypes.size()]; int index=0; while(it.hasNext()){ types[index++]=it.next(); }*/ } @Override public int executionTime() { return (int)exeTime; } @Override public int getUpdateCount() { throw notSupported(); } @Override public int size() { return columnNames.length; } @Override public Key[] keys() { return columnNames; } @Override public Object removeEL(Key key) { throw notSupported(); } @Override public Object remove(Key key) throws PageException { throw notSupported(); } @Override public void clear() { throw notSupported(); } @Override public Object get(Key key, Object defaultValue) { int pid = getPid(); return getAt(key, getCurrentrow(pid),pid,defaultValue); } @Override public Object get(String key, Object defaultValue) { return get(KeyImpl.init(key),defaultValue); } @Override public Object get(String key) throws PageException { return get(KeyImpl.init(key)); } @Override public Object get(Key key) throws PageException { int pid = getPid(); return getAt(key, getCurrentrow(pid),pid); } public Object getAt(Key key, int row, int pid, Object defaultValue) { char c=key.lowerCharAt(0); if(c=='r') { if(key.equals(KeyConstants._RECORDCOUNT)) return new Double(getRecordcount()); } else if(c=='c') { if(key.equals(KeyConstants._CURRENTROW)) return new Double(getCurrentrow(pid)); else if(key.equals(KeyConstants._COLUMNLIST)) return getColumnlist(); } SimpleQueryColumn column = columns.get(key.getLowerString()); if(column==null) return null; try { return column.get(row,defaultValue); } catch (Throwable t) { return defaultValue; } } public Object getAt(Key key, int row,int pid) throws PageException { Object res = getAt(key,row,pid,DEFAULT_VALUE); if(res!=DEFAULT_VALUE) return res; throw new DatabaseException("key ["+key+"] not found",null,null,null); } @Override public Object getAt(Key key, int row, Object defaultValue) { return getAt(key, row,getPid(),defaultValue); } public Object getAt(Key key, int row) throws PageException { Object res = getAt(key,row,getPid(),DEFAULT_VALUE); if(res!=DEFAULT_VALUE) return res; throw new DatabaseException("key ["+key+"] not found",null,null,null); } public Object getAt(String key, int row, Object defaultValue) { return getAt(KeyImpl.init(key), row,defaultValue); } @Override public Object getAt(String key, int row) throws PageException { return getAt(KeyImpl.init(key), row); } @Override public synchronized int removeRow(int row) throws PageException { throw notSupported(); } @Override public int removeRowEL(int row) { throw notSupported(); } @Override public QueryColumn removeColumn(String key) throws DatabaseException { throw notSupported(); } @Override public QueryColumn removeColumn(Key key) throws DatabaseException { throw notSupported(); } @Override public synchronized QueryColumn removeColumnEL(String key) { throw notSupported(); } @Override public QueryColumn removeColumnEL(Key key) { throw notSupported(); } @Override public Object setEL(String key, Object value) { throw notSupported(); } @Override public Object setEL(Key key, Object value) { throw notSupported(); } @Override public Object set(String key, Object value) throws PageException { throw notSupported(); } @Override public Object set(Key key, Object value) throws PageException { throw notSupported(); } @Override public Object setAt(String key, int row, Object value) throws PageException { throw notSupported(); } @Override public Object setAt(Key key, int row, Object value) throws PageException { throw notSupported(); } @Override public Object setAtEL(String key, int row, Object value) { throw notSupported(); } @Override public Object setAtEL(Key key, int row, Object value) { throw notSupported(); } @Override public synchronized boolean next() { return next(getPid()); } @Override public synchronized boolean next(int pid) { if(recordcount>=(arrCurrentRow.set(pid,arrCurrentRow.get(pid,0)+1))) { return true; } arrCurrentRow.set(pid,0); return false; } @Override public synchronized void reset() { reset(getPid()); } @Override public synchronized void reset(int pid) { arrCurrentRow.set(pid,0); } @Override public int getRecordcount() { return recordcount; } @Override public synchronized int getCurrentrow(int pid) { return arrCurrentRow.get(pid, 1); } public String getColumnlist(boolean upperCase) { Key[] columnNames = keys(); 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; } /*public synchronized boolean go(int index) { if(index==getCurrentrow()) return true; try { return res.absolute(index); } catch (SQLException e) { throw toRuntimeExc(e); } } public boolean go(int index, int pid) { return go(index); }*/ @Override public boolean isEmpty() { return recordcount+columnNames.length==0; } @Override public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp) { return QueryUtil.toDumpData(this, pageContext, maxlevel, dp); } @Override public void sort(String column) throws PageException { throw notSupported(); } @Override public void sort(Key column) throws PageException { throw notSupported(); } @Override public synchronized void sort(String strColumn, int order) throws PageException { throw notSupported(); } @Override public synchronized void sort(Key keyColumn, int order) throws PageException { throw notSupported(); } @Override public synchronized boolean addRow(int count) { throw notSupported(); } @Override public boolean addColumn(String columnName, railo.runtime.type.Array content) throws DatabaseException { throw notSupported(); } @Override public boolean addColumn(Key columnName, railo.runtime.type.Array content) throws PageException { throw notSupported(); } @Override public synchronized boolean addColumn(String columnName, railo.runtime.type.Array content, int type) throws DatabaseException { throw notSupported(); } @Override public boolean addColumn(Key columnName, railo.runtime.type.Array content, int type) throws DatabaseException { throw notSupported(); } @Override public Object clone() { return cloneQuery(true); } @Override public Collection duplicate(boolean deepCopy) { return cloneQuery(deepCopy); } public QueryImpl cloneQuery(boolean deepCopy) { return QueryImpl.cloneQuery(this, deepCopy); } @Override public synchronized int[] getTypes() { if(_types==null) { _types=new int[columns.size()]; int i=0; Iterator<Entry<String, SimpleQueryColumn>> it = columns.entrySet().iterator(); while(it.hasNext()){ _types[i++]=it.next().getValue().getType(); } } return _types; } @Override public synchronized Map getTypesAsMap() { Map<String,String> map=new HashMap<String,String>(); Iterator<SimpleQueryColumn> it = columns.values().iterator(); SimpleQueryColumn c; while(it.hasNext()){ c=it.next(); map.put(c.getKeyAsString(), c.getTypeAsString()); } return map; } @Override public QueryColumn getColumn(String key) throws DatabaseException { return getColumn(KeyImpl.init(key)); } @Override public QueryColumn getColumn(Key key) throws DatabaseException { QueryColumn rtn = getColumn(key,null); if(rtn!=null) return rtn; throw new DatabaseException("key ["+key.getString()+"] not found in query, columns are ["+getColumnlist(false)+"]",null,null,null); } @Override public QueryColumn getColumn(String key, QueryColumn defaultValue) { return getColumn(KeyImpl.init(key),defaultValue); } @Override public QueryColumn getColumn(Key key, QueryColumn defaultValue) { if(key.getString().length()>0) { char c=key.lowerCharAt(0); if(c=='r') { if(key.equals(KeyConstants._RECORDCOUNT)) return new QueryColumnRef(this,key,Types.INTEGER); } else if(c=='c') { if(key.equals(KeyConstants._CURRENTROW)) return new QueryColumnRef(this,key,Types.INTEGER); else if(key.equals(KeyConstants._COLUMNLIST)) return new QueryColumnRef(this,key,Types.INTEGER); } SimpleQueryColumn col = columns.get(key.getLowerString()); if(col!=null) return col; } return defaultValue; } @Override public synchronized void rename(Key columnName, Key newColumnName) throws ExpressionException { throw notSupported(); //Integer index=mappings.get(columnName); //if(index==null) throw new ExpressionException("invalid column name definitions"); // TODO implement } @Override public String toString() { return res.toString(); } @Override public void setExecutionTime(long exeTime) { throw notSupported(); } public synchronized boolean cutRowsTo(int maxrows) { throw notSupported(); } @Override public void setCached(boolean isCached) { throw notSupported(); } @Override public boolean isCached() { return false; } @Override public int addRow() { throw notSupported(); } public Key getColumnName(int columnIndex) { Iterator<SimpleQueryColumn> it = columns.values().iterator(); SimpleQueryColumn c; while(it.hasNext()){ c = it.next(); if(c.getIndex()==columnIndex) return c.getKey(); } return null; } @Override public int getColumnIndex(String coulmnName) { SimpleQueryColumn col = columns.get(coulmnName.toLowerCase()); if(col==null) return -1; return col.getIndex(); } @Override public String[] getColumns() { return getColumnNamesAsString(); } @Override public Key[] getColumnNames() { Key[] _columns=new Key[columnNames.length]; for(int i=0;i<columnNames.length;i++){ _columns[i]=columnNames[i]; } return _columns; } public void setColumnNames(Key[] trg) { throw notSupported(); } @Override public String[] getColumnNamesAsString() { String[] _columns=new String[columnNames.length]; for(int i=0;i<columnNames.length;i++){ _columns[i]=columnNames[i].getString(); } return _columns; } @Override public synchronized String getData(int row, int col) throws IndexOutOfBoundsException { try{ int rowBefore=res.getRow(); try{ res.absolute(row); if(col<1 || col>columnNames.length) { new IndexOutOfBoundsException("invalid column index to retrieve Data from query, valid index goes from 1 to "+columnNames.length); } return Caster.toString(get(columnNames[col])); } finally{ res.absolute(rowBefore); } } catch(Throwable t){ throw toRuntimeExc(t); } } @Override public String getName() { return name; } @Override public int getRowCount() { return getRecordcount(); } @Override public void setData(int row, int col, String value) throws IndexOutOfBoundsException { throw notSupported(); } @Override public boolean containsKey(String key) { return columns.get(key.toLowerCase())!=null; } @Override public boolean containsKey(Key key) { return containsKey(key.getString()); } @Override public String castToString() throws ExpressionException { throw notSupported(); } @Override public String castToString(String defaultValue) { throw notSupported(); } @Override public boolean castToBooleanValue() throws ExpressionException { throw notSupported(); } @Override public Boolean castToBoolean(Boolean defaultValue) { throw notSupported(); } @Override public double castToDoubleValue() throws ExpressionException { throw notSupported(); } @Override public double castToDoubleValue(double defaultValue) { throw notSupported(); } @Override public DateTime castToDateTime() throws ExpressionException { throw notSupported(); } @Override public DateTime castToDateTime(DateTime defaultValue) { throw notSupported(); } @Override public int compareTo(boolean b) throws ExpressionException { throw notSupported(); } @Override public int compareTo(DateTime dt) throws PageException { throw notSupported(); } @Override public int compareTo(double d) throws PageException { throw notSupported(); } @Override public int compareTo(String str) throws PageException { throw notSupported(); } @Override public synchronized railo.runtime.type.Array getMetaDataSimple() { railo.runtime.type.Array cols=new ArrayImpl(); SimpleQueryColumn sqc; Struct column; Iterator<SimpleQueryColumn> it = columns.values().iterator(); while(it.hasNext()){ sqc=it.next(); column=new StructImpl(); column.setEL(KeyConstants._name,sqc.getKey()); column.setEL("isCaseSensitive",Boolean.FALSE); column.setEL("typeName",sqc.getTypeAsString()); cols.appendEL(column); } return cols; } @Override public Object getObject(String columnName) throws SQLException { return res.getObject(toIndex(columnName)); } @Override public Object getObject(int columnIndex) throws SQLException { return res.getObject(columnIndex); } @Override public String getString(int columnIndex) throws SQLException { return res.getString(columnIndex); } @Override public String getString(String columnName) throws SQLException { return res.getString(toIndex(columnName)); } @Override public boolean getBoolean(int columnIndex) throws SQLException { return res.getBoolean(columnIndex); } @Override public boolean getBoolean(String columnName) throws SQLException { return res.getBoolean(toIndex(columnName)); } @Override public Object call(PageContext pc, Key methodName, Object[] arguments) throws PageException { throw notSupported(); } @Override public Object callWithNamedValues(PageContext pc, Key methodName, Struct args) throws PageException { throw notSupported(); } @Override public Object get(PageContext pc, Key key, Object defaultValue) { return getAt(key, getCurrentrow(pc.getId()), pc.getId(),defaultValue); } @Override public Object get(PageContext pc, Key key) throws PageException { return getAt(key, getCurrentrow(pc.getId()), pc.getId()); } public boolean isInitalized() { return true; } @Override public Object set(PageContext pc, Key propertyName, Object value) throws PageException { throw notSupported(); } @Override public Object setEL(PageContext pc, Key propertyName, Object value) { throw notSupported(); } @Override public boolean wasNull() { try { return res.wasNull(); } catch (SQLException e) { throw toRuntimeExc(e); } } @Override public synchronized boolean absolute(int row) throws SQLException { return res.absolute(row); } @Override public synchronized void afterLast() throws SQLException { res.afterLast(); } @Override public synchronized void beforeFirst() throws SQLException { res.beforeFirst(); } @Override public synchronized void cancelRowUpdates() throws SQLException { res.cancelRowUpdates(); } @Override public synchronized void clearWarnings() throws SQLException { res.clearWarnings(); } @Override public synchronized void close() throws SQLException { res.close(); } @Override public synchronized void deleteRow() throws SQLException { res.deleteRow(); } @Override public int findColumn(String columnName) throws SQLException { return res.findColumn(columnName); } @Override public synchronized boolean first() throws SQLException { return res.first(); } @Override public Array getArray(int i) throws SQLException { return res.getArray(i); } @Override public Array getArray(String colName) throws SQLException { return res.getArray(toIndex(colName)); } @Override public InputStream getAsciiStream(int columnIndex) throws SQLException { return res.getAsciiStream(columnIndex); } @Override public InputStream getAsciiStream(String columnName) throws SQLException { return res.getAsciiStream(toIndex(columnName)); } @Override public BigDecimal getBigDecimal(int columnIndex) throws SQLException { return res.getBigDecimal(columnIndex); } @Override public BigDecimal getBigDecimal(String columnName) throws SQLException { return res.getBigDecimal(toIndex(columnName)); } @Override public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException { return res.getBigDecimal(columnIndex, scale); } @Override public BigDecimal getBigDecimal(String columnName, int scale) throws SQLException { return res.getBigDecimal(toIndex(columnName), scale); } @Override public InputStream getBinaryStream(int columnIndex) throws SQLException { return res.getBinaryStream(columnIndex); } @Override public InputStream getBinaryStream(String columnName) throws SQLException { return res.getBinaryStream(toIndex(columnName)); } @Override public Blob getBlob(int i) throws SQLException { return res.getBlob(i); } @Override public Blob getBlob(String colName) throws SQLException { return res.getBlob(toIndex(colName)); } @Override public byte getByte(int columnIndex) throws SQLException { return res.getByte(columnIndex); } @Override public byte getByte(String columnName) throws SQLException { return res.getByte(toIndex(columnName)); } @Override public byte[] getBytes(int columnIndex) throws SQLException { return res.getBytes(columnIndex); } @Override public byte[] getBytes(String columnName) throws SQLException { return res.getBytes(toIndex(columnName)); } @Override public Reader getCharacterStream(int columnIndex) throws SQLException { return res.getCharacterStream(columnIndex); } @Override public Reader getCharacterStream(String columnName) throws SQLException { return res.getCharacterStream(toIndex(columnName)); } @Override public Clob getClob(int i) throws SQLException { return res.getClob(i); } @Override public Clob getClob(String colName) throws SQLException { return res.getClob(toIndex(colName)); } @Override public int getConcurrency() throws SQLException { return res.getConcurrency(); } @Override public String getCursorName() throws SQLException { return res.getCursorName(); } @Override public Date getDate(int columnIndex) throws SQLException { return res.getDate(columnIndex); } @Override public Date getDate(String columnName) throws SQLException { return res.getDate(toIndex(columnName)); } @Override public Date getDate(int columnIndex, Calendar cal) throws SQLException { return res.getDate(columnIndex, cal); } @Override public Date getDate(String columnName, Calendar cal) throws SQLException { return res.getDate(toIndex(columnName), cal); } @Override public double getDouble(int columnIndex) throws SQLException { return res.getDouble(columnIndex); } @Override public double getDouble(String columnName) throws SQLException { return res.getDouble(toIndex(columnName)); } @Override public int getFetchDirection() throws SQLException { return res.getFetchDirection(); } @Override public int getFetchSize() throws SQLException { return res.getFetchSize(); } @Override public float getFloat(int columnIndex) throws SQLException { return res.getFloat(columnIndex); } @Override public float getFloat(String columnName) throws SQLException { return res.getFloat(toIndex(columnName)); } @Override public int getInt(int columnIndex) throws SQLException { return res.getInt(columnIndex); } @Override public int getInt(String columnName) throws SQLException { return res.getInt(toIndex(columnName)); } @Override public long getLong(int columnIndex) throws SQLException { return res.getLong(columnIndex); } @Override public long getLong(String columnName) throws SQLException { return res.getLong(toIndex(columnName)); } @Override public Object getObject(int i, Map map) throws SQLException { return res.getObject(i, map); } @Override public Object getObject(String colName, Map map) throws SQLException { return res.getObject(toIndex(colName), map); } // 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 { return res.getRef(i); } @Override public Ref getRef(String colName) throws SQLException { return res.getRef(toIndex(colName)); } @Override public int getRow() throws SQLException { return res.getRow(); } @Override public short getShort(int columnIndex) throws SQLException { return res.getShort(columnIndex); } @Override public short getShort(String columnName) throws SQLException { return res.getShort(toIndex(columnName)); } @Override public Statement getStatement() throws SQLException { return res.getStatement(); } @Override public Time getTime(int columnIndex) throws SQLException { return res.getTime(columnIndex); } @Override public Time getTime(String columnName) throws SQLException { return res.getTime(toIndex(columnName)); } @Override public Time getTime(int columnIndex, Calendar cal) throws SQLException { return res.getTime(columnIndex, cal); } @Override public Time getTime(String columnName, Calendar cal) throws SQLException { return res.getTime(toIndex(columnName), cal); } @Override public Timestamp getTimestamp(int columnIndex) throws SQLException { return res.getTimestamp(columnIndex); } @Override public Timestamp getTimestamp(String columnName) throws SQLException { return res.getTimestamp(toIndex(columnName)); } @Override public Timestamp getTimestamp(int columnIndex, Calendar cal) throws SQLException { return res.getTimestamp(columnIndex, cal); } @Override public Timestamp getTimestamp(String columnName, Calendar cal) throws SQLException { return res.getTimestamp(toIndex(columnName), cal); } @Override public int getType() throws SQLException { return res.getType(); } @Override public URL getURL(int columnIndex) throws SQLException { return res.getURL(columnIndex); } @Override public URL getURL(String columnName) throws SQLException { return res.getURL(toIndex(columnName)); } @Override public InputStream getUnicodeStream(int columnIndex) throws SQLException { return res.getUnicodeStream(columnIndex); } @Override public InputStream getUnicodeStream(String columnName) throws SQLException { return res.getUnicodeStream(toIndex(columnName)); } @Override public SQLWarning getWarnings() throws SQLException { return res.getWarnings(); } @Override public void insertRow() throws SQLException { res.insertRow(); } @Override public boolean isAfterLast() throws SQLException { return res.isAfterLast(); } @Override public boolean isBeforeFirst() throws SQLException { return res.isBeforeFirst(); } @Override public boolean isFirst() throws SQLException { return res.isFirst(); } @Override public boolean isLast() throws SQLException { return res.isLast(); } @Override public boolean last() throws SQLException { return res.last(); } @Override public void moveToCurrentRow() throws SQLException { res.moveToCurrentRow(); } @Override public void moveToInsertRow() throws SQLException { res.moveToInsertRow(); } @Override public boolean previous() { throw notSupported(); } @Override public boolean previous(int pid) { throw notSupported(); } @Override public void refreshRow() throws SQLException { res.refreshRow(); } @Override public boolean relative(int rows) throws SQLException { return res.relative(rows); } @Override public boolean rowDeleted() throws SQLException { return res.rowDeleted(); } @Override public boolean rowInserted() throws SQLException { return res.rowInserted(); } @Override public boolean rowUpdated() throws SQLException { return res.rowUpdated(); } @Override public void setFetchDirection(int direction) throws SQLException { res.setFetchDirection(direction); } @Override public void setFetchSize(int rows) throws SQLException { res.setFetchSize(rows); } @Override public void updateArray(int columnIndex, Array x) throws SQLException { res.updateArray(columnIndex, x); } @Override public void updateArray(String columnName, Array x) throws SQLException { res.updateArray(toIndex(columnName), x); } @Override public void updateAsciiStream(int columnIndex, InputStream x, int length) throws SQLException { res.updateAsciiStream(columnIndex, x, length); } @Override public void updateAsciiStream(String columnName, InputStream x, int length) throws SQLException { res.updateAsciiStream(toIndex(columnName), x, length); } @Override public void updateBigDecimal(int columnIndex, BigDecimal x) throws SQLException { res.updateBigDecimal(columnIndex, x); } @Override public void updateBigDecimal(String columnName, BigDecimal x) throws SQLException { res.updateBigDecimal(toIndex(columnName), x); } @Override public void updateBinaryStream(int columnIndex, InputStream x, int length) throws SQLException { res.updateBinaryStream(columnIndex, x, length); } @Override public void updateBinaryStream(String columnName, InputStream x, int length) throws SQLException { res.updateBinaryStream(toIndex(columnName), x, length); } @Override public void updateBlob(int columnIndex, Blob x) throws SQLException { res.updateBlob(columnIndex, x); } @Override public void updateBlob(String columnName, Blob x) throws SQLException { res.updateBlob(toIndex(columnName), x); } @Override public void updateBoolean(int columnIndex, boolean x) throws SQLException { res.updateBoolean(columnIndex, x); } @Override public void updateBoolean(String columnName, boolean x) throws SQLException { res.updateBoolean(toIndex(columnName), x); } @Override public void updateByte(int columnIndex, byte x) throws SQLException { res.updateByte(columnIndex, x); } @Override public void updateByte(String columnName, byte x) throws SQLException { res.updateByte(toIndex(columnName), x); } @Override public void updateBytes(int columnIndex, byte[] x) throws SQLException { res.updateBytes(columnIndex, x); } @Override public void updateBytes(String columnName, byte[] x) throws SQLException { res.updateBytes(toIndex(columnName), x); } @Override public void updateCharacterStream(int columnIndex, Reader reader, int length) throws SQLException { res.updateCharacterStream(columnIndex, reader, length); } @Override public void updateCharacterStream(String columnName, Reader reader, int length) throws SQLException { res.updateCharacterStream(toIndex(columnName), reader, length); } @Override public void updateClob(int columnIndex, Clob x) throws SQLException { res.updateClob(columnIndex, x); } @Override public void updateClob(String columnName, Clob x) throws SQLException { res.updateClob(toIndex(columnName), x); } @Override public void updateDate(int columnIndex, Date x) throws SQLException { res.updateDate(columnIndex, x); } @Override public void updateDate(String columnName, Date x) throws SQLException { res.updateDate(toIndex(columnName), x); } @Override public void updateDouble(int columnIndex, double x) throws SQLException { res.updateDouble(columnIndex, x); } @Override public void updateDouble(String columnName, double x) throws SQLException { res.updateDouble(toIndex(columnName), x); } @Override public void updateFloat(int columnIndex, float x) throws SQLException { res.updateFloat(columnIndex, x); } @Override public void updateFloat(String columnName, float x) throws SQLException { res.updateFloat(toIndex(columnName), x); } @Override public void updateInt(int columnIndex, int x) throws SQLException { res.updateInt(columnIndex, x); } @Override public void updateInt(String columnName, int x) throws SQLException { res.updateInt(toIndex(columnName), x); } @Override public void updateLong(int columnIndex, long x) throws SQLException { res.updateLong(columnIndex, x); } @Override public void updateLong(String columnName, long x) throws SQLException { res.updateLong(toIndex(columnName), x); } @Override public void updateNull(int columnIndex) throws SQLException { res.updateNull(columnIndex); } @Override public void updateNull(String columnName) throws SQLException { res.updateNull(toIndex(columnName)); } @Override public void updateObject(int columnIndex, Object x) throws SQLException { res.updateObject(columnIndex, x); } @Override public void updateObject(String columnName, Object x) throws SQLException { res.updateObject(toIndex(columnName), x); } @Override public void updateObject(int columnIndex, Object x, int scale) throws SQLException { res.updateObject(columnIndex, x, scale); } @Override public void updateObject(String columnName, Object x, int scale) throws SQLException { res.updateObject(toIndex(columnName), x, scale); } @Override public void updateRef(int columnIndex, Ref x) throws SQLException { res.updateRef(columnIndex, x); } @Override public void updateRef(String columnName, Ref x) throws SQLException { res.updateRef(toIndex(columnName), x); } @Override public void updateRow() throws SQLException { res.updateRow(); } @Override public void updateShort(int columnIndex, short x) throws SQLException { res.updateShort(columnIndex, x); } @Override public void updateShort(String columnName, short x) throws SQLException { res.updateShort(toIndex(columnName), x); } @Override public void updateString(int columnIndex, String x) throws SQLException { res.updateString(columnIndex, x); } @Override public void updateString(String columnName, String x) throws SQLException { res.updateString(toIndex(columnName), x); } @Override public void updateTime(int columnIndex, Time x) throws SQLException { res.updateTime(columnIndex, x); } @Override public void updateTime(String columnName, Time x) throws SQLException { res.updateTime(toIndex(columnName), x); } @Override public void updateTimestamp(int columnIndex, Timestamp x) throws SQLException { res.updateTimestamp(columnIndex, x); } @Override public void updateTimestamp(String columnName, Timestamp x) throws SQLException { res.updateTimestamp(toIndex(columnName), x); } @Override public ResultSetMetaData getMetaData() throws SQLException { return res.getMetaData(); } @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()); } @Override public Iterator<Object> valueIterator() { return new CollectionIterator(keys(),this); } @Override public boolean equals(Object obj) { return res.equals(obj); } @Override public int getHoldability() throws SQLException { return res.getHoldability(); } @Override public boolean isClosed() throws SQLException { return res.isClosed(); } @Override public void updateNString(int columnIndex, String nString) throws SQLException { res.updateNString(columnIndex, nString); } @Override public void updateNString(String columnLabel, String nString) throws SQLException { res.updateNString(toIndex(columnLabel), nString); } @Override public String getNString(int columnIndex) throws SQLException { return res.getNString(columnIndex); } @Override public String getNString(String columnLabel) throws SQLException { return res.getNString(toIndex(columnLabel)); } @Override public Reader getNCharacterStream(int columnIndex) throws SQLException { return res.getNCharacterStream(columnIndex); } @Override public Reader getNCharacterStream(String columnLabel) throws SQLException { return res.getNCharacterStream(toIndex(columnLabel)); } @Override public void updateNCharacterStream(int columnIndex, Reader x, long length) throws SQLException { res.updateNCharacterStream(columnIndex, x, length); } @Override public void updateNCharacterStream(String columnLabel, Reader reader, long length) throws SQLException { res.updateNCharacterStream(toIndex(columnLabel), reader, length); } @Override public void updateAsciiStream(int columnIndex, InputStream x, long length) throws SQLException { res.updateAsciiStream(columnIndex, x, length); } @Override public void updateBinaryStream(int columnIndex, InputStream x, long length) throws SQLException { res.updateBinaryStream(columnIndex, x, length); } @Override public void updateCharacterStream(int columnIndex, Reader x, long length) throws SQLException { res.updateCharacterStream(columnIndex, x, length); } @Override public void updateAsciiStream(String columnLabel, InputStream x, long length) throws SQLException { res.updateAsciiStream(toIndex(columnLabel), x, length); } @Override public void updateBinaryStream(String columnLabel, InputStream x, long length) throws SQLException { res.updateBinaryStream(toIndex(columnLabel), x, length); } @Override public void updateCharacterStream(String columnLabel, Reader reader, long length) throws SQLException { res.updateCharacterStream(toIndex(columnLabel), reader, length); } @Override public void updateBlob(int columnIndex, InputStream inputStream, long length) throws SQLException { res.updateBlob(columnIndex, inputStream, length); } @Override public void updateBlob(String columnLabel, InputStream inputStream, long length) throws SQLException { res.updateBlob(toIndex(columnLabel), inputStream, length); } @Override public void updateClob(int columnIndex, Reader reader, long length) throws SQLException { res.updateClob(columnIndex, reader, length); } @Override public void updateClob(String columnLabel, Reader reader, long length) throws SQLException { res.updateClob(toIndex(columnLabel), reader, length); } @Override public void updateNClob(int columnIndex, Reader reader, long length) throws SQLException { res.updateNClob(columnIndex, reader, length); } @Override public void updateNClob(String columnLabel, Reader reader, long length) throws SQLException { res.updateNClob(toIndex(columnLabel), reader, length); } @Override public void updateNCharacterStream(int columnIndex, Reader x) throws SQLException { res.updateNCharacterStream(columnIndex, x); } @Override public void updateNCharacterStream(String columnLabel, Reader reader) throws SQLException { res.updateNCharacterStream(toIndex(columnLabel), reader); } @Override public void updateAsciiStream(int columnIndex, InputStream x) throws SQLException { res.updateAsciiStream(columnIndex, x); } @Override public void updateBinaryStream(int columnIndex, InputStream x) throws SQLException { res.updateBinaryStream(columnIndex, x); } @Override public void updateCharacterStream(int columnIndex, Reader x) throws SQLException { res.updateCharacterStream(columnIndex, x); } @Override public void updateAsciiStream(String columnLabel, InputStream x) throws SQLException { res.updateAsciiStream(toIndex(columnLabel), x); } @Override public void updateBinaryStream(String columnLabel, InputStream x) throws SQLException { res.updateBinaryStream(columnLabel, x); } @Override public void updateCharacterStream(String columnLabel, Reader reader) throws SQLException { res.updateCharacterStream(toIndex(columnLabel), reader); } @Override public void updateBlob(int columnIndex, InputStream inputStream) throws SQLException { res.updateBlob(columnIndex, inputStream); } @Override public void updateBlob(String columnLabel, InputStream inputStream) throws SQLException { res.updateBlob(toIndex(columnLabel), inputStream); } @Override public void updateClob(int columnIndex, Reader reader) throws SQLException { res.updateClob(columnIndex, reader); } @Override public void updateClob(String columnLabel, Reader reader) throws SQLException { res.updateClob(toIndex(columnLabel), reader); } @Override public void updateNClob(int columnIndex, Reader reader) throws SQLException { res.updateNClob(columnIndex, reader); } @Override public void updateNClob(String columnLabel, Reader reader) throws SQLException { res.updateNClob(toIndex(columnLabel), reader); } @Override public <T> T unwrap(Class<T> iface) throws SQLException { return res.unwrap(iface); } @Override public boolean isWrapperFor(Class<?> iface) throws SQLException { return res.isWrapperFor(iface); } @Override public void updateNClob(int columnIndex, NClob nClob) throws SQLException { res.updateNClob(columnIndex, nClob); } @Override public void updateNClob(String columnLabel, NClob nClob) throws SQLException { res.updateNClob(toIndex(columnLabel), nClob); } @Override public NClob getNClob(int columnIndex) throws SQLException { return res.getNClob(columnIndex); } @Override public NClob getNClob(String columnLabel) throws SQLException { return res.getNClob(toIndex(columnLabel)); } @Override public SQLXML getSQLXML(int columnIndex) throws SQLException { return res.getSQLXML(columnIndex); } @Override public SQLXML getSQLXML(String columnLabel) throws SQLException { return res.getSQLXML(toIndex(columnLabel)); } @Override public void updateSQLXML(int columnIndex, SQLXML xmlObject) throws SQLException { res.updateSQLXML(columnIndex, xmlObject); } @Override public void updateSQLXML(String columnLabel, SQLXML xmlObject) throws SQLException { res.updateSQLXML(toIndex(columnLabel), xmlObject); } @Override public RowId getRowId(int columnIndex) throws SQLException { return res.getRowId(columnIndex); } @Override public RowId getRowId(String columnLabel) throws SQLException { return res.getRowId(toIndex(columnLabel)); } @Override public void updateRowId(int columnIndex, RowId x) throws SQLException { res.updateRowId(columnIndex, x); } @Override public void updateRowId(String columnLabel, RowId x) throws SQLException { res.updateRowId(toIndex(columnLabel), x); } public synchronized void enableShowQueryUsage() { throw notSupported(); } public static PageRuntimeException notSupported() { return toRuntimeExc(new SQLFeatureNotSupportedException("not supported")); } public static PageRuntimeException toRuntimeExc(Throwable t) { return new PageRuntimeException(Caster.toPageException(t)); } public static PageException toPageExc(Throwable t) { return Caster.toPageException(t); } private int toIndex(String columnName) throws SQLException { SimpleQueryColumn col = columns.get(columnName.toLowerCase()); if(col==null) throw new SQLException("There is no column with name ["+columnName+"], available columns are ["+getColumnlist()+"]"); return col.getIndex(); } 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 Query getGeneratedKeys() { return null; } @Override public SQL getSql() { return sql; } @Override public String getTemplate() { return template; } @Override public long getExecutionTime() { return exeTime; } @Override public java.util.Iterator getIterator() { return new ForEachQueryIterator(this, ThreadLocalPageContext.get().getId()); } }