Skip to content

Commit 720a6f1

Browse files
committed
#822 Improve schema test coverage (getProcedures/getProcedureColumns)
1 parent 5350741 commit 720a6f1

3 files changed

Lines changed: 267 additions & 106 deletions

File tree

src/test/org/firebirdsql/common/FBTestProperties.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,21 @@ public static <T> T ifSchemaElse(T forSchema, T withoutSchema) {
382382
return getDefaultSupportInfo().ifSchemaElse(forSchema, withoutSchema);
383383
}
384384

385+
/**
386+
* Helper method that replaces {@code "PUBLIC"} with {@code ""} if schemas are not supported.
387+
*
388+
* @param schemaName
389+
* schema name
390+
* @return {@code schemaName}, or &mdash; if {@code schemaName} is {@code "PUBLIC"} and schemas are not supported
391+
* &mdash; {@code ""}
392+
*/
393+
public static String resolveSchema(String schemaName) {
394+
if (!getDefaultSupportInfo().supportsSchemas() && "PUBLIC".equals(schemaName)) {
395+
return "";
396+
}
397+
return schemaName;
398+
}
399+
385400
private FBTestProperties() {
386401
// No instantiation
387402
}

src/test/org/firebirdsql/jdbc/FBDatabaseMetaDataProcedureColumnsTest.java

Lines changed: 115 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import org.firebirdsql.common.extension.UsesDatabaseExtension;
66
import org.firebirdsql.jaybird.props.PropertyNames;
7+
import org.firebirdsql.jaybird.util.ObjectReference;
78
import org.firebirdsql.jdbc.metadata.FbMetadataConstants;
89
import org.firebirdsql.util.FirebirdSupportInfo;
910
import org.junit.jupiter.api.AfterAll;
@@ -12,6 +13,7 @@
1213
import org.junit.jupiter.api.Test;
1314
import org.junit.jupiter.api.extension.RegisterExtension;
1415
import org.junit.jupiter.params.ParameterizedTest;
16+
import org.junit.jupiter.params.provider.CsvSource;
1517
import org.junit.jupiter.params.provider.NullSource;
1618
import org.junit.jupiter.params.provider.ValueSource;
1719

@@ -24,6 +26,8 @@
2426
import static org.firebirdsql.common.FBTestProperties.getDefaultSupportInfo;
2527
import static org.firebirdsql.common.FBTestProperties.getUrl;
2628
import static org.firebirdsql.common.FBTestProperties.ifSchemaElse;
29+
import static org.firebirdsql.common.FBTestProperties.resolveSchema;
30+
import static org.firebirdsql.common.FbAssumptions.assumeFeature;
2731
import static org.firebirdsql.common.JdbcResourceHelper.closeQuietly;
2832
import static org.firebirdsql.jdbc.FBDatabaseMetaDataProceduresTest.isIgnoredProcedure;
2933
import static org.firebirdsql.jdbc.metadata.FbMetadataConstants.*;
@@ -38,8 +42,7 @@
3842
*/
3943
class FBDatabaseMetaDataProcedureColumnsTest {
4044

41-
// TODO Add schema support: tests involving other schema
42-
// TODO This test will need to be expanded with version dependent features
45+
// TODO This test will need to be expanded with version dependent features
4346
// (eg TYPE OF <domain> (2.1), TYPE OF COLUMN <table.column> (2.5), NOT NULL (2.1), DEFAULT <value> (2.0)
4447

4548
private static final String CREATE_NORMAL_PROC_NO_ARG_NO_RETURN = """
@@ -104,6 +107,18 @@ param2 VARCHAR(100) default 'param2 default')
104107
end
105108
end""";
106109

110+
private static final String CREATE_OTHER_SCHEMA = "create schema OTHER_SCHEMA";
111+
112+
private static final String CREATE_OTHER_SCHEMA_PROC_WITH_RETURN = """
113+
create procedure OTHER_SCHEMA.PROC_WITH_RETURN
114+
( PARAM1 varchar(100),
115+
PARAM2 decimal(18,2))
116+
RETURNS (return1 VARCHAR(200))
117+
AS
118+
BEGIN
119+
return1 = param1 || param1;
120+
END""";
121+
107122
private static final MetadataResultSetDefinition getProcedureColumnsDefinition =
108123
new MetadataResultSetDefinition(ProcedureColumnMetaData.class);
109124

@@ -147,6 +162,10 @@ private static List<String> getCreateStatements() {
147162
statements.add(CREATE_PACKAGE_WITH_PROCEDURE);
148163
statements.add(CREATE_PACKAGE_BODY_WITH_PROCEDURE);
149164
}
165+
if (supportInfo.supportsSchemas()) {
166+
statements.add(CREATE_OTHER_SCHEMA);
167+
statements.add(CREATE_OTHER_SCHEMA_PROC_WITH_RETURN);
168+
}
150169
return statements;
151170
}
152171

