Skip to content

Commit 43848a7

Browse files
committed
Add support for materialized view redirection
1 parent 2cf9749 commit 43848a7

29 files changed

+257
-131
lines changed

Diff for: client/trino-jdbc/src/test/java/io/trino/jdbc/TestTrinoDatabaseMetaData.java

+38-38
Large diffs are not rendered by default.

Diff for: core/trino-main/src/main/java/io/trino/execution/CreateMaterializedViewTask.java

+1
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ Analysis executeInternal(
157157
});
158158

159159
MaterializedViewDefinition definition = new MaterializedViewDefinition(
160+
name,
160161
sql,
161162
session.getCatalog(),
162163
session.getSchema(),

Diff for: core/trino-main/src/main/java/io/trino/metadata/MaterializedViewDefinition.java

+8
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,12 @@
3030
public class MaterializedViewDefinition
3131
extends ViewDefinition
3232
{
33+
private final QualifiedObjectName viewName;
3334
private final Optional<Duration> gracePeriod;
3435
private final Optional<CatalogSchemaTableName> storageTable;
3536

3637
public MaterializedViewDefinition(
38+
QualifiedObjectName viewName,
3739
String originalSql,
3840
Optional<String> catalog,
3941
Optional<String> schema,
@@ -45,11 +47,17 @@ public MaterializedViewDefinition(
4547
Optional<CatalogSchemaTableName> storageTable)
4648
{
4749
super(originalSql, catalog, schema, columns, comment, Optional.of(owner), path);
50+
this.viewName = requireNonNull(viewName, "viewName is null");
4851
this.gracePeriod = requireNonNull(gracePeriod, "gracePeriod is null");
4952
checkArgument(gracePeriod.isEmpty() || !gracePeriod.get().isNegative(), "gracePeriod cannot be negative: %s", gracePeriod);
5053
this.storageTable = requireNonNull(storageTable, "storageTable is null");
5154
}
5255

56+
public QualifiedObjectName getViewName()
57+
{
58+
return viewName;
59+
}
60+
5361
public Optional<Duration> getGracePeriod()
5462
{
5563
return gracePeriod;

Diff for: core/trino-main/src/main/java/io/trino/metadata/MetadataManager.java

+19-14
Original file line numberDiff line numberDiff line change
@@ -665,7 +665,7 @@ public List<TableColumnsMetadata> listTableColumns(Session session, QualifiedTab
665665

666666
try {
667667
return Optional.<RelationColumnsMetadata>empty()
668-
.or(() -> getMaterializedViewInternal(session, objectName)
668+
.or(() -> getMaterializedViewInternal(session, getRedirectedTableName(session, objectName, Optional.empty(), Optional.empty()))
669669
.map(materializedView -> RelationColumnsMetadata.forMaterializedView(schemaTableName, materializedView.getColumns())))
670670
.or(() -> getViewInternal(session, objectName)
671671
.map(view -> RelationColumnsMetadata.forView(schemaTableName, view.getColumns())))
@@ -1649,13 +1649,14 @@ public void createMaterializedView(
16491649
@Override
16501650
public void dropMaterializedView(Session session, QualifiedObjectName viewName)
16511651
{
1652-
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, viewName.catalogName());
1652+
QualifiedObjectName targetViewName = getRedirectedTableName(session, viewName, Optional.empty(), Optional.empty());
1653+
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, targetViewName.catalogName());
16531654
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
16541655
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
16551656

1656-
metadata.dropMaterializedView(session.toConnectorSession(catalogHandle), viewName.asSchemaTableName());
1657+
metadata.dropMaterializedView(session.toConnectorSession(catalogHandle), targetViewName.asSchemaTableName());
16571658
if (catalogMetadata.getSecurityManagement() == SYSTEM) {
1658-
systemSecurityMetadata.tableDropped(session, viewName.asCatalogSchemaTableName());
1659+
systemSecurityMetadata.tableDropped(session, targetViewName.asCatalogSchemaTableName());
16591660
}
16601661
}
16611662

@@ -1737,31 +1738,34 @@ public Map<QualifiedObjectName, ViewInfo> getMaterializedViews(Session session,
17371738
@Override
17381739
public boolean isMaterializedView(Session session, QualifiedObjectName viewName)
17391740
{
1740-
return getMaterializedViewInternal(session, viewName).isPresent();
1741+
QualifiedObjectName targetViewName = getRedirectedTableName(session, viewName, Optional.empty(), Optional.empty());
1742+
return getMaterializedViewInternal(session, targetViewName).isPresent();
17411743
}
17421744

17431745
@Override
17441746
public Optional<MaterializedViewDefinition> getMaterializedView(Session session, QualifiedObjectName viewName)
17451747
{
1746-
Optional<ConnectorMaterializedViewDefinition> connectorView = getMaterializedViewInternal(session, viewName);
1748+
QualifiedObjectName targetViewName = getRedirectedTableName(session, viewName, Optional.empty(), Optional.empty());
1749+
Optional<ConnectorMaterializedViewDefinition> connectorView = getMaterializedViewInternal(session, targetViewName);
17471750
if (connectorView.isEmpty()) {
17481751
return Optional.empty();
17491752
}
17501753

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

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

1762-
private static MaterializedViewDefinition createMaterializedViewDefinition(ConnectorMaterializedViewDefinition view, Identity runAsIdentity)
1765+
private static MaterializedViewDefinition createMaterializedViewDefinition(QualifiedObjectName name, ConnectorMaterializedViewDefinition view, Identity runAsIdentity)
17631766
{
17641767
return new MaterializedViewDefinition(
1768+
name,
17651769
view.getOriginalSql(),
17661770
view.getCatalog(),
17671771
view.getSchema(),
@@ -1814,14 +1818,15 @@ public Map<String, Object> getMaterializedViewProperties(Session session, Qualif
18141818
@Override
18151819
public MaterializedViewFreshness getMaterializedViewFreshness(Session session, QualifiedObjectName viewName)
18161820
{
1817-
Optional<CatalogMetadata> catalog = getOptionalCatalogMetadata(session, viewName.catalogName());
1821+
QualifiedObjectName targetViewName = getRedirectedTableName(session, viewName, Optional.empty(), Optional.empty());
1822+
Optional<CatalogMetadata> catalog = getOptionalCatalogMetadata(session, targetViewName.catalogName());
18181823
if (catalog.isPresent()) {
18191824
CatalogMetadata catalogMetadata = catalog.get();
1820-
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle(session, viewName, Optional.empty(), Optional.empty());
1825+
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle(session, targetViewName, Optional.empty(), Optional.empty());
18211826
ConnectorMetadata metadata = catalogMetadata.getMetadataFor(session, catalogHandle);
18221827

18231828
ConnectorSession connectorSession = session.toConnectorSession(catalogHandle);
1824-
return metadata.getMaterializedViewFreshness(connectorSession, viewName.asSchemaTableName());
1829+
return metadata.getMaterializedViewFreshness(connectorSession, targetViewName.asSchemaTableName());
18251830
}
18261831
return new MaterializedViewFreshness(STALE, Optional.empty());
18271832
}

Diff for: core/trino-main/src/main/java/io/trino/sql/analyzer/StatementAnalyzer.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -2577,9 +2577,13 @@ private Scope createScopeForView(
25772577
private List<Field> analyzeStorageTable(Table table, List<Field> viewFields, TableHandle storageTable)
25782578
{
25792579
TableSchema tableSchema = metadata.getTableSchema(session, storageTable);
2580+
CatalogSchemaTableName storageTableName = metadata.getTableName(session, storageTable);
25802581
Map<String, ColumnHandle> columnHandles = metadata.getColumnHandles(session, storageTable);
25812582
QualifiedObjectName tableName = createQualifiedObjectName(session, table, table.getName());
2582-
checkStorageTableNotRedirected(tableName);
2583+
checkStorageTableNotRedirected(new QualifiedObjectName(
2584+
storageTableName.getCatalogName(),
2585+
storageTableName.getSchemaTableName().getSchemaName(),
2586+
storageTableName.getSchemaTableName().getTableName()));
25832587
List<Field> tableFields = analyzeTableOutputFields(table, tableName, tableSchema, columnHandles)
25842588
.stream()
25852589
.filter(field -> !field.isHidden())

Diff for: core/trino-main/src/main/java/io/trino/sql/rewrite/ShowQueriesRewrite.java

+19-5
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@
106106
import java.util.Set;
107107

108108
import static com.google.common.base.Strings.nullToEmpty;
109+
import static com.google.common.base.Verify.verify;
109110
import static com.google.common.collect.ImmutableList.toImmutableList;
110111
import static io.trino.connector.informationschema.InformationSchemaTable.COLUMNS;
111112
import static io.trino.connector.informationschema.InformationSchemaTable.SCHEMATA;
@@ -467,6 +468,14 @@ protected Node visitShowColumns(ShowColumns showColumns, Void context)
467468
targetTableName = redirection.redirectedTableName().orElse(tableName);
468469
}
469470
}
471+
else {
472+
Optional<MaterializedViewDefinition> viewDefinition = metadata.getMaterializedView(session, tableName);
473+
if (viewDefinition.isEmpty()) {
474+
throw semanticException(TABLE_NOT_FOUND, showColumns, "Table '%s' does not exist", tableName);
475+
}
476+
477+
targetTableName = viewDefinition.get().getViewName();
478+
}
470479

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

548-
accessControl.checkCanShowCreateTable(session.toSecurityContext(), new QualifiedObjectName(catalogName.getValue(), schemaName.getValue(), tableName.getValue()));
556+
QualifiedObjectName viewName = viewDefinition.get().getViewName();
557+
558+
verify(schemaName.getValue().equals(viewName.schemaName()));
559+
verify(tableName.getValue().equals(viewName.objectName()));
560+
561+
accessControl.checkCanShowCreateTable(session.toSecurityContext(), viewName);
562+
563+
Map<String, Object> properties = metadata.getMaterializedViewProperties(session, viewName, viewDefinition.get());
564+
CatalogHandle catalogHandle = getRequiredCatalogHandle(metadata, session, node, viewName.catalogName());
549565

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

555569
String sql = formatSql(new CreateMaterializedView(
556570
node.getLocation().orElseThrow(),
557-
QualifiedName.of(ImmutableList.of(catalogName, schemaName, tableName)),
571+
QualifiedName.of(ImmutableList.of(new Identifier(viewName.catalogName()), schemaName, tableName)),
558572
query,
559573
false,
560574
false,

Diff for: core/trino-main/src/test/java/io/trino/execution/BaseDataDefinitionTaskTest.java

+7-6
Original file line numberDiff line numberDiff line change
@@ -185,14 +185,15 @@ protected static QualifiedName asQualifiedName(QualifiedObjectName qualifiedObje
185185
return QualifiedName.of(qualifiedObjectName.catalogName(), qualifiedObjectName.schemaName(), qualifiedObjectName.objectName());
186186
}
187187

188-
protected MaterializedViewDefinition someMaterializedView()
188+
protected MaterializedViewDefinition someMaterializedView(QualifiedObjectName viewName)
189189
{
190-
return someMaterializedView("select * from some_table", ImmutableList.of(new ViewColumn("test", BIGINT.getTypeId(), Optional.empty())));
190+
return someMaterializedView(viewName, "select * from some_table", ImmutableList.of(new ViewColumn("test", BIGINT.getTypeId(), Optional.empty())));
191191
}
192192

193-
protected MaterializedViewDefinition someMaterializedView(String sql, List<ViewColumn> columns)
193+
protected MaterializedViewDefinition someMaterializedView(QualifiedObjectName viewName, String sql, List<ViewColumn> columns)
194194
{
195195
return new MaterializedViewDefinition(
196+
viewName,
196197
sql,
197198
Optional.empty(),
198199
Optional.empty(),
@@ -536,10 +537,10 @@ public synchronized void setMaterializedViewProperties(
536537
@Override
537538
public void setMaterializedViewColumnComment(Session session, QualifiedObjectName viewName, String columnName, Optional<String> comment)
538539
{
539-
MaterializedViewDefinition view = materializedViews.get(viewName.asSchemaTableName());
540-
materializedViews.put(
540+
materializedViews.compute(
541541
viewName.asSchemaTableName(),
542-
new MaterializedViewDefinition(
542+
(_, view) -> new MaterializedViewDefinition(
543+
viewName,
543544
view.getOriginalSql(),
544545
view.getCatalog(),
545546
view.getSchema(),

Diff for: core/trino-main/src/test/java/io/trino/execution/TestAddColumnTask.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ public void testAddColumnOnView()
198198
public void testAddColumnOnMaterializedView()
199199
{
200200
QualifiedObjectName materializedViewName = qualifiedObjectName("existing_materialized_view");
201-
metadata.createMaterializedView(testSession, QualifiedObjectName.valueOf(materializedViewName.toString()), someMaterializedView(), MATERIALIZED_VIEW_PROPERTIES, false, false);
201+
metadata.createMaterializedView(testSession, QualifiedObjectName.valueOf(materializedViewName.toString()), someMaterializedView(materializedViewName), MATERIALIZED_VIEW_PROPERTIES, false, false);
202202

203203
assertTrinoExceptionThrownBy(() -> getFutureValue(executeAddColumn(asQualifiedName(materializedViewName), QualifiedName.of("test"), INTEGER, Optional.empty(), new ColumnPosition.Last(), false, false)))
204204
.hasErrorCode(TABLE_NOT_FOUND)

Diff for: core/trino-main/src/test/java/io/trino/execution/TestCommentTask.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ public void testCommentTableOnView()
7373
public void testCommentTableOnMaterializedView()
7474
{
7575
QualifiedObjectName materializedViewName = qualifiedObjectName("existing_materialized_view");
76-
metadata.createMaterializedView(testSession, QualifiedObjectName.valueOf(materializedViewName.toString()), someMaterializedView(), MATERIALIZED_VIEW_PROPERTIES, false, false);
76+
metadata.createMaterializedView(testSession, QualifiedObjectName.valueOf(materializedViewName.toString()), someMaterializedView(materializedViewName), MATERIALIZED_VIEW_PROPERTIES, false, false);
7777

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

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

173173
QualifiedName columnName = qualifiedColumnName("existing_materialized_view", "test");

Diff for: core/trino-main/src/test/java/io/trino/execution/TestCreateViewTask.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ public void testReplaceViewOnTableIfExists()
136136
public void testCreateViewOnMaterializedView()
137137
{
138138
QualifiedObjectName viewName = qualifiedObjectName("existing_materialized_view");
139-
metadata.createMaterializedView(testSession, viewName, someMaterializedView(), MATERIALIZED_VIEW_PROPERTIES, false, false);
139+
metadata.createMaterializedView(testSession, viewName, someMaterializedView(viewName), MATERIALIZED_VIEW_PROPERTIES, false, false);
140140

141141
assertTrinoExceptionThrownBy(() -> getFutureValue(executeCreateView(asQualifiedName(viewName), false)))
142142
.hasErrorCode(TABLE_ALREADY_EXISTS)

Diff for: core/trino-main/src/test/java/io/trino/execution/TestDropColumnTask.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ public void testDropColumnOnView()
158158
public void testDropColumnOnMaterializedView()
159159
{
160160
QualifiedObjectName materializedViewName = qualifiedObjectName("existing_materialized_view");
161-
metadata.createMaterializedView(testSession, QualifiedObjectName.valueOf(materializedViewName.toString()), someMaterializedView(), MATERIALIZED_VIEW_PROPERTIES, false, false);
161+
metadata.createMaterializedView(testSession, QualifiedObjectName.valueOf(materializedViewName.toString()), someMaterializedView(materializedViewName), MATERIALIZED_VIEW_PROPERTIES, false, false);
162162

163163
assertTrinoExceptionThrownBy(() -> getFutureValue(executeDropColumn(asQualifiedName(materializedViewName), QualifiedName.of("test"), false, false)))
164164
.hasErrorCode(TABLE_NOT_FOUND)

Diff for: core/trino-main/src/test/java/io/trino/execution/TestDropMaterializedViewTask.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public class TestDropMaterializedViewTask
3838
public void testDropExistingMaterializedView()
3939
{
4040
QualifiedObjectName viewName = qualifiedObjectName("existing_materialized_view");
41-
metadata.createMaterializedView(testSession, viewName, someMaterializedView(), MATERIALIZED_VIEW_PROPERTIES, false, false);
41+
metadata.createMaterializedView(testSession, viewName, someMaterializedView(viewName), MATERIALIZED_VIEW_PROPERTIES, false, false);
4242
assertThat(metadata.isMaterializedView(testSession, viewName)).isTrue();
4343

4444
getFutureValue(executeDropMaterializedView(asQualifiedName(viewName), false));

Diff for: core/trino-main/src/test/java/io/trino/execution/TestDropNotNullConstraintConstraintTask.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ public void testDropNotNullConstraintOnView()
133133
public void testDropNotNullConstraintOnMaterializedView()
134134
{
135135
QualifiedObjectName materializedViewName = qualifiedObjectName("existing_materialized_view");
136-
metadata.createMaterializedView(testSession, QualifiedObjectName.valueOf(materializedViewName.toString()), someMaterializedView(), MATERIALIZED_VIEW_PROPERTIES, false, false);
136+
metadata.createMaterializedView(testSession, QualifiedObjectName.valueOf(materializedViewName.toString()), someMaterializedView(materializedViewName), MATERIALIZED_VIEW_PROPERTIES, false, false);
137137

138138
assertTrinoExceptionThrownBy(() -> getFutureValue(executeDropNotNullConstraint(asQualifiedName(materializedViewName), identifier("test"), false)))
139139
.hasErrorCode(TABLE_NOT_FOUND)

0 commit comments

Comments
 (0)