Wrappers for PreparedStatement and ResultSet

This commit is contained in:
Andrew Golovashevich 2025-03-25 01:00:04 +03:00
parent a33ecc068c
commit 0c553c7c3d
2 changed files with 386 additions and 0 deletions

View File

@ -0,0 +1,357 @@
package ru.langrafhomyak.db.jdbc_resources_manager
import java.io.InputStream
import java.io.Reader
import java.math.BigDecimal
import java.net.URL
import java.sql.Array
import java.sql.Blob
import java.sql.Clob
import java.sql.Connection
import java.sql.Date
import java.sql.NClob
import java.sql.ParameterMetaData
import java.sql.PreparedStatement
import java.sql.Ref
import java.sql.ResultSet
import java.sql.ResultSetMetaData
import java.sql.RowId
import java.sql.SQLException
import java.sql.SQLWarning
import java.sql.SQLXML
import java.sql.Statement
import java.sql.Time
import java.sql.Timestamp
import java.util.Calendar
import ru.landrafhomyak.utility.reference_counter.CloseableReferenceCounter
@Suppress("UsePropertyAccessSyntax")
internal abstract class PreparedStatementWrapper(protected val _orig: PreparedStatement) : PreparedStatement {
private val _refcnt = CloseableReferenceCounter("This prepared statement was returned to pool to be used in future")
private var _currentQuery: ResultSetWrapper? = null
private var _closeOnCompletion: Boolean = false
protected abstract fun _onClose()
override fun close() {
this._refcnt.close("Can't close prepared statement while it's in use")
this._onClose()
}
override fun closeOnCompletion() =
this._refcnt.withRef { this._closeOnCompletion = true }
override fun isCloseOnCompletion(): Boolean =
this._refcnt.withRef { this._closeOnCompletion }
private inner class _BoundResultSetWrapper(orig: ResultSet) : ResultSetWrapper(orig) {
override fun close() {
if (this._orig.isClosed)
return
this._orig.close()
this@PreparedStatementWrapper._currentQuery = null
if (this@PreparedStatementWrapper._closeOnCompletion)
this@PreparedStatementWrapper.close()
}
override fun getStatement(): Statement? = this@PreparedStatementWrapper
}
private fun _prepareRS(rs: ResultSet): ResultSet {
val wrapped = this._BoundResultSetWrapper(rs)
this._currentQuery = wrapped
return wrapped
}
override fun executeQuery(): ResultSet? =
this._refcnt.withRef { this._orig.executeQuery()?.let(this::_prepareRS) }
override fun getResultSet(): ResultSet? =
this._refcnt.withRef { this._orig.getResultSet()?.let(this::_prepareRS) }
override fun getGeneratedKeys(): ResultSet? =
this._refcnt.withRef { this._orig.getGeneratedKeys()?.let(this::_prepareRS) }
override fun <T : Any?> unwrap(iface: Class<T?>): T? =
iface.cast(this) ?: this._orig.unwrap(iface)
override fun isWrapperFor(iface: Class<*>): Boolean =
iface.isInstance(this) || this._orig.isWrapperFor(iface)
override fun cancel() =
this._refcnt.withRef(this._orig::cancel)
override fun executeUpdate(): Int =
this._refcnt.withRef(this._orig::executeUpdate)
override fun setNull(parameterIndex: Int, sqlType: Int) =
this._refcnt.withRef { this._orig.setNull(parameterIndex, sqlType) }
override fun setBoolean(parameterIndex: Int, x: Boolean) =
this._refcnt.withRef { this._orig.setBoolean(parameterIndex, x) }
override fun setByte(parameterIndex: Int, x: Byte) =
this._refcnt.withRef { this._orig.setByte(parameterIndex, x) }
override fun setShort(parameterIndex: Int, x: Short) =
this._refcnt.withRef { this._orig.setShort(parameterIndex, x) }
override fun setInt(parameterIndex: Int, x: Int) =
this._refcnt.withRef { this._orig.setInt(parameterIndex, x) }
override fun setLong(parameterIndex: Int, x: Long) =
this._refcnt.withRef { this._orig.setLong(parameterIndex, x) }
override fun setFloat(parameterIndex: Int, x: Float) =
this._refcnt.withRef { this._orig.setFloat(parameterIndex, x) }
override fun setDouble(parameterIndex: Int, x: Double) =
this._refcnt.withRef { this._orig.setDouble(parameterIndex, x) }
override fun setBigDecimal(parameterIndex: Int, x: BigDecimal?) =
this._refcnt.withRef { this._orig.setBigDecimal(parameterIndex, x) }
override fun setString(parameterIndex: Int, x: String?) =
this._refcnt.withRef { this._orig.setString(parameterIndex, x) }
override fun setBytes(parameterIndex: Int, x: ByteArray?) =
this._refcnt.withRef { this._orig.setBytes(parameterIndex, x) }
override fun setDate(parameterIndex: Int, x: Date?) =
this._refcnt.withRef { this._orig.setDate(parameterIndex, x) }
override fun setTime(parameterIndex: Int, x: Time?) =
this._refcnt.withRef { this._orig.setTime(parameterIndex, x) }
override fun setTimestamp(parameterIndex: Int, x: Timestamp?) =
this._refcnt.withRef { this._orig.setTimestamp(parameterIndex, x) }
override fun setAsciiStream(parameterIndex: Int, x: InputStream?, length: Int) =
this._refcnt.withRef { this._orig.setAsciiStream(parameterIndex, x, length) }
@Deprecated("Deprecated in Java")
override fun setUnicodeStream(parameterIndex: Int, x: InputStream?, length: Int) =
this._refcnt.withRef { this._orig.setUnicodeStream(parameterIndex, x, length) }
override fun setBinaryStream(parameterIndex: Int, x: InputStream?, length: Int) =
this._refcnt.withRef { this._orig.setBinaryStream(parameterIndex, x) }
override fun clearParameters() =
this._refcnt.withRef(this._orig::clearParameters)
override fun setObject(parameterIndex: Int, x: Any?, targetSqlType: Int) =
this._refcnt.withRef { this._orig.setObject(parameterIndex, x, targetSqlType) }
override fun setObject(parameterIndex: Int, x: Any?) =
this._refcnt.withRef { this._orig.setObject(parameterIndex, x) }
override fun execute(): Boolean =
this._refcnt.withRef(this._orig::execute)
override fun addBatch() =
this._refcnt.withRef(this._orig::addBatch)
override fun setCharacterStream(parameterIndex: Int, reader: Reader?, length: Int) =
this._refcnt.withRef { this._orig.setCharacterStream(parameterIndex, reader, length) }
override fun setRef(parameterIndex: Int, x: Ref?) =
this._refcnt.withRef { this._orig.setRef(parameterIndex, x) }
override fun setBlob(parameterIndex: Int, x: Blob?) =
this._refcnt.withRef { this._orig.setBlob(parameterIndex, x) }
override fun setClob(parameterIndex: Int, x: Clob?) =
this._refcnt.withRef { this._orig.setClob(parameterIndex, x) }
override fun setArray(parameterIndex: Int, x: Array?) =
this._refcnt.withRef { this._orig.setArray(parameterIndex, x) }
override fun getMetaData(): ResultSetMetaData? =
this._refcnt.withRef(this._orig::getMetaData)
override fun setDate(parameterIndex: Int, x: Date?, cal: Calendar?) =
this._refcnt.withRef { this._orig.setDate(parameterIndex, x) }
override fun setTime(parameterIndex: Int, x: Time?, cal: Calendar?) =
this._refcnt.withRef { this._orig.setTime(parameterIndex, x) }
override fun setTimestamp(parameterIndex: Int, x: Timestamp?, cal: Calendar?) =
this._refcnt.withRef { this._orig.setTimestamp(parameterIndex, x) }
override fun setNull(parameterIndex: Int, sqlType: Int, typeName: String?) =
this._refcnt.withRef { this._orig.setNull(parameterIndex, sqlType, typeName) }
override fun setURL(parameterIndex: Int, x: URL?) =
this._refcnt.withRef { this._orig.setURL(parameterIndex, x) }
override fun getParameterMetaData(): ParameterMetaData? =
this._refcnt.withRef(this._orig::getParameterMetaData)
override fun setRowId(parameterIndex: Int, x: RowId?) =
this._refcnt.withRef { this._orig.setRowId(parameterIndex, x) }
override fun setNString(parameterIndex: Int, value: String?) =
this._refcnt.withRef { this._orig.setNString(parameterIndex, value) }
override fun setNCharacterStream(parameterIndex: Int, value: Reader?, length: Long) =
this._refcnt.withRef { this._orig.setNCharacterStream(parameterIndex, value, length) }
override fun setNClob(parameterIndex: Int, value: NClob?) =
this._refcnt.withRef { this._orig.setNClob(parameterIndex, value) }
override fun setClob(parameterIndex: Int, reader: Reader?, length: Long) =
this._refcnt.withRef { this._orig.setClob(parameterIndex, reader, length) }
override fun setBlob(parameterIndex: Int, inputStream: InputStream?, length: Long) =
this._refcnt.withRef { this._orig.setBlob(parameterIndex, inputStream, length) }
override fun setNClob(parameterIndex: Int, reader: Reader?, length: Long) =
this._refcnt.withRef { this._orig.setNClob(parameterIndex, reader, length) }
override fun setSQLXML(parameterIndex: Int, xmlObject: SQLXML?) =
this._refcnt.withRef { this._orig.setSQLXML(parameterIndex, xmlObject) }
override fun setObject(parameterIndex: Int, x: Any?, targetSqlType: Int, scaleOrLength: Int) =
this._refcnt.withRef { this._orig.setObject(parameterIndex, x, targetSqlType, scaleOrLength) }
override fun setAsciiStream(parameterIndex: Int, x: InputStream?, length: Long) =
this._refcnt.withRef { this._orig.setAsciiStream(parameterIndex, x, length) }
override fun setBinaryStream(parameterIndex: Int, x: InputStream?, length: Long) =
this._refcnt.withRef { this._orig.setBinaryStream(parameterIndex, x, length) }
override fun setCharacterStream(parameterIndex: Int, reader: Reader?, length: Long) =
this._refcnt.withRef { this._orig.setCharacterStream(parameterIndex, reader, length) }
override fun setAsciiStream(parameterIndex: Int, x: InputStream?) =
this._refcnt.withRef { this._orig.setAsciiStream(parameterIndex, x) }
override fun setBinaryStream(parameterIndex: Int, x: InputStream?) =
this._refcnt.withRef { this._orig.setBinaryStream(parameterIndex, x) }
override fun setCharacterStream(parameterIndex: Int, reader: Reader?) =
this._refcnt.withRef { this._orig.setCharacterStream(parameterIndex, reader) }
override fun setNCharacterStream(parameterIndex: Int, value: Reader?) =
this._refcnt.withRef { this._orig.setNCharacterStream(parameterIndex, value) }
override fun setClob(parameterIndex: Int, reader: Reader?) =
this._refcnt.withRef { this._orig.setClob(parameterIndex, reader) }
override fun setBlob(parameterIndex: Int, inputStream: InputStream?) =
this._refcnt.withRef { this._orig.setBlob(parameterIndex, inputStream) }
override fun setNClob(parameterIndex: Int, reader: Reader?) =
this._refcnt.withRef { this._orig.setNClob(parameterIndex, reader) }
override fun executeQuery(sql: String?): ResultSet? =
throw SQLException("executeQuery(String) not allowed on PreparedStatement")
override fun executeUpdate(sql: String?): Int =
throw SQLException("executeUpdate(String) not allowed on PreparedStatement")
override fun getMaxFieldSize(): Int =
this._refcnt.withRef(this._orig::getMaxFieldSize)
override fun setMaxFieldSize(max: Int) =
this._refcnt.withRef { this._orig.setMaxFieldSize(max) }
override fun getMaxRows(): Int =
this._refcnt.withRef(this._orig::getMaxRows)
override fun setMaxRows(max: Int) =
this._refcnt.withRef { this._orig.setMaxRows(max) }
override fun setEscapeProcessing(enable: Boolean) =
this._refcnt.withRef { this._orig.setEscapeProcessing(enable) }
override fun getQueryTimeout(): Int =
this._refcnt.withRef(this._orig::getQueryTimeout)
override fun setQueryTimeout(seconds: Int) =
this._refcnt.withRef { this._orig.setQueryTimeout(seconds) }
override fun getWarnings(): SQLWarning? =
this._refcnt.withRef(this._orig::getWarnings)
override fun clearWarnings() =
this._refcnt.withRef(this._orig::clearWarnings)
override fun setCursorName(name: String?) =
this._refcnt.withRef { this._orig.setCursorName(name) }
override fun execute(sql: String?): Boolean =
throw SQLException("execute(String) not allowed on PreparedStatement")
override fun getUpdateCount(): Int =
this._refcnt.withRef(this._orig::getUpdateCount)
override fun getMoreResults() =
this._refcnt.withRef(this._orig::getMoreResults)
override fun setFetchDirection(direction: Int) =
this._refcnt.withRef { this._orig.setFetchDirection(direction) }
override fun getFetchDirection() =
this._refcnt.withRef(this._orig::getFetchDirection)
override fun setFetchSize(rows: Int) =
this._refcnt.withRef { this._orig.setFetchSize(rows) }
override fun getFetchSize() =
this._refcnt.withRef(this._orig::getFetchSize)
override fun getResultSetConcurrency() =
this._refcnt.withRef(this._orig::getFetchSize)
override fun getResultSetType() =
this._refcnt.withRef(this._orig::getFetchSize)
override fun addBatch(sql: String?) =
throw SQLException("addBatch(String) not allowed on PreparedStatement")
override fun clearBatch() =
this._refcnt.withRef(this._orig::clearBatch)
override fun executeBatch(): IntArray? =
this._refcnt.withRef(this._orig::executeBatch)
override fun getConnection(): Connection? =
this._orig.getConnection()
override fun getMoreResults(current: Int): Boolean =
this._refcnt.withRef { this._orig.getMoreResults(current) }
override fun executeUpdate(sql: String?, autoGeneratedKeys: Int): Int =
throw SQLException("executeUpdate(String, int) not allowed on PreparedStatement")
override fun executeUpdate(sql: String?, columnIndexes: IntArray?): Int =
throw SQLException("executeUpdate(String, int[]) not allowed on PreparedStatement")
override fun executeUpdate(sql: String?, columnNames: kotlin.Array<out String?>?): Int =
throw SQLException("executeUpdate(String, String[]) not allowed on PreparedStatement")
override fun execute(sql: String?, autoGeneratedKeys: Int): Boolean =
throw SQLException("execute(String, int) not allowed on PreparedStatement")
override fun execute(sql: String?, columnIndexes: IntArray?): Boolean =
throw SQLException("executeUpdate(String, int[]) not allowed on PreparedStatement")
override fun execute(sql: String?, columnNames: kotlin.Array<out String?>?): Boolean =
throw SQLException("execute(String, String[]) not allowed on PreparedStatement")
override fun getResultSetHoldability(): Int =
this._refcnt.withRef(this._orig::getResultSetHoldability)
override fun isClosed(): Boolean =
this._refcnt.withRef(this._orig::isClosed)
override fun setPoolable(poolable: Boolean) {
if (poolable)
return
throw SQLException("Disabling pooling not allowed on prepared statements driven by PreparedStatementsCompilationCache")
}
override fun isPoolable(): Boolean = true
}

View File

@ -0,0 +1,29 @@
package ru.langrafhomyak.db.jdbc_resources_manager
import java.sql.Clob
import java.sql.ResultSet
import java.sql.ResultSetMetaData
import java.sql.SQLType
import java.sql.Statement
internal abstract class ResultSetWrapper(protected val _orig: ResultSet) : ResultSet by _orig {
abstract override fun close()
abstract override fun getStatement(): Statement?
override fun updateObject(columnIndex: Int, x: Any?, targetSqlType: SQLType?, scaleOrLength: Int) {
this._orig.updateObject(columnIndex, x, targetSqlType, scaleOrLength)
}
override fun updateObject(columnLabel: String?, x: Any?, targetSqlType: SQLType?, scaleOrLength: Int) {
this._orig.updateObject(columnLabel, x, targetSqlType, scaleOrLength)
}
override fun updateObject(columnIndex: Int, x: Any?, targetSqlType: SQLType?) {
this._orig.updateObject(columnIndex, x, targetSqlType)
}
override fun updateObject(columnLabel: String?, x: Any?, targetSqlType: SQLType?) {
this._orig.updateObject(columnLabel, x, targetSqlType)
}
}