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,11 @@ 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 <Map <ProcedureColumnMetaData , Object >>();
305+ if (supportInfo .supportsSchemas ()) {
306+ expectedColumns .addAll (getOtherSchemaProcWithReturn_allColumns ());
307+ }
308+ expectedColumns .addAll (getNormalProcNoReturn_allColumns ());
277309 expectedColumns .addAll (getNormalProcWithReturn_allColumns ());
278310 expectedColumns .addAll (getQuotedProcNoReturn_allColumns ());
279311 withCatalog ("" , expectedColumns );
@@ -330,10 +362,10 @@ void testProcedureColumns_useCatalogAsPackage_specificPackageProcedureColumn(Str
330362 dbmd = connection .getMetaData ();
331363
332364 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 ))));
365+ withCatalog ("WITH$PROCEDURE" , withSpecificName (
366+ ObjectReference . of (ifSchemaElse ("PUBLIC" , "" ), " WITH$PROCEDURE" , "IN$PACKAGE" ). toString () ,
367+ List .of (createNumericalType (Types .INTEGER , "IN$PACKAGE" , "RETURN1" , 1 , 10 , 0 , true ,
368+ DatabaseMetaData .procedureColumnOut ))));
337369
338370 ResultSet procedureColumns = dbmd .getProcedureColumns (catalog , null , "IN$PACKAGE" , "RETURN1" );
339371 validate (procedureColumns , expectedColumns );
@@ -349,7 +381,11 @@ void testProcedureColumns_useCatalogAsPackage_nonPackagedOnly() throws Exception
349381 try (var connection = DriverManager .getConnection (getUrl (), props )) {
350382 dbmd = connection .getMetaData ();
351383
352- var expectedColumns = new ArrayList <>(getNormalProcNoReturn_allColumns ());
384+ var expectedColumns = new ArrayList <Map <ProcedureColumnMetaData , Object >>();
385+ if (supportInfo .supportsSchemas ()) {
386+ expectedColumns .addAll (getOtherSchemaProcWithReturn_allColumns ());
387+ }
388+ expectedColumns .addAll (getNormalProcNoReturn_allColumns ());
353389 expectedColumns .addAll (getNormalProcWithReturn_allColumns ());
354390 expectedColumns .addAll (getQuotedProcNoReturn_allColumns ());
355391 withCatalog ("" , expectedColumns );
@@ -360,15 +396,47 @@ void testProcedureColumns_useCatalogAsPackage_nonPackagedOnly() throws Exception
360396 }
361397
362398 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 ))));
399+ return withCatalog ("WITH$PROCEDURE" , withSpecificName (
400+ ObjectReference .of (ifSchemaElse ("PUBLIC" , "" ), "WITH$PROCEDURE" , "IN$PACKAGE" ).toString (),
401+ // TODO Having result columns first might be against JDBC spec
402+ // TODO Describing result columns as procedureColumnOut might be against JDBC spec
403+ List .of (
404+ createNumericalType (Types .INTEGER , "IN$PACKAGE" , "RETURN1" , 1 , 10 , 0 , true ,
405+ DatabaseMetaData .procedureColumnOut ),
406+ createNumericalType (Types .INTEGER , "IN$PACKAGE" , "PARAM1" , 1 , 10 , 0 , true ,
407+ DatabaseMetaData .procedureColumnIn ))));
408+ }
409+
410+ /**
411+ * Tests getProcedureColumn with OTHER_SCHEMA.PROC_WITH_RETURN, expecting result set with all defined rows.
412+ */
413+ @ ParameterizedTest
414+ @ CsvSource (useHeadersInDisplayName = true , nullValues = "<NIL>" , textBlock = """
415+ schemaPattern, procedureNamePattern, columnNamePattern
416+ OTHER_SCHEMA, PROC_WITH_RETURN, %
417+ OTHER\\ _SCHEMA, PROC\\ _WITH\\ _RETURN, <NIL>
418+ OTHER%, PROC\\ _WITH\\ _RETURN, <NIL>
419+ """ )
420+ void testProcedureColumns_otherSchemaProcWithReturn_all (String schemaPattern , String procedureNamePattern ,
421+ String columnNamePattern ) throws Exception {
422+ assumeFeature (FirebirdSupportInfo ::supportsSchemas , "Test requires schema support" );
423+ var expectedColumns = getOtherSchemaProcWithReturn_allColumns ();
424+
425+ ResultSet procedureColumns = dbmd
426+ .getProcedureColumns (null , schemaPattern , procedureNamePattern , columnNamePattern );
427+ validate (procedureColumns , expectedColumns );
428+ }
429+
430+ private static List <Map <ProcedureColumnMetaData , Object >> getOtherSchemaProcWithReturn_allColumns () {
431+ return List .of (
432+ // TODO Having result columns first might be against JDBC spec
433+ // TODO Describing result columns as procedureColumnOut might be against JDBC spec
434+ createStringType (Types .VARCHAR , "OTHER_SCHEMA" , "PROC_WITH_RETURN" , "RETURN1" , 1 , 200 , true ,
435+ DatabaseMetaData .procedureColumnOut ),
436+ createStringType (Types .VARCHAR , "OTHER_SCHEMA" , "PROC_WITH_RETURN" , "PARAM1" , 1 , 100 , true ,
437+ DatabaseMetaData .procedureColumnIn ),
438+ createNumericalType (Types .DECIMAL , "OTHER_SCHEMA" , "PROC_WITH_RETURN" , "PARAM2" , 2 ,
439+ NUMERIC_BIGINT_PRECISION , 2 , true , DatabaseMetaData .procedureColumnIn ));
372440 }
373441
374442 // TODO Add tests for more complex patterns for procedure and column
@@ -392,12 +460,6 @@ private void validate(ResultSet procedureColumns, List<Map<ProcedureColumnMetaDa
392460 }
393461 }
394462
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-
401463 private static Map <ProcedureColumnMetaData , Object > createColumn (String schema , String procedureName ,
402464 String columnName , int ordinalPosition , boolean nullable , int columnType ) {
403465 Map <ProcedureColumnMetaData , Object > rules = getDefaultValueValidationRules ();
@@ -416,19 +478,21 @@ private static Map<ProcedureColumnMetaData, Object> createColumn(String schema,
416478
417479 private static String getProcedureSpecificName (String schema , String procedureName ) {
418480 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 ();
481+ return ObjectReference .of (schema , procedureName ).toString ();
425482 }
426483
427484 @ SuppressWarnings ("SameParameterValue" )
428485 private static Map <ProcedureColumnMetaData , Object > createStringType (int jdbcType , String procedureName ,
429486 String columnName , int ordinalPosition , int length , boolean nullable , int columnType ) {
487+ return createStringType (jdbcType , ifSchemaElse ("PUBLIC" , null ), procedureName , columnName , ordinalPosition , length ,
488+ nullable , columnType );
489+ }
490+
491+ private static Map <ProcedureColumnMetaData , Object > createStringType (int jdbcType , String schema ,
492+ String procedureName , String columnName , int ordinalPosition , int length , boolean nullable ,
493+ int columnType ) {
430494 Map <ProcedureColumnMetaData , Object > rules =
431- createColumn (procedureName , columnName , ordinalPosition , nullable , columnType );
495+ createColumn (schema , procedureName , columnName , ordinalPosition , nullable , columnType );
432496 rules .put (ProcedureColumnMetaData .DATA_TYPE , jdbcType );
433497 String typeName = switch (jdbcType ) {
434498 case Types .CHAR , Types .BINARY -> "CHAR" ;
@@ -445,8 +509,15 @@ private static Map<ProcedureColumnMetaData, Object> createStringType(int jdbcTyp
445509 @ SuppressWarnings ("SameParameterValue" )
446510 private static Map <ProcedureColumnMetaData , Object > createNumericalType (int jdbcType , String procedureName ,
447511 String columnName , int ordinalPosition , int precision , int scale , boolean nullable , int columnType ) {
512+ return createNumericalType (jdbcType , ifSchemaElse ("PUBLIC" , null ), procedureName , columnName , ordinalPosition ,
513+ precision , scale , nullable , columnType );
514+ }
515+
516+ private static Map <ProcedureColumnMetaData , Object > createNumericalType (int jdbcType , String schema ,
517+ String procedureName , String columnName , int ordinalPosition , int precision , int scale , boolean nullable ,
518+ int columnType ) {
448519 Map <ProcedureColumnMetaData , Object > rules =
449- createColumn (procedureName , columnName , ordinalPosition , nullable , columnType );
520+ createColumn (schema , procedureName , columnName , ordinalPosition , nullable , columnType );
450521 rules .put (ProcedureColumnMetaData .DATA_TYPE , jdbcType );
451522 String typeName ;
452523 int length ;
@@ -483,8 +554,15 @@ private static Map<ProcedureColumnMetaData, Object> createNumericalType(int jdbc
483554 @ SuppressWarnings ("SameParameterValue" )
484555 private static Map <ProcedureColumnMetaData , Object > createDateTime (int jdbcType , String procedureName ,
485556 String columnName , int ordinalPosition , boolean nullable , int columnType ) {
557+ return createDateTime (jdbcType , ifSchemaElse ("PUBLIC" , null ), procedureName , columnName , ordinalPosition ,
558+ nullable , columnType );
559+ }
560+
561+ @ SuppressWarnings ("SameParameterValue" )
562+ private static Map <ProcedureColumnMetaData , Object > createDateTime (int jdbcType , String schema ,
563+ String procedureName , String columnName , int ordinalPosition , boolean nullable , int columnType ) {
486564 Map <ProcedureColumnMetaData , Object > rules =
487- createColumn (procedureName , columnName , ordinalPosition , nullable , columnType );
565+ createColumn (schema , procedureName , columnName , ordinalPosition , nullable , columnType );
488566 rules .put (ProcedureColumnMetaData .DATA_TYPE , jdbcType );
489567 String typeName ;
490568 int precision ;
@@ -526,8 +604,14 @@ private static Map<ProcedureColumnMetaData, Object> createDateTime(int jdbcType,
526604 @ SuppressWarnings ("SameParameterValue" )
527605 private static Map <ProcedureColumnMetaData , Object > createDouble (String procedureName , String columnName ,
528606 int ordinalPosition , boolean nullable , int columnType ) {
607+ return createDouble (ifSchemaElse ("PUBLIC" , null ), procedureName , columnName , ordinalPosition , nullable ,
608+ columnType );
609+ }
610+
611+ private static Map <ProcedureColumnMetaData , Object > createDouble (String schema , String procedureName ,
612+ String columnName , int ordinalPosition , boolean nullable , int columnType ) {
529613 Map <ProcedureColumnMetaData , Object > rules =
530- createColumn (procedureName , columnName , ordinalPosition , nullable , columnType );
614+ createColumn (schema , procedureName , columnName , ordinalPosition , nullable , columnType );
531615 rules .put (ProcedureColumnMetaData .DATA_TYPE , Types .DOUBLE );
532616 rules .put (ProcedureColumnMetaData .TYPE_NAME , "DOUBLE PRECISION" );
533617 if (getDefaultSupportInfo ().supportsFloatBinaryPrecision ()) {
@@ -547,6 +631,7 @@ private static Map<ProcedureColumnMetaData, Object> withRemark(Map<ProcedureColu
547631 return column ;
548632 }
549633
634+ @ SuppressWarnings ("SameParameterValue" )
550635 private static Map <ProcedureColumnMetaData , Object > withDefault (String defaultDefinition ,
551636 Map <ProcedureColumnMetaData , Object > rules ) {
552637 rules .put (ProcedureColumnMetaData .COLUMN_DEF , defaultDefinition );
0 commit comments