Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
9591d7d
#882 jdp-2025-06: Schema Support
mrotteveel Jun 18, 2025
9865b6b
#882 Fix tests failing due to Firebird 6 schemas
mrotteveel Jun 18, 2025
a3c5979
#882 Implement to DatabaseMetaData.getSchemas return schemas
mrotteveel Jun 19, 2025
7deb6ed
#882 Implement DatabaseMetaData informational methods to report schem…
mrotteveel Jun 19, 2025
740ce4d
Use isNullOrEmpty
mrotteveel Jun 19, 2025
286eea0
#882 Schema support for DatabaseMetaData.getProcedures
mrotteveel Jun 19, 2025
44cccc2
#882 Use SYSTEM unquoted due to dialect 1 support
mrotteveel Jun 19, 2025
d34af61
#882 Schema support for getBestRowIdentifier
mrotteveel Jun 21, 2025
05edd2d
#882 Schema support for getColumnPrivileges
mrotteveel Jun 21, 2025
7699234
#882 Schema support for getColumns
mrotteveel Jun 21, 2025
1d30a6d
#882 Schema support for getImportedKeys/getExportedKeys/getCrossRefer…
mrotteveel Jun 21, 2025
69effeb
#882 Schema support for getFunctionColumns
mrotteveel Jun 22, 2025
a5d8434
#882 Schema support for getFunctions
mrotteveel Jun 22, 2025
c08df8b
#882 Schema support for getIndexInfo
mrotteveel Jun 22, 2025
a1655eb
#882 Schema support for getPrimaryKeys
mrotteveel Jun 22, 2025
6b55727
#882 Schema support for getProcedureColumns
mrotteveel Jun 22, 2025
584e2cc
#882 Schema support for getPseudoColumns
mrotteveel Jun 22, 2025
6bdb4bc
#882 Schema support for getTablePrivileges
mrotteveel Jun 23, 2025
73ebef5
#882 Schema support for getTables
mrotteveel Jun 23, 2025
90ce855
#882 Schema support for getCatalogs
mrotteveel Jun 23, 2025
11349a7
Mark metadata classes sealed or final
mrotteveel Jun 23, 2025
ea0a273
#882 Schema support for getXXXSourceCode
mrotteveel Jun 23, 2025
b60c7d6
Add ifSchemaElse also to FirebirdSupportInfo
mrotteveel Jun 23, 2025
a154551
#882 Client props, xid detection
mrotteveel Jun 24, 2025
18a5228
#882 Retrieve schema name in column information
mrotteveel Jun 24, 2025
bed0828
#882 Incomplete change to selectable procedure detection
mrotteveel Jun 24, 2025
ce3abcc
#882 Misc wording of jdp-2025-06
mrotteveel Jun 24, 2025
d365d92
#882 Define connection property searchPath
mrotteveel Jun 24, 2025
276d8bc
Add supportInfoFor(FirebirdConnection) to avoid wrapper check
mrotteveel Jun 25, 2025
501eb78
Tighten up StoredProcedureMetaData, use support info
mrotteveel Jun 25, 2025
ca102d2
#882 Implement Connection.get/setSchema
mrotteveel Jul 9, 2025
6a7b308
#882 Additional schema tests for FBResultSetMetaData
mrotteveel Jul 12, 2025
aa3d585
#882 Modify FBRowUpdater to search for schema
mrotteveel Jul 13, 2025
1f839f0
Deduplicate strings in StatementInfoProcessor
mrotteveel Jul 13, 2025
fbff0a6
Add some todo for later
mrotteveel Jul 14, 2025
10ed654
#882 Improve schema test coverage
mrotteveel Jul 17, 2025
3662432
#882 Improve schema test coverage (getFunctions)
mrotteveel Jul 17, 2025
b83f275
Replace QualifiedName with ObjectReference
mrotteveel Jul 18, 2025
2cb017e
Add schema support assumption to test
mrotteveel Jul 18, 2025
b8769ad
#882 Improve schema test coverage (getProcedures/getProcedureColumns)
mrotteveel Jul 22, 2025
099a4b2
#882 Improve schema test coverage (getIndexInfo/getPrimaryKeys)
mrotteveel Jul 22, 2025
6a9febc
#882 Improve schema test coverage (getPseudoColumns/getTables)
mrotteveel Jul 22, 2025
48f4b7c
#882 Improve schema test coverage (getTablePrivileges)
mrotteveel Jul 22, 2025
24478cf
#882 schema support for generated keys
mrotteveel Jul 29, 2025
d251d84
#882 Add schema support for FBCallableStatement
mrotteveel Oct 9, 2025
82aa541
Fix test failure on Firebird 5 and older
mrotteveel Oct 9, 2025
a7542c0
#882 Document decision not to backport schema support to Jaybird 6
mrotteveel Oct 11, 2025
04523d7
Misc. copy editing and fixing typos
mrotteveel Oct 11, 2025
381b792
#882 Add JB_PROCEDURE_SOURCE column to getProcedures
mrotteveel Oct 13, 2025
102a856
#882 Reject idea to add column with schemas to getCatalogs
mrotteveel Oct 13, 2025
567cdea
Remove unnecessary caching from BasicVersion
mrotteveel Oct 17, 2025
e2e4e87
#882 Schema support for StatisticsManager.getTableStatistics
mrotteveel Oct 17, 2025
2353b24
#882 Schema support for FBTableStatisticsManager
mrotteveel Oct 18, 2025
c2320ed
Fixed wrong name
mrotteveel Oct 19, 2025
180999c
#882 Added setters to FirebirdConnection to set search path
mrotteveel Oct 19, 2025
d934271
Document compatibility issue with schema(Pattern) in dbmd
mrotteveel Oct 25, 2025
a35a3a0
Correct documentation of getXXXSourceCode methods
mrotteveel Oct 30, 2025
48514d5
Misc review changes
mrotteveel Oct 30, 2025
13e38c3
Use Collection instead of List, use common code path
mrotteveel Nov 3, 2025
4a83dec
Simplify version string creation in GDSServerVersion
mrotteveel Nov 3, 2025
ec1056e
SPECIFIC_NAME should not include the schema
mrotteveel Nov 3, 2025
0c9efec
Update error codes and messages from 6.0.0.1338
mrotteveel Nov 4, 2025
e37afa1
Ignore drop schema failure, refactor to single code path
mrotteveel Nov 4, 2025
588a017
Finalize jdp-2025-06
mrotteveel Nov 4, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
#882 Schema support for getColumnPrivileges
  • Loading branch information
