Skip to content

Commit 6383a0d

Browse files
committed
Merge branch '6.1.x'
2 parents 3fb1700 + 5d6501c commit 6383a0d

File tree

3 files changed

+306
-70
lines changed

3 files changed

+306
-70
lines changed

Diff for: spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/GenericCallMetaDataProvider.java

+72-40
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import java.sql.Types;
2323
import java.util.ArrayList;
2424
import java.util.List;
25-
import java.util.Objects;
2625

2726
import org.apache.commons.logging.Log;
2827
import org.apache.commons.logging.LogFactory;
@@ -305,47 +304,42 @@ private void processProcedureColumns(DatabaseMetaData databaseMetaData,
305304
String metaDataSchemaName = metaDataSchemaNameToUse(schemaName);
306305
String metaDataProcedureName = procedureNameToUse(procedureName);
307306
try {
308-
String searchStringEscape = databaseMetaData.getSearchStringEscape();
309-
String escapedSchemaName = escapeNamePattern(metaDataSchemaName, searchStringEscape);
310-
String escapedProcedureName = escapeNamePattern(metaDataProcedureName, searchStringEscape);
311-
if (logger.isDebugEnabled()) {
312-
String schemaInfo = (Objects.equals(escapedSchemaName, metaDataSchemaName)
313-
? metaDataSchemaName : metaDataCatalogName + "(" + escapedSchemaName + ")");
314-
String procedureInfo = (Objects.equals(escapedProcedureName, metaDataProcedureName)
315-
? metaDataProcedureName : metaDataProcedureName + "(" + escapedProcedureName + ")");
316-
logger.debug("Retrieving meta-data for " + metaDataCatalogName + '/' +
317-
schemaInfo + '/' + procedureInfo);
318-
}
319-
320-
List<String> found = new ArrayList<>();
321-
boolean function = false;
322-
323-
try (ResultSet procedures = databaseMetaData.getProcedures(
324-
metaDataCatalogName, escapedSchemaName, escapedProcedureName)) {
325-
while (procedures.next()) {
326-
found.add(procedures.getString("PROCEDURE_CAT") + '.' + procedures.getString("PROCEDURE_SCHEM") +
327-
'.' + procedures.getString("PROCEDURE_NAME"));
307+
ProcedureMetadata procedureMetadata = getProcedureMetadata(databaseMetaData,
308+
metaDataCatalogName, metaDataSchemaName, metaDataProcedureName);
309+
if (procedureMetadata.hits() > 1) {
310+
// Try again with exact match in case of placeholders
311+
String searchStringEscape = databaseMetaData.getSearchStringEscape();
312+
if (searchStringEscape != null) {
313+
procedureMetadata = getProcedureMetadata(databaseMetaData, metaDataCatalogName,
314+
escapeNamePattern(metaDataSchemaName, searchStringEscape),
315+
escapeNamePattern(metaDataProcedureName, searchStringEscape));
328316
}
329317
}
330-
331-
if (found.isEmpty()) {
318+
if (procedureMetadata.hits() == 0) {
332319
// Functions not exposed as procedures anymore on PostgreSQL driver 42.2.11
333-
try (ResultSet functions = databaseMetaData.getFunctions(
334-
metaDataCatalogName, escapedSchemaName, escapedProcedureName)) {
335-
while (functions.next()) {
336-
found.add(functions.getString("FUNCTION_CAT") + '.' + functions.getString("FUNCTION_SCHEM") +
337-
'.' + functions.getString("FUNCTION_NAME"));
338-
function = true;
320+
procedureMetadata = getProcedureMetadataAsFunction(databaseMetaData,
321+
metaDataCatalogName, metaDataSchemaName, metaDataProcedureName);
322+
if (procedureMetadata.hits() > 1) {
323+
// Try again with exact match in case of placeholders
324+
String searchStringEscape = databaseMetaData.getSearchStringEscape();
325+
if (searchStringEscape != null) {
326+
procedureMetadata = getProcedureMetadataAsFunction(
327+
databaseMetaData, metaDataCatalogName,
328+
escapeNamePattern(metaDataSchemaName, searchStringEscape),
329+
escapeNamePattern(metaDataProcedureName, searchStringEscape));
339330
}
340331
}
341332
}
333+
// Handling matches
342334

343-
if (found.size() > 1) {
335+
boolean isFunction = procedureMetadata.function();
336+
List<String> matches = procedureMetadata.matches;
337+
if (matches.size() > 1) {
344338
throw new InvalidDataAccessApiUsageException(
345339
"Unable to determine the correct call signature - multiple signatures for '" +
346-
metaDataProcedureName + "': found " + found + " " + (function ? "functions" : "procedures"));
340+
metaDataProcedureName + "': found " + matches + " " + (isFunction ? "functions" : "procedures"));
347341
}
348-
else if (found.isEmpty()) {
342+
else if (matches.isEmpty()) {
349343
if (metaDataProcedureName != null && metaDataProcedureName.contains(".") &&
350344
!StringUtils.hasText(metaDataCatalogName)) {
351345
String packageName = metaDataProcedureName.substring(0, metaDataProcedureName.indexOf('.'));
@@ -368,25 +362,25 @@ else if ("Oracle".equals(databaseMetaData.getDatabaseProductName())) {
368362
}
369363

370364
if (logger.isDebugEnabled()) {
371-
logger.debug("Retrieving column meta-data for " + (function ? "function" : "procedure") + ' ' +
372-
metaDataCatalogName + '/' + metaDataSchemaName + '/' + metaDataProcedureName);
365+
logger.debug("Retrieving column meta-data for " + (isFunction ? "function" : "procedure") + ' ' +
366+
metaDataCatalogName + '/' + procedureMetadata.schemaName + '/' + procedureMetadata.procedureName);
373367
}
374-
try (ResultSet columns = function ?
375-
databaseMetaData.getFunctionColumns(metaDataCatalogName, escapedSchemaName, escapedProcedureName, null) :
376-
databaseMetaData.getProcedureColumns(metaDataCatalogName, escapedSchemaName, escapedProcedureName, null)) {
368+
try (ResultSet columns = isFunction ?
369+
databaseMetaData.getFunctionColumns(metaDataCatalogName, procedureMetadata.schemaName, procedureMetadata.procedureName, null) :
370+
databaseMetaData.getProcedureColumns(metaDataCatalogName, procedureMetadata.schemaName, procedureMetadata.procedureName, null)) {
377371
while (columns.next()) {
378372
String columnName = columns.getString("COLUMN_NAME");
379373
int columnType = columns.getInt("COLUMN_TYPE");
380-
if (columnName == null && isInOrOutColumn(columnType, function)) {
374+
if (columnName == null && isInOrOutColumn(columnType, isFunction)) {
381375
if (logger.isDebugEnabled()) {
382376
logger.debug("Skipping meta-data for: " + columnType + " " + columns.getInt("DATA_TYPE") +
383377
" " + columns.getString("TYPE_NAME") + " " + columns.getInt("NULLABLE") +
384378
" (probably a member of a collection)");
385379
}
386380
}
387381
else {
388-
int nullable = (function ? DatabaseMetaData.functionNullable : DatabaseMetaData.procedureNullable);
389-
CallParameterMetaData meta = new CallParameterMetaData(function, columnName, columnType,
382+
int nullable = (isFunction ? DatabaseMetaData.functionNullable : DatabaseMetaData.procedureNullable);
383+
CallParameterMetaData meta = new CallParameterMetaData(isFunction, columnName, columnType,
390384
columns.getInt("DATA_TYPE"), columns.getString("TYPE_NAME"),
391385
columns.getInt("NULLABLE") == nullable);
392386
this.callParameterMetaData.add(meta);
@@ -413,6 +407,36 @@ else if ("Oracle".equals(databaseMetaData.getDatabaseProductName())) {
413407
}
414408
}
415409

410+
private ProcedureMetadata getProcedureMetadata(DatabaseMetaData databaseMetaData,
411+
@Nullable String catalogName, @Nullable String schemaName, @Nullable String procedureName) throws SQLException {
412+
if (logger.isDebugEnabled()) {
413+
logger.debug("Retrieving meta-data for " + catalogName + '/' + schemaName + '/' + procedureName);
414+
}
415+
List<String> matches = new ArrayList<>();
416+
try (ResultSet procedures = databaseMetaData.getProcedures(catalogName, schemaName, procedureName)) {
417+
while (procedures.next()) {
418+
matches.add(procedures.getString("PROCEDURE_CAT") + '.' + procedures.getString("PROCEDURE_SCHEM") +
419+
'.' + procedures.getString("PROCEDURE_NAME"));
420+
}
421+
}
422+
return new ProcedureMetadata(schemaName, procedureName, matches, false);
423+
}
424+
425+
private ProcedureMetadata getProcedureMetadataAsFunction(DatabaseMetaData databaseMetaData,
426+
@Nullable String catalogName, @Nullable String schemaName, @Nullable String procedureName) throws SQLException {
427+
if (logger.isDebugEnabled()) {
428+
logger.debug("Fallback on retrieving function meta-data for " + catalogName + '/' + schemaName + '/' + procedureName);
429+
}
430+
List<String> matches = new ArrayList<>();
431+
try (ResultSet functions = databaseMetaData.getFunctions(catalogName, schemaName, procedureName)) {
432+
while (functions.next()) {
433+
matches.add(functions.getString("FUNCTION_CAT") + '.' + functions.getString("FUNCTION_SCHEM") +
434+
'.' + functions.getString("FUNCTION_NAME"));
435+
}
436+
}
437+
return new ProcedureMetadata(schemaName, procedureName, matches, true);
438+
}
439+
416440
@Nullable
417441
private static String escapeNamePattern(@Nullable String name, @Nullable String escape) {
418442
if (name == null || escape == null) {
@@ -436,4 +460,12 @@ private static boolean isInOrOutColumn(int columnType, boolean function) {
436460
}
437461
}
438462

463+
private record ProcedureMetadata(@Nullable String schemaName, @Nullable String procedureName,
464+
List<String> matches, boolean function) {
465+
466+
int hits() {
467+
return this.matches.size();
468+
}
469+
}
470+
439471
}

0 commit comments

Comments
 (0)