FileDocCategorySizeDatePackage
MsqlResultSet.javaAPI DocExample16833Tue Jan 01 00:00:00 GMT 1980COM.imaginary.sql.msql

MsqlResultSet.java

/* Copyright (c) 1997 George Reese */
package COM.imaginary.sql.msql;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Date;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.Statement;
import java.sql.Time;
import java.sql.Timestamp;
import java.sql.Types;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Hashtable;
import java.util.Vector;

/**
 * The MsqlResultSet class implements the JDBC ResultSet interface.
 * This class represents a SQL result set whose values can be retrieved
 * through the class' methods.  This class should never be directly
 * referenced.  Instead, you should use the JDBC API.<BR>
 * Last modified %D%
 * @version %A%
 * @author George Reese (borg@imaginary.com)
 */
public class MsqlResultSet implements ResultSet, Runnable {
    private final int         column_count;
    private Hashtable         column_map       = null;
    private boolean           complete         = false;
    private int               current_row      = -1;
    private byte[][]          current_row_data = null;
    private MsqlResultSet     field_info       = null;
    private byte[]            last_column      = null;
    private MsqlInputStream   input            = null;
    private ResultSetMetaData meta_data        = null;
    private boolean           meta_set         = false;
    private MsqlException     read_exception   = null;
    private Vector            rows             = new Vector();
    private MsqlStatement     statement        = null;
    private SQLWarning        warnings         = null;

    // Constructs the result set
    MsqlResultSet(MsqlStatement s, MsqlInputStream in, int count)
    throws SQLException {
	this(s, in, count, false);
	column_count = count;
    }

    // constructs the result set where the last arg signifies that this
    // result set is simply the meta data information
    MsqlResultSet(MsqlStatement s, MsqlInputStream in, int count, boolean meta)
    throws SQLException {
	super();
	statement = s;
	input = in;
	column_count = count;
	meta_set = meta;
	(new Thread(this)).start();
    }

    /**
     * @return true if the last value read was null
     * @exception java.sql.SQLException never thrown
     */
    public synchronized boolean wasNull() throws SQLException {
	if( last_column == null ) {
	    return true;
	}
	else {
	    return false;
	}
    }

    /**
     * For performance reasons, you should get values by column
     * number when at all possible.
     * @param cname the name of the desired column
     * @return an ASCII input stream for the column
     * @exception java.sql.SQLException thrown when the column cannot be read
     */
    public synchronized InputStream getAsciiStream(String cname)
    throws SQLException {
	return getAsciiStream(findColumn(cname));
    }

    /**
     * @param column the column number for the desired column
     * @return an ASCII input stream for the desired column
     * @exception java.sql.SQLException thrown when the columb cannot be read
     */
    public synchronized InputStream getAsciiStream(int column)
    throws SQLException {
	getColumn(column);
	return new MsqlAsciiInputStream(last_column);
    }

    public synchronized BigDecimal getBigDecimal(String cname, int scale)
    throws SQLException {
	return getBigDecimal(findColumn(cname), scale);
    }
    
    public synchronized BigDecimal getBigDecimal(int column, int scale)
    throws SQLException {
	String tmp = getString(column);
	     
	if( tmp == null ) {
	    return new BigDecimal(new BigInteger("0"), scale);
	}
	else {
	    return new BigDecimal(new BigInteger(tmp), scale);
	}
    }

    public synchronized InputStream getBinaryStream(String cname)
    throws SQLException {
	return getBinaryStream(findColumn(cname));
    }
    
    public synchronized InputStream getBinaryStream(int column)
    throws SQLException {
	getColumn(column);
	return new ByteArrayInputStream(last_column);
    }
  
    public synchronized boolean getBoolean(String cname) throws SQLException {
	return getBoolean(findColumn(cname));
    }
    
    public synchronized boolean getBoolean(int column) throws SQLException {
	getColumn(column);
	if( wasNull() ) {
	    return false;
	}
	if( last_column.length == 0 ) {
	    return false;
	}
	else if( last_column[0] == '0' || last_column[0] == '\0' ) {
	    return false;
	}
	else {
	    return true;
	}
    }

    public synchronized byte getByte(String cname) throws SQLException {
	return getByte(findColumn(cname));
    }
    
