Use cached PreparedStatement for HSQLDB.assertEmptyTransaction + other minor HSQLDB fixes

This commit is contained in:
catbref 2020-10-07 09:45:44 +01:00
parent 1958444bc4
commit 6a4388fecc

View File

@ -24,6 +24,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Stream;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
@ -208,7 +209,7 @@ public class HSQLDBRepository implements Repository {
this.savepoints.clear(); this.savepoints.clear();
// Before clearing statements so we can log what led to assertion error // Before clearing statements so we can log what led to assertion error
assertEmptyTransaction("transaction commit"); assertEmptyTransaction("transaction rollback");
if (this.sqlStatements != null) if (this.sqlStatements != null)
this.sqlStatements.clear(); this.sqlStatements.clear();
@ -298,11 +299,12 @@ public class HSQLDBRepository implements Repository {
Path oldRepoDirPath = Paths.get(dbPathname).getParent(); Path oldRepoDirPath = Paths.get(dbPathname).getParent();
// Delete old repository files // Delete old repository files
Files.walk(oldRepoDirPath) try (Stream<Path> paths = Files.walk(oldRepoDirPath)) {
.sorted(Comparator.reverseOrder()) paths.sorted(Comparator.reverseOrder())
.map(Path::toFile) .map(Path::toFile)
.filter(file -> file.getPath().startsWith(dbPathname)) .filter(file -> file.getPath().startsWith(dbPathname))
.forEach(File::delete); .forEach(File::delete);
}
} }
} catch (NoSuchFileException e) { } catch (NoSuchFileException e) {
// Nothing to remove // Nothing to remove
@ -342,11 +344,12 @@ public class HSQLDBRepository implements Repository {
Path backupDirPath = Paths.get(backupPathname).getParent(); Path backupDirPath = Paths.get(backupPathname).getParent();
String backupDirPathname = backupDirPath.toString(); String backupDirPathname = backupDirPath.toString();
Files.walk(backupDirPath) try (Stream<Path> paths = Files.walk(backupDirPath)) {
.sorted(Comparator.reverseOrder()) paths.sorted(Comparator.reverseOrder())
.map(Path::toFile) .map(Path::toFile)
.filter(file -> file.getPath().startsWith(backupDirPathname)) .filter(file -> file.getPath().startsWith(backupDirPathname))
.forEach(File::delete); .forEach(File::delete);
}
} catch (NoSuchFileException e) { } catch (NoSuchFileException e) {
// Nothing to remove // Nothing to remove
} catch (SQLException | IOException e) { } catch (SQLException | IOException e) {
@ -411,11 +414,12 @@ public class HSQLDBRepository implements Repository {
LOGGER.info("Attempting repository recovery using backup"); LOGGER.info("Attempting repository recovery using backup");
// Move old repository files out the way // Move old repository files out the way
Files.walk(oldRepoDirPath) try (Stream<Path> paths = Files.walk(oldRepoDirPath)) {
.sorted(Comparator.reverseOrder()) paths.sorted(Comparator.reverseOrder())
.map(Path::toFile) .map(Path::toFile)
.filter(file -> file.getPath().startsWith(dbPathname)) .filter(file -> file.getPath().startsWith(dbPathname))
.forEach(File::delete); .forEach(File::delete);
}
try (Statement stmt = connection.createStatement()) { try (Statement stmt = connection.createStatement()) {
// Now "backup" the backup back to original repository location (the parent). // Now "backup" the backup back to original repository location (the parent).
@ -455,6 +459,10 @@ public class HSQLDBRepository implements Repository {
if (this.sqlStatements != null) if (this.sqlStatements != null)
this.sqlStatements.add(sql); this.sqlStatements.add(sql);
return cachePreparedStatement(sql);
}
private PreparedStatement cachePreparedStatement(String sql) throws SQLException {
/* /*
* We cache a duplicate PreparedStatement for this SQL string, * We cache a duplicate PreparedStatement for this SQL string,
* which we never close, which means HSQLDB also caches a parsed, * which we never close, which means HSQLDB also caches a parsed,
@ -799,7 +807,7 @@ public class HSQLDBRepository implements Repository {
/** Logs other HSQLDB sessions then returns passed exception */ /** Logs other HSQLDB sessions then returns passed exception */
public SQLException examineException(SQLException e) { public SQLException examineException(SQLException e) {
LOGGER.error(String.format("HSQLDB error (session %d): %s", this.sessionId, e.getMessage()), e); LOGGER.error(() -> String.format("HSQLDB error (session %d): %s", this.sessionId, e.getMessage()), e);
logStatements(); logStatements();
@ -833,14 +841,19 @@ public class HSQLDBRepository implements Repository {
} }
private void assertEmptyTransaction(String context) throws DataException { private void assertEmptyTransaction(String context) throws DataException {
try (Statement stmt = this.connection.createStatement()) { String sql = "SELECT transaction, transaction_size FROM information_schema.system_sessions WHERE session_id = ?";
try {
PreparedStatement stmt = this.cachePreparedStatement(sql);
stmt.setLong(1, this.sessionId);
// Diagnostic check for uncommitted changes // Diagnostic check for uncommitted changes
if (!stmt.execute("SELECT transaction, transaction_size FROM information_schema.system_sessions WHERE session_id = " + this.sessionId)) // TRANSACTION_SIZE() broken? if (!stmt.execute()) // TRANSACTION_SIZE() broken?
throw new DataException("Unable to check repository status after " + context); throw new DataException("Unable to check repository status after " + context);
try (ResultSet resultSet = stmt.getResultSet()) { try (ResultSet resultSet = stmt.getResultSet()) {
if (resultSet == null || !resultSet.next()) { if (resultSet == null || !resultSet.next()) {
LOGGER.warn(String.format("Unable to check repository status after %s", context)); LOGGER.warn(() -> String.format("Unable to check repository status after %s", context));
return; return;
} }
@ -848,7 +861,11 @@ public class HSQLDBRepository implements Repository {
int transactionCount = resultSet.getInt(2); int transactionCount = resultSet.getInt(2);
if (inTransaction && transactionCount != 0) { if (inTransaction && transactionCount != 0) {
LOGGER.warn(String.format("Uncommitted changes (%d) after %s, session [%d]", transactionCount, context, this.sessionId), new Exception("Uncommitted repository changes")); LOGGER.warn(() -> String.format("Uncommitted changes (%d) after %s, session [%d]",
transactionCount,
context,
this.sessionId),
new Exception("Uncommitted repository changes"));
logStatements(); logStatements();
} }
} }