Check JDBC 4 getFunctions (for compatibility with PostgreSQL driver 42.2.11)

Closes gh-25399
This commit is contained in:
Juergen Hoeller 2020-07-17 17:47:53 +02:00
parent 01bab89dba
commit 30bf870810
1 changed files with 66 additions and 46 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -46,9 +46,8 @@ public class GenericCallMetaDataProvider implements CallMetaDataProvider {
/** Logger available to subclasses. */ /** Logger available to subclasses. */
protected static final Log logger = LogFactory.getLog(CallMetaDataProvider.class); protected static final Log logger = LogFactory.getLog(CallMetaDataProvider.class);
private boolean procedureColumnMetaDataUsed = false;
private String userName; private final String userName;
private boolean supportsCatalogsInProcedureCalls = true; private boolean supportsCatalogsInProcedureCalls = true;
@ -58,7 +57,9 @@ public class GenericCallMetaDataProvider implements CallMetaDataProvider {
private boolean storesLowerCaseIdentifiers = false; private boolean storesLowerCaseIdentifiers = false;
private List<CallParameterMetaData> callParameterMetaData = new ArrayList<>(); private boolean procedureColumnMetaDataUsed = false;
private final List<CallParameterMetaData> callParameterMetaData = new ArrayList<>();
/** /**
@ -328,20 +329,34 @@ public class GenericCallMetaDataProvider implements CallMetaDataProvider {
metaDataSchemaName + '/' + metaDataProcedureName); metaDataSchemaName + '/' + metaDataProcedureName);
} }
ResultSet procs = null;
try { try {
procs = databaseMetaData.getProcedures(metaDataCatalogName, metaDataSchemaName, metaDataProcedureName);
List<String> found = new ArrayList<>(); List<String> found = new ArrayList<>();
while (procs.next()) { boolean function = false;
found.add(procs.getString("PROCEDURE_CAT") + '.' + procs.getString("PROCEDURE_SCHEM") +
'.' + procs.getString("PROCEDURE_NAME")); try (ResultSet procedures = databaseMetaData.getProcedures(
metaDataCatalogName, metaDataSchemaName, metaDataProcedureName)) {
while (procedures.next()) {
found.add(procedures.getString("PROCEDURE_CAT") + '.' + procedures.getString("PROCEDURE_SCHEM") +
'.' + procedures.getString("PROCEDURE_NAME"));
}
}
if (found.isEmpty()) {
// Functions not exposed as procedures anymore on PostgreSQL driver 42.2.11
try (ResultSet functions = databaseMetaData.getFunctions(
metaDataCatalogName, metaDataSchemaName, metaDataProcedureName)) {
while (functions.next()) {
found.add(functions.getString("FUNCTION_CAT") + '.' + functions.getString("FUNCTION_SCHEM") +
'.' + functions.getString("FUNCTION_NAME"));
function = true;
}
}
} }
procs.close();
if (found.size() > 1) { if (found.size() > 1) {
throw new InvalidDataAccessApiUsageException( throw new InvalidDataAccessApiUsageException(
"Unable to determine the correct call signature - multiple " + "Unable to determine the correct call signature - multiple signatures for '" +
"procedures/functions/signatures for '" + metaDataProcedureName + "': found " + found); metaDataProcedureName + "': found " + found + " " + (function ? "functions" : "procedures"));
} }
else if (found.isEmpty()) { else if (found.isEmpty()) {
if (metaDataProcedureName != null && metaDataProcedureName.contains(".") && if (metaDataProcedureName != null && metaDataProcedureName.contains(".") &&
@ -365,30 +380,34 @@ public class GenericCallMetaDataProvider implements CallMetaDataProvider {
} }
} }
procs = databaseMetaData.getProcedureColumns( if (logger.isDebugEnabled()) {
metaDataCatalogName, metaDataSchemaName, metaDataProcedureName, null); logger.debug("Retrieving column meta-data for " + (function ? "function" : "procedure") + ' ' +
while (procs.next()) { metaDataCatalogName + '/' + metaDataSchemaName + '/' + metaDataProcedureName);
String columnName = procs.getString("COLUMN_NAME"); }
int columnType = procs.getInt("COLUMN_TYPE"); try (ResultSet columns = function ?
if (columnName == null && ( databaseMetaData.getFunctionColumns(metaDataCatalogName, metaDataSchemaName, metaDataProcedureName, null) :
columnType == DatabaseMetaData.procedureColumnIn || databaseMetaData.getProcedureColumns(metaDataCatalogName, metaDataSchemaName, metaDataProcedureName, null)) {
columnType == DatabaseMetaData.procedureColumnInOut || while (columns.next()) {
columnType == DatabaseMetaData.procedureColumnOut)) { String columnName = columns.getString("COLUMN_NAME");
if (logger.isDebugEnabled()) { int columnType = columns.getInt("COLUMN_TYPE");
logger.debug("Skipping meta-data for: " + columnType + " " + procs.getInt("DATA_TYPE") + if (columnName == null && isInOrOutColumn(columnType, function)) {
" " + procs.getString("TYPE_NAME") + " " + procs.getInt("NULLABLE") + if (logger.isDebugEnabled()) {
" (probably a member of a collection)"); logger.debug("Skipping meta-data for: " + columnType + " " + columns.getInt("DATA_TYPE") +
" " + columns.getString("TYPE_NAME") + " " + columns.getInt("NULLABLE") +
" (probably a member of a collection)");
}
} }
} else {
else { int nullable = (function ? DatabaseMetaData.functionNullable : DatabaseMetaData.procedureNullable);
CallParameterMetaData meta = new CallParameterMetaData(columnName, columnType, CallParameterMetaData meta = new CallParameterMetaData(columnName, columnType,
procs.getInt("DATA_TYPE"), procs.getString("TYPE_NAME"), columns.getInt("DATA_TYPE"), columns.getString("TYPE_NAME"),
procs.getInt("NULLABLE") == DatabaseMetaData.procedureNullable); columns.getInt("NULLABLE") == nullable);
this.callParameterMetaData.add(meta); this.callParameterMetaData.add(meta);
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("Retrieved meta-data: " + meta.getParameterName() + " " + logger.debug("Retrieved meta-data: " + meta.getParameterName() + " " +
meta.getParameterType() + " " + meta.getSqlType() + " " + meta.getParameterType() + " " + meta.getSqlType() + " " +
meta.getTypeName() + " " + meta.isNullable()); meta.getTypeName() + " " + meta.isNullable());
}
} }
} }
} }
@ -398,17 +417,18 @@ public class GenericCallMetaDataProvider implements CallMetaDataProvider {
logger.warn("Error while retrieving meta-data for procedure columns: " + ex); logger.warn("Error while retrieving meta-data for procedure columns: " + ex);
} }
} }
finally { }
try {
if (procs != null) { private static boolean isInOrOutColumn(int columnType, boolean function) {
procs.close(); if (function) {
} return (columnType == DatabaseMetaData.functionColumnIn ||
} columnType == DatabaseMetaData.functionColumnInOut ||
catch (SQLException ex) { columnType == DatabaseMetaData.functionColumnOut);
if (logger.isWarnEnabled()) { }
logger.warn("Problem closing ResultSet for procedure column meta-data: " + ex); else {
} return (columnType == DatabaseMetaData.procedureColumnIn ||
} columnType == DatabaseMetaData.procedureColumnInOut ||
columnType == DatabaseMetaData.procedureColumnOut);
} }
} }