/* * Copyright (c) 2000 Dustin Sallings <dustin@spy.net> */ package net.spy.db; import java.math.BigDecimal; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.SQLWarning; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import net.spy.SpyObject; /** * This object contains all the common stuff required to stub a ResultSet * implementation. */ public abstract class GenericResultSetStub extends SpyObject implements Cloneable { // Here is where the ResultSet data gets stored. private List<Object[]> results=null; private Iterator<Object[]> resultIter=null; // Map column names to ints private Map<String, Integer> columns=null; // This is the current result we're looking at. private Object[] result=null; // We're going to keep a copy of the ResultSetMetaData from the // original query. Let's find out if those things require an active // ResultSet, shall we? private ResultSetMetaData metadata=null; // Used for wasNull() private boolean wasNull=false; /** * Magically transform the passed in ResultSet to a * GenericResultSetStub * * @param rs the ResultSet we want to magically transform * * @exception SQLException if the ResultSet somehow fails us. */ public GenericResultSetStub(ResultSet rs) throws SQLException { super(); setMetaData(rs.getMetaData()); initResults(rs); } /** * Get an instance of a GenericResultSetStub with no initialization. * * The subclass is expected to do whatever is necessary, and then call * setResults(List) and setMetaData(ResultSetMetaData) to make * everything happy. * * @throws SQLException (never) */ protected GenericResultSetStub() throws SQLException { super(); } // result set initializer private void initResults(ResultSet rs) throws SQLException { // Initialize the results vector ArrayList<Object[]> r=new ArrayList<Object[]>(); int ncolumns=metadata.getColumnCount(); // Flip through each result while(rs.next()) { // Get an array to store them Object[] ars=new Object[ncolumns]; // Flip through the columns for(int i=1; i<=ncolumns; i++) { // Get the object from the result set. ars[i-1]=rs.getObject(i); // If we did a numeric thingy if(rs.wasNull()) { ars[i-1]=null; } } // columns // Stick it in our resultset. r.add(ars); } // results setResults(r); } // initresults /** * Reset the results to the beginning. */ protected void resetResults() { this.resultIter=null; } /** * Set the results for this ResultSet to use. * * @param to results list to use */ protected void setResults(List<Object[]> to) { this.results=to; resetResults(); } /** * Set the ResultSetMetaData used for this ResultSet. * * @param rsmd the ResultSetMetaData * @throws SQLException if there's a problem examining the signature */ protected void setMetaData(ResultSetMetaData rsmd) throws SQLException { this.metadata=rsmd; // Get the column count int ncolumns=metadata.getColumnCount(); // Initialize columns columns=new HashMap<String, Integer>(); for(int i=1; i<=ncolumns; i++) { String name=metadata.getColumnName(i).toLowerCase(); columns.put(name, new Integer(i)); } } /** * Get the Object at the given result column for the current result * row. * * @param index the numeric index of the column * @return whatever Object is found at that column (may be null) * @throws SQLException if there is not a current ResultSet row, or the * index is out of bounds */ protected Object getResultColumn(int index) throws SQLException { // (jdbc is offset at 1, we're offset at 0) index--; if(result==null) { throw new SQLException("No current result."); } if(index<0) { throw new SQLException("ResultSets start at one, nothing less."); } if(index>=result.length) { throw new SQLException("There are only " + result.length + " columns in this set."); } // Check for NULL wasNull = result[index]==null; // OK, return the column return(result[index]); } /** * Debug routine for displaying the current row of the ResultSet. */ @Override public String toString() { StringBuilder sb=new StringBuilder(256); sb.append("Result row:\n"); int ncolumns=0; try { ncolumns=metadata.getColumnCount(); } catch(SQLException e) { ncolumns=0; } for(int i=1; i<=ncolumns; i++) { try { Object o=getResultColumn(i); if(o!=null) { sb.append("\t"); sb.append(metadata.getColumnName(i)); sb.append("="); sb.append(o); sb.append(" ("); sb.append(o.getClass().getName()); sb.append(")\n"); } else { sb.append("\t"); sb.append(metadata.getColumnName(i)); sb.append(" - null\n"); } } catch(SQLException e) { // Ignore these columns, it's apparently broken getLogger().info("Error with column %d", i, e); } } return(sb.toString()); } // OK, begin disgustingly long stream of interface implementation /** * Seek to the next row in this ResultSet. * * @return true if there was another row. * @throws SQLException if there's a problem seeking...or something */ public boolean next() throws SQLException { boolean rv=true; // Make sure we've got our enumeration going. if(resultIter==null) { resultIter=results.iterator(); } if(resultIter.hasNext()) { result=resultIter.next(); } else { rv=false; } return(rv); } /** * Close the ResultSet. * * This currently does nothing. * * @throws SQLException (never) */ public void close() throws SQLException { // Nothing. } /** * Check to see if the last column fetched was null. * * @return true if it was null * @throws SQLException (never) */ public boolean wasNull() throws SQLException { return(wasNull); } /** * Get the given column as a string. * * @param index the index of the column * @return the String value of the column, or null * @throws SQLException if misused */ public String getString(int index) throws SQLException { Object o=getResultColumn(index); if(o==null) { return(null); } return(o.toString()); } /** * Get the given value as a boolean. * * @param index the index of the column * @return the boolean value of the column * @throws SQLException if there's a problem getting the value */ public boolean getBoolean(int index) throws SQLException { boolean rv=false; Object o=getResultColumn(index); if(o!=null) { Boolean b=(Boolean)o; rv=b.booleanValue(); } return(rv); } /** * @see ResultSet */ public short getShort(int index) throws SQLException { Number n=getNumber(index); return(n.shortValue()); } /** * @see ResultSet */ public int getInt(int index) throws SQLException { Number n=getNumber(index); return(n.intValue()); } /** * @see ResultSet */ public long getLong(int index) throws SQLException { Number n=getNumber(index); return(n.longValue()); } /** * @see ResultSet */ public float getFloat(int index) throws SQLException { Number n=getNumber(index); return(n.floatValue()); } /** * @see ResultSet */ public double getDouble(int index) throws SQLException { Number n=getNumber(index); return(n.doubleValue()); } /** * @see ResultSet */ private Number getNumber(int index) throws SQLException { Number n=null; Object o=getResultColumn(index); if(o!=null) { try { n=(Number)o; } catch(ClassCastException e) { throw new SQLException("Error getting Number value: " + e); } } else { n=new Integer(0); } return(n); } /** * @see ResultSet */ public BigDecimal getBigDecimal(int index) throws SQLException { BigDecimal rv=null; Object o=getResultColumn(index); if(o!=null) { try { rv=(BigDecimal)o; } catch(ClassCastException e) { throw new SQLException("Error getting date value: " + e); } } return(rv); } /** * @see ResultSet */ public java.sql.Date getDate(int index) throws SQLException { java.sql.Date rv=null; Object o=getResultColumn(index); if(o!=null) { try { rv=(java.sql.Date)o; } catch(ClassCastException e) { throw new SQLException("Error getting date value: " + e); } } return(rv); } /** * @see ResultSet */ public java.sql.Time getTime(int index) throws SQLException { java.sql.Time rv=null; Object o=getResultColumn(index); if(o!=null) { try { rv=(java.sql.Time)o; } catch(ClassCastException e) { throw new SQLException("Error getting time value: " + e); } } return(rv); } /** * @see ResultSet */ public java.sql.Timestamp getTimestamp(int index) throws SQLException { java.sql.Timestamp rv=null; Object o=getResultColumn(index); if(o!=null) { try { rv=(java.sql.Timestamp)o; } catch(ClassCastException e) { throw new SQLException("Error getting timestamp value: " + e); } } return(rv); } /** * @see ResultSet */ public Object getObject(int index) throws SQLException { return(getResultColumn(index)); } // // OK, now we gotta do them all again, but this time, by name // /** * @see ResultSet */ public int findColumn(String columnName) throws SQLException { String name=columnName.toLowerCase(); Integer value=columns.get(name); if(value==null) { throw new SQLException("No such column: " + columnName); } return(value.intValue()); } // OK, now it's basically cut, change types, paste /** * @see ResultSet */ public String getString(String name) throws SQLException { return(getString(findColumn(name))); } /** * @see ResultSet */ public boolean getBoolean(String name) throws SQLException { return(getBoolean(findColumn(name))); } /** * @see ResultSet */ public short getShort(String name) throws SQLException { return(getShort(findColumn(name))); } /** * @see ResultSet */ public int getInt(String name) throws SQLException { return(getInt(findColumn(name))); } /** * @see ResultSet */ public long getLong(String name) throws SQLException { return(getLong(findColumn(name))); } /** * @see ResultSet */ public float getFloat(String name) throws SQLException { return(getFloat(findColumn(name))); } /** * @see ResultSet */ public double getDouble(String name) throws SQLException { return(getDouble(findColumn(name))); } /** * @see ResultSet */ public java.sql.Date getDate(String name) throws SQLException { return(getDate(findColumn(name))); } /** * @see ResultSet */ public java.sql.Time getTime(String name) throws SQLException { return(getTime(findColumn(name))); } /** * @see ResultSet */ public java.sql.Timestamp getTimestamp(String name) throws SQLException { return(getTimestamp(findColumn(name))); } /** * @see ResultSet */ public BigDecimal getBigDecimal(String name) throws SQLException { return(getBigDecimal(findColumn(name))); } /** * @see ResultSet */ public Object getObject(String name) throws SQLException { return(getObject(findColumn(name))); } // OK, that sucked, on to more stuff we don't use right now... /** * @see ResultSet */ public SQLWarning getWarnings() throws SQLException { return(null); } /** * @see ResultSet */ public void clearWarnings() throws SQLException { // nothing } /** * @see ResultSet */ public ResultSetMetaData getMetaData() throws SQLException { return(metadata); } }