Skip to content

Add support for materialized view redirection #25230

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ Analysis executeInternal(
});

MaterializedViewDefinition definition = new MaterializedViewDefinition(
name,
sql,
session.getCatalog(),
session.getSchema(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,12 @@
public class MaterializedViewDefinition
extends ViewDefinition
{
private final QualifiedObjectName viewName;
private final Optional<Duration> gracePeriod;
private final Optional<CatalogSchemaTableName> storageTable;

public MaterializedViewDefinition(
QualifiedObjectName viewName,
String originalSql,
Optional<String> catalog,
Optional<String> schema,
Expand All @@ -45,11 +47,17 @@ public MaterializedViewDefinition(
Optional<CatalogSchemaTableName> storageTable)
{
super(originalSql, catalog, schema, columns, comment, Optional.of(owner), path);
this.viewName = requireNonNull(viewName, "viewName is null");
this.gracePeriod = requireNonNull(gracePeriod, "gracePeriod is null");
checkArgument(gracePeriod.isEmpty() || !gracePeriod.get().isNegative(), "gracePeriod cannot be negative: %s", gracePeriod);
this.storageTable = requireNonNull(storageTable, "storageTable is null");
}

public QualifiedObjectName getViewName()
{
return viewName;
}

public Optional<Duration> getGracePeriod()
{
return gracePeriod;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -665,7 +665,7 @@ public List<TableColumnsMetadata> listTableColumns(Session session, QualifiedTab

try {
return Optional.<RelationColumnsMetadata>empty()
.or(() -> getMaterializedViewInternal(session, objectName)
.or(() -> getMaterializedViewInternal(session, getRedirectedTableName(session, objectName, Optional.empty(), Optional.empty()))
.map(materializedView -> RelationColumnsMetadata.forMaterializedView(schemaTableName, materializedView.getColumns())))
.or(() -> getViewInternal(session, objectName)
.map(view -> RelationColumnsMetadata.forView(schemaTableName, view.getColumns())))
Expand Down Expand Up @@ -1649,13 +1649,14 @@ public void createMaterializedView(
@Override
public void dropMaterializedView(Session session, QualifiedObjectName viewName)
{
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, viewName.catalogName());
QualifiedObjectName targetViewName = getRedirectedTableName(session, viewName, Optional.empty(), Optional.empty());
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, targetViewName.catalogName());
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);

metadata.dropMaterializedView(session.toConnectorSession(catalogHandle), viewName.asSchemaTableName());
metadata.dropMaterializedView(session.toConnectorSession(catalogHandle), targetViewName.asSchemaTableName());
if (catalogMetadata.getSecurityManagement() == SYSTEM) {
systemSecurityMetadata.tableDropped(session, viewName.asCatalogSchemaTableName());
systemSecurityMetadata.tableDropped(session, targetViewName.asCatalogSchemaTableName());
}
}

Expand Down Expand Up @@ -1737,31 +1738,34 @@ public Map<QualifiedObjectName, ViewInfo> getMaterializedViews(Session session,
@Override
public boolean isMaterializedView(Session session, QualifiedObjectName viewName)
{
return getMaterializedViewInternal(session, viewName).isPresent();
QualifiedObjectName targetViewName = getRedirectedTableName(session, viewName, Optional.empty(), Optional.empty());
return getMaterializedViewInternal(session, targetViewName).isPresent();
}

@Override
public Optional<MaterializedViewDefinition> getMaterializedView(Session session, QualifiedObjectName viewName)
{
Optional<ConnectorMaterializedViewDefinition> connectorView = getMaterializedViewInternal(session, viewName);
QualifiedObjectName targetViewName = getRedirectedTableName(session, viewName, Optional.empty(), Optional.empty());
Optional<ConnectorMaterializedViewDefinition> connectorView = getMaterializedViewInternal(session, targetViewName);
if (connectorView.isEmpty()) {
return Optional.empty();
}

if (isCatalogManagedSecurity(session, viewName.catalogName())) {
if (isCatalogManagedSecurity(session, targetViewName.catalogName())) {
String runAsUser = connectorView.get().getOwner().orElseThrow(() -> new TrinoException(INVALID_VIEW, "Owner not set for a run-as invoker view: " + viewName));
return Optional.of(createMaterializedViewDefinition(connectorView.get(), Identity.ofUser(runAsUser)));
return Optional.of(createMaterializedViewDefinition(targetViewName, connectorView.get(), Identity.ofUser(runAsUser)));
}

Identity runAsIdentity = systemSecurityMetadata.getViewRunAsIdentity(session, viewName.asCatalogSchemaTableName())
Identity runAsIdentity = systemSecurityMetadata.getViewRunAsIdentity(session, targetViewName.asCatalogSchemaTableName())
.or(() -> connectorView.get().getOwner().map(Identity::ofUser))
.orElseThrow(() -> new TrinoException(NOT_SUPPORTED, "Materialized view does not have an owner: " + viewName));
return Optional.of(createMaterializedViewDefinition(connectorView.get(), runAsIdentity));
return Optional.of(createMaterializedViewDefinition(targetViewName, connectorView.get(), runAsIdentity));
}

private static MaterializedViewDefinition createMaterializedViewDefinition(ConnectorMaterializedViewDefinition view, Identity runAsIdentity)
private static MaterializedViewDefinition createMaterializedViewDefinition(QualifiedObjectName name, ConnectorMaterializedViewDefinition view, Identity runAsIdentity)
{
return new MaterializedViewDefinition(
name,
view.getOriginalSql(),
view.getCatalog(),
view.getSchema(),
Expand Down Expand Up @@ -1814,14 +1818,15 @@ public Map<String, Object> getMaterializedViewProperties(Session session, Qualif
@Override
public MaterializedViewFreshness getMaterializedViewFreshness(Session session, QualifiedObjectName viewName)
{
Optional<CatalogMetadata> catalog = getOptionalCatalogMetadata(session, viewName.catalogName());
QualifiedObjectName targetViewName = getRedirectedTableName(session, viewName, Optional.empty(), Optional.empty());
Optional<CatalogMetadata> catalog = getOptionalCatalogMetadata(session, targetViewName.catalogName());
if (catalog.isPresent()) {
CatalogMetadata catalogMetadata = catalog.get();
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle(session, viewName, Optional.empty(), Optional.empty());
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle(session, targetViewName, Optional.empty(), Optional.empty());
ConnectorMetadata metadata = catalogMetadata.getMetadataFor(session, catalogHandle);

ConnectorSession connectorSession = session.toConnectorSession(catalogHandle);
return metadata.getMaterializedViewFreshness(connectorSession, viewName.asSchemaTableName());
return metadata.getMaterializedViewFreshness(connectorSession, targetViewName.asSchemaTableName());
}
return new MaterializedViewFreshness(STALE, Optional.empty());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2577,9 +2577,13 @@ private Scope createScopeForView(
private List<Field> analyzeStorageTable(Table table, List<Field> viewFields, TableHandle storageTable)
{
TableSchema tableSchema = metadata.getTableSchema(session, storageTable);
CatalogSchemaTableName storageTableName = metadata.getTableName(session, storageTable);
Map<String, ColumnHandle> columnHandles = metadata.getColumnHandles(session, storageTable);
QualifiedObjectName tableName = createQualifiedObjectName(session, table, table.getName());
checkStorageTableNotRedirected(tableName);
checkStorageTableNotRedirected(new QualifiedObjectName(
storageTableName.getCatalogName(),
storageTableName.getSchemaTableName().getSchemaName(),
storageTableName.getSchemaTableName().getTableName()));
List<Field> tableFields = analyzeTableOutputFields(table, tableName, tableSchema, columnHandles)
.stream()
.filter(field -> !field.isHidden())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@
import java.util.Set;

import static com.google.common.base.Strings.nullToEmpty;
import static com.google.common.base.Verify.verify;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static io.trino.connector.informationschema.InformationSchemaTable.COLUMNS;
import static io.trino.connector.informationschema.InformationSchemaTable.SCHEMATA;
Expand Down Expand Up @@ -467,6 +468,14 @@ protected Node visitShowColumns(ShowColumns showColumns, Void context)
targetTableName = redirection.redirectedTableName().orElse(tableName);
}
}
else {
Optional<MaterializedViewDefinition> viewDefinition = metadata.getMaterializedView(session, tableName);
if (viewDefinition.isEmpty()) {
throw semanticException(TABLE_NOT_FOUND, showColumns, "Table '%s' does not exist", tableName);
}

targetTableName = viewDefinition.get().getViewName();
}

if (!isMaterializedView && !isView) {
// We are using information_schema which may ignore errors when getting the list
Expand Down Expand Up @@ -543,18 +552,23 @@ private Query showCreateMaterializedView(ShowCreate node)
List<Identifier> parts = node.getName().getOriginalParts().reversed();
Identifier tableName = parts.get(0);
Identifier schemaName = (parts.size() > 1) ? parts.get(1) : new Identifier(objectName.schemaName());
Identifier catalogName = (parts.size() > 2) ? parts.get(2) : new Identifier(objectName.catalogName());

accessControl.checkCanShowCreateTable(session.toSecurityContext(), new QualifiedObjectName(catalogName.getValue(), schemaName.getValue(), tableName.getValue()));
QualifiedObjectName viewName = viewDefinition.get().getViewName();

verify(schemaName.getValue().equals(viewName.schemaName()));
verify(tableName.getValue().equals(viewName.objectName()));

accessControl.checkCanShowCreateTable(session.toSecurityContext(), viewName);

Map<String, Object> properties = metadata.getMaterializedViewProperties(session, viewName, viewDefinition.get());
CatalogHandle catalogHandle = getRequiredCatalogHandle(metadata, session, node, viewName.catalogName());

Map<String, Object> properties = metadata.getMaterializedViewProperties(session, objectName, viewDefinition.get());
CatalogHandle catalogHandle = getRequiredCatalogHandle(metadata, session, node, catalogName.getValue());
Collection<PropertyMetadata<?>> allMaterializedViewProperties = materializedViewPropertyManager.getAllProperties(catalogHandle);
List<Property> propertyNodes = toSqlProperties("materialized view " + objectName, INVALID_MATERIALIZED_VIEW_PROPERTY, properties, allMaterializedViewProperties);

String sql = formatSql(new CreateMaterializedView(
node.getLocation().orElseThrow(),
QualifiedName.of(ImmutableList.of(catalogName, schemaName, tableName)),
QualifiedName.of(ImmutableList.of(new Identifier(viewName.catalogName()), schemaName, tableName)),
query,
false,
false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,14 +185,15 @@ protected static QualifiedName asQualifiedName(QualifiedObjectName qualifiedObje
return QualifiedName.of(qualifiedObjectName.catalogName(), qualifiedObjectName.schemaName(), qualifiedObjectName.objectName());
}

protected MaterializedViewDefinition someMaterializedView()
protected MaterializedViewDefinition someMaterializedView(QualifiedObjectName viewName)
{
return someMaterializedView("select * from some_table", ImmutableList.of(new ViewColumn("test", BIGINT.getTypeId(), Optional.empty())));
return someMaterializedView(viewName, "select * from some_table", ImmutableList.of(new ViewColumn("test", BIGINT.getTypeId(), Optional.empty())));
}

protected MaterializedViewDefinition someMaterializedView(String sql, List<ViewColumn> columns)
protected MaterializedViewDefinition someMaterializedView(QualifiedObjectName viewName, String sql, List<ViewColumn> columns)
{
return new MaterializedViewDefinition(
viewName,
sql,
Optional.empty(),
Optional.empty(),
Expand Down Expand Up @@ -536,10 +537,10 @@ public synchronized void setMaterializedViewProperties(
@Override
public void setMaterializedViewColumnComment(Session session, QualifiedObjectName viewName, String columnName, Optional<String> comment)
{
MaterializedViewDefinition view = materializedViews.get(viewName.asSchemaTableName());
materializedViews.put(
materializedViews.compute(
viewName.asSchemaTableName(),
new MaterializedViewDefinition(
(_, view) -> new MaterializedViewDefinition(
viewName,
view.getOriginalSql(),
view.getCatalog(),
view.getSchema(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ public void testAddColumnOnView()
public void testAddColumnOnMaterializedView()
{
QualifiedObjectName materializedViewName = qualifiedObjectName("existing_materialized_view");
metadata.createMaterializedView(testSession, QualifiedObjectName.valueOf(materializedViewName.toString()), someMaterializedView(), MATERIALIZED_VIEW_PROPERTIES, false, false);
metadata.createMaterializedView(testSession, QualifiedObjectName.valueOf(materializedViewName.toString()), someMaterializedView(materializedViewName), MATERIALIZED_VIEW_PROPERTIES, false, false);

assertTrinoExceptionThrownBy(() -> getFutureValue(executeAddColumn(asQualifiedName(materializedViewName), QualifiedName.of("test"), INTEGER, Optional.empty(), new ColumnPosition.Last(), false, false)))
.hasErrorCode(TABLE_NOT_FOUND)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public void testCommentTableOnView()
public void testCommentTableOnMaterializedView()
{
QualifiedObjectName materializedViewName = qualifiedObjectName("existing_materialized_view");
metadata.createMaterializedView(testSession, QualifiedObjectName.valueOf(materializedViewName.toString()), someMaterializedView(), MATERIALIZED_VIEW_PROPERTIES, false, false);
metadata.createMaterializedView(testSession, QualifiedObjectName.valueOf(materializedViewName.toString()), someMaterializedView(materializedViewName), MATERIALIZED_VIEW_PROPERTIES, false, false);

assertTrinoExceptionThrownBy(() -> getFutureValue(setComment(TABLE, asQualifiedName(materializedViewName), Optional.of("new comment"))))
.hasErrorCode(TABLE_NOT_FOUND)
Expand Down Expand Up @@ -106,7 +106,7 @@ public void testCommentViewOnTable()
public void testCommentViewOnMaterializedView()
{
QualifiedObjectName materializedViewName = qualifiedObjectName("existing_materialized_view");
metadata.createMaterializedView(testSession, QualifiedObjectName.valueOf(materializedViewName.toString()), someMaterializedView(), MATERIALIZED_VIEW_PROPERTIES, false, false);
metadata.createMaterializedView(testSession, QualifiedObjectName.valueOf(materializedViewName.toString()), someMaterializedView(materializedViewName), MATERIALIZED_VIEW_PROPERTIES, false, false);

assertTrinoExceptionThrownBy(() -> getFutureValue(setComment(VIEW, asQualifiedName(materializedViewName), Optional.of("new comment"))))
.hasErrorCode(TABLE_NOT_FOUND)
Expand Down Expand Up @@ -167,7 +167,7 @@ public void testCommentOnMixedCaseViewColumn()
public void testCommentMaterializedViewColumn()
{
QualifiedObjectName materializedViewName = qualifiedObjectName("existing_materialized_view");
metadata.createMaterializedView(testSession, QualifiedObjectName.valueOf(materializedViewName.toString()), someMaterializedView(), MATERIALIZED_VIEW_PROPERTIES, false, false);
metadata.createMaterializedView(testSession, QualifiedObjectName.valueOf(materializedViewName.toString()), someMaterializedView(materializedViewName), MATERIALIZED_VIEW_PROPERTIES, false, false);
assertThat(metadata.isMaterializedView(testSession, materializedViewName)).isTrue();

QualifiedName columnName = qualifiedColumnName("existing_materialized_view", "test");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ public void testReplaceViewOnTableIfExists()
public void testCreateViewOnMaterializedView()
{
QualifiedObjectName viewName = qualifiedObjectName("existing_materialized_view");
metadata.createMaterializedView(testSession, viewName, someMaterializedView(), MATERIALIZED_VIEW_PROPERTIES, false, false);
metadata.createMaterializedView(testSession, viewName, someMaterializedView(viewName), MATERIALIZED_VIEW_PROPERTIES, false, false);

assertTrinoExceptionThrownBy(() -> getFutureValue(executeCreateView(asQualifiedName(viewName), false)))
.hasErrorCode(TABLE_ALREADY_EXISTS)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ public void testDropColumnOnView()
public void testDropColumnOnMaterializedView()
{
QualifiedObjectName materializedViewName = qualifiedObjectName("existing_materialized_view");
metadata.createMaterializedView(testSession, QualifiedObjectName.valueOf(materializedViewName.toString()), someMaterializedView(), MATERIALIZED_VIEW_PROPERTIES, false, false);
metadata.createMaterializedView(testSession, QualifiedObjectName.valueOf(materializedViewName.toString()), someMaterializedView(materializedViewName), MATERIALIZED_VIEW_PROPERTIES, false, false);

assertTrinoExceptionThrownBy(() -> getFutureValue(executeDropColumn(asQualifiedName(materializedViewName), QualifiedName.of("test"), false, false)))
.hasErrorCode(TABLE_NOT_FOUND)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public class TestDropMaterializedViewTask
public void testDropExistingMaterializedView()
{
QualifiedObjectName viewName = qualifiedObjectName("existing_materialized_view");
metadata.createMaterializedView(testSession, viewName, someMaterializedView(), MATERIALIZED_VIEW_PROPERTIES, false, false);
metadata.createMaterializedView(testSession, viewName, someMaterializedView(viewName), MATERIALIZED_VIEW_PROPERTIES, false, false);
assertThat(metadata.isMaterializedView(testSession, viewName)).isTrue();

getFutureValue(executeDropMaterializedView(asQualifiedName(viewName), false));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ public void testDropNotNullConstraintOnView()
public void testDropNotNullConstraintOnMaterializedView()
{
QualifiedObjectName materializedViewName = qualifiedObjectName("existing_materialized_view");
metadata.createMaterializedView(testSession, QualifiedObjectName.valueOf(materializedViewName.toString()), someMaterializedView(), MATERIALIZED_VIEW_PROPERTIES, false, false);
metadata.createMaterializedView(testSession, QualifiedObjectName.valueOf(materializedViewName.toString()), someMaterializedView(materializedViewName), MATERIALIZED_VIEW_PROPERTIES, false, false);

assertTrinoExceptionThrownBy(() -> getFutureValue(executeDropNotNullConstraint(asQualifiedName(materializedViewName), identifier("test"), false)))
.hasErrorCode(TABLE_NOT_FOUND)
Expand Down
Loading