bitronix.tm.resource.jdbc.JdbcPreparedStatementHandle Maven / Gradle / Ivy
/*
* Bitronix Transaction Manager
*
* Copyright (c) 2010, Bitronix Software.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package bitronix.tm.resource.jdbc;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
/**
* Caching {@link PreparedStatement} wrapper.
*
* This class is a proxy handler for a PreparedStatement. It does not
* implement the PreparedStatement interface or extend a class directly,
* but you methods implemented here will override those of the
* underlying delegate. Simply implement a method with the same
* signature, and the local method will be called rather than the delegate.
*
*
* @author lorban, brettw
*/
public class JdbcPreparedStatementHandle extends BaseProxyHandlerClass { // implements PreparedStatement
private PreparedStatement delegate;
private boolean pretendClosed = false;
// The 'parent' connection. Used to return the connection to the pool upon
// close().
private JdbcPooledConnection parentConnection;
// Brett Wooldridge: the following must be taken into account when caching a
// prepared statement. Defaults are per JDBC-specification.
//
// All of these attributes must match a proposed statement before the
// statement can be considered "the same" and delivered from the cache.
private final String sql;
private int resultSetType = ResultSet.TYPE_FORWARD_ONLY;
private int resultSetConcurrency = ResultSet.CONCUR_READ_ONLY;
private Integer resultSetHoldability;
private Integer autoGeneratedKeys;
private int[] columnIndexes;
private String[] columnNames;
/*
* PreparedStatement Constructors
*/
public JdbcPreparedStatementHandle(String sql) {
this.sql = sql;
}
public JdbcPreparedStatementHandle(String sql, int autoGeneratedKeys) {
this.sql = sql;
this.autoGeneratedKeys = new Integer(autoGeneratedKeys);
}
public JdbcPreparedStatementHandle(String sql, int resultSetType, int resultSetConcurrency) {
this.sql = sql;
this.resultSetType = resultSetType;
this.resultSetConcurrency = resultSetConcurrency;
}
public JdbcPreparedStatementHandle(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) {
this.sql = sql;
this.resultSetType = resultSetType;
this.resultSetConcurrency = resultSetConcurrency;
this.resultSetHoldability = new Integer(resultSetHoldability);
}
public JdbcPreparedStatementHandle(String sql, int[] columnIndexes) {
this.sql = sql;
this.columnIndexes = new int[columnIndexes.length];
System.arraycopy(columnIndexes, 0, this.columnIndexes, 0, columnIndexes.length);
}
public JdbcPreparedStatementHandle(String sql, String[] columnNames) {
this.sql = sql;
this.columnNames = new String[columnNames.length];
System.arraycopy(columnNames, 0, this.columnNames, 0, columnNames.length);
}
/* java.sql.Wrapper implementation */
public boolean isWrapperFor(Class> iface) throws SQLException {
return iface.isAssignableFrom(delegate.getClass());
}
public T unwrap(Class iface) throws SQLException {
if (iface.isAssignableFrom(delegate.getClass())) {
return (T) delegate;
}
throw new SQLException(getClass().getName() + " is not a wrapper for interface " + iface.getName());
}
/* Internal methods */
/**
* Set the parent connection that created this statement. We need this to
* return the PreparedStatement to the pool.
*
* @param pooledConnection the parent JdbcPooledConnection
*/
protected void setPooledConnection(JdbcPooledConnection pooledConnection) {
this.parentConnection = pooledConnection;
}
protected JdbcPooledConnection getPooledConnection() {
return parentConnection;
}
private PreparedStatement getDelegate() throws SQLException {
if (pretendClosed)
throw new SQLException("prepared statement closed");
return delegate;
}
protected PreparedStatement getDelegateUnchecked() {
return delegate;
}
protected void setDelegate(PreparedStatement delegate) {
this.delegate = delegate;
}
public Object getProxiedDelegate() throws Exception {
return getDelegate();
}
/* Overridden java.lang.Object methods */
/**
* Overridden equals() that takes all PreparedStatement attributes into
* account.
*/
public boolean equals(Object obj) {
if (!(obj instanceof JdbcPreparedStatementHandle)) {
return false;
}
JdbcPreparedStatementHandle otherStmt = (JdbcPreparedStatementHandle) obj;
if (!sql.equals(otherStmt.sql)) {
return false;
} else if (resultSetType != otherStmt.resultSetType) {
return false;
} else if (resultSetConcurrency != otherStmt.resultSetConcurrency) {
return false;
} else if (!Arrays.equals(columnIndexes, otherStmt.columnIndexes)) {
return false;
} else if (!Arrays.equals(columnNames, otherStmt.columnNames)) {
return false;
} else if ((autoGeneratedKeys == null && otherStmt.autoGeneratedKeys != null) ||
(autoGeneratedKeys != null && !autoGeneratedKeys.equals(otherStmt.autoGeneratedKeys))) {
return false;
} else if ((resultSetHoldability == null && otherStmt.resultSetHoldability != null) ||
(resultSetHoldability != null && !resultSetHoldability.equals(otherStmt.resultSetHoldability))) {
return false;
}
return true;
}
public int hashCode() {
return sql != null ? sql.hashCode() : System.identityHashCode(this);
}
public String toString() {
return "a JdbcPreparedStatementHandle with sql=[" + sql + "]";
}
/* Overridden methods of java.sql.PreparedStatement */
public void close() throws SQLException {
if (!pretendClosed) {
// Clear the parameters so the next use of this cached statement
// doesn't pick up unexpected values.
delegate.clearParameters();
// Return to cache so the usage count can be updated
parentConnection.putCachedStatement(this);
}
pretendClosed = true;
}
public boolean isClosed() throws SQLException {
return pretendClosed;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy