Skip to content

Commit 81b0c61

Browse files
committed
Add engine support for refreshing view
1 parent 755e1e4 commit 81b0c61

33 files changed

+613
-0
lines changed
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (the "License");
3+
* you may not use this file except in compliance with the License.
4+
* You may obtain a copy of the License at
5+
*
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
*
8+
* Unless required by applicable law or agreed to in writing, software
9+
* distributed under the License is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
*/
14+
package io.trino.execution;
15+
16+
import com.google.common.collect.ImmutableMap;
17+
import com.google.common.util.concurrent.ListenableFuture;
18+
import com.google.inject.Inject;
19+
import io.trino.Session;
20+
import io.trino.execution.warnings.WarningCollector;
21+
import io.trino.metadata.Metadata;
22+
import io.trino.metadata.QualifiedObjectName;
23+
import io.trino.metadata.ViewColumn;
24+
import io.trino.metadata.ViewDefinition;
25+
import io.trino.security.AccessControl;
26+
import io.trino.spi.security.GroupProvider;
27+
import io.trino.spi.security.Identity;
28+
import io.trino.sql.PlannerContext;
29+
import io.trino.sql.analyzer.Analysis;
30+
import io.trino.sql.analyzer.AnalyzerFactory;
31+
import io.trino.sql.parser.SqlParser;
32+
import io.trino.sql.tree.Expression;
33+
import io.trino.sql.tree.RefreshView;
34+
import io.trino.sql.tree.Statement;
35+
36+
import java.util.List;
37+
import java.util.Map;
38+
import java.util.Optional;
39+
40+
import static com.google.common.base.Preconditions.checkArgument;
41+
import static com.google.common.collect.ImmutableList.toImmutableList;
42+
import static com.google.common.util.concurrent.Futures.immediateVoidFuture;
43+
import static io.trino.metadata.MetadataUtil.createQualifiedObjectName;
44+
import static io.trino.spi.StandardErrorCode.TABLE_NOT_FOUND;
45+
import static io.trino.sql.analyzer.SemanticExceptions.semanticException;
46+
import static java.util.Objects.requireNonNull;
47+
import static org.weakref.jmx.$internal.guava.collect.ImmutableMap.toImmutableMap;
48+
49+
public class RefreshViewTask
50+
implements DataDefinitionTask<RefreshView>
51+
{
52+
private final PlannerContext plannerContext;
53+
private final AccessControl accessControl;
54+
private final GroupProvider groupProvider;
55+
private final SqlParser sqlParser;
56+
private final AnalyzerFactory analyzerFactory;
57+
58+
@Inject
59+
public RefreshViewTask(
60+
PlannerContext plannerContext,
61+
AccessControl accessControl,
62+
GroupProvider groupProvider,
63+
SqlParser sqlParser,
64+
AnalyzerFactory analyzerFactory)
65+
{
66+
this.plannerContext = requireNonNull(plannerContext, "plannerContext is null");
67+
this.accessControl = requireNonNull(accessControl, "accessControl is null");
68+
this.groupProvider = requireNonNull(groupProvider, "groupProvider is null");
69+
this.sqlParser = requireNonNull(sqlParser, "sqlParser is null");
70+
this.analyzerFactory = requireNonNull(analyzerFactory, "analyzerFactory is null");
71+
}
72+
73+
@Override
74+
public String getName()
75+
{
76+
return "REFRESH VIEW";
77+
}
78+
79+
@Override
80+
public ListenableFuture<Void> execute(
81+
RefreshView refreshView,
82+
QueryStateMachine stateMachine,
83+
List<Expression> parameters,
84+
WarningCollector warningCollector)
85+
{
86+
Metadata metadata = plannerContext.getMetadata();
87+
Session session = stateMachine.getSession();
88+
QualifiedObjectName viewName = createQualifiedObjectName(session, refreshView, refreshView.getName());
89+
90+
ViewDefinition viewDefinition = metadata.getView(session, viewName)
91+
.orElseThrow(() -> semanticException(TABLE_NOT_FOUND, refreshView, "View '%s' not found", viewName));
92+
93+
accessControl.checkCanRefreshView(session.toSecurityContext(), viewName);
94+
95+
Identity identity = session.getIdentity();
96+
97+
if (!viewDefinition.isRunAsInvoker()) {
98+
checkArgument(viewDefinition.getRunAsIdentity().isPresent(), "View owner detail is missing");
99+
Identity owner = viewDefinition.getRunAsIdentity().get();
100+
identity = Identity.from(owner)
101+
.withGroups(groupProvider.getGroups(owner.getUser()))
102+
.build();
103+
}
104+
105+
Session viewSession = session.createViewSession(viewDefinition.getCatalog(), viewDefinition.getSchema(), identity, viewDefinition.getPath());
106+
107+
Statement viewDefinitionSql = sqlParser.createStatement(viewDefinition.getOriginalSql());
108+
109+
Analysis analysis = analyzerFactory.createAnalyzer(viewSession, parameters, ImmutableMap.of(), stateMachine.getWarningCollector(), stateMachine.getPlanOptimizersStatsCollector())
110+
.analyze(viewDefinitionSql);
111+
112+
Map<String, String> columnComments =
113+
viewDefinition.getColumns()
114+
.stream()
115+
.filter(viewColumn -> viewColumn.comment().isPresent())
116+
.collect(toImmutableMap(ViewColumn::name, viewColumn -> viewColumn.comment().get()));
117+
118+
List<ViewColumn> columns = analysis.getOutputDescriptor(viewDefinitionSql)
119+
.getVisibleFields().stream()
120+
.map(field -> new ViewColumn(field.getName().get(), field.getType().getTypeId(), Optional.ofNullable(columnComments.get(field.getName().get()))))
121+
.collect(toImmutableList());
122+
123+
ViewDefinition viewDefinitionWithNewColumns = new ViewDefinition(
124+
viewDefinition.getOriginalSql(),
125+
viewDefinition.getCatalog(),
126+
viewDefinition.getSchema(),
127+
columns,
128+
viewDefinition.getComment(),
129+
viewDefinition.getRunAsIdentity(),
130+
viewDefinition.getPath());
131+
132+
metadata.refreshView(session, viewName, viewDefinitionWithNewColumns);
133+
134+
return immediateVoidFuture();
135+
}
136+
}

