package net.sourceforge.mayfly;
import net.sourceforge.mayfly.datastore.Cell;
import net.sourceforge.mayfly.datastore.NullCell;
import net.sourceforge.mayfly.evaluation.ResultRow;
import net.sourceforge.mayfly.evaluation.ResultRows;
import net.sourceforge.mayfly.evaluation.Value;
import net.sourceforge.mayfly.evaluation.ValueList;
import net.sourceforge.mayfly.evaluation.what.Selected;
import net.sourceforge.mayfly.parser.Location;
import org.joda.time.DateTimeZone;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import java.math.BigDecimal;
import java.sql.Blob;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Calendar;
public final class MayflyResultSet extends ResultSetStub {
private int pos = -1;
private boolean wasNull = false;
private final ResultRows rows;
private final Selected selected;
public MayflyResultSet(Selected selected, ResultRows rows) {
super();
this.selected = selected;
this.rows = rows;
}
@Override
public boolean next() {
++pos;
if (pos >= rows.rowCount()) {
return false;
} else {
return true;
}
}
@Override
public byte getByte(String columnName) throws SQLException {
return cellFromName(columnName).asByte();
}
@Override
public byte getByte(int oneBasedColumn) throws SQLException {
return cellFromIndex(oneBasedColumn).asByte();
}
@Override
public short getShort(String columnName) throws SQLException {
return cellFromName(columnName).asShort();
}
@Override
public short getShort(int oneBasedColumn) throws SQLException {
return cellFromIndex(oneBasedColumn).asShort();
}
@Override
public int getInt(String columnName) throws SQLException {
return cellFromName(columnName).asInt();
}
@Override
public int getInt(int oneBasedColumn) throws SQLException {
return cellFromIndex(oneBasedColumn).asInt();
}
@Override
public long getLong(String columnName) throws SQLException {
try {
return cellFromName(columnName).asLong();
} catch (MayflyException e) {
throw e.asSqlException();
}
}
@Override
public long getLong(int oneBasedColumn) throws SQLException {
try {
return cellFromIndex(oneBasedColumn).asLong();
} catch (MayflyException e) {
throw e.asSqlException();
}
}
@Override
public BigDecimal getBigDecimal(String columnName) throws SQLException {
return cellFromName(columnName).asBigDecimal();
}
@Override
public BigDecimal getBigDecimal(int oneBasedColumn) throws SQLException {
return cellFromIndex(oneBasedColumn).asBigDecimal();
}
private static final String SUGGEST_SET_SCALE =
"Instead of passing a scale to getBigDecimal, \n" +
"call getBigDecimal without a scale and then call setScale on the returned BigDecimal";
/** @internal
* @deprecated */
@Override
public BigDecimal getBigDecimal(String columnName, int scale) throws SQLException {
throw new SQLException(SUGGEST_SET_SCALE);
}
/** @internal
* @deprecated */
@Override
public BigDecimal getBigDecimal(int oneBasedColumn, int scale) throws SQLException {
throw new SQLException(SUGGEST_SET_SCALE);
}
@Override
public double getDouble(String columnName) throws SQLException {
return cellFromName(columnName).asDouble();
}
@Override
public float getFloat(String columnName) throws SQLException {
/* As float is an inexact type, I think that truncating is
probably the right thing, rather than throwing an exception
for values out of range. */
return (float) cellFromName(columnName).asDouble();
}
@Override
public double getDouble(int oneBasedColumn) throws SQLException {
return cellFromIndex(oneBasedColumn).asDouble();
}
@Override
public float getFloat(int oneBasedColumn) throws SQLException {
return (float) cellFromIndex(oneBasedColumn).asDouble();
}
@Override
public String getString(String columnName) throws SQLException {
try {
return cellFromName(columnName).asString();
}
catch (MayflyException e) {
throw e.asSqlException();
}
}
@Override
public String getString(int oneBasedColumn) throws SQLException {
try {
return cellFromIndex(oneBasedColumn).asString();
}
catch (MayflyException e) {
throw e.asSqlException();
}
}
@Override
public Reader getCharacterStream(String columnName) throws SQLException {
return new StringReader(getString(columnName));
}
@Override
public Reader getCharacterStream(int columnIndex) throws SQLException {
return new StringReader(getString(columnIndex));
}
@Override
public InputStream getBinaryStream(int columnIndex) throws SQLException {
return cellFromIndex(columnIndex).asBinaryStream();
}
@Override
public InputStream getBinaryStream(String columnName) throws SQLException {
return cellFromName(columnName).asBinaryStream();
}
@Override
public Blob getBlob(int columnIndex) throws SQLException {
return cellFromIndex(columnIndex).asBlob();
}
@Override
public Blob getBlob(String columnName) throws SQLException {
return cellFromName(columnName).asBlob();
}
@Override
public byte[] getBytes(int columnIndex) throws SQLException {
return cellFromIndex(columnIndex).asBytes();
}
@Override
public byte[] getBytes(String columnName) throws SQLException {
return cellFromName(columnName).asBytes();
}
private static final String SUGGEST_GET_CHARACTER_STREAM =
"We suggest getCharacterStream instead";
/**
* @deprecated
*/
@Override
public InputStream getUnicodeStream(int columnIndex) throws SQLException {
throw new UnimplementedException(SUGGEST_GET_CHARACTER_STREAM);
}
/**
* @deprecated
*/
@Override
public InputStream getUnicodeStream(String columnName) throws SQLException {
throw new UnimplementedException(SUGGEST_GET_CHARACTER_STREAM);
}
@Override
public InputStream getAsciiStream(int columnIndex) throws SQLException {
throw new UnimplementedException(SUGGEST_GET_CHARACTER_STREAM);
}
@Override
public InputStream getAsciiStream(String columnName) throws SQLException {
throw new UnimplementedException(SUGGEST_GET_CHARACTER_STREAM);
}
@Override
public java.sql.Date getDate(String columnName, Calendar calendar)
throws SQLException {
return cellFromName(columnName).asDate(timeZone(calendar));
}
@Override
public java.sql.Date getDate(String columnName) throws SQLException {
return cellFromName(columnName).asDate(DateTimeZone.getDefault());
}
@Override
public java.sql.Date getDate(int oneBasedColumn, Calendar calendar)
throws SQLException {
return cellFromIndex(oneBasedColumn).asDate(timeZone(calendar));
}
@Override
public java.sql.Date getDate(int oneBasedColumn) throws SQLException {
return cellFromIndex(oneBasedColumn).asDate(DateTimeZone.getDefault());
}
@Override
public Timestamp getTimestamp(String columnName) throws SQLException {
return cellFromName(columnName).asTimestamp(DateTimeZone.getDefault());
}
@Override
public Timestamp getTimestamp(int oneBasedColumn) throws SQLException {
return cellFromIndex(oneBasedColumn)
.asTimestamp(DateTimeZone.getDefault());
}
private DateTimeZone timeZone(Calendar calendar) {
return DateTimeZone.forTimeZone(calendar.getTimeZone());
}
@Override
public Object getObject(String columnName) throws SQLException {
try {
return cellFromName(columnName).asObject();
} catch (MayflyException e) {
throw e.asSqlException();
}
}
@Override
public Object getObject(int oneBasedColumn) throws SQLException {
try {
return cellFromIndex(oneBasedColumn).asObject();
} catch (MayflyException e) {
throw e.asSqlException();
}
}
@Override
public boolean wasNull() throws SQLException {
return wasNull;
}
private Cell cellFromName(String columnName) throws SQLException {
try {
Cell cell = selected.evaluate(columnName, currentRow());
wasNull = cell instanceof NullCell;
return cell;
} catch (MayflyException e) {
throw e.asSqlException();
}
}
private Cell cellFromIndex(int oneBasedColumn) throws SQLException {
try {
Cell cell = selected.evaluate(oneBasedColumn, currentRow());
wasNull = cell instanceof NullCell;
return cell;
} catch (MayflyException e) {
throw e.asSqlException();
}
}
private ResultRow currentRow() throws MayflyException {
return rows.row(checkedRowNumber());
}
private int checkedRowNumber() throws MayflyException {
if (pos < 0) {
throw new MayflyException("no current result row");
}
if (pos >= rows.rowCount()) {
throw new MayflyException("already read last result row");
}
return pos;
}
@Override
public void close() throws SQLException {
}
public Cell scalar() {
return scalar(Location.UNKNOWN);
}
/**
* @internal
* Return the result of a query which returns just a single cell.
*/
public Cell scalar(Location location) {
checkOneColumn(location);
if (rows.rowCount() == 0) {
return NullCell.INSTANCE;
}
else if (rows.rowCount() != 1) {
throw new MayflyException(
"subselect expects one row but got " + rows.rowCount(),
location);
}
return selected.evaluate(1, rows.row(0));
}
/**
* @internal
* Return the single cell from the current row.
*/
public Cell singleColumn(Location location) {
checkOneColumn(location);
return selected.evaluate(1, currentRow());
}
private void checkOneColumn(Location location) {
if (selected.size() != 1) {
throw new MayflyException(
"attempt to specify " + selected.size() +
" expressions in a subselect",
location);
}
}
/**
* @internal
* Return the values from the current row.
*/
public ValueList asValues(Location location) {
ResultRow row = currentRow();
ValueList values = new ValueList(location);
for (int zeroBasedColumn = 0;
zeroBasedColumn < selected.size();
++zeroBasedColumn) {
Cell cell = selected.evaluate(zeroBasedColumn + 1, row);
values = values.with(new Value(cell, location));
}
return values;
}
public String debugString() {
return rows.debugString();
}
}