/* * Copyright (c) 2004, 2005, 2006 TADA AB - Taby Sweden * Copyright (c) 2008, 2010, 2011 PostgreSQL Global Development Group * * Distributed under the terms shown in the file COPYRIGHT * found in the root folder of this project or at * http://wiki.tada.se/index.php?title=PLJava_License */ package org.postgresql.pljava.jdbc; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.sql.SQLWarning; import java.sql.Statement; import java.util.ArrayList; import org.postgresql.pljava.internal.ExecutionPlan; import org.postgresql.pljava.internal.Portal; import org.postgresql.pljava.internal.SPI; import org.postgresql.pljava.internal.SPIException; /** * * @author Thomas Hallgren */ public class SPIStatement implements Statement { private final SPIConnection m_connection; // Default settings. // private String m_cursorName = null; private int m_fetchSize = 1000; private int m_maxRows = 0; private ResultSet m_resultSet = null; private int m_updateCount = 0; private ArrayList m_batch = null; private boolean m_closed = false; public SPIStatement(SPIConnection conn) { m_connection = conn; } public void addBatch(String statement) throws SQLException { // Statements are converted to native SQL once they // are executed. // this.internalAddBatch(statement); } public void cancel() throws SQLException { } public void clearBatch() throws SQLException { m_batch = null; } public void clearWarnings() throws SQLException { } private void clear() throws SQLException { if(m_resultSet != null) // // The close will call back to the resultSetClosed method // and set the m_resultSet to null. // m_resultSet.close(); m_updateCount = -1; m_cursorName = null; m_batch = null; } public void close() throws SQLException { clear(); m_closed = true; } public boolean execute(String statement) throws SQLException { // Ensure that the last statement is cleaned up // before we re-execute // this.clear(); ExecutionPlan plan = ExecutionPlan.prepare( m_connection.nativeSQL(statement), null); int result = SPI.getResult(); if(plan == null) throw new SPIException(result); try { return this.executePlan(plan, null); } finally { try { plan.close(); } catch(Exception e) {} } } protected boolean executePlan(ExecutionPlan plan, Object[] paramValues) throws SQLException { m_updateCount = -1; m_resultSet = null; boolean isResultSet = plan.isCursorPlan(); if(isResultSet) { Portal portal = plan.cursorOpen(m_cursorName, paramValues); m_resultSet = new SPIResultSet(this, portal, m_maxRows); } else { try { plan.execute(paramValues, m_maxRows); m_updateCount = SPI.getProcessed(); } finally { SPI.freeTupTable(); } } return isResultSet; } /** * Return of auto generated keys is not yet supported. * @throws SQLException indicating that this feature is not supported. */ public boolean execute(String statement, int autoGeneratedKeys) throws SQLException { throw new UnsupportedFeatureException("Statement.execute(String,int)"); } /** * Return of auto generated keys is not yet supported. * @throws SQLException indicating that this feature is not supported. */ public boolean execute(String statement, int[] columnIndexes) throws SQLException { throw new UnsupportedFeatureException("Statement.execute(String,int[])"); } /** * Return of auto generated keys is not yet supported. * @throws SQLException indicating that this feature is not supported. */ public boolean execute(String statement, String[] columnNames) throws SQLException { throw new UnsupportedFeatureException("Statement.execute(String,String[])"); } public int[] executeBatch() throws SQLException { int numBatches = (m_batch == null) ? 0 : m_batch.size(); int[] result = new int[numBatches]; for(int idx = 0; idx < numBatches; ++idx) result[idx] = this.executeBatchEntry(m_batch.get(idx)); return result; } public ResultSet executeQuery(String statement) throws SQLException { this.execute(statement); return this.getResultSet(); } public int executeUpdate(String statement) throws SQLException { this.execute(statement); return this.getUpdateCount(); } /** * Return of auto generated keys is not yet supported. * @throws SQLException indicating that this feature is not supported. */ public int executeUpdate(String statement, int autoGeneratedKeys) throws SQLException { throw new UnsupportedFeatureException("Auto generated key support not yet implemented"); } /** * Return of auto generated keys is not yet supported. * @throws SQLException indicating that this feature is not supported. */ public int executeUpdate(String statement, int[] columnIndexes) throws SQLException { throw new UnsupportedFeatureException("Auto generated key support not yet implemented"); } /** * Return of auto generated keys is not yet supported. * @throws SQLException indicating that this feature is not supported. */ public int executeUpdate(String statement, String[] columnNames) throws SQLException { throw new UnsupportedFeatureException("Auto generated key support not yet implemented"); } /** * Returns the Connection from that created this statement. * @throws SQLException if the statement is closed. */ public Connection getConnection() throws SQLException { if(m_connection == null) throw new StatementClosedException(); return m_connection; } public int getFetchDirection() throws SQLException { return ResultSet.FETCH_FORWARD; } public int getFetchSize() throws SQLException { return m_fetchSize; } public ResultSet getGeneratedKeys() throws SQLException { throw new SQLException("JDK 1.4 functionality not yet implemented"); } public int getMaxFieldSize() throws SQLException { return Integer.MAX_VALUE; } public int getMaxRows() throws SQLException { return m_maxRows; } public boolean getMoreResults() throws SQLException { return false; } public boolean getMoreResults(int current) throws SQLException { return false; } public int getQueryTimeout() throws SQLException { return 0; } public ResultSet getResultSet() throws SQLException { return m_resultSet; } public int getResultSetConcurrency() { return ResultSet.CONCUR_READ_ONLY; } public int getResultSetHoldability() throws SQLException { throw new SQLException("JDK 1.4 functionality not yet implemented"); } public int getResultSetType() { return ResultSet.TYPE_FORWARD_ONLY; } public int getUpdateCount() throws SQLException { return m_updateCount; } public SQLWarning getWarnings() throws SQLException { if (m_closed) { throw new SQLException("getWarnings: Statement is closed"); } return null; } public void setCursorName(String cursorName) throws SQLException { m_cursorName = cursorName; } public void setEscapeProcessing(boolean enable) throws SQLException { throw new UnsupportedFeatureException("Statement.setEscapeProcessing"); } /** * Only {@link ResultSet#FETCH_FORWARD} is supported. * @throws SQLException indicating that this feature is not supported * for other values on <code>direction</code>. */ public void setFetchDirection(int direction) throws SQLException { if(direction != ResultSet.FETCH_FORWARD) throw new UnsupportedFeatureException("Non forward fetch direction"); } public void setFetchSize(int size) throws SQLException { m_fetchSize = size; } public void setMaxFieldSize(int size) throws SQLException { throw new UnsupportedFeatureException("Statement.setMaxFieldSize"); } public void setMaxRows(int rows) throws SQLException { m_maxRows = rows; } public void setQueryTimeout(int seconds) throws SQLException { throw new UnsupportedFeatureException("Statement.setQueryTimeout"); } protected void internalAddBatch(Object batch) throws SQLException { if(m_batch == null) m_batch = new ArrayList(); m_batch.add(batch); } protected int executeBatchEntry(Object batchEntry) throws SQLException { int ret = SUCCESS_NO_INFO; if(this.execute(m_connection.nativeSQL((String)batchEntry))) this.getResultSet().close(); else if(m_updateCount >= 0) ret = m_updateCount; return ret; } void resultSetClosed(ResultSet rs) { if(rs == m_resultSet) m_resultSet = null; } // ************************************************************ // Non-implementation of JDBC 4 methods. // ************************************************************ public void setPoolable(boolean poolable) throws SQLException { throw new SQLFeatureNotSupportedException ( this.getClass() + ".setPoolable( boolean ) not implemented yet.", "0A000" ); } public boolean isPoolable() throws SQLException { throw new SQLFeatureNotSupportedException ( this.getClass() + ".isPoolable() not implemented yet.", "0A000" ); } public boolean isClosed() throws SQLException { throw new SQLFeatureNotSupportedException ( this.getClass() + ".isClosed() not implemented yet.", "0A000" ); } public boolean isWrapperFor(Class<?> iface) throws SQLException { throw new SQLFeatureNotSupportedException ( this.getClass() + ".isWrapperFor( Class<?> ) not implemented yet.", "0A000" ); } public <T> T unwrap(Class<T> iface) throws SQLException { throw new SQLFeatureNotSupportedException ( this.getClass() + ".unwrapClass( Class<T> ) not implemented yet.", "0A000" ); } public void closeOnCompletion() throws SQLException { throw new SQLFeatureNotSupportedException ( this.getClass() + ".closeOneCompletion() not implemented yet.", "0A000" ); } public boolean isCloseOnCompletion() throws SQLException { return false; } }