    public synchronized byte getByte(int column) throws SQLException {
	getColumn(column);
	if( wasNull() ) {
	    return (byte)0;
	}
	else {
	    return last_column[0];
	}
    }

    public synchronized byte[] getBytes(String cname) throws SQLException {
	return getBytes(findColumn(cname));
    }
    
    public synchronized byte[] getBytes(int column) throws SQLException {
	getColumn(column);
	return last_column;
    }

    private synchronized void getColumn(int column) throws SQLException {
	try {
	    last_column = current_row_data[column-1];
	}
	catch( Exception e ) {
	    if( current_row_data == null ) {
		throw new MsqlException("-1:Result set positioned before " +
					"first row.");
	    }
	    throw new MsqlException(e);
	}
    }

    public String getCursorName() throws SQLException {
	throw new SQLException("mSQL does not support cursors.");
    }

    public synchronized Date getDate(String cname) throws SQLException {
	return getDate(findColumn(cname));
    }
    
    public synchronized Date getDate(int column) throws SQLException {
	long time = getTimeAsLong(column);

	if( wasNull() ) {
	    return null;
	}
	else {
	    return new Date(time);
	}
    }
    
    public synchronized double getDouble(String cname) throws SQLException {
	return getDouble(findColumn(cname));
    }
    
    public synchronized double getDouble(int column) throws SQLException {
	String tmp = getString(column);
	
	if( tmp == null ) return 0;
	try {
	    return Double.valueOf(tmp).doubleValue();
	}
	catch( NumberFormatException e ) {
	    throw new MsqlException(e);
	}
    }  

    public synchronized float getFloat(String cname) throws SQLException {
	return getFloat(findColumn(cname));
    }
    
    public synchronized float getFloat(int column) throws SQLException {
	String tmp = getString(column);

	if( tmp == null ) {
	    return 0;
	}
	try {
	    return Float.valueOf(tmp).floatValue();
	}
	catch( NumberFormatException e ) {
	    throw new MsqlException(e);
	}
    }  

    public synchronized int getInt(String cname) throws SQLException {
	return getInt(findColumn(cname));
    }
    
    public synchronized int getInt(int column) throws SQLException {
	String tmp = getString(column);
	
	if( tmp == null ) {
	    return 0;
	}
	try {
	    return Integer.parseInt(tmp);
	}
	catch( NumberFormatException e ) {
	    throw new MsqlException(e);
	}
    }

    public synchronized long getLong(String cname) throws SQLException {
	return getLong(findColumn(cname));
    }
    
    public synchronized long getLong(int column) throws SQLException {
	String tmp = getString(column);

	if( tmp == null ) {
	    return 0;
	}
	try {
	    return Long.parseLong(tmp);
	}
	catch( NumberFormatException e ) {
	    throw new MsqlException(e);
	}
    }  

    public ResultSetMetaData getMetaData() throws SQLException {
	ResultSetMetaData meta;
	
	synchronized( this ) {
	    if( meta_data != null ) {
		return meta_data;
	    }
	}
	synchronized( rows ) {
	    while( field_info == null ) {
		try {
		    rows.wait();
		}
		catch( InterruptedException e ) {
		    if( field_info == null ) {
			throw new MsqlException(e);
		    }
		}
	    }
	    meta = new MsqlResultSetMetaData(field_info);
	}
	synchronized( this ) {
	    meta_data = meta;
	}
	return meta_data;
    }

    public synchronized Object getObject(String cname) throws SQLException {
	return getObject(findColumn(cname));
    }
  
