close ResultSets in JdbcUtils (#6206)
* close ResultSets in JdbcUtils * Credit for #6206 * Apply spotless --------- Co-authored-by: James Agnew <jamesagnew@gmail.com>
This commit is contained in:
parent
5e48e38b1d
commit
049c28d3e6
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 6206
|
||||||
|
title: "A resource leak during database migration on Oracle could cause a failure `ORA-01000 maximum open cursors for session`. This has been corrected. Thanks to Jonas Beyer for the contribution!"
|
|
@ -85,19 +85,16 @@ public class JdbcUtils {
|
||||||
try {
|
try {
|
||||||
metadata = connection.getMetaData();
|
metadata = connection.getMetaData();
|
||||||
|
|
||||||
ResultSet indexes = getIndexInfo(theTableName, connection, metadata, false);
|
|
||||||
Set<String> indexNames = new HashSet<>();
|
Set<String> indexNames = new HashSet<>();
|
||||||
while (indexes.next()) {
|
|
||||||
ourLog.debug("*** Next index: {}", new ColumnMapRowMapper().mapRow(indexes, 0));
|
|
||||||
String indexName = indexes.getString("INDEX_NAME");
|
|
||||||
indexNames.add(indexName);
|
|
||||||
}
|
|
||||||
|
|
||||||
indexes = getIndexInfo(theTableName, connection, metadata, true);
|
for (boolean unique : Set.of(false, true)) {
|
||||||
while (indexes.next()) {
|
try (ResultSet indexes = getIndexInfo(theTableName, connection, metadata, unique)) {
|
||||||
ourLog.debug("*** Next index: {}", new ColumnMapRowMapper().mapRow(indexes, 0));
|
while (indexes.next()) {
|
||||||
String indexName = indexes.getString("INDEX_NAME");
|
ourLog.debug("*** Next index: {}", new ColumnMapRowMapper().mapRow(indexes, 0));
|
||||||
indexNames.add(indexName);
|
String indexName = indexes.getString("INDEX_NAME");
|
||||||
|
indexNames.add(indexName);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
indexNames = indexNames.stream()
|
indexNames = indexNames.stream()
|
||||||
|
@ -124,13 +121,14 @@ public class JdbcUtils {
|
||||||
DatabaseMetaData metadata;
|
DatabaseMetaData metadata;
|
||||||
try {
|
try {
|
||||||
metadata = connection.getMetaData();
|
metadata = connection.getMetaData();
|
||||||
ResultSet indexes = getIndexInfo(theTableName, connection, metadata, false);
|
try (ResultSet indexes = getIndexInfo(theTableName, connection, metadata, false)) {
|
||||||
|
|
||||||
while (indexes.next()) {
|
while (indexes.next()) {
|
||||||
String indexName = indexes.getString("INDEX_NAME");
|
String indexName = indexes.getString("INDEX_NAME");
|
||||||
if (theIndexName.equalsIgnoreCase(indexName)) {
|
if (theIndexName.equalsIgnoreCase(indexName)) {
|
||||||
boolean nonUnique = indexes.getBoolean("NON_UNIQUE");
|
boolean nonUnique = indexes.getBoolean("NON_UNIQUE");
|
||||||
return !nonUnique;
|
return !nonUnique;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,65 +169,69 @@ public class JdbcUtils {
|
||||||
metadata = connection.getMetaData();
|
metadata = connection.getMetaData();
|
||||||
String catalog = connection.getCatalog();
|
String catalog = connection.getCatalog();
|
||||||
String schema = connection.getSchema();
|
String schema = connection.getSchema();
|
||||||
ResultSet indexes =
|
try (ResultSet indexes =
|
||||||
metadata.getColumns(catalog, schema, massageIdentifier(metadata, theTableName), null);
|
metadata.getColumns(catalog, schema, massageIdentifier(metadata, theTableName), null)) {
|
||||||
|
|
||||||
while (indexes.next()) {
|
while (indexes.next()) {
|
||||||
|
|
||||||
String tableName = indexes.getString("TABLE_NAME").toUpperCase(Locale.US);
|
String tableName = indexes.getString("TABLE_NAME").toUpperCase(Locale.US);
|
||||||
if (!theTableName.equalsIgnoreCase(tableName)) {
|
if (!theTableName.equalsIgnoreCase(tableName)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
String columnName = indexes.getString("COLUMN_NAME").toUpperCase(Locale.US);
|
String columnName = indexes.getString("COLUMN_NAME").toUpperCase(Locale.US);
|
||||||
if (!theColumnName.equalsIgnoreCase(columnName)) {
|
if (!theColumnName.equalsIgnoreCase(columnName)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
int dataType = indexes.getInt("DATA_TYPE");
|
int dataType = indexes.getInt("DATA_TYPE");
|
||||||
Long length = indexes.getLong("COLUMN_SIZE");
|
Long length = indexes.getLong("COLUMN_SIZE");
|
||||||
switch (dataType) {
|
switch (dataType) {
|
||||||
case Types.LONGVARCHAR:
|
case Types.LONGVARCHAR:
|
||||||
return new ColumnType(ColumnTypeEnum.TEXT, length);
|
return new ColumnType(ColumnTypeEnum.TEXT, length);
|
||||||
case Types.BIT:
|
case Types.BIT:
|
||||||
case Types.BOOLEAN:
|
case Types.BOOLEAN:
|
||||||
return new ColumnType(ColumnTypeEnum.BOOLEAN, length);
|
return new ColumnType(ColumnTypeEnum.BOOLEAN, length);
|
||||||
case Types.VARCHAR:
|
case Types.VARCHAR:
|
||||||
return new ColumnType(ColumnTypeEnum.STRING, length);
|
return new ColumnType(ColumnTypeEnum.STRING, length);
|
||||||
case Types.NUMERIC:
|
case Types.NUMERIC:
|
||||||
case Types.BIGINT:
|
case Types.BIGINT:
|
||||||
case Types.DECIMAL:
|
case Types.DECIMAL:
|
||||||
return new ColumnType(ColumnTypeEnum.LONG, length);
|
return new ColumnType(ColumnTypeEnum.LONG, length);
|
||||||
case Types.INTEGER:
|
case Types.INTEGER:
|
||||||
return new ColumnType(ColumnTypeEnum.INT, length);
|
return new ColumnType(ColumnTypeEnum.INT, length);
|
||||||
case Types.TIMESTAMP:
|
case Types.TIMESTAMP:
|
||||||
case Types.TIMESTAMP_WITH_TIMEZONE:
|
case Types.TIMESTAMP_WITH_TIMEZONE:
|
||||||
return new ColumnType(ColumnTypeEnum.DATE_TIMESTAMP, length);
|
return new ColumnType(ColumnTypeEnum.DATE_TIMESTAMP, length);
|
||||||
case Types.BLOB:
|
case Types.BLOB:
|
||||||
return new ColumnType(ColumnTypeEnum.BLOB, length);
|
|
||||||
case Types.LONGVARBINARY:
|
|
||||||
return new ColumnType(ColumnTypeEnum.BINARY, length);
|
|
||||||
case Types.VARBINARY:
|
|
||||||
if (DriverTypeEnum.MSSQL_2012.equals(theConnectionProperties.getDriverType())) {
|
|
||||||
// MS SQLServer seems to be mapping BLOB to VARBINARY under the covers, so we need
|
|
||||||
// to reverse that mapping
|
|
||||||
return new ColumnType(ColumnTypeEnum.BLOB, length);
|
return new ColumnType(ColumnTypeEnum.BLOB, length);
|
||||||
|
case Types.LONGVARBINARY:
|
||||||
|
return new ColumnType(ColumnTypeEnum.BINARY, length);
|
||||||
|
case Types.VARBINARY:
|
||||||
|
if (DriverTypeEnum.MSSQL_2012.equals(theConnectionProperties.getDriverType())) {
|
||||||
|
// MS SQLServer seems to be mapping BLOB to VARBINARY under the covers,
|
||||||
|
// so we need to reverse that mapping
|
||||||
|
return new ColumnType(ColumnTypeEnum.BLOB, length);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
Msg.code(33) + "Don't know how to handle datatype " + dataType
|
||||||
|
+ " for column " + theColumnName
|
||||||
|
+ " on table " + theTableName);
|
||||||
|
}
|
||||||
|
case Types.CLOB:
|
||||||
|
return new ColumnType(ColumnTypeEnum.CLOB, length);
|
||||||
|
case Types.DOUBLE:
|
||||||
|
return new ColumnType(ColumnTypeEnum.DOUBLE, length);
|
||||||
|
case Types.FLOAT:
|
||||||
|
return new ColumnType(ColumnTypeEnum.FLOAT, length);
|
||||||
|
case Types.TINYINT:
|
||||||
|
return new ColumnType(ColumnTypeEnum.TINYINT, length);
|
||||||
|
default:
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
Msg.code(33) + "Don't know how to handle datatype " + dataType
|
Msg.code(34) + "Don't know how to handle datatype " + dataType
|
||||||
+ " for column " + theColumnName + " on table " + theTableName);
|
+ " for column " + theColumnName
|
||||||
}
|
+ " on table " + theTableName);
|
||||||
case Types.CLOB:
|
}
|
||||||
return new ColumnType(ColumnTypeEnum.CLOB, length);
|
|
||||||
case Types.DOUBLE:
|
|
||||||
return new ColumnType(ColumnTypeEnum.DOUBLE, length);
|
|
||||||
case Types.FLOAT:
|
|
||||||
return new ColumnType(ColumnTypeEnum.FLOAT, length);
|
|
||||||
case Types.TINYINT:
|
|
||||||
return new ColumnType(ColumnTypeEnum.TINYINT, length);
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException(Msg.code(34) + "Don't know how to handle datatype "
|
|
||||||
+ dataType + " for column " + theColumnName + " on table " + theTableName);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,13 +276,13 @@ public class JdbcUtils {
|
||||||
|
|
||||||
Set<String> fkNames = new HashSet<>();
|
Set<String> fkNames = new HashSet<>();
|
||||||
for (String nextParentTable : parentTables) {
|
for (String nextParentTable : parentTables) {
|
||||||
ResultSet indexes = metadata.getCrossReference(
|
try (ResultSet indexes = metadata.getCrossReference(
|
||||||
catalog, schema, nextParentTable, catalog, schema, foreignTable);
|
catalog, schema, nextParentTable, catalog, schema, foreignTable)) {
|
||||||
|
while (indexes.next()) {
|
||||||
while (indexes.next()) {
|
String fkName = indexes.getString("FK_NAME");
|
||||||
String fkName = indexes.getString("FK_NAME");
|
fkName = fkName.toUpperCase(Locale.US);
|
||||||
fkName = fkName.toUpperCase(Locale.US);
|
fkNames.add(fkName);
|
||||||
fkNames.add(fkName);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,14 +319,14 @@ public class JdbcUtils {
|
||||||
|
|
||||||
Set<String> fkNames = new HashSet<>();
|
Set<String> fkNames = new HashSet<>();
|
||||||
for (String nextParentTable : parentTables) {
|
for (String nextParentTable : parentTables) {
|
||||||
ResultSet indexes = metadata.getCrossReference(
|
try (ResultSet indexes = metadata.getCrossReference(
|
||||||
catalog, schema, nextParentTable, catalog, schema, foreignTable);
|
catalog, schema, nextParentTable, catalog, schema, foreignTable)) {
|
||||||
|
while (indexes.next()) {
|
||||||
while (indexes.next()) {
|
if (theForeignKeyColumn.equals(indexes.getString("FKCOLUMN_NAME"))) {
|
||||||
if (theForeignKeyColumn.equals(indexes.getString("FKCOLUMN_NAME"))) {
|
String fkName = indexes.getString("FK_NAME");
|
||||||
String fkName = indexes.getString("FK_NAME");
|
fkName = fkName.toUpperCase(Locale.US);
|
||||||
fkName = fkName.toUpperCase(Locale.US);
|
fkNames.add(fkName);
|
||||||
fkNames.add(fkName);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -348,22 +350,24 @@ public class JdbcUtils {
|
||||||
DatabaseMetaData metadata;
|
DatabaseMetaData metadata;
|
||||||
try {
|
try {
|
||||||
metadata = connection.getMetaData();
|
metadata = connection.getMetaData();
|
||||||
ResultSet indexes = metadata.getColumns(
|
LinkedCaseInsensitiveMap<String> columnNames = new LinkedCaseInsensitiveMap<>();
|
||||||
|
|
||||||
|
try (ResultSet indexes = metadata.getColumns(
|
||||||
connection.getCatalog(),
|
connection.getCatalog(),
|
||||||
connection.getSchema(),
|
connection.getSchema(),
|
||||||
massageIdentifier(metadata, theTableName),
|
massageIdentifier(metadata, theTableName),
|
||||||
null);
|
null)) {
|
||||||
|
|
||||||
LinkedCaseInsensitiveMap<String> columnNames = new LinkedCaseInsensitiveMap<>();
|
while (indexes.next()) {
|
||||||
while (indexes.next()) {
|
String tableName = indexes.getString("TABLE_NAME").toUpperCase(Locale.US);
|
||||||
String tableName = indexes.getString("TABLE_NAME").toUpperCase(Locale.US);
|
if (!theTableName.equalsIgnoreCase(tableName)) {
|
||||||
if (!theTableName.equalsIgnoreCase(tableName)) {
|
continue;
|
||||||
continue;
|
}
|
||||||
|
|
||||||
|
String columnName = indexes.getString("COLUMN_NAME");
|
||||||
|
columnName = columnName.toUpperCase(Locale.US);
|
||||||
|
columnNames.put(columnName, columnName);
|
||||||
}
|
}
|
||||||
|
|
||||||
String columnName = indexes.getString("COLUMN_NAME");
|
|
||||||
columnName = columnName.toUpperCase(Locale.US);
|
|
||||||
columnNames.put(columnName, columnName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return columnNames.keySet();
|
return columnNames.keySet();
|
||||||
|
@ -391,6 +395,7 @@ public class JdbcUtils {
|
||||||
SequenceInformationExtractor sequenceInformationExtractor =
|
SequenceInformationExtractor sequenceInformationExtractor =
|
||||||
dialect.getSequenceInformationExtractor();
|
dialect.getSequenceInformationExtractor();
|
||||||
ExtractionContext extractionContext = new ExtractionContext.EmptyExtractionContext() {
|
ExtractionContext extractionContext = new ExtractionContext.EmptyExtractionContext() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Connection getJdbcConnection() {
|
public Connection getJdbcConnection() {
|
||||||
return connection;
|
return connection;
|
||||||
|
@ -404,6 +409,7 @@ public class JdbcUtils {
|
||||||
@Override
|
@Override
|
||||||
public JdbcEnvironment getJdbcEnvironment() {
|
public JdbcEnvironment getJdbcEnvironment() {
|
||||||
return new JdbcEnvironment() {
|
return new JdbcEnvironment() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Dialect getDialect() {
|
public Dialect getDialect() {
|
||||||
return dialect;
|
return dialect;
|
||||||
|
@ -480,22 +486,25 @@ public class JdbcUtils {
|
||||||
DatabaseMetaData metadata;
|
DatabaseMetaData metadata;
|
||||||
try {
|
try {
|
||||||
metadata = connection.getMetaData();
|
metadata = connection.getMetaData();
|
||||||
ResultSet tables = metadata.getTables(connection.getCatalog(), connection.getSchema(), null, null);
|
|
||||||
|
|
||||||
Set<String> columnNames = new HashSet<>();
|
Set<String> columnNames = new HashSet<>();
|
||||||
while (tables.next()) {
|
|
||||||
String tableName = tables.getString("TABLE_NAME");
|
|
||||||
tableName = tableName.toUpperCase(Locale.US);
|
|
||||||
|
|
||||||
String tableType = tables.getString("TABLE_TYPE");
|
try (ResultSet tables =
|
||||||
if ("SYSTEM TABLE".equalsIgnoreCase(tableType)) {
|
metadata.getTables(connection.getCatalog(), connection.getSchema(), null, null)) {
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (SchemaMigrator.HAPI_FHIR_MIGRATION_TABLENAME.equalsIgnoreCase(tableName)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
columnNames.add(tableName);
|
while (tables.next()) {
|
||||||
|
String tableName = tables.getString("TABLE_NAME");
|
||||||
|
tableName = tableName.toUpperCase(Locale.US);
|
||||||
|
|
||||||
|
String tableType = tables.getString("TABLE_TYPE");
|
||||||
|
if ("SYSTEM TABLE".equalsIgnoreCase(tableType)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (SchemaMigrator.HAPI_FHIR_MIGRATION_TABLENAME.equalsIgnoreCase(tableName)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
columnNames.add(tableName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return columnNames;
|
return columnNames;
|
||||||
|
@ -516,26 +525,27 @@ public class JdbcUtils {
|
||||||
DatabaseMetaData metadata;
|
DatabaseMetaData metadata;
|
||||||
try {
|
try {
|
||||||
metadata = connection.getMetaData();
|
metadata = connection.getMetaData();
|
||||||
ResultSet tables = metadata.getColumns(
|
try (ResultSet tables = metadata.getColumns(
|
||||||
connection.getCatalog(),
|
connection.getCatalog(),
|
||||||
connection.getSchema(),
|
connection.getSchema(),
|
||||||
massageIdentifier(metadata, theTableName),
|
massageIdentifier(metadata, theTableName),
|
||||||
null);
|
null)) {
|
||||||
|
|
||||||
while (tables.next()) {
|
while (tables.next()) {
|
||||||
String tableName = tables.getString("TABLE_NAME").toUpperCase(Locale.US);
|
String tableName = tables.getString("TABLE_NAME").toUpperCase(Locale.US);
|
||||||
if (!theTableName.equalsIgnoreCase(tableName)) {
|
if (!theTableName.equalsIgnoreCase(tableName)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (theColumnName.equalsIgnoreCase(tables.getString("COLUMN_NAME"))) {
|
if (theColumnName.equalsIgnoreCase(tables.getString("COLUMN_NAME"))) {
|
||||||
String nullable = tables.getString("IS_NULLABLE");
|
String nullable = tables.getString("IS_NULLABLE");
|
||||||
if ("YES".equalsIgnoreCase(nullable)) {
|
if ("YES".equalsIgnoreCase(nullable)) {
|
||||||
return true;
|
return true;
|
||||||
} else if ("NO".equalsIgnoreCase(nullable)) {
|
} else if ("NO".equalsIgnoreCase(nullable)) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException(Msg.code(41) + "Unknown nullable: " + nullable);
|
throw new IllegalStateException(Msg.code(41) + "Unknown nullable: " + nullable);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
4
pom.xml
4
pom.xml
|
@ -934,6 +934,10 @@
|
||||||
<name>Alex Cote</name>
|
<name>Alex Cote</name>
|
||||||
<organization>athenahealth</organization>
|
<organization>athenahealth</organization>
|
||||||
</developer>
|
</developer>
|
||||||
|
<developer>
|
||||||
|
<id>plchldr</id>
|
||||||
|
<name>Jonas Beyer</name>
|
||||||
|
</developer>
|
||||||
</developers>
|
</developers>
|
||||||
|
|
||||||
<licenses>
|
<licenses>
|
||||||
|
|
Loading…
Reference in New Issue