core/trino-main/src/main/java/io/trino/metadata/Metadata.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,11 @@ Optional<ConnectorOutputMetadata> finishRefreshMaterializedView(
513513
*/
514514
void renameView(Session session, QualifiedObjectName existingViewName, QualifiedObjectName newViewName);
515515

516+
/**
517+
* Refreshes the view definition.
518+
*/
519+
void refreshView(Session session, QualifiedObjectName viewName, ViewDefinition definition);
520+
516521
/**
517522
* Drops the specified view.
518523
*/

core/trino-main/src/main/java/io/trino/metadata/MetadataManager.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1585,6 +1585,15 @@ public void renameView(Session session, QualifiedObjectName source, QualifiedObj
15851585
}
15861586
}
15871587

1588+
@Override
1589+
public void refreshView(Session session, QualifiedObjectName viewName, ViewDefinition definition)
1590+
{
1591+
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, viewName.catalogName());
1592+
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
1593+
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
1594+
metadata.refreshView(session.toConnectorSession(catalogHandle), viewName.asSchemaTableName(), definition.toConnectorViewDefinition());
1595+
}
1596+
15881597
@Override
15891598
public void dropView(Session session, QualifiedObjectName viewName)
15901599
{

core/trino-main/src/main/java/io/trino/security/AccessControl.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,13 @@ public interface AccessControl
322322
*/
323323
void checkCanRenameView(SecurityContext context, QualifiedObjectName viewName, QualifiedObjectName newViewName);
324324

325+
/**
326+
* Check if identity is allowed to refresh the specified view.
327+
*
328+
* @throws AccessDeniedException if not allowed
329+
*/
330+
void checkCanRefreshView(SecurityContext context, QualifiedObjectName viewName);
331+
325332
/**
326333
* Check if identity is allowed to drop the specified view.
327334
*

core/trino-main/src/main/java/io/trino/security/AccessControlManager.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -797,6 +797,19 @@ public void checkCanRenameView(SecurityContext securityContext, QualifiedObjectN
797797
catalogAuthorizationCheck(viewName.catalogName(), securityContext, (control, context) -> control.checkCanRenameView(context, viewName.asSchemaTableName(), newViewName.asSchemaTableName()));
798798
}
799799

800+
@Override
801+
public void checkCanRefreshView(SecurityContext securityContext, QualifiedObjectName viewName)
802+
{
803+
requireNonNull(securityContext, "securityContext is null");
804+
requireNonNull(viewName, "viewName is null");
805+
806+
checkCanAccessCatalog(securityContext, viewName.catalogName());
807+
808+
systemAuthorizationCheck(control -> control.checkCanRefreshView(securityContext.toSystemSecurityContext(), viewName.asCatalogSchemaTableName()));
809+
810+
catalogAuthorizationCheck(viewName.catalogName(), securityContext, (control, context) -> control.checkCanRefreshView(context, viewName.asSchemaTableName()));
811+
}
812+
800813
@Override
801814
public void checkCanDropView(SecurityContext securityContext, QualifiedObjectName viewName)
802815
{

core/trino-main/src/main/java/io/trino/security/AllowAllAccessControl.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,9 @@ public void checkCanCreateView(SecurityContext context, QualifiedObjectName view
166166
@Override
167167
public void checkCanRenameView(SecurityContext context, QualifiedObjectName viewName, QualifiedObjectName newViewName) {}
168168

169+
@Override
170+
public void checkCanRefreshView(SecurityContext context, QualifiedObjectName viewName) {}
171+
169172
@Override
170173
public void checkCanDropView(SecurityContext context, QualifiedObjectName viewName) {}
171174

core/trino-main/src/main/java/io/trino/security/DenyAllAccessControl.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
import static io.trino.spi.security.AccessDeniedException.denyKillQuery;
7575
import static io.trino.spi.security.AccessDeniedException.denyReadSystemInformationAccess;
7676
import static io.trino.spi.security.AccessDeniedException.denyRefreshMaterializedView;
77+
import static io.trino.spi.security.AccessDeniedException.denyRefreshView;
7778
import static io.trino.spi.security.AccessDeniedException.denyRenameColumn;
7879
import static io.trino.spi.security.AccessDeniedException.denyRenameMaterializedView;
7980
import static io.trino.spi.security.AccessDeniedException.denyRenameSchema;
@@ -344,6 +345,12 @@ public void checkCanRenameView(SecurityContext context, QualifiedObjectName view
344345
denyRenameView(viewName.toString(), newViewName.toString());
345346
}
346347

348+
@Override
349+
public void checkCanRefreshView(SecurityContext context, QualifiedObjectName viewName)
350+
{
351+
denyRefreshView(viewName.toString());
352+
}
353+
347354
@Override
348355
public void checkCanDropView(SecurityContext context, QualifiedObjectName viewName)
349356
{

core/trino-main/src/main/java/io/trino/security/ForwardingAccessControl.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,12 @@ public void checkCanRenameView(SecurityContext context, QualifiedObjectName view
290290
delegate().checkCanRenameView(context, viewName, newViewName);
291291
}
292292

293+
@Override
294+
public void checkCanRefreshView(SecurityContext context, QualifiedObjectName viewName)
295+
{
296+
delegate().checkCanRefreshView(context, viewName);
297+
}
298+
293299
@Override
294300
public void checkCanDropView(SecurityContext context, QualifiedObjectName viewName)
295301
{

core/trino-main/src/main/java/io/trino/security/InjectedConnectorAccessControl.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,13 @@ public void checkCanRenameView(ConnectorSecurityContext context, SchemaTableName
279279
accessControl.checkCanRenameView(securityContext, getQualifiedObjectName(viewName), getQualifiedObjectName(viewName));
280280
}
281281

282+
@Override
283+
public void checkCanRefreshView(ConnectorSecurityContext context, SchemaTableName viewName)
284+
{
285+
checkArgument(context == null, "context must be null");
286+
accessControl.checkCanRefreshView(securityContext, getQualifiedObjectName(viewName));
287+
}
288+
282289
@Override
283290
public void checkCanDropView(ConnectorSecurityContext context, SchemaTableName viewName)
284291
{

core/trino-main/src/main/java/io/trino/server/QueryExecutionFactoryModule.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
import io.trino.execution.GrantTask;
5050
import io.trino.execution.PrepareTask;
5151
import io.trino.execution.QueryExecution.QueryExecutionFactory;
52+
import io.trino.execution.RefreshViewTask;
5253
import io.trino.execution.RenameColumnTask;
5354
import io.trino.execution.RenameMaterializedViewTask;
5455
import io.trino.execution.RenameSchemaTask;
@@ -99,6 +100,7 @@
99100
import io.trino.sql.tree.Grant;
100101
import io.trino.sql.tree.GrantRoles;
101102
import io.trino.sql.tree.Prepare;
103+
import io.trino.sql.tree.RefreshView;
102104
import io.trino.sql.tree.RenameColumn;
103105
import io.trino.sql.tree.RenameMaterializedView;
104106
import io.trino.sql.tree.RenameSchema;
@@ -170,6 +172,7 @@ public void configure(Binder binder)
170172
bindDataDefinitionTask(binder, executionBinder, Grant.class, GrantTask.class);
171173
bindDataDefinitionTask(binder, executionBinder, GrantRoles.class, GrantRolesTask.class);
172174
bindDataDefinitionTask(binder, executionBinder, Prepare.class, PrepareTask.class);
175+
bindDataDefinitionTask(binder, executionBinder, RefreshView.class, RefreshViewTask.class);
173176
bindDataDefinitionTask(binder, executionBinder, RenameColumn.class, RenameColumnTask.class);
174177
bindDataDefinitionTask(binder, executionBinder, RenameMaterializedView.class, RenameMaterializedViewTask.class);
175178
bindDataDefinitionTask(binder, executionBinder, RenameSchema.class, RenameSchemaTask.class);

0 commit comments

Comments
 (0)