@@ -174,11 +193,20 @@ void testProcedureColumns_noArg_noReturn() throws Exception {
174193
/**
175194
* Tests getProcedureColumn with normal_proc_no_return using all columnPattern, expecting result set with all defined rows.
176195
*/
177-
@Test
178-
void testProcedureColumns_normalProc_noReturn_allPattern() throws Exception {
196+
@ParameterizedTest
197+
@CsvSource(useHeadersInDisplayName = true, nullValues = "<NIL>", textBlock = """
198+
schemaPattern, columnNamePattern
199+
<NIL>, <NIL>
200+
%, <NIL>
201+
PUBLIC, %
202+
<NIL>, %
203+
""")
204+
void testProcedureColumns_normalProc_noReturn_allPattern(String schemaPattern, String columnNamePattern)
205+
throws Exception {
179206
var expectedColumns = getNormalProcNoReturn_allColumns();
180207

181-
ResultSet procedureColumns = dbmd.getProcedureColumns(null, null, "NORMAL_PROC_NO_RETURN", "%");
208+
ResultSet procedureColumns = dbmd
209+
.getProcedureColumns(null, resolveSchema(schemaPattern), "NORMAL_PROC_NO_RETURN", columnNamePattern);
182210
validate(procedureColumns, expectedColumns);
183211
}
184212

@@ -273,7 +301,8 @@ void testProcedureColumns_useCatalogAsPackage_everything() throws Exception {
273301
try (var connection = DriverManager.getConnection(getUrl(), props)) {
274302
dbmd = connection.getMetaData();
275303

276-
var expectedColumns = new ArrayList<>(getNormalProcNoReturn_allColumns());
304+
var expectedColumns = new ArrayList<>(getOtherSchemaProcWithReturn_allColumns());
305+
expectedColumns.addAll(getNormalProcNoReturn_allColumns());
277306
expectedColumns.addAll(getNormalProcWithReturn_allColumns());
278307
expectedColumns.addAll(getQuotedProcNoReturn_allColumns());
279308
withCatalog("", expectedColumns);
@@ -330,10 +359,10 @@ void testProcedureColumns_useCatalogAsPackage_specificPackageProcedureColumn(Str
330359
dbmd = connection.getMetaData();
331360

332361
List<Map<ProcedureColumnMetaData, Object>> expectedColumns =
333-
withCatalog("WITH$PROCEDURE",
334-
withSpecificName(ifSchemaElse("\"PUBLIC\".", "") + "\"WITH$PROCEDURE\".\"IN$PACKAGE\"",
335-
List.of(createNumericalType(Types.INTEGER, "IN$PACKAGE", "RETURN1", 1, 10, 0, true,
336-
DatabaseMetaData.procedureColumnOut))));
362+
withCatalog("WITH$PROCEDURE", withSpecificName(
363+
ObjectReference.of(ifSchemaElse("PUBLIC", ""), "WITH$PROCEDURE", "IN$PACKAGE").toString(),
364+
List.of(createNumericalType(Types.INTEGER, "IN$PACKAGE", "RETURN1", 1, 10, 0, true,
365+
DatabaseMetaData.procedureColumnOut))));
337366

338367
ResultSet procedureColumns = dbmd.getProcedureColumns(catalog, null, "IN$PACKAGE", "RETURN1");
339368
validate(procedureColumns, expectedColumns);
@@ -349,7 +378,8 @@ void testProcedureColumns_useCatalogAsPackage_nonPackagedOnly() throws Exception
349378
try (var connection = DriverManager.getConnection(getUrl(), props)) {
350379
dbmd = connection.getMetaData();
351380

352-
var expectedColumns = new ArrayList<>(getNormalProcNoReturn_allColumns());
381+
var expectedColumns = new ArrayList<>(getOtherSchemaProcWithReturn_allColumns());
382+
expectedColumns.addAll(getNormalProcNoReturn_allColumns());
353383
expectedColumns.addAll(getNormalProcWithReturn_allColumns());
354384
expectedColumns.addAll(getQuotedProcNoReturn_allColumns());
355385
withCatalog("", expectedColumns);
@@ -360,15 +390,47 @@ void testProcedureColumns_useCatalogAsPackage_nonPackagedOnly() throws Exception
360390
}
361391

362392
private static List<Map<ProcedureColumnMetaData, Object>> getInPackage_allColumns() {
363-
return withCatalog("WITH$PROCEDURE",
364-
withSpecificName(ifSchemaElse("\"PUBLIC\".", "") + "\"WITH$PROCEDURE\".\"IN$PACKAGE\"",
365-
// TODO Having result columns first might be against JDBC spec
366-
// TODO Describing result columns as procedureColumnOut might be against JDBC spec
367-
List.of(
368-
createNumericalType(Types.INTEGER, "IN$PACKAGE", "RETURN1", 1, 10, 0, true,
369-
DatabaseMetaData.procedureColumnOut),
370-
createNumericalType(Types.INTEGER, "IN$PACKAGE", "PARAM1", 1, 10, 0, true,
371-
DatabaseMetaData.procedureColumnIn))));
393+
return withCatalog("WITH$PROCEDURE", withSpecificName(
394+
ObjectReference.of(ifSchemaElse("PUBLIC", ""), "WITH$PROCEDURE", "IN$PACKAGE").toString(),
395+
// TODO Having result columns first might be against JDBC spec
396+
// TODO Describing result columns as procedureColumnOut might be against JDBC spec
397+
List.of(
398+
createNumericalType(Types.INTEGER, "IN$PACKAGE", "RETURN1", 1, 10, 0, true,
399+
DatabaseMetaData.procedureColumnOut),
400+
createNumericalType(Types.INTEGER, "IN$PACKAGE", "PARAM1", 1, 10, 0, true,
401+
DatabaseMetaData.procedureColumnIn))));
402+
}
403+
404+
/**
405+
* Tests getProcedureColumn with OTHER_SCHEMA.PROC_WITH_RETURN, expecting result set with all defined rows.
406+
*/
407+
@ParameterizedTest
408+
@CsvSource(useHeadersInDisplayName = true, nullValues = "<NIL>", textBlock = """
409+
schemaPattern, procedureNamePattern, columnNamePattern
410+
OTHER_SCHEMA, PROC_WITH_RETURN, %
411+
OTHER\\_SCHEMA, PROC\\_WITH\\_RETURN, <NIL>
412+
OTHER%, PROC\\_WITH\\_RETURN, <NIL>
413+
""")
414+
void testProcedureColumns_otherSchemaProcWithReturn_all(String schemaPattern, String procedureNamePattern,
415+
String columnNamePattern) throws Exception {
416+
assumeFeature(FirebirdSupportInfo::supportsSchemas, "Test requires schema support");
417+
var expectedColumns = getOtherSchemaProcWithReturn_allColumns();
418+
419+
ResultSet procedureColumns = dbmd
420+
.getProcedureColumns(null, schemaPattern, procedureNamePattern, columnNamePattern);
421+
validate(procedureColumns, expectedColumns);
422+
}
423+
424+
private static List<Map<ProcedureColumnMetaData, Object>> getOtherSchemaProcWithReturn_allColumns() {
425+
return List.of(
426+
// TODO Having result columns first might be against JDBC spec
427+
// TODO Describing result columns as procedureColumnOut might be against JDBC spec
428+
createStringType(Types.VARCHAR, "OTHER_SCHEMA", "PROC_WITH_RETURN", "RETURN1", 1, 200, true,
429+
DatabaseMetaData.procedureColumnOut),
430+
createStringType(Types.VARCHAR, "OTHER_SCHEMA", "PROC_WITH_RETURN", "PARAM1", 1, 100, true,
431+
DatabaseMetaData.procedureColumnIn),
432+
createNumericalType(Types.DECIMAL, "OTHER_SCHEMA", "PROC_WITH_RETURN", "PARAM2", 2,
433+
NUMERIC_BIGINT_PRECISION, 2, true, DatabaseMetaData.procedureColumnIn));
372434
}
373435

374436
// TODO Add tests for more complex patterns for procedure and column
@@ -392,12 +454,6 @@ private void validate(ResultSet procedureColumns, List<Map<ProcedureColumnMetaDa
392454
}
393455
}
394456

395-
private static Map<ProcedureColumnMetaData, Object> createColumn(String procedureName, String columnName,
396-
int ordinalPosition, boolean nullable, int columnType) {
397-
return createColumn(ifSchemaElse("PUBLIC", null), procedureName, columnName, ordinalPosition, nullable,
398-
columnType);
399-
}
400-
401457
private static Map<ProcedureColumnMetaData, Object> createColumn(String schema, String procedureName,
402458
String columnName, int ordinalPosition, boolean nullable, int columnType) {
403459
Map<ProcedureColumnMetaData, Object> rules = getDefaultValueValidationRules();
@@ -416,19 +472,21 @@ private static Map<ProcedureColumnMetaData, Object> createColumn(String schema,
416472

417473
private static String getProcedureSpecificName(String schema, String procedureName) {
418474
if (schema == null || schema.isEmpty()) return procedureName;
419-
var quote = QuoteStrategy.DIALECT_3;
420-
// 5 = 4 quotes + 1 period
421-
var sb = new StringBuilder(schema.length() + procedureName.length() + 5);
422-
quote.appendQuoted(schema, sb).append('.');
423-
quote.appendQuoted(procedureName, sb);
424-
return sb.toString();
475+
return ObjectReference.of(schema, procedureName).toString();
425476
}
426477

427478
@SuppressWarnings("SameParameterValue")
428479
private static Map<ProcedureColumnMetaData, Object> createStringType(int jdbcType, String procedureName,
429480
String columnName, int ordinalPosition, int length, boolean nullable, int columnType) {
481+
return createStringType(jdbcType, ifSchemaElse("PUBLIC", ""), procedureName, columnName, ordinalPosition, length,
482+
nullable, columnType);
483+
}
484+
485+
private static Map<ProcedureColumnMetaData, Object> createStringType(int jdbcType, String schema,
486+
String procedureName, String columnName, int ordinalPosition, int length, boolean nullable,
487+
int columnType) {
430488
Map<ProcedureColumnMetaData, Object> rules =
431-
createColumn(procedureName, columnName, ordinalPosition, nullable, columnType);
489+
createColumn(schema, procedureName, columnName, ordinalPosition, nullable, columnType);
432490
rules.put(ProcedureColumnMetaData.DATA_TYPE, jdbcType);
433491
String typeName = switch (jdbcType) {
434492
case Types.CHAR, Types.BINARY -> "CHAR";
@@ -445,8 +503,15 @@ private static Map<ProcedureColumnMetaData, Object> createStringType(int jdbcTyp
445503
@SuppressWarnings("SameParameterValue")
446504
private static Map<ProcedureColumnMetaData, Object> createNumericalType(int jdbcType, String procedureName,
447505
String columnName, int ordinalPosition, int precision, int scale, boolean nullable, int columnType) {
506+
return createNumericalType(jdbcType, ifSchemaElse("PUBLIC", ""), procedureName, columnName, ordinalPosition,
507+
precision, scale, nullable, columnType);
508+
}
509+
510+
private static Map<ProcedureColumnMetaData, Object> createNumericalType(int jdbcType, String schema,
511+
String procedureName, String columnName, int ordinalPosition, int precision, int scale, boolean nullable,
512+
int columnType) {
448513
Map<ProcedureColumnMetaData, Object> rules =
449-
createColumn(procedureName, columnName, ordinalPosition, nullable, columnType);
514+
createColumn(schema, procedureName, columnName, ordinalPosition, nullable, columnType);
450515
rules.put(ProcedureColumnMetaData.DATA_TYPE, jdbcType);
451516
String typeName;
452517
int length;
@@ -483,8 +548,15 @@ private static Map<ProcedureColumnMetaData, Object> createNumericalType(int jdbc
483548
@SuppressWarnings("SameParameterValue")
484549
private static Map<ProcedureColumnMetaData, Object> createDateTime(int jdbcType, String procedureName,
485550
String columnName, int ordinalPosition, boolean nullable, int columnType) {
551+
return createDateTime(jdbcType, ifSchemaElse("PUBLIC", ""), procedureName, columnName, ordinalPosition,
552+
nullable, columnType);
553+
}
554+
555+
@SuppressWarnings("SameParameterValue")
556+
private static Map<ProcedureColumnMetaData, Object> createDateTime(int jdbcType, String schema,
557+
String procedureName, String columnName, int ordinalPosition, boolean nullable, int columnType) {
486558
Map<ProcedureColumnMetaData, Object> rules =
487-
createColumn(procedureName, columnName, ordinalPosition, nullable, columnType);
559+
createColumn(schema, procedureName, columnName, ordinalPosition, nullable, columnType);
488560
rules.put(ProcedureColumnMetaData.DATA_TYPE, jdbcType);
489561
String typeName;
490562
int precision;
@@ -526,8 +598,14 @@ private static Map<ProcedureColumnMetaData, Object> createDateTime(int jdbcType,
526598
@SuppressWarnings("SameParameterValue")
527599
private static Map<ProcedureColumnMetaData, Object> createDouble(String procedureName, String columnName,
528600
int ordinalPosition, boolean nullable, int columnType) {
601+
return createDouble(ifSchemaElse("PUBLIC", ""), procedureName, columnName, ordinalPosition, nullable,
602+
columnType);
603+
}
604+
605+
private static Map<ProcedureColumnMetaData, Object> createDouble(String schema, String procedureName,
606+
String columnName, int ordinalPosition, boolean nullable, int columnType) {
529607
Map<ProcedureColumnMetaData, Object> rules =
530-
createColumn(procedureName, columnName, ordinalPosition, nullable, columnType);
608+
createColumn(schema, procedureName, columnName, ordinalPosition, nullable, columnType);
531609
rules.put(ProcedureColumnMetaData.DATA_TYPE, Types.DOUBLE);
532610
rules.put(ProcedureColumnMetaData.TYPE_NAME, "DOUBLE PRECISION");
533611
if (getDefaultSupportInfo().supportsFloatBinaryPrecision()) {
@@ -547,6 +625,7 @@ private static Map<ProcedureColumnMetaData, Object> withRemark(Map<ProcedureColu
547625
return column;
548626
}
549627

628+
@SuppressWarnings("SameParameterValue")
550629
private static Map<ProcedureColumnMetaData, Object> withDefault(String defaultDefinition,
551630
Map<ProcedureColumnMetaData, Object> rules) {
552631
rules.put(ProcedureColumnMetaData.COLUMN_DEF, defaultDefinition);

0 commit comments

Comments
 (0)