    public synchronized Object getObject(int column) throws SQLException {
	ResultSetMetaData meta = getMetaData();
	int type = meta.getColumnType(column);
	
	switch(type) {
	case Types.BIT:
	    return new Boolean(getBoolean(column));
	    
	case Types.TINYINT:
	    return new Character((char)getInt(column));
	    
	case Types.SMALLINT:
	    return new Integer(getShort(column));
	    
	case Types.INTEGER:
	    return new Integer(getInt(column));
	    
	case Types.BIGINT:
	    return new Long(getLong(column));
	    
	case Types.FLOAT:
	    return new Float(getFloat(column));
	    
	case Types.REAL:
	    return new Float(getFloat(column));
	    
	case Types.DOUBLE:
	    return new Double(getDouble(column));
	    
	case Types.NUMERIC:
	    return getBigDecimal(column, 0);

	case Types.DECIMAL:
	    return getBigDecimal(column, 0);

	case Types.CHAR:
	    return getString(column);
	    
	case Types.VARCHAR:
	    return getString(column);
	    
	case Types.LONGVARCHAR:
	    return getString(column);
	    
	case Types.DATE:
	    return getDate(column);
	    
	case Types.TIME:
	    return getTime(column);
	    
	case Types.TIMESTAMP:
	    return getTimestamp(column);
	    
	case Types.BINARY:
	    return getBytes(column);
	    
	case Types.VARBINARY:
	    return getBytes(column);
	    
	case Types.LONGVARBINARY:
	    return getBytes(column);
	    
	default:
	    return getString(column);
	}
    }

    private byte[][] getRow(int row) throws SQLException {
	if( row < 0 ) {
	    throw new SQLException("Attempt to access a non-existent row.");
	}
	synchronized( rows ) {
	    if( read_exception != null ) {
		throw read_exception;
	    }
	    while( rows.size() <= row ) {
		if( complete ) {
		    throw new SQLException("Attempt to access a " +
					   "non-existent row.");
		}
		else {
		    try {
			rows.wait();
		    }
		    catch( InterruptedException e ) {
			throw new MsqlException(e);
		    }
		}
	    }
	}
	return (byte[][])rows.elementAt(row);
    }

    public synchronized short getShort(String cname) throws SQLException {
	return getShort(findColumn(cname));
    }
    
    public synchronized short getShort(int column) throws SQLException {
	String tmp = getString(column);

	if( tmp == null ) {
	    return 0;
	}
	try {
	    return (short)Short.parseShort(tmp);
	}
	catch( NumberFormatException e ) {
	    throw new MsqlException(e);
	}
    }

    MsqlStatement getStatement() {
	return statement;
    }
    
    public synchronized String getString(String cname) throws SQLException {
	return getString(findColumn(cname));
    }
    
    public synchronized String getString(int column) throws SQLException {
	getColumn(column);
	if( wasNull() ) {
	    return null;
	}
	else {
	    try {
		return new String(last_column, "8859_9");
	    }
	    catch( UnsupportedEncodingException e ) {
		throw new MsqlException(e);
	    }
	}
    }

    public synchronized Time getTime(String cname) throws SQLException {
	return getTime(findColumn(cname));
    }
    
    public synchronized Time getTime(int column) throws SQLException {
	long time = getTimeAsLong(column);

	if( wasNull() ) {
	    return null;
	}
	else {
	    return new Time(time);
	}
    }

    private long getTimeAsLong(int column) throws SQLException {
	String tmp = getString(column);  

	if( tmp == null ) {
	    return 0;
	}
	try {
	    return Long.parseLong(tmp);
	}
	catch( NumberFormatException e ) {
	    try {
		SimpleDateFormat format;
		java.util.Date date;
		
		format = new SimpleDateFormat("EEE MMM dd hh:mm:ss z yyyy");
		date = format.parse(tmp, new ParsePosition(0));
		return date.getTime();
	    }
	    catch( Exception real_e ) {
		throw new SQLException("Invalid date format.");
	    }
	}
    }

    public synchronized Timestamp getTimestamp(String cname)
    throws SQLException {
	return getTimestamp(findColumn(cname));
    }
    
    public synchronized Timestamp getTimestamp(int column)
    throws SQLException {
	long time = getTimeAsLong(column);

	if( wasNull() ) {
	    return null;
	}
	else {
	    return new Timestamp(time);
	}
    }

    public synchronized InputStream getUnicodeStream(String cname)
    throws SQLException {
	return getUnicodeStream(findColumn(cname));
    }
    
    public synchronized InputStream getUnicodeStream(int column)
    throws SQLException {
	getColumn(column);
	return new MsqlUnicodeInputStream(last_column);
    }

    public synchronized SQLWarning getWarnings() throws SQLException {
	return warnings;
    }

    public synchronized void clearWarnings() throws SQLException {
	warnings = null;
    }