mrotteveel committed Oct 25, 2025
commit 05edd2d4cd48aaf9c48ddf19df8c523af2ba86d3
10 changes: 8 additions & 2 deletions src/main/org/firebirdsql/jdbc/FBDatabaseMetaData.java
Original file line number Diff line number Diff line change
Expand Up @@ -1337,14 +1337,20 @@ public ResultSet getColumns(String catalog, String schemaPattern, String tableNa
* </p>
* <p>
* <b>NOTE:</b> This implementation returns <b>all</b> privileges, not just applicable to the current user. It is
* unclear if this complies with the JDBC requirements. This may change in the future to only return only privileges
* unclear if this complies with the JDBC requirements. This may change in the future to only return privileges
* applicable to the current user, user {@code PUBLIC} and &mdash; maybe &mdash; active roles.
* </p>
* <p>
* Contrary to specified in the JDBC API, the result set is ordered by {@code TABLE_SCHEM}, {@code COLUMN_NAME},
* {@code PRIVILEGE}, and {@code GRANTEE} (JDBC specifies ordering by {@code COLUMN_NAME} and {@code PRIVILEGE}).
* This only makes a difference when specifying {@code null} for {@code schema} (search all schemas) and there are
* multiples tables with the same {@code name}.
* </p>
*/
@Override
public ResultSet getColumnPrivileges(String catalog, String schema, String table, String columnNamePattern)
throws SQLException {
return GetColumnPrivileges.create(getDbMetadataMediator()).getColumnPrivileges(table, columnNamePattern);
return GetColumnPrivileges.create(getDbMetadataMediator()).getColumnPrivileges(schema, table, columnNamePattern);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import static org.firebirdsql.gds.ISCConstants.SQL_LONG;
import static org.firebirdsql.gds.ISCConstants.SQL_SHORT;
import static org.firebirdsql.gds.ISCConstants.SQL_VARYING;
import static org.firebirdsql.jaybird.util.StringUtils.isNullOrEmpty;
import static org.firebirdsql.jdbc.metadata.FbMetadataConstants.OBJECT_NAME_LENGTH;
import static org.firebirdsql.jdbc.metadata.FbMetadataConstants.char_type;
import static org.firebirdsql.jdbc.metadata.MetadataPattern.escapeWildcards;
Expand Down Expand Up @@ -63,7 +64,7 @@ private GetBestRowIdentifier(DbMetadataMediator mediator) {
@SuppressWarnings("unused")
public ResultSet getBestRowIdentifier(String catalog, String schema, String table, int scope, boolean nullable)
throws SQLException {
if (table == null || table.isEmpty()) {
if (isNullOrEmpty(table)) {
return createEmpty();
}

Expand Down Expand Up @@ -204,7 +205,6 @@ MetadataQuery createGetPrimaryKeyIdentifierQuery(String schema, String table) {
String sql = GET_BEST_ROW_IDENT_START
+ tableClause.getCondition(false)
+ GET_BEST_ROW_IDENT_END;

return new MetadataQuery(sql, Clause.parameters(tableClause));
}
}
Expand All @@ -217,7 +217,7 @@ private static final class FB6 extends GetBestRowIdentifier {
//@formatter:off
private static final String GET_BEST_ROW_IDENT_START_6 = """
select
RF.RDB$FIELD_NAME as COLUMN_NAME,
trim(trailing from RF.RDB$FIELD_NAME) as COLUMN_NAME,
""" +
" F.RDB$FIELD_TYPE as " + FIELD_TYPE + ",\n" +
" F.RDB$FIELD_SUB_TYPE as " + FIELD_SUB_TYPE + ",\n" +
Expand Down
164 changes: 122 additions & 42 deletions src/main/org/firebirdsql/jdbc/metadata/GetColumnPrivileges.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2001-2024 Firebird development team and individual contributors
// SPDX-FileCopyrightText: Copyright 2022-2024 Mark Rotteveel
// SPDX-FileCopyrightText: Copyright 2001-2025 Firebird development team and individual contributors
// SPDX-FileCopyrightText: Copyright 2022-2025 Mark Rotteveel
// SPDX-License-Identifier: LGPL-2.1-or-later
package org.firebirdsql.jdbc.metadata;

Expand All @@ -10,8 +10,11 @@

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import static org.firebirdsql.gds.ISCConstants.SQL_VARYING;
import static org.firebirdsql.jaybird.util.StringUtils.isNullOrEmpty;
import static org.firebirdsql.jdbc.metadata.FbMetadataConstants.OBJECT_NAME_LENGTH;
import static org.firebirdsql.jdbc.metadata.PrivilegeMapping.mapPrivilege;

Expand All @@ -27,7 +30,7 @@
* @author Mark Rotteveel
* @since 5
*/
public final class GetColumnPrivileges extends AbstractMetadataMethod {
public abstract class GetColumnPrivileges extends AbstractMetadataMethod {

private static final String COLUMNPRIV = "COLUMNPRIV";
private static final RowDescriptor ROW_DESCRIPTOR = DbMetadataMediator.newRowDescriptorBuilder(9)
Expand All @@ -42,60 +45,28 @@ public final class GetColumnPrivileges extends AbstractMetadataMethod {
.at(8).simple(SQL_VARYING, OBJECT_NAME_LENGTH, "JB_GRANTEE_TYPE", COLUMNPRIV).addField()
.toRowDescriptor();

//@formatter:off
private static final String GET_COLUMN_PRIVILEGES_START =
"select distinct \n"
+ " RF.RDB$RELATION_NAME as TABLE_NAME, \n"
+ " RF.RDB$FIELD_NAME as COLUMN_NAME, \n"
+ " UP.RDB$GRANTOR as GRANTOR, \n"
+ " UP.RDB$USER as GRANTEE, \n"
+ " UP.RDB$PRIVILEGE as PRIVILEGE, \n"
+ " UP.RDB$GRANT_OPTION as IS_GRANTABLE,\n"
+ " T.RDB$TYPE_NAME as JB_GRANTEE_TYPE\n"
+ "from RDB$RELATION_FIELDS RF\n"
+ "inner join RDB$USER_PRIVILEGES UP\n"
+ " on UP.RDB$RELATION_NAME = RF.RDB$RELATION_NAME \n"
+ " and (UP.RDB$FIELD_NAME is null or UP.RDB$FIELD_NAME = RF.RDB$FIELD_NAME) \n"
+ "left join RDB$TYPES T\n"
+ " on T.RDB$FIELD_NAME = 'RDB$OBJECT_TYPE' and T.RDB$TYPE = UP.RDB$USER_TYPE \n"
// Other privileges don't make sense for column privileges
+ "where UP.RDB$PRIVILEGE in ('A', 'D', 'I', 'R', 'S', 'U')\n"
// Only tables and views
+ "and UP.RDB$OBJECT_TYPE in (0, 1)\n"
+ "and ";

// NOTE: Sort by user is not defined in JDBC, but we do this to ensure a consistent order for tests
private static final String GET_COLUMN_PRIVILEGES_END =
"\norder by RF.RDB$FIELD_NAME, UP.RDB$PRIVILEGE, UP.RDB$USER";
//@formatter:on

GetColumnPrivileges(DbMetadataMediator mediator) {
super(ROW_DESCRIPTOR, mediator);
}

/**
* @see java.sql.DatabaseMetaData#getColumnPrivileges(String, String, String, String)
*/
public ResultSet getColumnPrivileges(String table, String columnNamePattern) throws SQLException {
if (table == null || "".equals(columnNamePattern)) {
public ResultSet getColumnPrivileges(String schema, String table, String columnNamePattern) throws SQLException {
if (isNullOrEmpty(table) || "".equals(columnNamePattern)) {
return createEmpty();
}
Clause tableClause = Clause.equalsClause("RF.RDB$RELATION_NAME", table);
Clause columnNameClause = new Clause("RF.RDB$FIELD_NAME", columnNamePattern);

String sql = GET_COLUMN_PRIVILEGES_START
+ tableClause.getCondition(columnNameClause.hasCondition())
+ columnNameClause.getCondition(false)
+ GET_COLUMN_PRIVILEGES_END;
MetadataQuery metadataQuery = new MetadataQuery(sql, Clause.parameters(tableClause, columnNameClause));
MetadataQuery metadataQuery = createMetadataQuery(schema, table, columnNamePattern);
return createMetaDataResultSet(metadataQuery);
}

abstract MetadataQuery createMetadataQuery(String schema, String table, String columnNamePattern);

@Override
RowValue createMetadataRow(ResultSet rs, RowValueBuilder valueBuilder) throws SQLException {
return valueBuilder
.at(0).set(null)
.at(1).set(null)
.at(1).setString(rs.getString("TABLE_SCHEM"))
.at(2).setString(rs.getString("TABLE_NAME"))
.at(3).setString(rs.getString("COLUMN_NAME"))
.at(4).setString(rs.getString("GRANTOR"))
Expand All @@ -107,6 +78,115 @@ RowValue createMetadataRow(ResultSet rs, RowValueBuilder valueBuilder) throws SQ
}

public static GetColumnPrivileges create(DbMetadataMediator mediator) {
return new GetColumnPrivileges(mediator);
if (mediator.getFirebirdSupportInfo().isVersionEqualOrAbove(6)) {
return FB6.createInstance(mediator);
} else {
return FB5.createInstance(mediator);
}
}

/**
* Implementation for Firebird 5.0 and older.
*/
private static final class FB5 extends GetColumnPrivileges {

private static final String GET_COLUMN_PRIVILEGES_START_5 = """
select distinct
cast(null as char(1)) as TABLE_SCHEM,
RF.RDB$RELATION_NAME as TABLE_NAME,
RF.RDB$FIELD_NAME as COLUMN_NAME,
UP.RDB$GRANTOR as GRANTOR,
UP.RDB$USER as GRANTEE,
UP.RDB$PRIVILEGE as PRIVILEGE,
UP.RDB$GRANT_OPTION as IS_GRANTABLE,
T.RDB$TYPE_NAME as JB_GRANTEE_TYPE
from RDB$RELATION_FIELDS RF
inner join RDB$USER_PRIVILEGES UP
on UP.RDB$RELATION_NAME = RF.RDB$RELATION_NAME
and (UP.RDB$FIELD_NAME is null or UP.RDB$FIELD_NAME = RF.RDB$FIELD_NAME)
left join RDB$TYPES T
on T.RDB$FIELD_NAME = 'RDB$OBJECT_TYPE' and T.RDB$TYPE = UP.RDB$USER_TYPE
where UP.RDB$PRIVILEGE in ('A', 'D', 'I', 'R', 'S', 'U') -- privileges relevant for columns
and UP.RDB$OBJECT_TYPE in (0, 1) -- only tables and views
and\s""";

// NOTE: Sort by user is not defined in JDBC, but we do this to ensure a consistent order for tests
private static final String GET_COLUMN_PRIVILEGES_END_5 =
"\norder by RF.RDB$FIELD_NAME, UP.RDB$PRIVILEGE, UP.RDB$USER";

private FB5(DbMetadataMediator mediator) {
super(mediator);
}

private static GetColumnPrivileges createInstance(DbMetadataMediator mediator) {
return new FB5(mediator);
}

@Override
MetadataQuery createMetadataQuery(String schema, String table, String columnNamePattern) {
var clauses = List.of(
Clause.equalsClause("RF.RDB$RELATION_NAME", table),
new Clause("RF.RDB$FIELD_NAME", columnNamePattern));
String sql = GET_COLUMN_PRIVILEGES_START_5
+ Clause.conjunction(clauses)
+ GET_COLUMN_PRIVILEGES_END_5;
return new MetadataQuery(sql, Clause.parameters(clauses));
}

}

/**
* Implementation for Firebird 6.0 and higher.
*/
private static final class FB6 extends GetColumnPrivileges {

private static final String GET_COLUMN_PRIVILEGES_START_6 = """
select distinct
trim(trailing from RF.RDB$SCHEMA_NAME) as TABLE_SCHEM,
trim(trailing from RF.RDB$RELATION_NAME) as TABLE_NAME,
trim(trailing from RF.RDB$FIELD_NAME) as COLUMN_NAME,
trim(trailing from UP.RDB$GRANTOR) as GRANTOR,
trim(trailing from UP.RDB$USER) as GRANTEE,
UP.RDB$PRIVILEGE as PRIVILEGE,
UP.RDB$GRANT_OPTION as IS_GRANTABLE,
T.RDB$TYPE_NAME as JB_GRANTEE_TYPE
from SYSTEM.RDB$RELATION_FIELDS RF
inner join SYSTEM.RDB$USER_PRIVILEGES UP
on UP.RDB$RELATION_SCHEMA_NAME = RF.RDB$SCHEMA_NAME and UP.RDB$RELATION_NAME = RF.RDB$RELATION_NAME
and (UP.RDB$FIELD_NAME is null or UP.RDB$FIELD_NAME = RF.RDB$FIELD_NAME)
left join SYSTEM.RDB$TYPES T
on T.RDB$FIELD_NAME = 'RDB$OBJECT_TYPE' and T.RDB$TYPE = UP.RDB$USER_TYPE
where UP.RDB$PRIVILEGE in ('A', 'D', 'I', 'R', 'S', 'U') -- privileges relevant for columns
and UP.RDB$OBJECT_TYPE in (0, 1) -- only tables and views
and\s""";

// NOTE: Sort by user and schema is not defined in JDBC, but we do this to ensure a consistent order for tests
private static final String GET_COLUMN_PRIVILEGES_END_6 =
"\norder by RF.RDB$FIELD_NAME, UP.RDB$PRIVILEGE, UP.RDB$USER, RF.RDB$SCHEMA_NAME";

private FB6(DbMetadataMediator mediator) {
super(mediator);
}

private static GetColumnPrivileges createInstance(DbMetadataMediator mediator) {
return new FB6(mediator);
}

@Override
MetadataQuery createMetadataQuery(String schema, String table, String columnNamePattern) {
var clauses = new ArrayList<Clause>(3);
if (schema != null) {
// NOTE: empty string will return no rows as required ("" retrieves those without a schema)
clauses.add(Clause.equalsClause("RF.RDB$SCHEMA_NAME", schema));
}
clauses.add(Clause.equalsClause("RF.RDB$RELATION_NAME", table));
clauses.add(new Clause("RF.RDB$FIELD_NAME", columnNamePattern));
String sql = GET_COLUMN_PRIVILEGES_START_6
+ Clause.conjunction(clauses)
+ GET_COLUMN_PRIVILEGES_END_6;
return new MetadataQuery(sql, Clause.parameters(clauses));
}

}

}
4 changes: 2 additions & 2 deletions src/main/org/firebirdsql/jdbc/metadata/GetProcedures.java
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,8 @@ private static final class FB2_5 extends GetProcedures {

private static final String GET_PROCEDURES_FRAGMENT_2_5 = """
select
null as PROCEDURE_CAT,
null as PROCEDURE_SCHEM,
cast(null as char(1)) as PROCEDURE_CAT,
cast(null as char(1)) as PROCEDURE_SCHEM,
RDB$PROCEDURE_NAME as PROCEDURE_NAME,
RDB$DESCRIPTION as REMARKS,
RDB$PROCEDURE_OUTPUTS as PROCEDURE_TYPE
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2022-2023 Mark Rotteveel
// SPDX-FileCopyrightText: Copyright 2022-2025 Mark Rotteveel
// SPDX-License-Identifier: LGPL-2.1-or-later
package org.firebirdsql.jdbc;

Expand All @@ -24,6 +24,7 @@

import static org.firebirdsql.common.FBTestProperties.getConnectionViaDriverManager;
import static org.firebirdsql.common.FBTestProperties.getDefaultSupportInfo;
import static org.firebirdsql.common.FBTestProperties.ifSchemaElse;
import static org.firebirdsql.common.matchers.MatcherAssume.assumeThat;
import static org.hamcrest.Matchers.equalToIgnoringCase;
import static org.junit.jupiter.api.Assertions.assertEquals;
Expand All @@ -35,6 +36,8 @@
*/
class FBDatabaseMetaDataColumnPrivilegesTest {

// TODO Add schema support: tests involving other schema

private static final String SYSDBA = "SYSDBA";
private static final String USER1 = "USER1";
private static final String user2 = getDefaultSupportInfo().supportsCaseSensitiveUserNames() ? "user2" : "USER2";
Expand Down Expand Up @@ -125,7 +128,9 @@ void testColumnPrivileges_TBL1_all(String allPattern) throws Exception {
createRule("TBL1", "val3", USER1, false, "UPDATE"),
createRule("TBL1", "val3", user2, false, "UPDATE"));

validateExpectedColumnPrivileges("TBL1", allPattern, rules);
validateExpectedColumnPrivileges(ifSchemaElse("PUBLIC", ""), "TBL1", allPattern, rules);
// schema = null should also find it:
validateExpectedColumnPrivileges(null, "TBL1", allPattern, rules);
}

@Test
Expand Down Expand Up @@ -155,7 +160,9 @@ void testColumnPrivileges_TBL1_COL_wildcard() throws Exception {
createRule("TBL1", "COL2", SYSDBA, true, "UPDATE"),
createRule("TBL1", "COL2", USER1, false, "UPDATE"));

validateExpectedColumnPrivileges("TBL1", "COL%", rules);
validateExpectedColumnPrivileges(ifSchemaElse("PUBLIC", ""), "TBL1", "COL%", rules);
// schema = null should also find it:
validateExpectedColumnPrivileges(null, "TBL1", "COL%", rules);
}

@Test
Expand All @@ -181,23 +188,29 @@ void testColumnPrivileges_tbl2_all() throws Exception {
createRule("tbl2", "val3", user2, true, "SELECT"),
createRule("tbl2", "val3", SYSDBA, true, "UPDATE"));

validateExpectedColumnPrivileges("tbl2", "%", rules);
validateExpectedColumnPrivileges(ifSchemaElse("PUBLIC", ""), "tbl2", "%", rules);
}

private Map<ColumnPrivilegesMetadata, Object> createRule(String tableName, String columnName, String grantee,
private Map<ColumnPrivilegesMetadata, Object> createRule(String table, String columnName, String grantee,
boolean grantable, String privilege) {
return createRule(ifSchemaElse("PUBLIC", null), table, columnName, grantee, grantable, privilege);
}

private Map<ColumnPrivilegesMetadata, Object> createRule(String schema, String table, String columnName,
String grantee, boolean grantable, String privilege) {
Map<ColumnPrivilegesMetadata, Object> rules = getDefaultValueValidationRules();
rules.put(ColumnPrivilegesMetadata.TABLE_NAME, tableName);
rules.put(ColumnPrivilegesMetadata.TABLE_SCHEM, schema);
rules.put(ColumnPrivilegesMetadata.TABLE_NAME, table);
rules.put(ColumnPrivilegesMetadata.COLUMN_NAME, columnName);
rules.put(ColumnPrivilegesMetadata.GRANTEE, grantee);
rules.put(ColumnPrivilegesMetadata.PRIVILEGE, privilege);
rules.put(ColumnPrivilegesMetadata.IS_GRANTABLE, grantable ? "YES" : "NO");
return rules;
}

private void validateExpectedColumnPrivileges(String tableName, String columnNamePattern,
private void validateExpectedColumnPrivileges(String schema, String table, String columnNamePattern,
List<Map<ColumnPrivilegesMetadata, Object>> expectedColumnPrivileges) throws SQLException {
try (ResultSet columnPrivileges = dbmd.getColumnPrivileges(null, null, tableName, columnNamePattern)) {
try (ResultSet columnPrivileges = dbmd.getColumnPrivileges(null, schema, table, columnNamePattern)) {
int privilegeCount = 0;
while (columnPrivileges.next()) {
if (privilegeCount < expectedColumnPrivileges.size()) {
Expand All @@ -215,7 +228,7 @@ private void validateExpectedColumnPrivileges(String tableName, String columnNam
static {
Map<ColumnPrivilegesMetadata, Object> defaults = new EnumMap<>(ColumnPrivilegesMetadata.class);
defaults.put(ColumnPrivilegesMetadata.TABLE_CAT, null);
defaults.put(ColumnPrivilegesMetadata.TABLE_SCHEM, null);
defaults.put(ColumnPrivilegesMetadata.TABLE_SCHEM, ifSchemaElse("PUBLIC", null));
defaults.put(ColumnPrivilegesMetadata.GRANTOR, SYSDBA);
defaults.put(ColumnPrivilegesMetadata.JB_GRANTEE_TYPE, "USER");

Expand Down