Skip to content

Commit

Permalink
Unclosed ResultSet in NonAutoIncEntities.testNotAutoIncTable #1279
Browse files Browse the repository at this point in the history
  • Loading branch information
Tapac committed Oct 11, 2021
1 parent 7a5902d commit 8c71562
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import org.jetbrains.exposed.sql.statements.Statement
import org.jetbrains.exposed.sql.statements.StatementType
import org.jetbrains.exposed.sql.transactions.TransactionManager
import java.sql.ResultSet
import java.util.concurrent.ConcurrentHashMap

abstract class AbstractQuery<T : AbstractQuery<T>>(targets: List<Table>) : SizedIterable<ResultRow>, Statement<ResultSet>(StatementType.SELECT, targets) {
protected val transaction get() = TransactionManager.current()
Expand Down Expand Up @@ -59,7 +60,7 @@ abstract class AbstractQuery<T : AbstractQuery<T>>(targets: List<Table>) : Sized

override fun iterator(): Iterator<ResultRow> {
val resultIterator = ResultIterator(transaction.exec(queryToExecute)!!)
return if (transaction.db.supportsMultipleResultSets) resultIterator
return if (transaction.db.supportsMultipleResultSets) resultIterator.also { trackStatementOpen(transaction, it) }
else {
Iterable { resultIterator }.toList().iterator()
}
Expand All @@ -79,8 +80,29 @@ abstract class AbstractQuery<T : AbstractQuery<T>>(targets: List<Table>) : Sized

override fun hasNext(): Boolean {
if (hasNext == null) hasNext = rs.next()
if (hasNext == false) rs.close()
if (hasNext == false) {
rs.close()
untrackStatement(transaction, this)
}
return hasNext!!
}
}

companion object {
private val trackedOpenResultIterators = ConcurrentHashMap<Transaction, MutableSet<AbstractQuery<*>.ResultIterator>>()

private fun trackStatementOpen(transaction: Transaction, iterator: AbstractQuery<*>.ResultIterator) {
trackedOpenResultIterators.getOrPut(transaction) { ConcurrentHashMap.newKeySet() }.add(iterator)
}

private fun untrackStatement(transaction: Transaction, iterator: AbstractQuery<*>.ResultIterator) {
trackedOpenResultIterators[transaction]?.remove(iterator)
}

internal fun closeOpenedStatements(transaction: Transaction) {
trackedOpenResultIterators.remove(transaction)?.forEach {
if (!it.rs.isClosed) it.rs.close()
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ open class Transaction(private val transactionImpl: TransactionInterface) : User
override fun commit() {
globalInterceptors.forEach { it.beforeCommit(this) }
interceptors.forEach { it.beforeCommit(this) }
AbstractQuery.closeOpenedStatements(this)
transactionImpl.commit()
globalInterceptors.forEach { it.afterCommit() }
interceptors.forEach { it.afterCommit() }
Expand All @@ -69,6 +70,7 @@ open class Transaction(private val transactionImpl: TransactionInterface) : User
override fun rollback() {
globalInterceptors.forEach { it.beforeRollback(this) }
interceptors.forEach { it.beforeRollback(this) }
AbstractQuery.closeOpenedStatements(this)
transactionImpl.rollback()
globalInterceptors.forEach { it.afterRollback() }
interceptors.forEach { it.afterRollback() }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,13 +100,13 @@ interface TransactionManager {
manager?.let { currentThreadManager.set(it) } ?: currentThreadManager.remove()
}

fun currentOrNew(isolation: Int) = currentOrNull() ?: manager.newTransaction(isolation)
fun currentOrNew(isolation: Int): Transaction = currentOrNull() ?: manager.newTransaction(isolation)

fun currentOrNull() = manager.currentOrNull()
fun currentOrNull(): Transaction? = manager.currentOrNull()

fun current() = currentOrNull() ?: error("No transaction in context.")
fun current(): Transaction = currentOrNull() ?: error("No transaction in context.")

fun isInitialized() = defaultDatabase != null
fun isInitialized(): Boolean = defaultDatabase != null
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class CreateTableTests : DatabaseTestsBase() {
fun createTableWithDuplicateColumn() {
val assertionFailureMessage = "Can't create a table with multiple columns having the same name"

withDb() {
withDb {
assertFails(assertionFailureMessage) {
SchemaUtils.create(TableWithDuplicatedColumn)
}
Expand All @@ -43,7 +43,7 @@ class CreateTableTests : DatabaseTestsBase() {

override val primaryKey = PrimaryKey(id1, id2)
}
withDb() {
withDb {
val id1ProperName = account.id1.name.inProperCase()
val id2ProperName = account.id2.name.inProperCase()
val tableName = account.tableName
Expand All @@ -63,7 +63,7 @@ class CreateTableTests : DatabaseTestsBase() {
val pkConstraintName = "PKConstraintName"

// Table with composite primary key
withDb() {
withDb {
val id1ProperName = Person.id1.name.inProperCase()
val id2ProperName = Person.id2.name.inProperCase()
val tableName = Person.tableName
Expand All @@ -83,7 +83,7 @@ class CreateTableTests : DatabaseTestsBase() {

override val primaryKey = PrimaryKey(user_name, name = pkConstraintName)
}
withDb() {
withDb {
val userNameProperName = user.user_name.name.inProperCase()
val tableName = TransactionManager.current().identity(user)

Expand Down

0 comments on commit 8c71562

Please sign in to comment.