Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
io.trino.metadata.MetadataManager Maven / Gradle / Ivy
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.trino.metadata;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Streams;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.errorprone.annotations.concurrent.GuardedBy;
import com.google.inject.Inject;
import io.airlift.log.Logger;
import io.airlift.slice.Slice;
import io.trino.FeaturesConfig;
import io.trino.Session;
import io.trino.connector.system.GlobalSystemConnector;
import io.trino.metadata.LanguageFunctionManager.RunAsIdentityLoader;
import io.trino.security.AccessControl;
import io.trino.security.AllowAllAccessControl;
import io.trino.security.InjectedConnectorAccessControl;
import io.trino.spi.ErrorCode;
import io.trino.spi.QueryId;
import io.trino.spi.RefreshType;
import io.trino.spi.TrinoException;
import io.trino.spi.block.BlockEncodingSerde;
import io.trino.spi.connector.AggregateFunction;
import io.trino.spi.connector.AggregationApplicationResult;
import io.trino.spi.connector.Assignment;
import io.trino.spi.connector.BeginTableExecuteResult;
import io.trino.spi.connector.CatalogHandle;
import io.trino.spi.connector.CatalogSchemaName;
import io.trino.spi.connector.CatalogSchemaTableName;
import io.trino.spi.connector.ColumnHandle;
import io.trino.spi.connector.ColumnMetadata;
import io.trino.spi.connector.ConnectorAnalyzeMetadata;
import io.trino.spi.connector.ConnectorCapabilities;
import io.trino.spi.connector.ConnectorInsertTableHandle;
import io.trino.spi.connector.ConnectorMaterializedViewDefinition;
import io.trino.spi.connector.ConnectorMergeTableHandle;
import io.trino.spi.connector.ConnectorMetadata;
import io.trino.spi.connector.ConnectorOutputMetadata;
import io.trino.spi.connector.ConnectorOutputTableHandle;
import io.trino.spi.connector.ConnectorPartitioningHandle;
import io.trino.spi.connector.ConnectorResolvedIndex;
import io.trino.spi.connector.ConnectorSession;
import io.trino.spi.connector.ConnectorTableExecuteHandle;
import io.trino.spi.connector.ConnectorTableHandle;
import io.trino.spi.connector.ConnectorTableMetadata;
import io.trino.spi.connector.ConnectorTableSchema;
import io.trino.spi.connector.ConnectorTableVersion;
import io.trino.spi.connector.ConnectorTransactionHandle;
import io.trino.spi.connector.ConnectorViewDefinition;
import io.trino.spi.connector.Constraint;
import io.trino.spi.connector.ConstraintApplicationResult;
import io.trino.spi.connector.EntityKindAndName;
import io.trino.spi.connector.EntityPrivilege;
import io.trino.spi.connector.JoinApplicationResult;
import io.trino.spi.connector.JoinStatistics;
import io.trino.spi.connector.JoinType;
import io.trino.spi.connector.LimitApplicationResult;
import io.trino.spi.connector.MaterializedViewFreshness;
import io.trino.spi.connector.ProjectionApplicationResult;
import io.trino.spi.connector.RelationColumnsMetadata;
import io.trino.spi.connector.RelationCommentMetadata;
import io.trino.spi.connector.RelationType;
import io.trino.spi.connector.RowChangeParadigm;
import io.trino.spi.connector.SampleApplicationResult;
import io.trino.spi.connector.SampleType;
import io.trino.spi.connector.SaveMode;
import io.trino.spi.connector.SchemaTableName;
import io.trino.spi.connector.SchemaTablePrefix;
import io.trino.spi.connector.SortItem;
import io.trino.spi.connector.SystemTable;
import io.trino.spi.connector.TableColumnsMetadata;
import io.trino.spi.connector.TableFunctionApplicationResult;
import io.trino.spi.connector.TableScanRedirectApplicationResult;
import io.trino.spi.connector.TopNApplicationResult;
import io.trino.spi.connector.WriterScalingOptions;
import io.trino.spi.expression.ConnectorExpression;
import io.trino.spi.expression.Constant;
import io.trino.spi.expression.Variable;
import io.trino.spi.function.AggregationFunctionMetadata;
import io.trino.spi.function.AggregationFunctionMetadata.AggregationFunctionMetadataBuilder;
import io.trino.spi.function.BoundSignature;
import io.trino.spi.function.CatalogSchemaFunctionName;
import io.trino.spi.function.FunctionDependencyDeclaration;
import io.trino.spi.function.FunctionId;
import io.trino.spi.function.FunctionMetadata;
import io.trino.spi.function.LanguageFunction;
import io.trino.spi.function.OperatorType;
import io.trino.spi.function.SchemaFunctionName;
import io.trino.spi.function.Signature;
import io.trino.spi.predicate.TupleDomain;
import io.trino.spi.security.GrantInfo;
import io.trino.spi.security.Identity;
import io.trino.spi.security.Privilege;
import io.trino.spi.security.RoleGrant;
import io.trino.spi.security.TrinoPrincipal;
import io.trino.spi.statistics.ComputedStatistics;
import io.trino.spi.statistics.TableStatistics;
import io.trino.spi.statistics.TableStatisticsMetadata;
import io.trino.spi.type.Type;
import io.trino.spi.type.TypeManager;
import io.trino.spi.type.TypeNotFoundException;
import io.trino.spi.type.TypeOperators;
import io.trino.sql.analyzer.TypeSignatureProvider;
import io.trino.sql.parser.SqlParser;
import io.trino.sql.planner.PartitioningHandle;
import io.trino.transaction.TransactionManager;
import io.trino.type.BlockTypeOperators;
import io.trino.type.TypeCoercion;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.OptionalInt;
import java.util.OptionalLong;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Verify.verify;
import static com.google.common.base.Verify.verifyNotNull;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.common.collect.Streams.stream;
import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
import static io.airlift.concurrent.MoreFutures.toListenableFuture;
import static io.trino.SystemSessionProperties.getRetryPolicy;
import static io.trino.client.NodeVersion.UNKNOWN;
import static io.trino.metadata.CatalogMetadata.SecurityManagement.CONNECTOR;
import static io.trino.metadata.CatalogMetadata.SecurityManagement.SYSTEM;
import static io.trino.metadata.GlobalFunctionCatalog.BUILTIN_SCHEMA;
import static io.trino.metadata.GlobalFunctionCatalog.isBuiltinFunctionName;
import static io.trino.metadata.LanguageFunctionManager.isTrinoSqlLanguageFunction;
import static io.trino.metadata.QualifiedObjectName.convertFromSchemaTableName;
import static io.trino.metadata.RedirectionAwareTableHandle.noRedirection;
import static io.trino.metadata.RedirectionAwareTableHandle.withRedirectionTo;
import static io.trino.metadata.SignatureBinder.applyBoundVariables;
import static io.trino.plugin.base.expression.ConnectorExpressions.extractVariables;
import static io.trino.spi.ErrorType.EXTERNAL;
import static io.trino.spi.StandardErrorCode.FUNCTION_IMPLEMENTATION_ERROR;
import static io.trino.spi.StandardErrorCode.FUNCTION_IMPLEMENTATION_MISSING;
import static io.trino.spi.StandardErrorCode.INVALID_VIEW;
import static io.trino.spi.StandardErrorCode.NOT_FOUND;
import static io.trino.spi.StandardErrorCode.NOT_SUPPORTED;
import static io.trino.spi.StandardErrorCode.SCHEMA_NOT_FOUND;
import static io.trino.spi.StandardErrorCode.SYNTAX_ERROR;
import static io.trino.spi.StandardErrorCode.TABLE_NOT_FOUND;
import static io.trino.spi.StandardErrorCode.TABLE_REDIRECTION_ERROR;
import static io.trino.spi.StandardErrorCode.UNSUPPORTED_TABLE_TYPE;
import static io.trino.spi.connector.MaterializedViewFreshness.Freshness.STALE;
import static io.trino.transaction.InMemoryTransactionManager.createTestTransactionManager;
import static io.trino.type.InternalTypeManager.TESTING_TYPE_MANAGER;
import static java.lang.String.format;
import static java.util.Collections.singletonList;
import static java.util.Locale.ENGLISH;
import static java.util.Objects.requireNonNull;
public final class MetadataManager
implements Metadata
{
private static final Logger log = Logger.get(MetadataManager.class);
@VisibleForTesting
public static final int MAX_TABLE_REDIRECTIONS = 10;
private final AccessControl accessControl;
private final GlobalFunctionCatalog functions;
private final BuiltinFunctionResolver functionResolver;
private final SystemSecurityMetadata systemSecurityMetadata;
private final TransactionManager transactionManager;
private final LanguageFunctionManager languageFunctionManager;
private final TypeManager typeManager;
private final TypeCoercion typeCoercion;
private final ConcurrentMap catalogsByQueryId = new ConcurrentHashMap<>();
@Inject
public MetadataManager(
AccessControl accessControl,
SystemSecurityMetadata systemSecurityMetadata,
TransactionManager transactionManager,
GlobalFunctionCatalog globalFunctionCatalog,
LanguageFunctionManager languageFunctionManager,
TypeManager typeManager)
{
this.accessControl = requireNonNull(accessControl, "accessControl is null");
this.typeManager = requireNonNull(typeManager, "typeManager is null");
functions = requireNonNull(globalFunctionCatalog, "globalFunctionCatalog is null");
functionResolver = new BuiltinFunctionResolver(this, typeManager, globalFunctionCatalog);
this.typeCoercion = new TypeCoercion(typeManager::getType);
this.systemSecurityMetadata = requireNonNull(systemSecurityMetadata, "systemSecurityMetadata is null");
this.transactionManager = requireNonNull(transactionManager, "transactionManager is null");
this.languageFunctionManager = requireNonNull(languageFunctionManager, "languageFunctionManager is null");
}
@Override
public Set getConnectorCapabilities(Session session, CatalogHandle catalogHandle)
{
return getCatalogMetadata(session, catalogHandle).getConnectorCapabilities();
}
@Override
public boolean catalogExists(Session session, String catalogName)
{
return getOptionalCatalogMetadata(session, catalogName).isPresent();
}
@Override
public boolean schemaExists(Session session, CatalogSchemaName schema)
{
Optional catalog = getOptionalCatalogMetadata(session, schema.getCatalogName());
if (catalog.isEmpty()) {
return false;
}
CatalogMetadata catalogMetadata = catalog.get();
ConnectorSession connectorSession = session.toConnectorSession(catalogMetadata.getCatalogHandle());
return catalogMetadata.listCatalogHandles().stream()
.map(catalogName -> catalogMetadata.getMetadataFor(session, catalogName))
.anyMatch(metadata -> metadata.schemaExists(connectorSession, schema.getSchemaName()));
}
@Override
public List listSchemaNames(Session session, String catalogName)
{
Optional catalog = getOptionalCatalogMetadata(session, catalogName);
ImmutableSet.Builder schemaNames = ImmutableSet.builder();
if (catalog.isPresent()) {
CatalogMetadata catalogMetadata = catalog.get();
ConnectorSession connectorSession = session.toConnectorSession(catalogMetadata.getCatalogHandle());
for (CatalogHandle catalogHandle : catalogMetadata.listCatalogHandles()) {
ConnectorMetadata metadata = catalogMetadata.getMetadataFor(session, catalogHandle);
metadata.listSchemaNames(connectorSession).stream()
.map(schema -> schema.toLowerCase(Locale.ENGLISH))
.filter(schema -> !isExternalInformationSchema(catalogHandle, schema))
.forEach(schemaNames::add);
}
}
return ImmutableList.copyOf(schemaNames.build());
}
@Override
public Optional getTableHandle(Session session, QualifiedObjectName table)
{
return getTableHandle(session, table, Optional.empty(), Optional.empty());
}
@Override
public Optional getTableHandle(Session session, QualifiedObjectName table, Optional startVersion, Optional endVersion)
{
requireNonNull(table, "table is null");
if (cannotExist(table)) {
return Optional.empty();
}
return getOptionalCatalogMetadata(session, table.catalogName()).flatMap(catalogMetadata -> {
Optional startTableVersion = toConnectorVersion(startVersion);
Optional endTableVersion = toConnectorVersion(endVersion);
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle(session, table, startTableVersion, endTableVersion);
ConnectorMetadata metadata = catalogMetadata.getMetadataFor(session, catalogHandle);
ConnectorSession connectorSession = session.toConnectorSession(catalogHandle);
ConnectorTableHandle tableHandle = metadata.getTableHandle(
connectorSession,
table.asSchemaTableName(),
startTableVersion,
endTableVersion);
return Optional.ofNullable(tableHandle)
.map(connectorTableHandle -> new TableHandle(
catalogHandle,
connectorTableHandle,
catalogMetadata.getTransactionHandleFor(catalogHandle)));
});
}
@Override
public Optional getTableHandleForExecute(Session session, TableHandle tableHandle, String procedure, Map executeProperties)
{
requireNonNull(session, "session is null");
requireNonNull(tableHandle, "tableHandle is null");
requireNonNull(procedure, "procedure is null");
requireNonNull(executeProperties, "executeProperties is null");
CatalogHandle catalogHandle = tableHandle.catalogHandle();
CatalogMetadata catalogMetadata = getCatalogMetadata(session, catalogHandle);
ConnectorMetadata metadata = catalogMetadata.getMetadataFor(session, catalogHandle);
Optional executeHandle = metadata.getTableHandleForExecute(
session.toConnectorSession(catalogHandle),
new InjectedConnectorAccessControl(accessControl, session.toSecurityContext(), catalogHandle.getCatalogName().toString()),
tableHandle.connectorHandle(),
procedure,
executeProperties,
getRetryPolicy(session).getRetryMode());
return executeHandle.map(handle -> new TableExecuteHandle(
catalogHandle,
tableHandle.transaction(),
handle));
}
@Override
public Optional getLayoutForTableExecute(Session session, TableExecuteHandle tableExecuteHandle)
{
CatalogHandle catalogHandle = tableExecuteHandle.catalogHandle();
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, catalogHandle);
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
return metadata.getLayoutForTableExecute(session.toConnectorSession(catalogHandle), tableExecuteHandle.connectorHandle())
.map(layout -> new TableLayout(catalogHandle, catalogMetadata.getTransactionHandleFor(catalogHandle), layout));
}
@Override
public BeginTableExecuteResult beginTableExecute(Session session, TableExecuteHandle tableExecuteHandle, TableHandle sourceHandle)
{
CatalogHandle catalogHandle = tableExecuteHandle.catalogHandle();
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, catalogHandle);
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
BeginTableExecuteResult connectorBeginResult = metadata.beginTableExecute(session.toConnectorSession(catalogHandle), tableExecuteHandle.connectorHandle(), sourceHandle.connectorHandle());
return new BeginTableExecuteResult<>(
tableExecuteHandle.withConnectorHandle(connectorBeginResult.getTableExecuteHandle()),
sourceHandle.withConnectorHandle(connectorBeginResult.getSourceHandle()));
}
@Override
public void finishTableExecute(Session session, TableExecuteHandle tableExecuteHandle, Collection fragments, List tableExecuteState)
{
CatalogHandle catalogHandle = tableExecuteHandle.catalogHandle();
ConnectorMetadata metadata = getMetadata(session, catalogHandle);
metadata.finishTableExecute(session.toConnectorSession(catalogHandle), tableExecuteHandle.connectorHandle(), fragments, tableExecuteState);
}
@Override
public void executeTableExecute(Session session, TableExecuteHandle tableExecuteHandle)
{
CatalogHandle catalogHandle = tableExecuteHandle.catalogHandle();
ConnectorMetadata metadata = getMetadata(session, catalogHandle);
metadata.executeTableExecute(session.toConnectorSession(catalogHandle), tableExecuteHandle.connectorHandle());
}
@Override
public Optional getSystemTable(Session session, QualifiedObjectName tableName)
{
requireNonNull(session, "session is null");
requireNonNull(tableName, "tableName is null");
Optional catalog = getOptionalCatalogMetadata(session, tableName.catalogName());
if (catalog.isPresent()) {
CatalogMetadata catalogMetadata = catalog.get();
// we query only main connector for runtime system tables
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
ConnectorMetadata metadata = catalogMetadata.getMetadataFor(session, catalogHandle);
return metadata.getSystemTable(session.toConnectorSession(catalogHandle), tableName.asSchemaTableName());
}
return Optional.empty();
}
@Override
public TableProperties getTableProperties(Session session, TableHandle handle)
{
CatalogHandle catalogHandle = handle.catalogHandle();
CatalogMetadata catalogMetadata = getCatalogMetadata(session, catalogHandle);
ConnectorMetadata metadata = catalogMetadata.getMetadataFor(session, catalogHandle);
ConnectorSession connectorSession = session.toConnectorSession(catalogHandle);
return new TableProperties(catalogHandle, handle.transaction(), metadata.getTableProperties(connectorSession, handle.connectorHandle()));
}
@Override
public TableHandle makeCompatiblePartitioning(Session session, TableHandle tableHandle, PartitioningHandle partitioningHandle)
{
checkArgument(partitioningHandle.getCatalogHandle().isPresent(), "Expect partitioning handle from connector, got system partitioning handle");
CatalogHandle catalogHandle = partitioningHandle.getCatalogHandle().get();
checkArgument(catalogHandle.equals(tableHandle.catalogHandle()), "ConnectorId of tableHandle and partitioningHandle does not match");
CatalogMetadata catalogMetadata = getCatalogMetadata(session, catalogHandle);
ConnectorMetadata metadata = catalogMetadata.getMetadataFor(session, catalogHandle);
ConnectorTransactionHandle transaction = catalogMetadata.getTransactionHandleFor(catalogHandle);
ConnectorTableHandle newTableHandle = metadata.makeCompatiblePartitioning(
session.toConnectorSession(catalogHandle),
tableHandle.connectorHandle(),
partitioningHandle.getConnectorHandle());
return new TableHandle(catalogHandle, newTableHandle, transaction);
}
@Override
public Optional getCommonPartitioning(Session session, PartitioningHandle left, PartitioningHandle right)
{
Optional leftCatalogHandle = left.getCatalogHandle();
Optional rightCatalogHandle = right.getCatalogHandle();
if (leftCatalogHandle.isEmpty() || rightCatalogHandle.isEmpty() || !leftCatalogHandle.equals(rightCatalogHandle)) {
return Optional.empty();
}
if (!left.getTransactionHandle().equals(right.getTransactionHandle())) {
return Optional.empty();
}
CatalogHandle catalogHandle = leftCatalogHandle.get();
CatalogMetadata catalogMetadata = getCatalogMetadata(session, catalogHandle);
ConnectorMetadata metadata = catalogMetadata.getMetadataFor(session, catalogHandle);
Optional commonHandle = metadata.getCommonPartitioningHandle(session.toConnectorSession(catalogHandle), left.getConnectorHandle(), right.getConnectorHandle());
return commonHandle.map(handle -> new PartitioningHandle(Optional.of(catalogHandle), left.getTransactionHandle(), handle));
}
@Override
public Optional getInfo(Session session, TableHandle handle)
{
CatalogHandle catalogHandle = handle.catalogHandle();
ConnectorMetadata metadata = getMetadata(session, catalogHandle);
return metadata.getInfo(handle.connectorHandle());
}
@Override
public CatalogSchemaTableName getTableName(Session session, TableHandle tableHandle)
{
CatalogHandle catalogHandle = tableHandle.catalogHandle();
CatalogMetadata catalogMetadata = getCatalogMetadata(session, catalogHandle);
ConnectorMetadata metadata = catalogMetadata.getMetadataFor(session, catalogHandle);
SchemaTableName tableName = metadata.getTableName(session.toConnectorSession(catalogHandle), tableHandle.connectorHandle());
return new CatalogSchemaTableName(catalogMetadata.getCatalogName().toString(), tableName);
}
@Override
public TableSchema getTableSchema(Session session, TableHandle tableHandle)
{
CatalogHandle catalogHandle = tableHandle.catalogHandle();
CatalogMetadata catalogMetadata = getCatalogMetadata(session, catalogHandle);
ConnectorMetadata metadata = catalogMetadata.getMetadataFor(session, catalogHandle);
ConnectorTableSchema tableSchema = metadata.getTableSchema(session.toConnectorSession(catalogHandle), tableHandle.connectorHandle());
return new TableSchema(catalogMetadata.getCatalogName(), tableSchema);
}
@Override
public TableMetadata getTableMetadata(Session session, TableHandle tableHandle)
{
CatalogHandle catalogHandle = tableHandle.catalogHandle();
CatalogMetadata catalogMetadata = getCatalogMetadata(session, catalogHandle);
ConnectorMetadata metadata = catalogMetadata.getMetadataFor(session, catalogHandle);
ConnectorTableMetadata tableMetadata = metadata.getTableMetadata(session.toConnectorSession(catalogHandle), tableHandle.connectorHandle());
return new TableMetadata(catalogMetadata.getCatalogName(), tableMetadata);
}
@Override
public TableStatistics getTableStatistics(Session session, TableHandle tableHandle)
{
CatalogHandle catalogHandle = tableHandle.catalogHandle();
ConnectorMetadata metadata = getMetadata(session, catalogHandle);
TableStatistics tableStatistics = metadata.getTableStatistics(session.toConnectorSession(catalogHandle), tableHandle.connectorHandle());
verifyNotNull(tableStatistics, "%s returned null tableStatistics for %s", metadata, tableHandle);
return tableStatistics;
}
@Override
public Map getColumnHandles(Session session, TableHandle tableHandle)
{
CatalogHandle catalogHandle = tableHandle.catalogHandle();
ConnectorMetadata metadata = getMetadata(session, catalogHandle);
Map handles = metadata.getColumnHandles(session.toConnectorSession(catalogHandle), tableHandle.connectorHandle());
ImmutableMap.Builder map = ImmutableMap.builder();
for (Entry mapEntry : handles.entrySet()) {
map.put(mapEntry.getKey().toLowerCase(ENGLISH), mapEntry.getValue());
}
return map.buildOrThrow();
}
@Override
public ColumnMetadata getColumnMetadata(Session session, TableHandle tableHandle, ColumnHandle columnHandle)
{
requireNonNull(tableHandle, "tableHandle is null");
requireNonNull(columnHandle, "columnHandle is null");
CatalogHandle catalogHandle = tableHandle.catalogHandle();
ConnectorMetadata metadata = getMetadata(session, catalogHandle);
return metadata.getColumnMetadata(session.toConnectorSession(catalogHandle), tableHandle.connectorHandle(), columnHandle);
}
@Override
public List listTables(Session session, QualifiedTablePrefix prefix)
{
requireNonNull(prefix, "prefix is null");
if (cannotExist(prefix)) {
return ImmutableList.of();
}
Optional objectName = prefix.asQualifiedObjectName();
if (objectName.isPresent()) {
try {
Optional relationType = getRelationTypeIfExists(session, objectName.get());
if (relationType.isPresent()) {
return ImmutableList.of(objectName.get());
}
// TODO we can probably return empty list here
}
catch (RuntimeException e) {
handleListingError(e, prefix);
// TODO This could be potentially improved to not return empty results https://github.com/trinodb/trino/issues/6551
return ImmutableList.of();
}
}
Optional catalog = getOptionalCatalogMetadata(session, prefix.getCatalogName());
Set tables = new LinkedHashSet<>();
if (catalog.isPresent()) {
CatalogMetadata catalogMetadata = catalog.get();
for (CatalogHandle catalogHandle : catalogMetadata.listCatalogHandles()) {
ConnectorMetadata metadata = catalogMetadata.getMetadataFor(session, catalogHandle);
ConnectorSession connectorSession = session.toConnectorSession(catalogHandle);
if (isExternalInformationSchema(catalogHandle, prefix.getSchemaName())) {
continue;
}
metadata.listTables(connectorSession, prefix.getSchemaName()).stream()
.map(convertFromSchemaTableName(prefix.getCatalogName()))
.filter(table -> !isExternalInformationSchema(catalogHandle, table.schemaName()))
.forEach(tables::add);
}
}
return ImmutableList.copyOf(tables);
}
@Override
public Map getRelationTypes(Session session, QualifiedTablePrefix prefix)
{
requireNonNull(prefix, "prefix is null");
if (cannotExist(prefix)) {
return ImmutableMap.of();
}
Optional objectName = prefix.asQualifiedObjectName();
if (objectName.isPresent()) {
Optional relationType = getRelationTypeIfExists(session, objectName.get());
if (relationType.isPresent()) {
return ImmutableMap.of(objectName.get().asSchemaTableName(), relationType.get());
}
return ImmutableMap.of();
}
Optional catalog = getOptionalCatalogMetadata(session, prefix.getCatalogName());
Map relationTypes = new LinkedHashMap<>();
if (catalog.isPresent()) {
CatalogMetadata catalogMetadata = catalog.get();
for (CatalogHandle catalogHandle : catalogMetadata.listCatalogHandles()) {
ConnectorMetadata metadata = catalogMetadata.getMetadataFor(session, catalogHandle);
ConnectorSession connectorSession = session.toConnectorSession(catalogHandle);
if (isExternalInformationSchema(catalogHandle, prefix.getSchemaName())) {
continue;
}
metadata.getRelationTypes(connectorSession, prefix.getSchemaName()).entrySet().stream()
.filter(entry -> !isExternalInformationSchema(catalogHandle, entry.getKey().getSchemaName()))
.forEach(entry -> relationTypes.put(entry.getKey(), entry.getValue()));
}
}
return ImmutableMap.copyOf(relationTypes);
}
private Optional getRelationTypeIfExists(Session session, QualifiedObjectName name)
{
if (isMaterializedView(session, name)) {
return Optional.of(RelationType.MATERIALIZED_VIEW);
}
if (isView(session, name)) {
return Optional.of(RelationType.VIEW);
}
// TODO: consider a better way to resolve relation names: https://github.com/trinodb/trino/issues/9400
try {
if (getRedirectionAwareTableHandle(session, name).tableHandle().isPresent()) {
return Optional.of(RelationType.TABLE);
}
return Optional.empty();
}
catch (TrinoException e) {
// ignore redirection errors for consistency with listing
if (e.getErrorCode().equals(TABLE_REDIRECTION_ERROR.toErrorCode())) {
return Optional.of(RelationType.TABLE);
}
return Optional.empty();
}
}
@Override
public List listTableColumns(Session session, QualifiedTablePrefix prefix, UnaryOperator> relationFilter)
{
requireNonNull(prefix, "prefix is null");
if (cannotExist(prefix)) {
return ImmutableList.of();
}
String catalogName = prefix.getCatalogName();
Optional schemaName = prefix.getSchemaName();
Optional relationName = prefix.getTableName();
if (relationName.isPresent()) {
QualifiedObjectName objectName = new QualifiedObjectName(catalogName, schemaName.orElseThrow(), relationName.get());
SchemaTableName schemaTableName = objectName.asSchemaTableName();
try {
return Optional.empty()
.or(() -> getMaterializedViewInternal(session, objectName)
.map(materializedView -> RelationColumnsMetadata.forMaterializedView(schemaTableName, materializedView.getColumns())))
.or(() -> getViewInternal(session, objectName)
.map(view -> RelationColumnsMetadata.forView(schemaTableName, view.getColumns())))
.or(() -> {
// TODO: redirects are handled inefficiently: we currently throw-away redirect info and redo it later
RedirectionAwareTableHandle redirectionAware = getRedirectionAwareTableHandle(session, objectName);
if (redirectionAware.redirectedTableName().isPresent()) {
return Optional.of(RelationColumnsMetadata.forRedirectedTable(schemaTableName));
}
if (redirectionAware.tableHandle().isPresent()) {
return Optional.of(RelationColumnsMetadata.forTable(schemaTableName, getTableMetadata(session, redirectionAware.tableHandle().get()).columns()));
}
// Not found
return Optional.empty();
})
.filter(relationColumnsMetadata -> relationFilter.apply(ImmutableSet.of(relationColumnsMetadata.name())).contains(relationColumnsMetadata.name()))
.map(relationColumnsMetadata -> ImmutableList.of(tableColumnsMetadata(catalogName, relationColumnsMetadata)))
.orElse(ImmutableList.of());
}
catch (RuntimeException e) {
handleListingError(e, prefix);
// Empty in case of metadata error.
return ImmutableList.of();
}
}
Optional catalog = getOptionalCatalogMetadata(session, catalogName);
Map tableColumns = new HashMap<>();
if (catalog.isPresent()) {
CatalogMetadata catalogMetadata = catalog.get();
for (CatalogHandle catalogHandle : catalogMetadata.listCatalogHandles()) {
if (isExternalInformationSchema(catalogHandle, schemaName)) {
continue;
}
ConnectorMetadata metadata = catalogMetadata.getMetadataFor(session, catalogHandle);
ConnectorSession connectorSession = session.toConnectorSession(catalogHandle);
metadata.streamRelationColumns(connectorSession, schemaName, relationFilter)
.forEachRemaining(relationColumnsMetadata -> {
if (!isExternalInformationSchema(catalogHandle, relationColumnsMetadata.name().getSchemaName())) {
// putIfAbsent to resolve any potential conflicts between system tables and regular tables
tableColumns.putIfAbsent(relationColumnsMetadata.name(), tableColumnsMetadata(catalogName, relationColumnsMetadata));
}
});
}
}
return ImmutableList.copyOf(tableColumns.values());
}
private static void handleListingError(RuntimeException e, QualifiedTablePrefix tablePrefix)
{
boolean silent = false;
if (e instanceof TrinoException trinoException) {
ErrorCode errorCode = trinoException.getErrorCode();
silent = errorCode.equals(UNSUPPORTED_TABLE_TYPE.toErrorCode()) ||
// e.g. table deleted concurrently
errorCode.equals(TABLE_NOT_FOUND.toErrorCode()) ||
errorCode.equals(NOT_FOUND.toErrorCode()) ||
// e.g. Iceberg/Delta table being deleted concurrently resulting in failure to load metadata from filesystem
errorCode.getType() == EXTERNAL;
}
if (silent) {
log.debug(e, "Failed to get metadata for table: %s", tablePrefix);
}
else {
log.warn(e, "Failed to get metadata for table: %s", tablePrefix);
}
}
private TableColumnsMetadata tableColumnsMetadata(String catalogName, RelationColumnsMetadata relationColumnsMetadata)
{
SchemaTableName relationName = relationColumnsMetadata.name();
Optional> columnsMetadata = Optional.>empty()
.or(() -> relationColumnsMetadata.materializedViewColumns()
.map(columns -> materializedViewColumnMetadata(catalogName, relationName, columns)))
.or(() -> relationColumnsMetadata.viewColumns()
.map(columns -> viewColumnMetadata(catalogName, relationName, columns)))
.or(relationColumnsMetadata::tableColumns)
.or(() -> {
checkState(relationColumnsMetadata.redirected(), "Invalid RelationColumnsMetadata: %s", relationColumnsMetadata);
return Optional.empty();
});
return new TableColumnsMetadata(relationName, columnsMetadata);
}
private List materializedViewColumnMetadata(String catalogName, SchemaTableName materializedViewName, List columns)
{
ImmutableList.Builder columnMetadata = ImmutableList.builderWithExpectedSize(columns.size());
for (ConnectorMaterializedViewDefinition.Column column : columns) {
try {
columnMetadata.add(ColumnMetadata.builder()
.setName(column.getName())
.setType(typeManager.getType(column.getType()))
.setComment(column.getComment())
.build());
}
catch (TypeNotFoundException e) {
QualifiedObjectName name = new QualifiedObjectName(catalogName, materializedViewName.getSchemaName(), materializedViewName.getTableName());
throw new TrinoException(INVALID_VIEW, format("Unknown type '%s' for column '%s' in materialized view: %s", column.getType(), column.getName(), name));
}
}
return columnMetadata.build();
}
private List viewColumnMetadata(String catalogName, SchemaTableName viewName, List columns)
{
ImmutableList.Builder columnMetadata = ImmutableList.builderWithExpectedSize(columns.size());
for (ConnectorViewDefinition.ViewColumn column : columns) {
try {
columnMetadata.add(ColumnMetadata.builder()
.setName(column.getName())
.setType(typeManager.getType(column.getType()))
.setComment(column.getComment())
.build());
}
catch (TypeNotFoundException e) {
QualifiedObjectName name = new QualifiedObjectName(catalogName, viewName.getSchemaName(), viewName.getTableName());
throw new TrinoException(INVALID_VIEW, format("Unknown type '%s' for column '%s' in view: %s", column.getType(), column.getName(), name));
}
}
return columnMetadata.build();
}
@Override
public List listRelationComments(Session session, String catalogName, Optional schemaName, UnaryOperator> relationFilter)
{
if (cannotExist(new QualifiedTablePrefix(catalogName, schemaName, Optional.empty()))) {
return ImmutableList.of();
}
Optional catalog = getOptionalCatalogMetadata(session, catalogName);
ImmutableList.Builder tableComments = ImmutableList.builder();
if (catalog.isPresent()) {
CatalogMetadata catalogMetadata = catalog.get();
for (CatalogHandle catalogHandle : catalogMetadata.listCatalogHandles()) {
if (isExternalInformationSchema(catalogHandle, schemaName)) {
continue;
}
ConnectorMetadata metadata = catalogMetadata.getMetadataFor(session, catalogHandle);
ConnectorSession connectorSession = session.toConnectorSession(catalogHandle);
stream(metadata.streamRelationComments(connectorSession, schemaName, relationFilter))
.filter(commentMetadata -> !isExternalInformationSchema(catalogHandle, commentMetadata.name().getSchemaName()))
.forEach(tableComments::add);
}
}
return tableComments.build();
}
@Override
public void createSchema(Session session, CatalogSchemaName schema, Map properties, TrinoPrincipal principal)
{
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, schema.getCatalogName());
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
metadata.createSchema(session.toConnectorSession(catalogHandle), schema.getSchemaName(), properties, principal);
if (catalogMetadata.getSecurityManagement() == SYSTEM) {
systemSecurityMetadata.schemaCreated(session, schema);
}
}
@Override
public void dropSchema(Session session, CatalogSchemaName schema, boolean cascade)
{
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, schema.getCatalogName());
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
metadata.dropSchema(session.toConnectorSession(catalogHandle), schema.getSchemaName(), cascade);
if (catalogMetadata.getSecurityManagement() == SYSTEM) {
systemSecurityMetadata.schemaDropped(session, schema);
}
}
@Override
public void renameSchema(Session session, CatalogSchemaName source, String target)
{
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, source.getCatalogName());
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
metadata.renameSchema(session.toConnectorSession(catalogHandle), source.getSchemaName(), target);
if (catalogMetadata.getSecurityManagement() == SYSTEM) {
systemSecurityMetadata.schemaRenamed(session, source, new CatalogSchemaName(source.getCatalogName(), target));
}
}
@Override
public void setSchemaAuthorization(Session session, CatalogSchemaName source, TrinoPrincipal principal)
{
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, source.getCatalogName());
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
if (catalogMetadata.getSecurityManagement() == SYSTEM) {
systemSecurityMetadata.setSchemaOwner(session, source, principal);
}
else {
metadata.setSchemaAuthorization(session.toConnectorSession(catalogHandle), source.getSchemaName(), principal);
}
}
@Override
public void createTable(Session session, String catalogName, ConnectorTableMetadata tableMetadata, SaveMode saveMode)
{
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, catalogName);
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
metadata.createTable(session.toConnectorSession(catalogHandle), tableMetadata, saveMode);
if (catalogMetadata.getSecurityManagement() == SYSTEM) {
systemSecurityMetadata.tableCreated(session, new CatalogSchemaTableName(catalogName, tableMetadata.getTable()));
}
}
@Override
public void renameTable(Session session, TableHandle tableHandle, CatalogSchemaTableName sourceTableName, QualifiedObjectName newTableName)
{
String catalogName = newTableName.catalogName();
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, catalogName);
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
if (!tableHandle.catalogHandle().equals(catalogHandle)) {
throw new TrinoException(SYNTAX_ERROR, "Cannot rename tables across catalogs");
}
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
metadata.renameTable(session.toConnectorSession(catalogHandle), tableHandle.connectorHandle(), newTableName.asSchemaTableName());
if (catalogMetadata.getSecurityManagement() != CONNECTOR) {
systemSecurityMetadata.tableRenamed(session, sourceTableName, newTableName.asCatalogSchemaTableName());
}
}
@Override
public void setTableProperties(Session session, TableHandle tableHandle, Map> properties)
{
CatalogHandle catalogHandle = tableHandle.catalogHandle();
ConnectorMetadata metadata = getMetadataForWrite(session, catalogHandle);
metadata.setTableProperties(session.toConnectorSession(catalogHandle), tableHandle.connectorHandle(), properties);
}
@Override
public void setTableComment(Session session, TableHandle tableHandle, Optional comment)
{
CatalogHandle catalogHandle = tableHandle.catalogHandle();
ConnectorMetadata metadata = getMetadataForWrite(session, catalogHandle);
metadata.setTableComment(session.toConnectorSession(catalogHandle), tableHandle.connectorHandle(), comment);
}
@Override
public void setViewComment(Session session, QualifiedObjectName viewName, Optional comment)
{
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, viewName.catalogName());
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
metadata.setViewComment(session.toConnectorSession(catalogHandle), viewName.asSchemaTableName(), comment);
}
@Override
public void setViewColumnComment(Session session, QualifiedObjectName viewName, String columnName, Optional comment)
{
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, viewName.catalogName());
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
metadata.setViewColumnComment(session.toConnectorSession(catalogHandle), viewName.asSchemaTableName(), columnName, comment);
}
@Override
public void setColumnComment(Session session, TableHandle tableHandle, ColumnHandle column, Optional comment)
{
CatalogHandle catalogHandle = tableHandle.catalogHandle();
ConnectorMetadata metadata = getMetadataForWrite(session, catalogHandle);
metadata.setColumnComment(session.toConnectorSession(catalogHandle), tableHandle.connectorHandle(), column, comment);
}
@Override
public void renameColumn(Session session, TableHandle tableHandle, CatalogSchemaTableName table, ColumnHandle source, String target)
{
CatalogHandle catalogHandle = tableHandle.catalogHandle();
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, catalogHandle.getCatalogName().toString());
ConnectorMetadata metadata = getMetadataForWrite(session, catalogHandle);
metadata.renameColumn(session.toConnectorSession(catalogHandle), tableHandle.connectorHandle(), source, target.toLowerCase(ENGLISH));
if (catalogMetadata.getSecurityManagement() == SYSTEM) {
ColumnMetadata columnMetadata = getColumnMetadata(session, tableHandle, source);
systemSecurityMetadata.columnRenamed(session, table, columnMetadata.getName(), target);
}
}
@Override
public void renameField(Session session, TableHandle tableHandle, List fieldPath, String target)
{
CatalogHandle catalogHandle = tableHandle.catalogHandle();
ConnectorMetadata metadata = getMetadataForWrite(session, catalogHandle);
metadata.renameField(session.toConnectorSession(catalogHandle), tableHandle.connectorHandle(), fieldPath, target.toLowerCase(ENGLISH));
}
@Override
public void addColumn(Session session, TableHandle tableHandle, CatalogSchemaTableName table, ColumnMetadata column)
{
CatalogHandle catalogHandle = tableHandle.catalogHandle();
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, catalogHandle.getCatalogName().toString());
ConnectorMetadata metadata = getMetadataForWrite(session, catalogHandle);
metadata.addColumn(session.toConnectorSession(catalogHandle), tableHandle.connectorHandle(), column);
if (catalogMetadata.getSecurityManagement() == SYSTEM) {
systemSecurityMetadata.columnCreated(session, table, column.getName());
}
}
@Override
public void addField(Session session, TableHandle tableHandle, List parentPath, String fieldName, Type type, boolean ignoreExisting)
{
CatalogHandle catalogHandle = tableHandle.catalogHandle();
ConnectorMetadata metadata = getMetadataForWrite(session, catalogHandle);
metadata.addField(session.toConnectorSession(catalogHandle), tableHandle.connectorHandle(), parentPath, fieldName, type, ignoreExisting);
}
@Override
public void dropColumn(Session session, TableHandle tableHandle, CatalogSchemaTableName table, ColumnHandle column)
{
CatalogHandle catalogHandle = tableHandle.catalogHandle();
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, catalogHandle.getCatalogName().toString());
ConnectorMetadata metadata = getMetadataForWrite(session, catalogHandle);
metadata.dropColumn(session.toConnectorSession(catalogHandle), tableHandle.connectorHandle(), column);
if (catalogMetadata.getSecurityManagement() == SYSTEM) {
ColumnMetadata columnMetadata = getColumnMetadata(session, tableHandle, column);
systemSecurityMetadata.columnDropped(session, table, columnMetadata.getName());
}
}
@Override
public void dropField(Session session, TableHandle tableHandle, ColumnHandle column, List fieldPath)
{
CatalogHandle catalogHandle = tableHandle.catalogHandle();
ConnectorMetadata metadata = getMetadataForWrite(session, catalogHandle);
metadata.dropField(session.toConnectorSession(catalogHandle), tableHandle.connectorHandle(), column, fieldPath);
}
@Override
public void setColumnType(Session session, TableHandle tableHandle, ColumnHandle column, Type type)
{
CatalogHandle catalogHandle = tableHandle.catalogHandle();
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, catalogHandle.getCatalogName().toString());
ConnectorMetadata metadata = getMetadataForWrite(session, catalogHandle);
ColumnMetadata columnMetadata = getColumnMetadata(session, tableHandle, column);
metadata.setColumnType(session.toConnectorSession(catalogHandle), tableHandle.connectorHandle(), column, type);
if (catalogMetadata.getSecurityManagement() == SYSTEM) {
systemSecurityMetadata.columnTypeChanged(
session,
getTableName(session, tableHandle),
columnMetadata.getName(),
columnMetadata.getType().getDisplayName(),
type.getDisplayName());
}
}
@Override
public void setFieldType(Session session, TableHandle tableHandle, List fieldPath, Type type)
{
CatalogHandle catalogHandle = tableHandle.catalogHandle();
ConnectorMetadata metadata = getMetadataForWrite(session, catalogHandle);
metadata.setFieldType(session.toConnectorSession(catalogHandle), tableHandle.connectorHandle(), fieldPath, type);
}
@Override
public void dropNotNullConstraint(Session session, TableHandle tableHandle, ColumnHandle column)
{
CatalogHandle catalogHandle = tableHandle.catalogHandle();
ConnectorMetadata metadata = getMetadataForWrite(session, catalogHandle);
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, catalogHandle);
ColumnMetadata columnMetadata = getColumnMetadata(session, tableHandle, column);
metadata.dropNotNullConstraint(session.toConnectorSession(catalogHandle), tableHandle.connectorHandle(), column);
if (catalogMetadata.getSecurityManagement() == SYSTEM) {
systemSecurityMetadata.columnNotNullConstraintDropped(
session,
getTableName(session, tableHandle),
columnMetadata.getName());
}
}
@Override
public void setTableAuthorization(Session session, CatalogSchemaTableName table, TrinoPrincipal principal)
{
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, table.getCatalogName());
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
if (catalogMetadata.getSecurityManagement() == SYSTEM) {
systemSecurityMetadata.setTableOwner(session, table, principal);
}
else {
metadata.setTableAuthorization(session.toConnectorSession(catalogMetadata.getCatalogHandle()), table.getSchemaTableName(), principal);
}
}
@Override
public void dropTable(Session session, TableHandle tableHandle, CatalogSchemaTableName tableName)
{
CatalogHandle catalogHandle = tableHandle.catalogHandle();
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, catalogHandle);
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
metadata.dropTable(session.toConnectorSession(catalogHandle), tableHandle.connectorHandle());
if (catalogMetadata.getSecurityManagement() != CONNECTOR) {
systemSecurityMetadata.tableDropped(session, tableName);
}
}
@Override
public void truncateTable(Session session, TableHandle tableHandle)
{
CatalogHandle catalogHandle = tableHandle.catalogHandle();
ConnectorMetadata metadata = getMetadataForWrite(session, catalogHandle);
metadata.truncateTable(session.toConnectorSession(catalogHandle), tableHandle.connectorHandle());
}
@Override
public Optional getInsertLayout(Session session, TableHandle table)
{
CatalogHandle catalogHandle = table.catalogHandle();
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, catalogHandle);
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
return metadata.getInsertLayout(session.toConnectorSession(catalogHandle), table.connectorHandle())
.map(layout -> new TableLayout(catalogHandle, catalogMetadata.getTransactionHandleFor(catalogHandle), layout));
}
@Override
public TableStatisticsMetadata getStatisticsCollectionMetadataForWrite(Session session, CatalogHandle catalogHandle, ConnectorTableMetadata tableMetadata)
{
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, catalogHandle);
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
return metadata.getStatisticsCollectionMetadataForWrite(session.toConnectorSession(catalogHandle), tableMetadata);
}
@Override
public AnalyzeMetadata getStatisticsCollectionMetadata(Session session, TableHandle tableHandle, Map analyzeProperties)
{
CatalogHandle catalogHandle = tableHandle.catalogHandle();
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, catalogHandle);
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
ConnectorAnalyzeMetadata analyze = metadata.getStatisticsCollectionMetadata(session.toConnectorSession(catalogHandle), tableHandle.connectorHandle(), analyzeProperties);
return new AnalyzeMetadata(analyze.getStatisticsMetadata(), new TableHandle(catalogHandle, analyze.getTableHandle(), tableHandle.transaction()));
}
@Override
public AnalyzeTableHandle beginStatisticsCollection(Session session, TableHandle tableHandle)
{
CatalogHandle catalogHandle = tableHandle.catalogHandle();
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, catalogHandle);
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
ConnectorTransactionHandle transactionHandle = catalogMetadata.getTransactionHandleFor(catalogHandle);
ConnectorTableHandle connectorTableHandle = metadata.beginStatisticsCollection(session.toConnectorSession(catalogHandle), tableHandle.connectorHandle());
return new AnalyzeTableHandle(catalogHandle, transactionHandle, connectorTableHandle);
}
@Override
public void finishStatisticsCollection(Session session, AnalyzeTableHandle tableHandle, Collection computedStatistics)
{
CatalogHandle catalogHandle = tableHandle.catalogHandle();
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, catalogHandle);
catalogMetadata.getMetadata(session).finishStatisticsCollection(session.toConnectorSession(catalogHandle), tableHandle.connectorHandle(), computedStatistics);
}
@Override
public Optional getNewTableLayout(Session session, String catalogName, ConnectorTableMetadata tableMetadata)
{
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, catalogName);
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
ConnectorTransactionHandle transactionHandle = catalogMetadata.getTransactionHandleFor(catalogHandle);
ConnectorSession connectorSession = session.toConnectorSession(catalogHandle);
return metadata.getNewTableLayout(connectorSession, tableMetadata)
.map(layout -> new TableLayout(catalogHandle, transactionHandle, layout));
}
@Override
public Optional getSupportedType(Session session, CatalogHandle catalogHandle, Map tableProperties, Type type)
{
CatalogMetadata catalogMetadata = getCatalogMetadata(session, catalogHandle);
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
return metadata.getSupportedType(session.toConnectorSession(catalogHandle), tableProperties, type)
.map(newType -> {
if (!typeCoercion.isCompatible(newType, type)) {
throw new TrinoException(FUNCTION_IMPLEMENTATION_ERROR, format("Type '%s' is not compatible with the supplied type '%s' in getSupportedType", type, newType));
}
return newType;
});
}
@Override
public void beginQuery(Session session)
{
languageFunctionManager.registerQuery(session);
}
@Override
public void cleanupQuery(Session session)
{
QueryCatalogs queryCatalogs = catalogsByQueryId.remove(session.getQueryId());
if (queryCatalogs != null) {
queryCatalogs.finish();
}
languageFunctionManager.unregisterQuery(session);
}
@Override
public OutputTableHandle beginCreateTable(Session session, String catalogName, ConnectorTableMetadata tableMetadata, Optional layout, boolean replace)
{
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, catalogName);
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
ConnectorTransactionHandle transactionHandle = catalogMetadata.getTransactionHandleFor(catalogHandle);
ConnectorSession connectorSession = session.toConnectorSession(catalogHandle);
ConnectorOutputTableHandle handle = metadata.beginCreateTable(connectorSession, tableMetadata, layout.map(TableLayout::getLayout), getRetryPolicy(session).getRetryMode(), replace);
return new OutputTableHandle(catalogHandle, tableMetadata.getTable(), transactionHandle, handle);
}
@Override
public Optional finishCreateTable(Session session, OutputTableHandle tableHandle, Collection fragments, Collection computedStatistics)
{
CatalogHandle catalogHandle = tableHandle.catalogHandle();
CatalogMetadata catalogMetadata = getCatalogMetadata(session, catalogHandle);
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
Optional output = metadata.finishCreateTable(session.toConnectorSession(catalogHandle), tableHandle.connectorHandle(), fragments, computedStatistics);
if (catalogMetadata.getSecurityManagement() == SYSTEM) {
systemSecurityMetadata.tableCreated(session, new CatalogSchemaTableName(catalogHandle.getCatalogName().toString(), tableHandle.tableName()));
}
return output;
}
@Override
public InsertTableHandle beginInsert(Session session, TableHandle tableHandle, List columns)
{
CatalogHandle catalogHandle = tableHandle.catalogHandle();
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, catalogHandle);
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
ConnectorTransactionHandle transactionHandle = catalogMetadata.getTransactionHandleFor(catalogHandle);
ConnectorInsertTableHandle handle = metadata.beginInsert(session.toConnectorSession(catalogHandle), tableHandle.connectorHandle(), columns, getRetryPolicy(session).getRetryMode());
return new InsertTableHandle(tableHandle.catalogHandle(), transactionHandle, handle);
}
@Override
public boolean supportsMissingColumnsOnInsert(Session session, TableHandle tableHandle)
{
CatalogHandle catalogHandle = tableHandle.catalogHandle();
CatalogMetadata catalogMetadata = getCatalogMetadata(session, catalogHandle);
return catalogMetadata.getMetadata(session).supportsMissingColumnsOnInsert();
}
@Override
public Optional finishInsert(Session session, InsertTableHandle tableHandle, List sourceTableHandles, Collection fragments, Collection computedStatistics)
{
CatalogHandle catalogHandle = tableHandle.catalogHandle();
ConnectorMetadata metadata = getMetadata(session, catalogHandle);
List sourceConnectorHandles = sourceTableHandles.stream()
.filter(handle -> handle.catalogHandle().equals(catalogHandle))
.map(TableHandle::connectorHandle)
.collect(toImmutableList());
return metadata.finishInsert(session.toConnectorSession(catalogHandle), tableHandle.connectorHandle(), sourceConnectorHandles, fragments, computedStatistics);
}
@Override
public boolean delegateMaterializedViewRefreshToConnector(Session session, QualifiedObjectName viewName)
{
CatalogMetadata catalogMetadata = getRequiredCatalogMetadata(session, viewName.catalogName());
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
return metadata.delegateMaterializedViewRefreshToConnector(session.toConnectorSession(catalogHandle), viewName.asSchemaTableName());
}
@Override
public ListenableFuture refreshMaterializedView(Session session, QualifiedObjectName viewName)
{
CatalogMetadata catalogMetadata = getRequiredCatalogMetadata(session, viewName.catalogName());
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
return asVoid(toListenableFuture(metadata.refreshMaterializedView(session.toConnectorSession(catalogHandle), viewName.asSchemaTableName())));
}
private static ListenableFuture asVoid(ListenableFuture future)
{
return Futures.transform(future, v -> null, directExecutor());
}
@Override
public InsertTableHandle beginRefreshMaterializedView(Session session, TableHandle tableHandle, List sourceTableHandles, RefreshType refreshType)
{
CatalogHandle catalogHandle = tableHandle.catalogHandle();
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, catalogHandle);
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
ConnectorTransactionHandle transactionHandle = catalogMetadata.getTransactionHandleFor(catalogHandle);
List sourceConnectorHandles = sourceTableHandles.stream()
.map(TableHandle::connectorHandle)
.collect(Collectors.toList());
ConnectorInsertTableHandle handle = metadata.beginRefreshMaterializedView(session.toConnectorSession(catalogHandle), tableHandle.connectorHandle(), sourceConnectorHandles, getRetryPolicy(session).getRetryMode(), refreshType);
return new InsertTableHandle(tableHandle.catalogHandle(), transactionHandle, handle);
}
@Override
public Optional finishRefreshMaterializedView(
Session session,
TableHandle tableHandle,
InsertTableHandle insertHandle,
Collection fragments,
Collection computedStatistics,
List sourceTableHandles,
List sourceTableFunctions)
{
CatalogHandle catalogHandle = insertHandle.catalogHandle();
ConnectorMetadata metadata = getMetadata(session, catalogHandle);
List sourceConnectorHandles = sourceTableHandles.stream()
.map(TableHandle::connectorHandle)
.collect(toImmutableList());
return metadata.finishRefreshMaterializedView(
session.toConnectorSession(catalogHandle),
tableHandle.connectorHandle(),
insertHandle.connectorHandle(),
fragments,
computedStatistics,
sourceConnectorHandles,
sourceTableFunctions);
}
@Override
public ColumnHandle getMergeRowIdColumnHandle(Session session, TableHandle tableHandle)
{
CatalogHandle catalogHandle = tableHandle.catalogHandle();
ConnectorMetadata metadata = getMetadata(session, catalogHandle);
return metadata.getMergeRowIdColumnHandle(session.toConnectorSession(catalogHandle), tableHandle.connectorHandle());
}
@Override
public Optional getUpdateLayout(Session session, TableHandle tableHandle)
{
CatalogHandle catalogHandle = tableHandle.catalogHandle();
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, catalogHandle);
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
ConnectorTransactionHandle transactionHandle = catalogMetadata.getTransactionHandleFor(catalogHandle);
return metadata.getUpdateLayout(session.toConnectorSession(catalogHandle), tableHandle.connectorHandle())
.map(partitioning -> new PartitioningHandle(Optional.of(catalogHandle), Optional.of(transactionHandle), partitioning));
}
@Override
public Optional applyUpdate(Session session, TableHandle table, Map assignments)
{
CatalogHandle catalogHandle = table.catalogHandle();
ConnectorMetadata metadata = getMetadata(session, catalogHandle);
ConnectorSession connectorSession = session.toConnectorSession(catalogHandle);
return metadata.applyUpdate(connectorSession, table.connectorHandle(), assignments)
.map(newHandle -> new TableHandle(catalogHandle, newHandle, table.transaction()));
}
@Override
public OptionalLong executeUpdate(Session session, TableHandle table)
{
CatalogHandle catalogHandle = table.catalogHandle();
ConnectorMetadata metadata = getMetadataForWrite(session, catalogHandle);
ConnectorSession connectorSession = session.toConnectorSession(catalogHandle);
return metadata.executeUpdate(connectorSession, table.connectorHandle());
}
@Override
public Optional applyDelete(Session session, TableHandle table)
{
CatalogHandle catalogHandle = table.catalogHandle();
ConnectorMetadata metadata = getMetadata(session, catalogHandle);
ConnectorSession connectorSession = session.toConnectorSession(catalogHandle);
return metadata.applyDelete(connectorSession, table.connectorHandle())
.map(newHandle -> new TableHandle(catalogHandle, newHandle, table.transaction()));
}
@Override
public OptionalLong executeDelete(Session session, TableHandle table)
{
CatalogHandle catalogHandle = table.catalogHandle();
ConnectorMetadata metadata = getMetadataForWrite(session, catalogHandle);
ConnectorSession connectorSession = session.toConnectorSession(catalogHandle);
return metadata.executeDelete(connectorSession, table.connectorHandle());
}
@Override
public RowChangeParadigm getRowChangeParadigm(Session session, TableHandle tableHandle)
{
CatalogHandle catalogHandle = tableHandle.catalogHandle();
ConnectorMetadata metadata = getMetadata(session, catalogHandle);
return metadata.getRowChangeParadigm(session.toConnectorSession(catalogHandle), tableHandle.connectorHandle());
}
@Override
public MergeHandle beginMerge(Session session, TableHandle tableHandle)
{
CatalogHandle catalogHandle = tableHandle.catalogHandle();
ConnectorMetadata metadata = getMetadataForWrite(session, catalogHandle);
ConnectorMergeTableHandle newHandle = metadata.beginMerge(session.toConnectorSession(catalogHandle), tableHandle.connectorHandle(), getRetryPolicy(session).getRetryMode());
return new MergeHandle(tableHandle.withConnectorHandle(newHandle.getTableHandle()), newHandle);
}
@Override
public void finishMerge(Session session, MergeHandle mergeHandle, List sourceTableHandles, Collection fragments, Collection computedStatistics)
{
CatalogHandle catalogHandle = mergeHandle.tableHandle().catalogHandle();
ConnectorMetadata metadata = getMetadata(session, catalogHandle);
List sourceConnectorHandles = sourceTableHandles.stream()
.filter(handle -> handle.catalogHandle().equals(catalogHandle))
.map(TableHandle::connectorHandle)
.collect(toImmutableList());
metadata.finishMerge(session.toConnectorSession(catalogHandle), mergeHandle.connectorMergeHandle(), sourceConnectorHandles, fragments, computedStatistics);
}
@Override
public Optional getCatalogHandle(Session session, String catalogName)
{
return transactionManager.getOptionalCatalogMetadata(session.getRequiredTransactionId(), catalogName).map(CatalogMetadata::getCatalogHandle);
}
@Override
public List listCatalogs(Session session)
{
return transactionManager.getCatalogs(session.getRequiredTransactionId());
}
@Override
public List listViews(Session session, QualifiedTablePrefix prefix)
{
requireNonNull(prefix, "prefix is null");
if (cannotExist(prefix)) {
return ImmutableList.of();
}
Optional objectName = prefix.asQualifiedObjectName();
if (objectName.isPresent()) {
return isView(session, objectName.get())
? ImmutableList.of(objectName.get())
: ImmutableList.of();
}
Optional catalog = getOptionalCatalogMetadata(session, prefix.getCatalogName());
Set views = new LinkedHashSet<>();
if (catalog.isPresent()) {
CatalogMetadata catalogMetadata = catalog.get();
for (CatalogHandle catalogHandle : catalogMetadata.listCatalogHandles()) {
if (isExternalInformationSchema(catalogHandle, prefix.getSchemaName())) {
continue;
}
ConnectorMetadata metadata = catalogMetadata.getMetadataFor(session, catalogHandle);
ConnectorSession connectorSession = session.toConnectorSession(catalogHandle);
metadata.listViews(connectorSession, prefix.getSchemaName()).stream()
.map(convertFromSchemaTableName(prefix.getCatalogName()))
.filter(view -> !isExternalInformationSchema(catalogHandle, view.schemaName()))
.forEach(views::add);
}
}
return ImmutableList.copyOf(views);
}
@Override
public Map getViews(Session session, QualifiedTablePrefix prefix)
{
requireNonNull(prefix, "prefix is null");
if (cannotExist(prefix)) {
return ImmutableMap.of();
}
Optional catalog = getOptionalCatalogMetadata(session, prefix.getCatalogName());
Map views = new LinkedHashMap<>();
if (catalog.isPresent()) {
CatalogMetadata catalogMetadata = catalog.get();
SchemaTablePrefix tablePrefix = prefix.asSchemaTablePrefix();
for (CatalogHandle catalogHandle : catalogMetadata.listCatalogHandles()) {
if (isExternalInformationSchema(catalogHandle, tablePrefix.getSchema())) {
continue;
}
ConnectorMetadata metadata = catalogMetadata.getMetadataFor(session, catalogHandle);
ConnectorSession connectorSession = session.toConnectorSession(catalogHandle);
Map viewMap;
if (tablePrefix.getTable().isPresent()) {
try {
viewMap = metadata.getView(connectorSession, tablePrefix.toSchemaTableName())
.map(view -> ImmutableMap.of(tablePrefix.toSchemaTableName(), view))
.orElse(ImmutableMap.of());
}
catch (RuntimeException e) {
handleListingError(e, prefix);
// Empty in case of metadata error.
viewMap = ImmutableMap.of();
}
}
else {
viewMap = metadata.getViews(connectorSession, tablePrefix.getSchema());
}
for (Entry entry : viewMap.entrySet()) {
if (isExternalInformationSchema(catalogHandle, entry.getKey().getSchemaName())) {
continue;
}
QualifiedObjectName viewName = new QualifiedObjectName(
prefix.getCatalogName(),
entry.getKey().getSchemaName(),
entry.getKey().getTableName());
views.put(viewName, new ViewInfo(entry.getValue()));
}
}
}
return ImmutableMap.copyOf(views);
}
@Override
public Map getSchemaProperties(Session session, CatalogSchemaName schemaName)
{
if (!schemaExists(session, schemaName)) {
throw new TrinoException(SCHEMA_NOT_FOUND, format("Schema '%s' does not exist", schemaName));
}
CatalogMetadata catalogMetadata = getRequiredCatalogMetadata(session, schemaName.getCatalogName());
CatalogHandle catalogHandle = catalogMetadata.getConnectorHandleForSchema(schemaName);
ConnectorMetadata metadata = catalogMetadata.getMetadataFor(session, catalogHandle);
ConnectorSession connectorSession = session.toConnectorSession(catalogHandle);
return metadata.getSchemaProperties(connectorSession, schemaName.getSchemaName());
}
@Override
public Optional getSchemaOwner(Session session, CatalogSchemaName schemaName)
{
if (!schemaExists(session, schemaName)) {
throw new TrinoException(SCHEMA_NOT_FOUND, format("Schema '%s' does not exist", schemaName));
}
CatalogMetadata catalogMetadata = getRequiredCatalogMetadata(session, schemaName.getCatalogName());
if (catalogMetadata.getSecurityManagement() == SYSTEM) {
return systemSecurityMetadata.getSchemaOwner(session, schemaName);
}
CatalogHandle catalogHandle = catalogMetadata.getConnectorHandleForSchema(schemaName);
ConnectorMetadata metadata = catalogMetadata.getMetadataFor(session, catalogHandle);
ConnectorSession connectorSession = session.toConnectorSession(catalogHandle);
return metadata.getSchemaOwner(connectorSession, schemaName.getSchemaName());
}
@Override
public boolean isView(Session session, QualifiedObjectName viewName)
{
if (cannotExist(viewName)) {
return false;
}
return getOptionalCatalogMetadata(session, viewName.catalogName())
.map(catalog -> {
CatalogHandle catalogHandle = catalog.getCatalogHandle(session, viewName, Optional.empty(), Optional.empty());
ConnectorMetadata metadata = catalog.getMetadataFor(session, catalogHandle);
ConnectorSession connectorSession = session.toConnectorSession(catalogHandle);
return metadata.isView(connectorSession, viewName.asSchemaTableName());
})
.orElse(false);
}
@Override
public Optional getView(Session session, QualifiedObjectName viewName)
{
Optional connectorView = getViewInternal(session, viewName);
if (connectorView.isEmpty() || connectorView.get().isRunAsInvoker() || isCatalogManagedSecurity(session, viewName.catalogName())) {
return connectorView.map(view -> createViewDefinition(viewName, view, view.getOwner().map(Identity::ofUser)));
}
Identity runAsIdentity = systemSecurityMetadata.getViewRunAsIdentity(session, viewName.asCatalogSchemaTableName())
.or(() -> connectorView.get().getOwner().map(Identity::ofUser))
.orElseThrow(() -> new TrinoException(NOT_SUPPORTED, "Catalog does not support run-as DEFINER views: " + viewName));
return Optional.of(createViewDefinition(viewName, connectorView.get(), Optional.of(runAsIdentity)));
}
@Override
public Map getViewProperties(Session session, QualifiedObjectName viewName)
{
Optional catalog = getOptionalCatalogMetadata(session, viewName.catalogName());
if (catalog.isPresent()) {
CatalogMetadata catalogMetadata = catalog.get();
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle(session, viewName, Optional.empty(), Optional.empty());
ConnectorMetadata metadata = catalogMetadata.getMetadataFor(session, catalogHandle);
ConnectorSession connectorSession = session.toConnectorSession(catalogHandle);
return ImmutableMap.copyOf(metadata.getViewProperties(
connectorSession,
viewName.asSchemaTableName()));
}
return ImmutableMap.of();
}
private static ViewDefinition createViewDefinition(QualifiedObjectName viewName, ConnectorViewDefinition view, Optional runAsIdentity)
{
if (view.isRunAsInvoker() && runAsIdentity.isPresent()) {
throw new TrinoException(INVALID_VIEW, "Run-as identity cannot be set for a run-as invoker view: " + viewName);
}
if (!view.isRunAsInvoker() && runAsIdentity.isEmpty()) {
throw new TrinoException(INVALID_VIEW, "Run-as identity must be set for a run-as definer view: " + viewName);
}
return new ViewDefinition(
view.getOriginalSql(),
view.getCatalog(),
view.getSchema(),
view.getColumns().stream()
.map(column -> new ViewColumn(column.getName(), column.getType(), column.getComment()))
.collect(toImmutableList()),
view.getComment(),
runAsIdentity,
view.getPath());
}
private Optional getViewInternal(Session session, QualifiedObjectName viewName)
{
if (cannotExist(viewName)) {
return Optional.empty();
}
Optional catalog = getOptionalCatalogMetadata(session, viewName.catalogName());
if (catalog.isPresent()) {
CatalogMetadata catalogMetadata = catalog.get();
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle(session, viewName, Optional.empty(), Optional.empty());
ConnectorMetadata metadata = catalogMetadata.getMetadataFor(session, catalogHandle);
ConnectorSession connectorSession = session.toConnectorSession(catalogHandle);
return metadata.getView(connectorSession, viewName.asSchemaTableName());
}
return Optional.empty();
}
@Override
public void createView(Session session, QualifiedObjectName viewName, ViewDefinition definition, Map viewProperties, boolean replace)
{
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, viewName.catalogName());
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
metadata.createView(session.toConnectorSession(catalogHandle), viewName.asSchemaTableName(), definition.toConnectorViewDefinition(), viewProperties, replace);
if (catalogMetadata.getSecurityManagement() == SYSTEM) {
systemSecurityMetadata.tableCreated(session, viewName.asCatalogSchemaTableName());
}
}
@Override
public void renameView(Session session, QualifiedObjectName source, QualifiedObjectName target)
{
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, target.catalogName());
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
if (!source.catalogName().equals(target.catalogName())) {
throw new TrinoException(SYNTAX_ERROR, "Cannot rename views across catalogs");
}
metadata.renameView(session.toConnectorSession(catalogHandle), source.asSchemaTableName(), target.asSchemaTableName());
if (catalogMetadata.getSecurityManagement() == SYSTEM) {
systemSecurityMetadata.tableRenamed(session, source.asCatalogSchemaTableName(), target.asCatalogSchemaTableName());
}
}
@Override
public void setViewAuthorization(Session session, CatalogSchemaTableName view, TrinoPrincipal principal)
{
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, view.getCatalogName());
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
if (catalogMetadata.getSecurityManagement() == SYSTEM) {
systemSecurityMetadata.setViewOwner(session, view, principal);
}
else {
metadata.setViewAuthorization(session.toConnectorSession(catalogHandle), view.getSchemaTableName(), principal);
}
}
@Override
public void dropView(Session session, QualifiedObjectName viewName)
{
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, viewName.catalogName());
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
metadata.dropView(session.toConnectorSession(catalogHandle), viewName.asSchemaTableName());
if (catalogMetadata.getSecurityManagement() == SYSTEM) {
systemSecurityMetadata.tableDropped(session, viewName.asCatalogSchemaTableName());
}
}
@Override
public void createMaterializedView(
Session session,
QualifiedObjectName viewName,
MaterializedViewDefinition definition,
Map properties,
boolean replace,
boolean ignoreExisting)
{
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, viewName.catalogName());
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
metadata.createMaterializedView(
session.toConnectorSession(catalogHandle),
viewName.asSchemaTableName(),
definition.toConnectorMaterializedViewDefinition(),
properties,
replace,
ignoreExisting);
if (catalogMetadata.getSecurityManagement() == SYSTEM) {
systemSecurityMetadata.tableCreated(session, viewName.asCatalogSchemaTableName());
}
}
@Override
public void dropMaterializedView(Session session, QualifiedObjectName viewName)
{
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, viewName.catalogName());
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
metadata.dropMaterializedView(session.toConnectorSession(catalogHandle), viewName.asSchemaTableName());
if (catalogMetadata.getSecurityManagement() == SYSTEM) {
systemSecurityMetadata.tableDropped(session, viewName.asCatalogSchemaTableName());
}
}
@Override
public List listMaterializedViews(Session session, QualifiedTablePrefix prefix)
{
requireNonNull(prefix, "prefix is null");
Optional objectName = prefix.asQualifiedObjectName();
if (objectName.isPresent()) {
return isMaterializedView(session, objectName.get()) ? ImmutableList.of(objectName.get()) : ImmutableList.of();
}
Optional catalog = getOptionalCatalogMetadata(session, prefix.getCatalogName());
Set materializedViews = new LinkedHashSet<>();
if (catalog.isPresent()) {
CatalogMetadata catalogMetadata = catalog.get();
for (CatalogHandle catalogHandle : catalogMetadata.listCatalogHandles()) {
if (isExternalInformationSchema(catalogHandle, prefix.getSchemaName())) {
continue;
}
ConnectorMetadata metadata = catalogMetadata.getMetadataFor(session, catalogHandle);
ConnectorSession connectorSession = session.toConnectorSession(catalogHandle);
metadata.listMaterializedViews(connectorSession, prefix.getSchemaName()).stream()
.map(convertFromSchemaTableName(prefix.getCatalogName()))
.filter(materializedView -> !isExternalInformationSchema(catalogHandle, materializedView.schemaName()))
.forEach(materializedViews::add);
}
}
return ImmutableList.copyOf(materializedViews);
}
@Override
public Map getMaterializedViews(Session session, QualifiedTablePrefix prefix)
{
requireNonNull(prefix, "prefix is null");
Optional catalog = getOptionalCatalogMetadata(session, prefix.getCatalogName());
Map views = new LinkedHashMap<>();
if (catalog.isPresent()) {
CatalogMetadata catalogMetadata = catalog.get();
SchemaTablePrefix tablePrefix = prefix.asSchemaTablePrefix();
for (CatalogHandle catalogHandle : catalogMetadata.listCatalogHandles()) {
if (isExternalInformationSchema(catalogHandle, tablePrefix.getSchema())) {
continue;
}
ConnectorMetadata metadata = catalogMetadata.getMetadataFor(session, catalogHandle);
ConnectorSession connectorSession = session.toConnectorSession(catalogHandle);
Map materializedViewMap;
if (tablePrefix.getTable().isPresent()) {
materializedViewMap = metadata.getMaterializedView(connectorSession, tablePrefix.toSchemaTableName())
.map(view -> ImmutableMap.of(tablePrefix.toSchemaTableName(), view))
.orElse(ImmutableMap.of());
}
else {
materializedViewMap = metadata.getMaterializedViews(connectorSession, tablePrefix.getSchema());
}
for (Entry entry : materializedViewMap.entrySet()) {
if (isExternalInformationSchema(catalogHandle, entry.getKey().getSchemaName())) {
continue;
}
QualifiedObjectName viewName = new QualifiedObjectName(
prefix.getCatalogName(),
entry.getKey().getSchemaName(),
entry.getKey().getTableName());
views.put(viewName, new ViewInfo(entry.getValue()));
}
}
}
return ImmutableMap.copyOf(views);
}
@Override
public boolean isMaterializedView(Session session, QualifiedObjectName viewName)
{
return getMaterializedViewInternal(session, viewName).isPresent();
}
@Override
public Optional getMaterializedView(Session session, QualifiedObjectName viewName)
{
Optional connectorView = getMaterializedViewInternal(session, viewName);
if (connectorView.isEmpty()) {
return Optional.empty();
}
if (isCatalogManagedSecurity(session, viewName.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)));
}
Identity runAsIdentity = systemSecurityMetadata.getViewRunAsIdentity(session, viewName.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));
}
private static MaterializedViewDefinition createMaterializedViewDefinition(ConnectorMaterializedViewDefinition view, Identity runAsIdentity)
{
return new MaterializedViewDefinition(
view.getOriginalSql(),
view.getCatalog(),
view.getSchema(),
view.getColumns().stream()
.map(column -> new ViewColumn(column.getName(), column.getType(), Optional.empty()))
.collect(toImmutableList()),
view.getGracePeriod(),
view.getComment(),
runAsIdentity,
view.getPath(),
view.getStorageTable());
}
private Optional getMaterializedViewInternal(Session session, QualifiedObjectName viewName)
{
if (cannotExist(viewName)) {
return Optional.empty();
}
Optional catalog = getOptionalCatalogMetadata(session, viewName.catalogName());
if (catalog.isPresent()) {
CatalogMetadata catalogMetadata = catalog.get();
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle(session, viewName, Optional.empty(), Optional.empty());
ConnectorMetadata metadata = catalogMetadata.getMetadataFor(session, catalogHandle);
ConnectorSession connectorSession = session.toConnectorSession(catalogHandle);
return metadata.getMaterializedView(connectorSession, viewName.asSchemaTableName());
}
return Optional.empty();
}
@Override
public Map getMaterializedViewProperties(Session session, QualifiedObjectName viewName, MaterializedViewDefinition materializedViewDefinition)
{
Optional catalog = getOptionalCatalogMetadata(session, viewName.catalogName());
if (catalog.isPresent()) {
CatalogMetadata catalogMetadata = catalog.get();
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle(session, viewName, Optional.empty(), Optional.empty());
ConnectorMetadata metadata = catalogMetadata.getMetadataFor(session, catalogHandle);
ConnectorSession connectorSession = session.toConnectorSession(catalogHandle);
return ImmutableMap.copyOf(metadata.getMaterializedViewProperties(
connectorSession,
viewName.asSchemaTableName(),
materializedViewDefinition.toConnectorMaterializedViewDefinition()));
}
return ImmutableMap.of();
}
@Override
public MaterializedViewFreshness getMaterializedViewFreshness(Session session, QualifiedObjectName viewName)
{
Optional catalog = getOptionalCatalogMetadata(session, viewName.catalogName());
if (catalog.isPresent()) {
CatalogMetadata catalogMetadata = catalog.get();
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle(session, viewName, Optional.empty(), Optional.empty());
ConnectorMetadata metadata = catalogMetadata.getMetadataFor(session, catalogHandle);
ConnectorSession connectorSession = session.toConnectorSession(catalogHandle);
return metadata.getMaterializedViewFreshness(connectorSession, viewName.asSchemaTableName());
}
return new MaterializedViewFreshness(STALE, Optional.empty());
}
@Override
public void renameMaterializedView(Session session, QualifiedObjectName source, QualifiedObjectName target)
{
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, target.catalogName());
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
if (!source.catalogName().equals(target.catalogName())) {
throw new TrinoException(SYNTAX_ERROR, "Cannot rename materialized views across catalogs");
}
metadata.renameMaterializedView(session.toConnectorSession(catalogHandle), source.asSchemaTableName(), target.asSchemaTableName());
if (catalogMetadata.getSecurityManagement() == SYSTEM) {
systemSecurityMetadata.tableRenamed(session, source.asCatalogSchemaTableName(), target.asCatalogSchemaTableName());
}
}
@Override
public void setMaterializedViewProperties(Session session, QualifiedObjectName viewName, Map> properties)
{
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, viewName.catalogName());
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
metadata.setMaterializedViewProperties(session.toConnectorSession(catalogHandle), viewName.asSchemaTableName(), properties);
}
@Override
public void setMaterializedViewColumnComment(Session session, QualifiedObjectName viewName, String columnName, Optional comment)
{
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, viewName.catalogName());
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
metadata.setMaterializedViewColumnComment(session.toConnectorSession(catalogHandle), viewName.asSchemaTableName(), columnName, comment);
}
private static boolean isExternalInformationSchema(CatalogHandle catalogHandle, Optional schemaName)
{
return schemaName.isPresent() && isExternalInformationSchema(catalogHandle, schemaName.get());
}
private static boolean isExternalInformationSchema(CatalogHandle catalogHandle, String schemaName)
{
return !catalogHandle.getType().isInternal() && "information_schema".equalsIgnoreCase(schemaName);
}
@Override
public Optional applyTableScanRedirect(Session session, TableHandle tableHandle)
{
CatalogHandle catalogHandle = tableHandle.catalogHandle();
CatalogMetadata catalogMetadata = getCatalogMetadata(session, catalogHandle);
ConnectorMetadata metadata = catalogMetadata.getMetadataFor(session, catalogHandle);
ConnectorSession connectorSession = session.toConnectorSession(catalogHandle);
return metadata.applyTableScanRedirect(connectorSession, tableHandle.connectorHandle());
}
private QualifiedObjectName getRedirectedTableName(Session session, QualifiedObjectName originalTableName, Optional startVersion, Optional endVersion)
{
requireNonNull(session, "session is null");
requireNonNull(originalTableName, "originalTableName is null");
if (cannotExist(originalTableName)) {
return originalTableName;
}
QualifiedObjectName tableName = originalTableName;
Set visitedTableNames = new LinkedHashSet<>();
visitedTableNames.add(tableName);
for (int count = 0; count < MAX_TABLE_REDIRECTIONS; count++) {
Optional catalog = getOptionalCatalogMetadata(session, tableName.catalogName());
if (catalog.isEmpty()) {
// Stop redirection
return tableName;
}
CatalogMetadata catalogMetadata = catalog.get();
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle(session, tableName, toConnectorVersion(startVersion), toConnectorVersion(endVersion));
ConnectorMetadata metadata = catalogMetadata.getMetadataFor(session, catalogHandle);
Optional redirectedTableName = metadata.redirectTable(session.toConnectorSession(catalogHandle), tableName.asSchemaTableName())
.map(name -> convertFromSchemaTableName(name.getCatalogName()).apply(name.getSchemaTableName()));
if (redirectedTableName.isEmpty()) {
return tableName;
}
tableName = redirectedTableName.get();
// Check for loop in redirection
if (!visitedTableNames.add(tableName)) {
throw new TrinoException(TABLE_REDIRECTION_ERROR,
format("Table redirections form a loop: %s",
Streams.concat(visitedTableNames.stream(), Stream.of(tableName))
.map(QualifiedObjectName::toString)
.collect(Collectors.joining(" -> "))));
}
}
throw new TrinoException(TABLE_REDIRECTION_ERROR, format("Table redirected too many times (%d): %s", MAX_TABLE_REDIRECTIONS, visitedTableNames));
}
@Override
public RedirectionAwareTableHandle getRedirectionAwareTableHandle(Session session, QualifiedObjectName tableName)
{
return getRedirectionAwareTableHandle(session, tableName, Optional.empty(), Optional.empty());
}
@Override
public RedirectionAwareTableHandle getRedirectionAwareTableHandle(Session session, QualifiedObjectName tableName, Optional startVersion, Optional endVersion)
{
QualifiedObjectName targetTableName = getRedirectedTableName(session, tableName, startVersion, endVersion);
if (targetTableName.equals(tableName)) {
return noRedirection(getTableHandle(session, tableName, startVersion, endVersion));
}
Optional tableHandle = getTableHandle(session, targetTableName, startVersion, endVersion);
if (tableHandle.isPresent()) {
return withRedirectionTo(targetTableName, tableHandle.get());
}
// Redirected table must exist
if (getCatalogHandle(session, targetTableName.catalogName()).isEmpty()) {
throw new TrinoException(TABLE_REDIRECTION_ERROR, format("Table '%s' redirected to '%s', but the target catalog '%s' does not exist", tableName, targetTableName, targetTableName.catalogName()));
}
if (!schemaExists(session, new CatalogSchemaName(targetTableName.catalogName(), targetTableName.schemaName()))) {
throw new TrinoException(TABLE_REDIRECTION_ERROR, format("Table '%s' redirected to '%s', but the target schema '%s' does not exist", tableName, targetTableName, targetTableName.schemaName()));
}
throw new TrinoException(TABLE_REDIRECTION_ERROR, format("Table '%s' redirected to '%s', but the target table '%s' does not exist", tableName, targetTableName, targetTableName));
}
@Override
public Optional resolveIndex(Session session, TableHandle tableHandle, Set indexableColumns, Set outputColumns, TupleDomain tupleDomain)
{
CatalogHandle catalogHandle = tableHandle.catalogHandle();
CatalogMetadata catalogMetadata = getCatalogMetadata(session, catalogHandle);
ConnectorMetadata metadata = catalogMetadata.getMetadataFor(session, catalogHandle);
ConnectorTransactionHandle transaction = catalogMetadata.getTransactionHandleFor(catalogHandle);
ConnectorSession connectorSession = session.toConnectorSession(catalogHandle);
Optional resolvedIndex = metadata.resolveIndex(connectorSession, tableHandle.connectorHandle(), indexableColumns, outputColumns, tupleDomain);
return resolvedIndex.map(resolved -> new ResolvedIndex(tableHandle.catalogHandle(), transaction, resolved));
}
@Override
public Optional> applyLimit(Session session, TableHandle table, long limit)
{
CatalogHandle catalogHandle = table.catalogHandle();
ConnectorMetadata metadata = getMetadata(session, catalogHandle);
ConnectorSession connectorSession = session.toConnectorSession(catalogHandle);
return metadata.applyLimit(connectorSession, table.connectorHandle(), limit)
.map(result -> new LimitApplicationResult<>(
new TableHandle(catalogHandle, result.getHandle(), table.transaction()),
result.isLimitGuaranteed(),
result.isPrecalculateStatistics()));
}
@Override
public Optional> applySample(Session session, TableHandle table, SampleType sampleType, double sampleRatio)
{
CatalogHandle catalogHandle = table.catalogHandle();
ConnectorMetadata metadata = getMetadata(session, catalogHandle);
ConnectorSession connectorSession = session.toConnectorSession(catalogHandle);
return metadata.applySample(connectorSession, table.connectorHandle(), sampleType, sampleRatio)
.map(result -> new SampleApplicationResult<>(new TableHandle(
catalogHandle,
result.getHandle(),
table.transaction()),
result.isPrecalculateStatistics()));
}
@Override
public Optional> applyAggregation(
Session session,
TableHandle table,
List aggregations,
Map assignments,
List> groupingSets)
{
// Global aggregation is represented by [[]]
checkArgument(!groupingSets.isEmpty(), "No grouping sets provided");
CatalogHandle catalogHandle = table.catalogHandle();
ConnectorMetadata metadata = getMetadata(session, catalogHandle);
ConnectorSession connectorSession = session.toConnectorSession(catalogHandle);
return metadata.applyAggregation(connectorSession, table.connectorHandle(), aggregations, assignments, groupingSets)
.map(result -> {
verifyProjection(table, result.getProjections(), result.getAssignments(), aggregations.size());
return new AggregationApplicationResult<>(
new TableHandle(catalogHandle, result.getHandle(), table.transaction()),
result.getProjections(),
result.getAssignments(),
result.getGroupingColumnMapping(),
result.isPrecalculateStatistics());
});
}
@Override
public Optional> applyJoin(
Session session,
JoinType joinType,
TableHandle left,
TableHandle right,
ConnectorExpression joinCondition,
Map leftAssignments,
Map rightAssignments,
JoinStatistics statistics)
{
if (!right.catalogHandle().equals(left.catalogHandle())) {
// Exact comparison is fine as catalog name here is passed from CatalogMetadata and is normalized to lowercase
return Optional.empty();
}
CatalogHandle catalogHandle = left.catalogHandle();
ConnectorTransactionHandle transaction = left.transaction();
ConnectorMetadata metadata = getMetadata(session, catalogHandle);
ConnectorSession connectorSession = session.toConnectorSession(catalogHandle);
Optional> connectorResult =
metadata.applyJoin(
connectorSession,
joinType,
left.connectorHandle(),
right.connectorHandle(),
joinCondition,
leftAssignments,
rightAssignments,
statistics);
return connectorResult.map(result -> {
Set leftColumnHandles = ImmutableSet.copyOf(getColumnHandles(session, left).values());
Set rightColumnHandles = ImmutableSet.copyOf(getColumnHandles(session, right).values());
Set leftColumnHandlesMappingKeys = result.getLeftColumnHandles().keySet();
Set rightColumnHandlesMappingKeys = result.getRightColumnHandles().keySet();
if (leftColumnHandlesMappingKeys.size() != leftColumnHandles.size()
|| rightColumnHandlesMappingKeys.size() != rightColumnHandles.size()
|| !leftColumnHandlesMappingKeys.containsAll(leftColumnHandles)
|| !rightColumnHandlesMappingKeys.containsAll(rightColumnHandles)) {
throw new IllegalStateException(format(
"Column handle mappings do not match old column handles: left=%s; right=%s; newLeft=%s, newRight=%s",
leftColumnHandles,
rightColumnHandles,
leftColumnHandlesMappingKeys,
rightColumnHandlesMappingKeys));
}
return new JoinApplicationResult<>(
new TableHandle(
catalogHandle,
result.getTableHandle(),
transaction),
result.getLeftColumnHandles(),
result.getRightColumnHandles(),
result.isPrecalculateStatistics());
});
}
@Override
public Optional> applyTopN(
Session session,
TableHandle table,
long topNCount,
List sortItems,
Map assignments)
{
CatalogHandle catalogHandle = table.catalogHandle();
ConnectorMetadata metadata = getMetadata(session, catalogHandle);
ConnectorSession connectorSession = session.toConnectorSession(catalogHandle);
return metadata.applyTopN(connectorSession, table.connectorHandle(), topNCount, sortItems, assignments)
.map(result -> new TopNApplicationResult<>(
new TableHandle(catalogHandle, result.getHandle(), table.transaction()),
result.isTopNGuaranteed(),
result.isPrecalculateStatistics()));
}
@Override
public Optional> applyTableFunction(Session session, TableFunctionHandle handle)
{
CatalogHandle catalogHandle = handle.catalogHandle();
ConnectorMetadata metadata = getMetadata(session, catalogHandle);
return metadata.applyTableFunction(session.toConnectorSession(catalogHandle), handle.functionHandle())
.map(result -> new TableFunctionApplicationResult<>(
new TableHandle(catalogHandle, result.getTableHandle(), handle.transactionHandle()),
result.getColumnHandles()));
}
private void verifyProjection(TableHandle table, List projections, List assignments, int expectedProjectionSize)
{
projections.forEach(projection -> requireNonNull(projection, "one of the projections is null"));
assignments.forEach(assignment -> requireNonNull(assignment, "one of the assignments is null"));
verify(
expectedProjectionSize == projections.size(),
"ConnectorMetadata returned invalid number of projections: %s instead of %s for %s",
projections.size(),
expectedProjectionSize,
table);
Set assignedVariables = assignments.stream()
.map(Assignment::getVariable)
.collect(toImmutableSet());
projections.stream()
.flatMap(connectorExpression -> extractVariables(connectorExpression).stream())
.map(Variable::getName)
.filter(variableName -> !assignedVariables.contains(variableName))
.findAny()
.ifPresent(variableName -> { throw new IllegalStateException("Unbound variable: " + variableName); });
}
@Override
public void validateScan(Session session, TableHandle table)
{
CatalogHandle catalogHandle = table.catalogHandle();
ConnectorMetadata metadata = getMetadata(session, catalogHandle);
metadata.validateScan(session.toConnectorSession(catalogHandle), table.connectorHandle());
}
@Override
public Optional> applyFilter(Session session, TableHandle table, Constraint constraint)
{
CatalogHandle catalogHandle = table.catalogHandle();
ConnectorMetadata metadata = getMetadata(session, catalogHandle);
ConnectorSession connectorSession = session.toConnectorSession(catalogHandle);
return metadata.applyFilter(connectorSession, table.connectorHandle(), constraint)
.map(result -> result.transform(handle -> new TableHandle(catalogHandle, handle, table.transaction())));
}
@Override
public Optional> applyProjection(Session session, TableHandle table, List projections, Map assignments)
{
CatalogHandle catalogHandle = table.catalogHandle();
ConnectorMetadata metadata = getMetadata(session, catalogHandle);
ConnectorSession connectorSession = session.toConnectorSession(catalogHandle);
return metadata.applyProjection(connectorSession, table.connectorHandle(), projections, assignments)
.map(result -> {
verifyProjection(table, result.getProjections(), result.getAssignments(), projections.size());
return new ProjectionApplicationResult<>(
new TableHandle(catalogHandle, result.getHandle(), table.transaction()),
result.getProjections(),
result.getAssignments(),
result.isPrecalculateStatistics());
});
}
//
// Roles and Grants
//
@Override
public boolean isCatalogManagedSecurity(Session session, String catalog)
{
return getRequiredCatalogMetadata(session, catalog).getSecurityManagement() == CONNECTOR;
}
@Override
public boolean roleExists(Session session, String role, Optional catalog)
{
if (catalog.isEmpty()) {
return systemSecurityMetadata.roleExists(session, role);
}
CatalogMetadata catalogMetadata = getRequiredCatalogMetadata(session, catalog.get());
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
return metadata.roleExists(session.toConnectorSession(catalogHandle), role);
}
@Override
public void createRole(Session session, String role, Optional grantor, Optional catalog)
{
if (catalog.isEmpty()) {
systemSecurityMetadata.createRole(session, role, grantor);
return;
}
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, catalog.get());
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
metadata.createRole(session.toConnectorSession(catalogHandle), role, grantor);
}
@Override
public void dropRole(Session session, String role, Optional catalog)
{
if (catalog.isEmpty()) {
systemSecurityMetadata.dropRole(session, role);
return;
}
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, catalog.get());
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
metadata.dropRole(session.toConnectorSession(catalogHandle), role);
}
@Override
public Set listRoles(Session session, Optional catalog)
{
if (catalog.isPresent()) {
Optional catalogMetadata = getOptionalCatalogMetadata(session, catalog.get());
if (catalogMetadata.isEmpty()) {
return ImmutableSet.of();
}
// If the connector is using system security management, we fall through to the system call
// instead of returning nothing, so information schema role tables will work properly
if (catalogMetadata.get().getSecurityManagement() == CONNECTOR) {
CatalogHandle catalogHandle = catalogMetadata.get().getCatalogHandle();
ConnectorSession connectorSession = session.toConnectorSession(catalogHandle);
ConnectorMetadata metadata = catalogMetadata.get().getMetadataFor(session, catalogHandle);
return metadata.listRoles(connectorSession).stream()
.map(role -> role.toLowerCase(ENGLISH))
.collect(toImmutableSet());
}
}
return systemSecurityMetadata.listRoles(session);
}
@Override
public Set listRoleGrants(Session session, Optional catalog, TrinoPrincipal principal)
{
if (catalog.isPresent()) {
Optional catalogMetadata = getOptionalCatalogMetadata(session, catalog.get());
if (catalogMetadata.isEmpty()) {
return ImmutableSet.of();
}
// If the connector is using system security management, we fall through to the system call
// instead of returning nothing, so information schema role tables will work properly
if (catalogMetadata.get().getSecurityManagement() == CONNECTOR) {
CatalogHandle catalogHandle = catalogMetadata.get().getCatalogHandle();
ConnectorSession connectorSession = session.toConnectorSession(catalogHandle);
ConnectorMetadata metadata = catalogMetadata.get().getMetadataFor(session, catalogHandle);
return metadata.listRoleGrants(connectorSession, principal);
}
}
return systemSecurityMetadata.listRoleGrants(session, principal);
}
@Override
public void grantRoles(Session session, Set roles, Set grantees, boolean adminOption, Optional grantor, Optional catalog)
{
if (catalog.isEmpty()) {
systemSecurityMetadata.grantRoles(session, roles, grantees, adminOption, grantor);
return;
}
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, catalog.get());
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
metadata.grantRoles(session.toConnectorSession(catalogHandle), roles, grantees, adminOption, grantor);
}
@Override
public void revokeRoles(Session session, Set roles, Set grantees, boolean adminOption, Optional grantor, Optional catalog)
{
if (catalog.isEmpty()) {
systemSecurityMetadata.revokeRoles(session, roles, grantees, adminOption, grantor);
return;
}
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, catalog.get());
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
metadata.revokeRoles(session.toConnectorSession(catalogHandle), roles, grantees, adminOption, grantor);
}
@Override
public Set listApplicableRoles(Session session, TrinoPrincipal principal, Optional catalog)
{
if (catalog.isPresent()) {
Optional catalogMetadata = getOptionalCatalogMetadata(session, catalog.get());
if (catalogMetadata.isEmpty()) {
return ImmutableSet.of();
}
// If the connector is using system security management, we fall through to the system call
// instead of returning nothing, so information schema role tables will work properly
if (catalogMetadata.get().getSecurityManagement() == CONNECTOR) {
CatalogHandle catalogHandle = catalogMetadata.get().getCatalogHandle();
ConnectorSession connectorSession = session.toConnectorSession(catalogHandle);
ConnectorMetadata metadata = catalogMetadata.get().getMetadataFor(session, catalogHandle);
return ImmutableSet.copyOf(metadata.listApplicableRoles(connectorSession, principal));
}
}
return systemSecurityMetadata.listApplicableRoles(session, principal);
}
@Override
public Set listEnabledRoles(Identity identity)
{
return systemSecurityMetadata.listEnabledRoles(identity);
}
@Override
public Set listEnabledRoles(Session session, String catalog)
{
Optional catalogMetadata = getOptionalCatalogMetadata(session, catalog);
if (catalogMetadata.isEmpty()) {
return ImmutableSet.of();
}
// If the connector is using system security management, we fall through to the system call
// instead of returning nothing, so information schema role tables will work properly
if (catalogMetadata.get().getSecurityManagement() == SYSTEM) {
return systemSecurityMetadata.listEnabledRoles(session.getIdentity());
}
CatalogHandle catalogHandle = catalogMetadata.get().getCatalogHandle();
ConnectorSession connectorSession = session.toConnectorSession(catalogHandle);
ConnectorMetadata metadata = catalogMetadata.get().getMetadataFor(session, catalogHandle);
return ImmutableSet.copyOf(metadata.listEnabledRoles(connectorSession));
}
@Override
public void grantTablePrivileges(Session session, QualifiedObjectName tableName, Set privileges, TrinoPrincipal grantee, boolean grantOption)
{
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, tableName.catalogName());
if (catalogMetadata.getSecurityManagement() == SYSTEM) {
systemSecurityMetadata.grantTablePrivileges(session, tableName, privileges, grantee, grantOption);
return;
}
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
metadata.grantTablePrivileges(session.toConnectorSession(catalogHandle), tableName.asSchemaTableName(), privileges, grantee, grantOption);
}
@Override
public void denyTablePrivileges(Session session, QualifiedObjectName tableName, Set privileges, TrinoPrincipal grantee)
{
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, tableName.catalogName());
if (catalogMetadata.getSecurityManagement() == SYSTEM) {
systemSecurityMetadata.denyTablePrivileges(session, tableName, privileges, grantee);
return;
}
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
metadata.denyTablePrivileges(session.toConnectorSession(catalogHandle), tableName.asSchemaTableName(), privileges, grantee);
}
@Override
public void revokeTablePrivileges(Session session, QualifiedObjectName tableName, Set privileges, TrinoPrincipal grantee, boolean grantOption)
{
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, tableName.catalogName());
if (catalogMetadata.getSecurityManagement() == SYSTEM) {
systemSecurityMetadata.revokeTablePrivileges(session, tableName, privileges, grantee, grantOption);
return;
}
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
metadata.revokeTablePrivileges(session.toConnectorSession(catalogHandle), tableName.asSchemaTableName(), privileges, grantee, grantOption);
}
@Override
public void grantSchemaPrivileges(Session session, CatalogSchemaName schemaName, Set privileges, TrinoPrincipal grantee, boolean grantOption)
{
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, schemaName.getCatalogName());
if (catalogMetadata.getSecurityManagement() == SYSTEM) {
systemSecurityMetadata.grantSchemaPrivileges(session, schemaName, privileges, grantee, grantOption);
return;
}
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
metadata.grantSchemaPrivileges(session.toConnectorSession(catalogHandle), schemaName.getSchemaName(), privileges, grantee, grantOption);
}
@Override
public void denySchemaPrivileges(Session session, CatalogSchemaName schemaName, Set privileges, TrinoPrincipal grantee)
{
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, schemaName.getCatalogName());
if (catalogMetadata.getSecurityManagement() == SYSTEM) {
systemSecurityMetadata.denySchemaPrivileges(session, schemaName, privileges, grantee);
return;
}
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
metadata.denySchemaPrivileges(session.toConnectorSession(catalogHandle), schemaName.getSchemaName(), privileges, grantee);
}
@Override
public void revokeSchemaPrivileges(Session session, CatalogSchemaName schemaName, Set privileges, TrinoPrincipal grantee, boolean grantOption)
{
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, schemaName.getCatalogName());
if (catalogMetadata.getSecurityManagement() == SYSTEM) {
systemSecurityMetadata.revokeSchemaPrivileges(session, schemaName, privileges, grantee, grantOption);
return;
}
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
metadata.revokeSchemaPrivileges(session.toConnectorSession(catalogHandle), schemaName.getSchemaName(), privileges, grantee, grantOption);
}
// TODO support table redirection
@Override
public List listTablePrivileges(Session session, QualifiedTablePrefix prefix)
{
requireNonNull(prefix, "prefix is null");
Optional catalog = getOptionalCatalogMetadata(session, prefix.getCatalogName());
ImmutableSet.Builder grantInfos = ImmutableSet.builder();
if (catalog.isPresent()) {
CatalogMetadata catalogMetadata = catalog.get();
ConnectorSession connectorSession = session.toConnectorSession(catalogMetadata.getCatalogHandle());
List catalogHandles = prefix.asQualifiedObjectName()
.map(qualifiedTableName -> singletonList(catalogMetadata.getCatalogHandle(session, qualifiedTableName, Optional.empty(), Optional.empty())))
.orElseGet(catalogMetadata::listCatalogHandles);
for (CatalogHandle catalogHandle : catalogHandles) {
ConnectorMetadata metadata = catalogMetadata.getMetadataFor(session, catalogHandle);
if (catalogMetadata.getSecurityManagement() == SYSTEM) {
grantInfos.addAll(systemSecurityMetadata.listTablePrivileges(session, prefix));
}
else {
grantInfos.addAll(metadata.listTablePrivileges(connectorSession, prefix.asSchemaTablePrefix()));
}
}
}
return ImmutableList.copyOf(grantInfos.build());
}
@Override
public Set getAllEntityKindPrivileges(String entityKind)
{
requireNonNull(entityKind, "entityKind is null");
return systemSecurityMetadata.getAllEntityKindPrivileges(entityKind);
}
@Override
public void grantEntityPrivileges(Session session, EntityKindAndName entity, Set privileges, TrinoPrincipal grantee, boolean grantOption)
{
systemSecurityMetadata.grantEntityPrivileges(session, entity, privileges, grantee, grantOption);
}
@Override
public void denyEntityPrivileges(Session session, EntityKindAndName entity, Set privileges, TrinoPrincipal grantee)
{
systemSecurityMetadata.denyEntityPrivileges(session, entity, privileges, grantee);
}
@Override
public void revokeEntityPrivileges(Session session, EntityKindAndName entity, Set privileges, TrinoPrincipal grantee, boolean grantOption)
{
systemSecurityMetadata.revokeEntityPrivileges(session, entity, privileges, grantee, grantOption);
}
//
// Functions
//
@Override
public Collection listGlobalFunctions(Session session)
{
return functions.listFunctions();
}
@Override
public Collection listFunctions(Session session, CatalogSchemaName schema)
{
ImmutableList.Builder functions = ImmutableList.builder();
getOptionalCatalogMetadata(session, schema.getCatalogName()).ifPresent(catalogMetadata -> {
ConnectorSession connectorSession = session.toConnectorSession(catalogMetadata.getCatalogHandle());
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
functions.addAll(metadata.listFunctions(connectorSession, schema.getSchemaName()));
functions.addAll(languageFunctionManager.listFunctions(session, metadata.listLanguageFunctions(connectorSession, schema.getSchemaName())));
});
return functions.build();
}
@Override
public ResolvedFunction resolveBuiltinFunction(String name, List parameterTypes)
{
return functionResolver.resolveBuiltinFunction(name, parameterTypes);
}
@Override
public ResolvedFunction resolveOperator(OperatorType operatorType, List extends Type> argumentTypes)
throws OperatorNotFoundException
{
return functionResolver.resolveOperator(operatorType, argumentTypes);
}
@Override
public ResolvedFunction getCoercion(OperatorType operatorType, Type fromType, Type toType)
{
return functionResolver.resolveCoercion(operatorType, fromType, toType);
}
@Override
public ResolvedFunction getCoercion(CatalogSchemaFunctionName name, Type fromType, Type toType)
{
// coercion can only be resolved for builtin functions
if (!isBuiltinFunctionName(name)) {
throw new TrinoException(FUNCTION_IMPLEMENTATION_MISSING, format("%s not found", name));
}
return functionResolver.resolveCoercion(name.getFunctionName(), fromType, toType);
}
@Override
public FunctionDependencyDeclaration getFunctionDependencies(Session session, CatalogHandle catalogHandle, FunctionId functionId, BoundSignature boundSignature)
{
if (isTrinoSqlLanguageFunction(functionId)) {
throw new IllegalArgumentException("Function dependencies for SQL functions must be fetched directly from the language manager");
}
if (catalogHandle.equals(GlobalSystemConnector.CATALOG_HANDLE)) {
return functions.getFunctionDependencies(functionId, boundSignature);
}
ConnectorSession connectorSession = session.toConnectorSession(catalogHandle);
return getMetadata(session, catalogHandle)
.getFunctionDependencies(connectorSession, functionId, boundSignature);
}
@Override
public Collection getFunctions(Session session, CatalogSchemaFunctionName name)
{
if (isBuiltinFunctionName(name)) {
return getBuiltinFunctions(name.getFunctionName());
}
return getOptionalCatalogMetadata(session, name.getCatalogName())
.map(metadata -> getFunctions(session, metadata.getMetadata(session), metadata.getCatalogHandle(), name.getSchemaFunctionName()))
.orElse(ImmutableList.of());
}
private Collection getBuiltinFunctions(String functionName)
{
return functions.getBuiltInFunctions(functionName).stream()
.map(function -> new CatalogFunctionMetadata(GlobalSystemConnector.CATALOG_HANDLE, BUILTIN_SCHEMA, function))
.collect(toImmutableList());
}
private List getFunctions(Session session, ConnectorMetadata metadata, CatalogHandle catalogHandle, SchemaFunctionName name)
{
ConnectorSession connectorSession = session.toConnectorSession(catalogHandle);
ImmutableList.Builder functions = ImmutableList.builder();
metadata.getFunctions(connectorSession, name).stream()
.map(function -> new CatalogFunctionMetadata(catalogHandle, name.getSchemaName(), function))
.forEach(functions::add);
RunAsIdentityLoader identityLoader = owner -> {
CatalogSchemaFunctionName functionName = new CatalogSchemaFunctionName(catalogHandle.getCatalogName().toString(), name);
Optional systemIdentity = Optional.empty();
if (getCatalogMetadata(session, catalogHandle).getSecurityManagement() == SYSTEM) {
systemIdentity = systemSecurityMetadata.getFunctionRunAsIdentity(session, functionName);
}
return systemIdentity.or(() -> owner.map(Identity::ofUser))
.orElseThrow(() -> new TrinoException(NOT_SUPPORTED, "No identity for SECURITY DEFINER function: " + functionName));
};
languageFunctionManager.getFunctions(session, catalogHandle, name, metadata::getLanguageFunctions, identityLoader).stream()
.map(function -> new CatalogFunctionMetadata(catalogHandle, name.getSchemaName(), function))
.forEach(functions::add);
return functions.build();
}
@Override
public AggregationFunctionMetadata getAggregationFunctionMetadata(Session session, ResolvedFunction resolvedFunction)
{
Signature functionSignature;
AggregationFunctionMetadata aggregationFunctionMetadata;
if (resolvedFunction.catalogHandle().equals(GlobalSystemConnector.CATALOG_HANDLE)) {
functionSignature = functions.getFunctionMetadata(resolvedFunction.functionId()).getSignature();
aggregationFunctionMetadata = functions.getAggregationFunctionMetadata(resolvedFunction.functionId());
}
else {
ConnectorSession connectorSession = session.toConnectorSession(resolvedFunction.catalogHandle());
ConnectorMetadata metadata = getMetadata(session, resolvedFunction.catalogHandle());
functionSignature = metadata.getFunctionMetadata(connectorSession, resolvedFunction.functionId()).getSignature();
aggregationFunctionMetadata = metadata.getAggregationFunctionMetadata(connectorSession, resolvedFunction.functionId());
}
AggregationFunctionMetadataBuilder builder = AggregationFunctionMetadata.builder();
if (aggregationFunctionMetadata.isOrderSensitive()) {
builder.orderSensitive();
}
if (!aggregationFunctionMetadata.getIntermediateTypes().isEmpty()) {
FunctionBinding functionBinding = toFunctionBinding(resolvedFunction.functionId(), resolvedFunction.signature(), functionSignature);
aggregationFunctionMetadata.getIntermediateTypes().stream()
.map(typeSignature -> applyBoundVariables(typeSignature, functionBinding))
.forEach(builder::intermediateType);
}
return builder.build();
}
@Override
public Collection getLanguageFunctions(Session session, QualifiedObjectName name)
{
CatalogMetadata catalogMetadata = getRequiredCatalogMetadata(session, name.catalogName());
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
return metadata.getLanguageFunctions(session.toConnectorSession(catalogHandle), name.asSchemaFunctionName());
}
@Override
public boolean languageFunctionExists(Session session, QualifiedObjectName name, String signatureToken)
{
return getOptionalCatalogMetadata(session, name.catalogName())
.map(catalogMetadata -> {
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
ConnectorSession connectorSession = session.toConnectorSession(catalogMetadata.getCatalogHandle());
return metadata.languageFunctionExists(connectorSession, name.asSchemaFunctionName(), signatureToken);
})
.orElse(false);
}
@Override
public void createLanguageFunction(Session session, QualifiedObjectName name, LanguageFunction function, boolean replace)
{
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, name.catalogName());
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
metadata.createLanguageFunction(session.toConnectorSession(catalogHandle), name.asSchemaFunctionName(), function, replace);
}
@Override
public void dropLanguageFunction(Session session, QualifiedObjectName name, String signatureToken)
{
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, name.catalogName());
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
metadata.dropLanguageFunction(session.toConnectorSession(catalogHandle), name.asSchemaFunctionName(), signatureToken);
}
@VisibleForTesting
public static FunctionBinding toFunctionBinding(FunctionId functionId, BoundSignature boundSignature, Signature functionSignature)
{
return SignatureBinder.bindFunction(
functionId,
functionSignature,
boundSignature);
}
//
// Helpers
//
private Optional getOptionalCatalogMetadata(Session session, String catalogName)
{
Optional optionalCatalogMetadata = transactionManager.getOptionalCatalogMetadata(session.getRequiredTransactionId(), catalogName);
optionalCatalogMetadata.ifPresent(catalogMetadata -> registerCatalogForQuery(session, catalogMetadata));
return optionalCatalogMetadata;
}
private CatalogMetadata getRequiredCatalogMetadata(Session session, String catalogName)
{
CatalogMetadata catalogMetadata = transactionManager.getRequiredCatalogMetadata(session.getRequiredTransactionId(), catalogName);
registerCatalogForQuery(session, catalogMetadata);
return catalogMetadata;
}
private CatalogMetadata getCatalogMetadata(Session session, CatalogHandle catalogHandle)
{
CatalogMetadata catalogMetadata = transactionManager.getCatalogMetadata(session.getRequiredTransactionId(), catalogHandle);
registerCatalogForQuery(session, catalogMetadata);
return catalogMetadata;
}
private CatalogMetadata getCatalogMetadataForWrite(Session session, String catalogName)
{
CatalogMetadata catalogMetadata = transactionManager.getCatalogMetadataForWrite(session.getRequiredTransactionId(), catalogName);
registerCatalogForQuery(session, catalogMetadata);
return catalogMetadata;
}
private CatalogMetadata getCatalogMetadataForWrite(Session session, CatalogHandle catalogHandle)
{
CatalogMetadata catalogMetadata = transactionManager.getCatalogMetadataForWrite(session.getRequiredTransactionId(), catalogHandle);
registerCatalogForQuery(session, catalogMetadata);
return catalogMetadata;
}
private ConnectorMetadata getMetadata(Session session, CatalogHandle catalogHandle)
{
return getCatalogMetadata(session, catalogHandle).getMetadataFor(session, catalogHandle);
}
private ConnectorMetadata getMetadataForWrite(Session session, CatalogHandle catalogHandle)
{
return getCatalogMetadataForWrite(session, catalogHandle).getMetadata(session);
}
private void registerCatalogForQuery(Session session, CatalogMetadata catalogMetadata)
{
catalogsByQueryId.computeIfAbsent(session.getQueryId(), queryId -> new QueryCatalogs(session))
.registerCatalog(catalogMetadata);
}
@VisibleForTesting
public Set getActiveQueryIds()
{
return ImmutableSet.copyOf(catalogsByQueryId.keySet());
}
private static class QueryCatalogs
{
private final Session session;
@GuardedBy("this")
private final Map catalogs = new HashMap<>();
@GuardedBy("this")
private boolean finished;
public QueryCatalogs(Session session)
{
this.session = requireNonNull(session, "session is null");
}
private synchronized void registerCatalog(CatalogMetadata catalogMetadata)
{
checkState(!finished, "Query is already finished");
if (catalogs.putIfAbsent(catalogMetadata.getCatalogHandle(), catalogMetadata) == null) {
ConnectorSession connectorSession = session.toConnectorSession(catalogMetadata.getCatalogHandle());
catalogMetadata.getMetadata(session).beginQuery(connectorSession);
}
}
private void finish()
{
List catalogs;
synchronized (this) {
checkState(!finished, "Query is already finished");
finished = true;
catalogs = new ArrayList<>(this.catalogs.values());
}
for (CatalogMetadata catalogMetadata : catalogs) {
ConnectorSession connectorSession = session.toConnectorSession(catalogMetadata.getCatalogHandle());
catalogMetadata.getMetadata(session).cleanupQuery(connectorSession);
}
}
}
@Override
public OptionalInt getMaxWriterTasks(Session session, String catalogName)
{
Optional catalog = getOptionalCatalogMetadata(session, catalogName);
if (catalog.isEmpty()) {
return OptionalInt.empty();
}
CatalogMetadata catalogMetadata = catalog.get();
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
return catalogMetadata.getMetadata(session).getMaxWriterTasks(session.toConnectorSession(catalogHandle));
}
@Override
public boolean allowSplittingReadIntoMultipleSubQueries(Session session, TableHandle tableHandle)
{
CatalogHandle catalogHandle = tableHandle.catalogHandle();
if (catalogHandle.getType().isInternal()) {
return false;
}
CatalogMetadata catalogMetadata = getCatalogMetadata(session, catalogHandle);
ConnectorSession connectorSession = session.toConnectorSession(catalogHandle);
return catalogMetadata.getMetadata(session).allowSplittingReadIntoMultipleSubQueries(connectorSession, tableHandle.connectorHandle());
}
@Override
public WriterScalingOptions getNewTableWriterScalingOptions(Session session, QualifiedObjectName tableName, Map tableProperties)
{
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, tableName.catalogName());
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle(session, tableName, Optional.empty(), Optional.empty());
ConnectorMetadata metadata = catalogMetadata.getMetadataFor(session, catalogHandle);
return metadata.getNewTableWriterScalingOptions(session.toConnectorSession(catalogHandle), tableName.asSchemaTableName(), tableProperties);
}
@Override
public WriterScalingOptions getInsertWriterScalingOptions(Session session, TableHandle tableHandle)
{
ConnectorMetadata metadata = getMetadataForWrite(session, tableHandle.catalogHandle());
return metadata.getInsertWriterScalingOptions(session.toConnectorSession(tableHandle.catalogHandle()), tableHandle.connectorHandle());
}
private Optional toConnectorVersion(Optional version)
{
Optional connectorVersion = Optional.empty();
if (version.isPresent()) {
connectorVersion = Optional.of(new ConnectorTableVersion(version.get().pointerType(), version.get().objectType(), version.get().pointer()));
}
return connectorVersion;
}
private static boolean cannotExist(QualifiedTablePrefix prefix)
{
return prefix.getCatalogName().isEmpty() ||
(prefix.getSchemaName().isPresent() && prefix.getSchemaName().get().isEmpty()) ||
(prefix.getTableName().isPresent() && prefix.getTableName().get().isEmpty());
}
private static boolean cannotExist(QualifiedObjectName name)
{
return name.catalogName().isEmpty() || name.schemaName().isEmpty() || name.objectName().isEmpty();
}
public static MetadataManager createTestMetadataManager()
{
return testMetadataManagerBuilder().build();
}
public static TestMetadataManagerBuilder testMetadataManagerBuilder()
{
return new TestMetadataManagerBuilder();
}
public static class TestMetadataManagerBuilder
{
private TransactionManager transactionManager;
private TypeManager typeManager = TESTING_TYPE_MANAGER;
private GlobalFunctionCatalog globalFunctionCatalog;
private LanguageFunctionManager languageFunctionManager;
private TestMetadataManagerBuilder() {}
public TestMetadataManagerBuilder withTransactionManager(TransactionManager transactionManager)
{
this.transactionManager = transactionManager;
return this;
}
public TestMetadataManagerBuilder withTypeManager(TypeManager typeManager)
{
this.typeManager = requireNonNull(typeManager, "typeManager is null");
return this;
}
public TestMetadataManagerBuilder withGlobalFunctionCatalog(GlobalFunctionCatalog globalFunctionCatalog)
{
this.globalFunctionCatalog = globalFunctionCatalog;
return this;
}
public TestMetadataManagerBuilder withLanguageFunctionManager(LanguageFunctionManager languageFunctionManager)
{
this.languageFunctionManager = languageFunctionManager;
return this;
}
public MetadataManager build()
{
TransactionManager transactionManager = this.transactionManager;
if (transactionManager == null) {
transactionManager = createTestTransactionManager();
}
GlobalFunctionCatalog globalFunctionCatalog = this.globalFunctionCatalog;
if (globalFunctionCatalog == null) {
globalFunctionCatalog = new GlobalFunctionCatalog(
() -> { throw new UnsupportedOperationException(); },
() -> { throw new UnsupportedOperationException(); },
() -> { throw new UnsupportedOperationException(); });
TypeOperators typeOperators = new TypeOperators();
globalFunctionCatalog.addFunctions(SystemFunctionBundle.create(new FeaturesConfig(), typeOperators, new BlockTypeOperators(typeOperators), UNKNOWN));
}
if (languageFunctionManager == null) {
BlockEncodingSerde blockEncodingSerde = new InternalBlockEncodingSerde(new BlockEncodingManager(), typeManager);
languageFunctionManager = new LanguageFunctionManager(new SqlParser(), typeManager, user -> ImmutableSet.of(), blockEncodingSerde);
}
return new MetadataManager(
new AllowAllAccessControl(),
new DisabledSystemSecurityMetadata(),
transactionManager,
globalFunctionCatalog,
languageFunctionManager,
typeManager);
}
}
}