/* * Copyright (c) 2004, 2005, 2006 TADA AB - Taby Sweden * Distributed under the terms shown in the file COPYRIGHT * found in the root folder of this project or at * http://eng.tada.se/osprojects/COPYRIGHT.html */ package org.postgresql.pljava.jdbc; import java.sql.SQLException; import java.sql.Statement; import java.sql.ResultSetMetaData; import org.postgresql.pljava.internal.Portal; import org.postgresql.pljava.internal.SPI; import org.postgresql.pljava.internal.TupleTable; import org.postgresql.pljava.internal.Tuple; import org.postgresql.pljava.internal.TupleDesc; /** * A Read-only ResultSet that provides direct access to a {@link * org.postgresql.pljava.internal.Portal Portal}. At present, only * forward positioning is implemented. Attempts to use reverse or * absolute positioning will fail. * * @author Thomas Hallgren */ public class SPIResultSet extends ResultSetBase { private final SPIStatement m_statement; private final Portal m_portal; private final TupleDesc m_tupleDesc; private final int m_maxRows; private Tuple m_currentRow; private Tuple m_nextRow; private TupleTable m_table; private int m_tableRow; SPIResultSet(SPIStatement statement, Portal portal, int maxRows) throws SQLException { super(statement.getFetchSize()); m_statement = statement; m_portal = portal; m_maxRows = maxRows; m_tupleDesc = portal.getTupleDesc(); m_tableRow = -1; } public int getFetchDirection() throws SQLException { return FETCH_FORWARD; } public void close() throws SQLException { if(m_portal.isValid()) { m_portal.close(); m_statement.resultSetClosed(this); m_table = null; m_tableRow = -1; m_currentRow = null; m_nextRow = null; super.close(); } } public boolean isLast() throws SQLException { return m_currentRow != null && this.peekNext() == null; } public boolean next() throws SQLException { m_currentRow = this.peekNext(); m_nextRow = null; boolean result = (m_currentRow != null); this.setRow(result ? this.getRow() + 1 : -1); return result; } public String getCursorName() throws SQLException { return this.getPortal().getName(); } public int findColumn(String columnName) throws SQLException { return m_tupleDesc.getColumnIndex(columnName); } public Statement getStatement() throws SQLException { return m_statement; } protected final Portal getPortal() throws SQLException { if(!m_portal.isValid()) throw new SQLException("ResultSet is closed"); return m_portal; } protected final TupleTable getTupleTable() throws SQLException { if(m_table == null) { Portal portal = this.getPortal(); if(portal.isAtEnd()) return null; int mx; int fetchSize = this.getFetchSize(); if(m_maxRows > 0) { mx = m_maxRows - portal.getPortalPos(); if(mx <= 0) return null; if(mx > fetchSize) mx = fetchSize; } else mx = fetchSize; try { int result = portal.fetch(true, mx); if(result > 0) m_table = SPI.getTupTable(m_tupleDesc); m_tableRow = -1; } finally { SPI.freeTupTable(); } } return m_table; } protected final Tuple getCurrentRow() throws SQLException { if(m_currentRow == null) throw new SQLException("ResultSet is not positioned on a valid row"); return m_currentRow; } protected final Tuple peekNext() throws SQLException { if(m_nextRow != null) return m_nextRow; TupleTable table = this.getTupleTable(); if(table == null) return null; if(m_tableRow >= table.getCount() - 1) { // Current table is exhaused, get the next // one. // m_table = null; table = this.getTupleTable(); if(table == null) return null; } m_nextRow = table.getSlot(++m_tableRow); return m_nextRow; } protected Object getObjectValue(int columnIndex) throws SQLException { return this.getCurrentRow().getObject(m_tupleDesc, columnIndex); } public ResultSetMetaData getMetaData() throws SQLException { return new SPIResultSetMetaData(m_tupleDesc); } }