diff --git a/core/trino-main/src/main/java/io/trino/sql/rewrite/ShowQueriesRewrite.java b/core/trino-main/src/main/java/io/trino/sql/rewrite/ShowQueriesRewrite.java index e38718a6d6bb..779cd02ba20d 100644 --- a/core/trino-main/src/main/java/io/trino/sql/rewrite/ShowQueriesRewrite.java +++ b/core/trino-main/src/main/java/io/trino/sql/rewrite/ShowQueriesRewrite.java @@ -120,6 +120,7 @@ import static io.trino.sql.QueryUtil.aliasedName; import static io.trino.sql.QueryUtil.aliasedNullToEmpty; import static io.trino.sql.QueryUtil.ascending; +import static io.trino.sql.QueryUtil.emptyQuery; import static io.trino.sql.QueryUtil.equal; import static io.trino.sql.QueryUtil.functionCall; import static io.trino.sql.QueryUtil.identifier; @@ -299,18 +300,14 @@ protected Node visitShowRoles(ShowRoles node, Void context) List rows = enabledRoles.stream() .map(role -> row(new StringLiteral(role))) .collect(toList()); - return simpleQuery( - selectList(new AllColumns()), - aliased(new Values(rows), "role_name", ImmutableList.of("Role"))); + return singleColumnValues(rows, "Role"); } else { accessControl.checkCanShowRoles(session.toSecurityContext(), catalog); List rows = metadata.listRoles(session, catalog).stream() .map(role -> row(new StringLiteral(role))) .collect(toList()); - return simpleQuery( - selectList(new AllColumns()), - aliased(new Values(rows), "role_name", ImmutableList.of("Role"))); + return singleColumnValues(rows, "Role"); } } @@ -325,10 +322,19 @@ protected Node visitShowRoleGrants(ShowRoleGrants node, Void context) .map(roleGrant -> row(new StringLiteral(roleGrant.getRoleName()))) .collect(toList()); + return singleColumnValues(rows, "Role Grants"); + } + + private Query singleColumnValues(List rows, String columnName) + { + List columns = ImmutableList.of(columnName); + if (rows.isEmpty()) { + return emptyQuery(columns); + } return simpleQuery( selectList(new AllColumns()), - aliased(new Values(rows), "role_grants", ImmutableList.of("Role Grants")), - ordering(ascending("Role Grants"))); + aliased(new Values(rows), "relation", columns), + ordering(ascending(columnName))); } @Override diff --git a/core/trino-parser/src/main/java/io/trino/sql/QueryUtil.java b/core/trino-parser/src/main/java/io/trino/sql/QueryUtil.java index 2f4a52bda6c7..f63161461f49 100644 --- a/core/trino-parser/src/main/java/io/trino/sql/QueryUtil.java +++ b/core/trino-parser/src/main/java/io/trino/sql/QueryUtil.java @@ -25,6 +25,7 @@ import io.trino.sql.tree.Identifier; import io.trino.sql.tree.LogicalBinaryExpression; import io.trino.sql.tree.Node; +import io.trino.sql.tree.NullLiteral; import io.trino.sql.tree.Offset; import io.trino.sql.tree.OrderBy; import io.trino.sql.tree.QualifiedName; @@ -267,6 +268,25 @@ public static Query singleValueQuery(String columnName, boolean value) aliased(values, "t", ImmutableList.of(columnName))); } + // TODO pass column types + public static Query emptyQuery(List columns) + { + Select select = selectList(columns.stream() + .map(column -> new SingleColumn(new NullLiteral(), QueryUtil.identifier(column))) + .toArray(SelectItem[]::new)); + Optional where = Optional.of(FALSE_LITERAL); + return query(new QuerySpecification( + select, + Optional.empty(), + where, + Optional.empty(), + Optional.empty(), + ImmutableList.of(), + Optional.empty(), + Optional.empty(), + Optional.empty())); + } + public static Query query(QueryBody body) { return new Query( diff --git a/testing/trino-tests/src/test/java/io/trino/security/TestAccessControl.java b/testing/trino-tests/src/test/java/io/trino/security/TestAccessControl.java index 166be8016bf3..9eb225fd7a1d 100644 --- a/testing/trino-tests/src/test/java/io/trino/security/TestAccessControl.java +++ b/testing/trino-tests/src/test/java/io/trino/security/TestAccessControl.java @@ -411,4 +411,13 @@ public void testNoCatalogIsNeededInSessionForShowRoles() assertQuery(session, "SHOW CURRENT ROLES FROM mock", "VALUES 'alice_role'"); assertQuery(session, "SELECT * FROM mock.information_schema.applicable_roles", "SELECT 'alice', 'USER', 'alice_role', 'NO'"); } + + @Test + public void testEmptyRoles() + { + assertQueryReturnsEmptyResult("SHOW ROLES"); + assertQueryReturnsEmptyResult("SHOW ROLE GRANTS"); + assertQueryReturnsEmptyResult("SHOW CURRENT ROLES"); + assertQueryReturnsEmptyResult("SELECT * FROM information_schema.applicable_roles"); + } }