44
55import org .firebirdsql .common .extension .UsesDatabaseExtension ;
66import org .firebirdsql .jaybird .props .PropertyNames ;
7+ import org .firebirdsql .jaybird .util .ObjectReference ;
78import org .firebirdsql .jdbc .metadata .FbMetadataConstants ;
89import org .firebirdsql .util .FirebirdSupportInfo ;
910import org .junit .jupiter .api .AfterAll ;
1213import org .junit .jupiter .api .Test ;
1314import org .junit .jupiter .api .extension .RegisterExtension ;
1415import org .junit .jupiter .params .ParameterizedTest ;
16+ import org .junit .jupiter .params .provider .CsvSource ;
1517import org .junit .jupiter .params .provider .NullSource ;
1618import org .junit .jupiter .params .provider .ValueSource ;
1719
2426import static org .firebirdsql .common .FBTestProperties .getDefaultSupportInfo ;
2527import static org .firebirdsql .common .FBTestProperties .getUrl ;
2628import static org .firebirdsql .common .FBTestProperties .ifSchemaElse ;
29+ import static org .firebirdsql .common .FBTestProperties .resolveSchema ;
30+ import static org .firebirdsql .common .FbAssumptions .assumeFeature ;
2731import static org .firebirdsql .common .JdbcResourceHelper .closeQuietly ;
2832import static org .firebirdsql .jdbc .FBDatabaseMetaDataProceduresTest .isIgnoredProcedure ;
2933import static org .firebirdsql .jdbc .metadata .FbMetadataConstants .*;
3842 */
3943class 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