Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -953,7 +953,7 @@ grantObject
;

ownedEntityKind
: TABLE | SCHEMA | VIEW | identifier
: TABLE | SCHEMA | VIEW | MATERIALIZED VIEW | identifier
;

qualifiedName
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,13 @@ private void setEntityAuthorization(Session session, SetAuthorizationStatement s
throw semanticException(TABLE_NOT_FOUND, statement, "View '%s' does not exist", viewName);
}
}
case "MATERIALIZED VIEW" -> {
QualifiedObjectName viewName = new QualifiedObjectName(name.get(0), name.get(1), name.get(2));
getRequiredCatalogHandle(metadata, session, statement, viewName.catalogName());
if (!metadata.isMaterializedView(session, viewName)) {
throw semanticException(TABLE_NOT_FOUND, statement, "Materialized view '%s' does not exist", viewName);
}
}
}

TrinoPrincipal principal = createPrincipal(statement.getPrincipal());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@
public final class MetadataManager
implements Metadata
{
private static final Set<String> ENTITY_KINDS_WITH_CATALOG = ImmutableSet.of("SCHEMA", "TABLE", "VIEW");
private static final Set<String> ENTITY_KINDS_WITH_CATALOG = ImmutableSet.of("SCHEMA", "TABLE", "VIEW", "MATERIALIZED VIEW");
private static final Logger log = Logger.get(MetadataManager.class);

@VisibleForTesting
Expand Down Expand Up @@ -2861,6 +2861,7 @@ public void setEntityAuthorization(Session session, EntityKindAndName entityKind
switch (ownedKind) {
case "TABLE" -> metadata.setTableAuthorization(session.toConnectorSession(catalogHandle), new SchemaTableName(name.get(1), name.get(2)), principal);
case "VIEW" -> metadata.setViewAuthorization(session.toConnectorSession(catalogHandle), new SchemaTableName(name.get(1), name.get(2)), principal);
case "MATERIALIZED VIEW" -> metadata.setMaterializedViewAuthorization(session.toConnectorSession(catalogHandle), new SchemaTableName(name.get(1), name.get(2)), principal);
case "SCHEMA" -> metadata.setSchemaAuthorization(session.toConnectorSession(catalogHandle), name.get(1), principal);
default -> throw new IllegalArgumentException("Unsupported owned kind: " + ownedKind);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ public static List<String> fillInNameParts(Session session, Node node, String en
throw new TrinoException(GENERIC_USER_ERROR, "Invalid entity %s for entity kind %s".formatted(joinName(name), entityKind));
}
break;
case "TABLE", "VIEW":
case "TABLE", "VIEW", "MATERIALIZED VIEW":
switch (name.size()) {
case 1:
if (session.getCatalog().isPresent() && session.getSchema().isPresent()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1416,6 +1416,9 @@ public void checkCanSetEntityAuthorization(SecurityContext securityContext, Enti
case "VIEW":
control.checkCanSetViewAuthorization(context, new SchemaTableName(name.get(1), name.get(2)), principal);
break;
case "MATERIALIZED VIEW":
control.checkCanSetMaterializedViewAuthorization(context, new SchemaTableName(name.get(1), name.get(2)), principal);
break;
default:
denySetEntityAuthorization(new EntityKindAndName(ownedKind, name), principal);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,13 @@ public void checkCanRenameMaterializedView(ConnectorSecurityContext context, Sch
accessControl.checkCanRenameMaterializedView(securityContext, getQualifiedObjectName(viewName), getQualifiedObjectName(newViewName));
}

@Override
public void checkCanSetMaterializedViewAuthorization(ConnectorSecurityContext context, SchemaTableName viewName, TrinoPrincipal principal)
{
checkArgument(context == null, "context must be null");
accessControl.checkCanSetEntityAuthorization(securityContext, new EntityKindAndName("MATERIALIZED VIEW", getQualifiedObjectNameParts(viewName)), principal);
}

@Override
public void checkCanSetMaterializedViewProperties(ConnectorSecurityContext context, SchemaTableName materializedViewName, Map<String, Optional<Object>> properties)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1332,6 +1332,15 @@ public void renameMaterializedView(ConnectorSession session, SchemaTableName sou
}
}

@Override
public void setMaterializedViewAuthorization(ConnectorSession session, SchemaTableName viewName, TrinoPrincipal principal)
{
Span span = startSpan("setMaterializedViewAuthorization", viewName);
try (var _ = scopedSpan(span)) {
delegate.setMaterializedViewAuthorization(session, viewName, principal);
}
}

@Override
public void setMaterializedViewProperties(ConnectorSession session, SchemaTableName viewName, Map<String, Optional<Object>> properties)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -689,6 +689,9 @@ public void renameView(ConnectorSession session, SchemaTableName source, SchemaT
@Override
public void setViewAuthorization(ConnectorSession session, SchemaTableName viewName, TrinoPrincipal principal) {}

@Override
public void setMaterializedViewAuthorization(ConnectorSession session, SchemaTableName viewName, TrinoPrincipal principal) {}

@Override
public void dropView(ConnectorSession session, SchemaTableName viewName) {}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import io.trino.grammar.sql.SqlBaseParser.CorrespondingContext;
import io.trino.grammar.sql.SqlBaseParser.CreateCatalogContext;
import io.trino.grammar.sql.SqlBaseParser.DropCatalogContext;
import io.trino.grammar.sql.SqlBaseParser.OwnedEntityKindContext;
import io.trino.sql.tree.AddColumn;
import io.trino.sql.tree.AliasedRelation;
import io.trino.sql.tree.AllColumns;
Expand Down Expand Up @@ -321,6 +322,7 @@
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.IntStream;
import java.util.stream.Stream;

import static com.google.common.base.Preconditions.checkArgument;
Expand Down Expand Up @@ -511,9 +513,13 @@ public Node visitRenameSchema(SqlBaseParser.RenameSchemaContext context)
@Override
public Node visitSetAuthorization(SqlBaseParser.SetAuthorizationContext context)
{
OwnedEntityKindContext ownedEntityKindContext = context.ownedEntityKind();
String ownedEntityKind = IntStream.range(0, ownedEntityKindContext.getChildCount())
.mapToObj(i -> ownedEntityKindContext.getChild(i).getText())
.reduce("", (a, b) -> String.format("%s %s", a, b).trim());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this is needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not necessary, but it's for keeping the owned entity kind to keep the spaces that MATERIALIZED VIEW has in it. Otherwise, the entity kind string would need to be MATERIALIZEDVIEW. I thought the former was more user friendly.

Happy to revert this change back and use MATERIALIZEDVIEW instead -- I can see the pros and cons of both approach.

return new SetAuthorizationStatement(
getLocation(context),
context.ownedEntityKind().getText().toUpperCase(ENGLISH),
ownedEntityKind.toUpperCase(ENGLISH),
getQualifiedName(context.qualifiedName()),
getPrincipalSpecification(context.principal()));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3556,6 +3556,29 @@ public void testAlterViewSetAuthorization()
new PrincipalSpecification(PrincipalSpecification.Type.ROLE, new Identifier(location(1, 47), "qux", false))));
}

@Test
public void testAlterMaterializedViewSetAuthorization()
{
assertThat(statement("ALTER MATERIALIZED VIEW foo.bar.baz SET AUTHORIZATION qux")).isEqualTo(
new SetAuthorizationStatement(
location(1, 1),
"MATERIALIZED VIEW",
QualifiedName.of(ImmutableList.of(new Identifier(location(1, 25), "foo", false), new Identifier(location(1, 29), "bar", false), new Identifier(location(1, 33), "baz", false))),
new PrincipalSpecification(PrincipalSpecification.Type.UNSPECIFIED, new Identifier(location(1, 55), "qux", false))));
assertThat(statement("ALTER MATERIALIZED VIEW foo.bar.baz SET AUTHORIZATION USER qux")).isEqualTo(
new SetAuthorizationStatement(
location(1, 1),
"MATERIALIZED VIEW",
QualifiedName.of(ImmutableList.of(new Identifier(location(1, 25), "foo", false), new Identifier(location(1, 29), "bar", false), new Identifier(location(1, 33), "baz", false))),
new PrincipalSpecification(PrincipalSpecification.Type.USER, new Identifier(location(1, 60), "qux", false))));
assertThat(statement("ALTER MATERIALIZED VIEW foo.bar.baz SET AUTHORIZATION ROLE qux")).isEqualTo(
new SetAuthorizationStatement(
location(1, 1),
"MATERIALIZED VIEW",
QualifiedName.of(ImmutableList.of(new Identifier(location(1, 25), "foo", false), new Identifier(location(1, 29), "bar", false), new Identifier(location(1, 33), "baz", false))),
new PrincipalSpecification(PrincipalSpecification.Type.ROLE, new Identifier(location(1, 60), "qux", false))));
}

@Test
public void testTableExecute()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
import static io.trino.spi.security.AccessDeniedException.denyRevokeTablePrivilege;
import static io.trino.spi.security.AccessDeniedException.denySelectColumns;
import static io.trino.spi.security.AccessDeniedException.denySetCatalogSessionProperty;
import static io.trino.spi.security.AccessDeniedException.denySetEntityAuthorization;
import static io.trino.spi.security.AccessDeniedException.denySetMaterializedViewProperties;
import static io.trino.spi.security.AccessDeniedException.denySetRole;
import static io.trino.spi.security.AccessDeniedException.denySetSchemaAuthorization;
Expand Down Expand Up @@ -415,6 +416,16 @@ default void checkCanSetViewAuthorization(ConnectorSecurityContext context, Sche
denySetViewAuthorization(viewName.toString(), principal);
}

/**
* Check if identity is allowed to change the specified materialized view's user/role.
*
* @throws io.trino.spi.security.AccessDeniedException if not allowed
*/
default void checkCanSetMaterializedViewAuthorization(ConnectorSecurityContext context, SchemaTableName viewName, TrinoPrincipal principal)
{
denySetEntityAuthorization(new EntityKindAndName("MATERIALIZED VIEW", List.of(viewName.getSchemaName(), viewName.getTableName())), principal);
}

/**
* Check if identity is allowed to drop the specified view.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1655,6 +1655,14 @@ default List<SchemaTableName> listMaterializedViews(ConnectorSession session, Op
return List.of();
}

/**
* Sets the user/role on the specified materialized view.
*/
default void setMaterializedViewAuthorization(ConnectorSession session, SchemaTableName viewName, TrinoPrincipal principal)
{
throw new TrinoException(NOT_SUPPORTED, "This connector does not support setting an owner on a materialized view");
}

/**
* Gets the definitions of materialized views, possibly filtered by schema.
* This optional method may be implemented by connectors that can support fetching
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,19 @@ default void checkCanSetViewAuthorization(SystemSecurityContext context, Catalog
denySetEntityAuthorization(new EntityKindAndName("VIEW", List.of(view.getCatalogName(), view.getSchemaTableName().getSchemaName(), view.getSchemaTableName().getTableName())), principal);
}

/**
* Check if identity is allowed to change the specified materialized view's user/role.
*
* @throws AccessDeniedException if not allowed
*
* @deprecated {Use {@link #checkCanSetEntityAuthorization}
*/
@Deprecated(forRemoval = true)
default void checkCanSetMaterializedViewAuthorization(SystemSecurityContext context, CatalogSchemaTableName view, TrinoPrincipal principal)
{
denySetEntityAuthorization(new EntityKindAndName("MATERIALIZED VIEW", List.of(view.getCatalogName(), view.getSchemaTableName().getSchemaName(), view.getSchemaTableName().getTableName())), principal);
}

/**
* Check if identity is allowed to drop the specified view in a catalog.
*
Expand Down Expand Up @@ -961,10 +974,16 @@ default void checkCanSetEntityAuthorization(SystemSecurityContext context, Entit
break;
case "VIEW":
if (name.size() != 3) {
throw new TrinoException(StandardErrorCode.INVALID_ARGUMENTS, "The view name %s must have three elements".formatted(name));
throw new TrinoException(StandardErrorCode.INVALID_ARGUMENTS, "The %s name %s must have three elements".formatted(kind.toLowerCase(Locale.ROOT), name));
}
checkCanSetViewAuthorization(context, new CatalogSchemaTableName(name.get(0), name.get(1), name.get(2)), principal);
break;
case "MATERIALIZED VIEW":
if (name.size() != 3) {
throw new TrinoException(StandardErrorCode.INVALID_ARGUMENTS, "The %s name %s must have three elements".formatted(kind.toLowerCase(Locale.ROOT), name));
}
checkCanSetMaterializedViewAuthorization(context, new CatalogSchemaTableName(name.get(0), name.get(1), name.get(2)), principal);
break;
default:
denySetEntityAuthorization(new EntityKindAndName(kind, name), principal);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,14 @@ public void checkCanRenameMaterializedView(ConnectorSecurityContext context, Sch
}
}

@Override
public void checkCanSetMaterializedViewAuthorization(ConnectorSecurityContext context, SchemaTableName viewName, TrinoPrincipal principal)
{
try (ThreadContextClassLoader _ = new ThreadContextClassLoader(classLoader)) {
delegate.checkCanSetMaterializedViewAuthorization(context, viewName, principal);
}
}

@Override
public void checkCanSetMaterializedViewProperties(ConnectorSecurityContext context, SchemaTableName materializedViewName, Map<String, Optional<Object>> properties)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1169,6 +1169,14 @@ public void renameMaterializedView(ConnectorSession session, SchemaTableName sou
}
}

@Override
public void setMaterializedViewAuthorization(ConnectorSession session, SchemaTableName viewName, TrinoPrincipal principal)
{
try (ThreadContextClassLoader _ = new ThreadContextClassLoader(classLoader)) {
delegate.setMaterializedViewAuthorization(session, viewName, principal);
}
}

@Override
public void setMaterializedViewProperties(ConnectorSession session, SchemaTableName viewName, Map<String, Optional<Object>> properties)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,9 @@ public void checkCanDropMaterializedView(ConnectorSecurityContext context, Schem
@Override
public void checkCanRenameMaterializedView(ConnectorSecurityContext context, SchemaTableName viewName, SchemaTableName newViewName) {}

@Override
public void checkCanSetMaterializedViewAuthorization(ConnectorSecurityContext context, SchemaTableName viewName, TrinoPrincipal principal) {}

@Override
public void checkCanSetMaterializedViewProperties(ConnectorSecurityContext context, SchemaTableName materializedViewName, Map<String, Optional<Object>> properties) {}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,9 @@ public void checkCanDropMaterializedView(SystemSecurityContext context, CatalogS
@Override
public void checkCanRenameMaterializedView(SystemSecurityContext context, CatalogSchemaTableName view, CatalogSchemaTableName newView) {}

@Override
public void checkCanSetMaterializedViewAuthorization(SystemSecurityContext context, CatalogSchemaTableName view, TrinoPrincipal principal) {}

@Override
public void checkCanSetMaterializedViewProperties(SystemSecurityContext context, CatalogSchemaTableName materializedView, Map<String, Optional<Object>> properties) {}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import io.trino.spi.connector.ColumnSchema;
import io.trino.spi.connector.ConnectorAccessControl;
import io.trino.spi.connector.ConnectorSecurityContext;
import io.trino.spi.connector.EntityKindAndName;
import io.trino.spi.connector.SchemaRoutineName;
import io.trino.spi.connector.SchemaTableName;
import io.trino.spi.function.SchemaFunctionName;
Expand Down Expand Up @@ -87,6 +88,7 @@
import static io.trino.spi.security.AccessDeniedException.denyRevokeTablePrivilege;
import static io.trino.spi.security.AccessDeniedException.denySelectTable;
import static io.trino.spi.security.AccessDeniedException.denySetCatalogSessionProperty;
import static io.trino.spi.security.AccessDeniedException.denySetEntityAuthorization;
import static io.trino.spi.security.AccessDeniedException.denySetMaterializedViewProperties;
import static io.trino.spi.security.AccessDeniedException.denySetRole;
import static io.trino.spi.security.AccessDeniedException.denySetSchemaAuthorization;
Expand Down Expand Up @@ -516,6 +518,17 @@ public void checkCanRenameMaterializedView(ConnectorSecurityContext context, Sch
}
}

@Override
public void checkCanSetMaterializedViewAuthorization(ConnectorSecurityContext context, SchemaTableName viewName, TrinoPrincipal principal)
{
if (!checkTablePermission(context, viewName, OWNERSHIP)) {
denySetEntityAuthorization(new EntityKindAndName("MATERIALIZED VIEW", List.of(viewName.getSchemaName(), viewName.getTableName())), principal);
}
if (!checkCanSetAuthorization(context, principal)) {
denySetEntityAuthorization(new EntityKindAndName("MATERIALIZED VIEW", List.of(viewName.getSchemaName(), viewName.getTableName())), principal);
}
}

@Override
public void checkCanSetMaterializedViewProperties(ConnectorSecurityContext context, SchemaTableName materializedViewName, Map<String, Optional<Object>> properties)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -792,6 +792,13 @@ public void checkCanRenameMaterializedView(SystemSecurityContext context, Catalo
}
}

@Override
public void checkCanSetMaterializedViewAuthorization(SystemSecurityContext context, CatalogSchemaTableName view, TrinoPrincipal principal)
{
List<String> names = List.of(view.getCatalogName(), view.getSchemaTableName().getSchemaName(), view.getSchemaTableName().getTableName());
checkCanSetEntityAuthorization(context, new EntityKindAndName("MATERIALIZED VIEW", names), principal);
}

@Override
public void checkCanSetMaterializedViewProperties(SystemSecurityContext context, CatalogSchemaTableName materializedView, Map<String, Optional<Object>> properties)
{
Expand Down Expand Up @@ -1100,7 +1107,7 @@ public void checkCanSetEntityAuthorization(SystemSecurityContext context, Entity
CatalogSchemaName schema = new CatalogSchemaName(name.get(0), name.get(1));
denied = !isSchemaOwner(context, schema) || !checkCanSetAuthorization(context, principal);
break;
case "TABLE", "VIEW":
case "TABLE", "VIEW", "MATERIALIZED VIEW":
CatalogSchemaTableName table = new CatalogSchemaTableName(name.get(0), name.get(1), name.get(2));
denied = !checkTablePermission(context, table, OWNERSHIP) || !checkCanSetAuthorization(context, principal);
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,12 @@ public void checkCanRenameMaterializedView(ConnectorSecurityContext context, Sch
delegate().checkCanRenameMaterializedView(context, viewName, newViewName);
}

@Override
public void checkCanSetMaterializedViewAuthorization(ConnectorSecurityContext context, SchemaTableName viewName, TrinoPrincipal principal)
{
delegate().checkCanSetMaterializedViewAuthorization(context, viewName, principal);
}

@Override
public void checkCanSetMaterializedViewProperties(ConnectorSecurityContext context, SchemaTableName materializedViewName, Map<String, Optional<Object>> properties)
{
Expand Down
Loading