    /**
     * Closes the result set.
     * @exception java.sql.SQLException thrown for errors on closing
     */
    public void close() throws SQLException {
	synchronized( rows ) {
	    while( !complete ) {
		try {
		    rows.wait();
		}
		catch( InterruptedException e ) {
		}
	    }
	    if( !meta_set && field_info != null ) {
		field_info.close();
	    }
	    input = null;
	}
    }

    /**
     * @param name the name of the desired column
     * @return the column number for the specified column name
     * @exception java.sql.SQLException thrown on a read error
     */
    public synchronized int findColumn(String name) throws SQLException {
	Integer num;
    
	if( column_map == null ) {
	    ResultSetMetaData meta;
	    int maxi;
	    
	    // Thanks to Joern Kellermann for this fix
	    meta = getMetaData();
	    column_map = new Hashtable(maxi = meta.getColumnCount());
	    for(int i=1; i<=maxi; i++) {
		column_map.put(meta.getColumnName(i), new Integer(i));
	    }
	}
	num = (Integer)column_map.get(name);
	if( num == null ) {
	    throw new SQLException("Invalid column name: " + name);
	}
	return num.intValue();
    }

    /**
     * Moves to the next row of data for processing.  If there are no
     * more rows to be processed, then it will return false.
     * @return true if there are results to be processed, false otherwise
     * @exception java.sql.SQLException thrown if a read error occurs
     */
    public synchronized boolean next() throws SQLException {
	current_row++;
	try {
	    current_row_data = getRow(current_row);
	}
	catch( SQLException e ) {
	    return false;
	}
	return true;
    }

    // reads a single row of data
    private void readRow(byte[] data) throws SQLException {
	byte[][] cols = new byte[column_count][];
	String ascii;

	try {
	    ascii = new String(data, "8859_9");
	}
	catch( UnsupportedEncodingException e ) {
	    throw new MsqlException(e);
	}
	for(int i=0; i<column_count; i++) {
	    // we can get away with this since ascii arabics == unicode arabics
	    int colon = ascii.indexOf(':');
	    byte[] column;
	    int size;

	    try {
		size = Integer.parseInt(ascii.substring(0, colon));
	    }
	    catch( NumberFormatException e ) {
		throw new SQLException("Invalid row data format from mSQL.");
	    }
	    if( size == -2 ) {
		column = null;
		size = 0;
	    }
	    else {
		String tmp = ascii.substring(colon+1, colon+size+1);

		try {
		    column = tmp.getBytes("8859_9");
		}
		catch( UnsupportedEncodingException e ) {
		    throw new MsqlException(e);
		}
	    }
	    cols[i] = column;
	    ascii = ascii.substring(colon+size+1);
	}
	synchronized( rows ) {
	    rows.addElement(cols);
	    rows.notify();
	}
    }

    // loads the results
    public void run() {
	while( true ) {
	    byte[] data;
	    String tmp;

	    synchronized( input ) {
		try {
		    data = input.read();
		}
		catch( IOException e ) {
		    synchronized( rows ) {
			//statement.passIOException(e);
			read_exception = new MsqlException(e);
			complete = true;
			input = null;
			return;
		    }
		}
	    }
	    try {
		tmp = new String(data, "8859_9");
	    }
	    catch( UnsupportedEncodingException e ) {
		e.printStackTrace();
		synchronized( rows ) {
		    //statement.passIOException(e);
		    read_exception = new MsqlException(e);
		    complete = true;
		    rows.notify();
		}
		return;
	    }
	    if( tmp.startsWith("-1:") ) {
		synchronized( rows ) {
		    read_exception = new MsqlException(tmp);
		    complete = true;
		    rows.notify();
		}
		return;
	    }
	    else if( tmp.startsWith("-100") ) {
		break;
	    }
	    else {
		try {
		    readRow(data);
		}
		catch( SQLException e ) {
		    synchronized( rows ) {
			read_exception = new MsqlException(e);
			complete = true;
			rows.notify();
		    }
		    return;
		}
	    }
	}
	synchronized( rows ) {
	    if( !meta_set ) {
		try {
		    field_info = new MsqlResultSet(statement, input, 6, true);
		}
		catch( SQLException e ) {
		    e.printStackTrace();
		    field_info = null;
		}
	    }
	    complete = true;
	    rows.notify();
	}
    }
}