All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.trino.spi.connector.ConnectorMetadata Maven / Gradle / Ivy

There is a newer version: 468
Show newest version
/*
 * 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.spi.connector;

import io.airlift.slice.Slice;
import io.trino.spi.TrinoException;
import io.trino.spi.expression.ConnectorExpression;
import io.trino.spi.expression.Constant;
import io.trino.spi.expression.Variable;
import io.trino.spi.predicate.TupleDomain;
import io.trino.spi.security.GrantInfo;
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 javax.annotation.Nullable;

import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.OptionalLong;
import java.util.Set;
import java.util.stream.Collectors;

import static io.trino.spi.StandardErrorCode.GENERIC_INTERNAL_ERROR;
import static io.trino.spi.StandardErrorCode.NOT_SUPPORTED;
import static java.lang.String.format;
import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap;
import static java.util.stream.Collectors.toList;

public interface ConnectorMetadata
{
    /**
     * Checks if a schema exists. The connector may have schemas that exist
     * but are not enumerable via {@link #listSchemaNames}.
     */
    default boolean schemaExists(ConnectorSession session, String schemaName)
    {
        return listSchemaNames(session).contains(schemaName);
    }

    /**
     * Returns the schemas provided by this connector.
     */
    default List listSchemaNames(ConnectorSession session)
    {
        return emptyList();
    }

    /**
     * Returns a table handle for the specified table name, or null if the connector does not contain the table.
     */
    @Nullable
    default ConnectorTableHandle getTableHandle(ConnectorSession session, SchemaTableName tableName)
    {
        return null;
    }

    /**
     * Returns a table handle for the specified table name, or null if the connector does not contain the table.
     * The returned table handle can contain information in analyzeProperties.
     */
    @Nullable
    default ConnectorTableHandle getTableHandleForStatisticsCollection(ConnectorSession session, SchemaTableName tableName, Map analyzeProperties)
    {
        throw new TrinoException(NOT_SUPPORTED, "This connector does not support analyze");
    }

    /**
     * Returns the system table for the specified table name, if one exists.
     * The system tables handled via {@link #getSystemTable} differ form those returned by {@link Connector#getSystemTables()}.
     * The former mechanism allows dynamic resolution of system tables, while the latter is
     * based on static list of system tables built during startup.
     */
    default Optional getSystemTable(ConnectorSession session, SchemaTableName tableName)
    {
        return Optional.empty();
    }

    /**
     * Return a list of table layouts that satisfy the given constraint.
     * 

* For each layout, connectors must return an "unenforced constraint" representing the part of the constraint summary that isn't guaranteed by the layout. */ @Deprecated default List getTableLayouts( ConnectorSession session, ConnectorTableHandle table, Constraint constraint, Optional> desiredColumns) { if (usesLegacyTableLayouts()) { throw new IllegalStateException("Connector uses legacy Table Layout but doesn't implement getTableLayouts()"); } throw new UnsupportedOperationException("Not yet implemented"); } @Deprecated default ConnectorTableLayout getTableLayout(ConnectorSession session, ConnectorTableLayoutHandle handle) { if (usesLegacyTableLayouts()) { throw new IllegalStateException("Connector uses legacy Table Layout but doesn't implement getTableLayout()"); } throw new UnsupportedOperationException("Not yet implemented"); } /** * Return a table layout handle whose partitioning is converted to the provided partitioning handle, * but otherwise identical to the provided table layout handle. * The provided table layout handle must be one that the connector can transparently convert to from * the original partitioning handle associated with the provided table layout handle, * as promised by {@link #getCommonPartitioningHandle}. * * @deprecated use the version without layouts */ @Deprecated default ConnectorTableLayoutHandle makeCompatiblePartitioning(ConnectorSession session, ConnectorTableLayoutHandle tableLayoutHandle, ConnectorPartitioningHandle partitioningHandle) { throw new TrinoException(GENERIC_INTERNAL_ERROR, "ConnectorMetadata getCommonPartitioningHandle() is implemented without makeCompatiblePartitioning()"); } /** * Return a table handle whose partitioning is converted to the provided partitioning handle, * but otherwise identical to the provided table handle. * The provided table handle must be one that the connector can transparently convert to from * the original partitioning handle associated with the provided table handle, * as promised by {@link #getCommonPartitioningHandle}. */ default ConnectorTableHandle makeCompatiblePartitioning(ConnectorSession session, ConnectorTableHandle tableHandle, ConnectorPartitioningHandle partitioningHandle) { throw new TrinoException(GENERIC_INTERNAL_ERROR, "ConnectorMetadata getCommonPartitioningHandle() is implemented without makeCompatiblePartitioning()"); } /** * Return a partitioning handle which the connector can transparently convert both {@code left} and {@code right} into. */ default Optional getCommonPartitioningHandle(ConnectorSession session, ConnectorPartitioningHandle left, ConnectorPartitioningHandle right) { if (left.equals(right)) { return Optional.of(left); } return Optional.empty(); } /** * Return the metadata for the specified table handle. * * @throws RuntimeException if table handle is no longer valid */ default ConnectorTableMetadata getTableMetadata(ConnectorSession session, ConnectorTableHandle table) { throw new TrinoException(GENERIC_INTERNAL_ERROR, "ConnectorMetadata getTableHandle() is implemented without getTableMetadata()"); } /** * Return the connector-specific metadata for the specified table layout. This is the object that is passed to the event listener framework. * * @throws RuntimeException if table handle is no longer valid */ @Deprecated default Optional getInfo(ConnectorTableLayoutHandle layoutHandle) { return Optional.empty(); } default Optional getInfo(ConnectorTableHandle table) { return Optional.empty(); } /** * List table and view names, possibly filtered by schema. An empty list is returned if none match. */ default List listTables(ConnectorSession session, Optional schemaName) { return emptyList(); } /** * Gets all of the columns on the specified table, or an empty map if the columns cannot be enumerated. * * @throws RuntimeException if table handle is no longer valid */ default Map getColumnHandles(ConnectorSession session, ConnectorTableHandle tableHandle) { throw new TrinoException(GENERIC_INTERNAL_ERROR, "ConnectorMetadata getTableHandle() is implemented without getColumnHandles()"); } /** * Gets the metadata for the specified table column. * * @throws RuntimeException if table or column handles are no longer valid */ default ColumnMetadata getColumnMetadata(ConnectorSession session, ConnectorTableHandle tableHandle, ColumnHandle columnHandle) { throw new TrinoException(GENERIC_INTERNAL_ERROR, "ConnectorMetadata getTableHandle() is implemented without getColumnMetadata()"); } /** * Gets the metadata for all columns that match the specified table prefix. */ default Map> listTableColumns(ConnectorSession session, SchemaTablePrefix prefix) { return emptyMap(); } /** * Get statistics for table for given filtering constraint. */ default TableStatistics getTableStatistics(ConnectorSession session, ConnectorTableHandle tableHandle, Constraint constraint) { return TableStatistics.empty(); } /** * Creates a schema. */ default void createSchema(ConnectorSession session, String schemaName, Map properties, TrinoPrincipal owner) { throw new TrinoException(NOT_SUPPORTED, "This connector does not support creating schemas"); } /** * Drops the specified schema. * * @throws TrinoException with {@code SCHEMA_NOT_EMPTY} if the schema is not empty */ default void dropSchema(ConnectorSession session, String schemaName) { throw new TrinoException(NOT_SUPPORTED, "This connector does not support dropping schemas"); } /** * Renames the specified schema. */ default void renameSchema(ConnectorSession session, String source, String target) { throw new TrinoException(NOT_SUPPORTED, "This connector does not support renaming schemas"); } /** * Sets the user/role on the specified schema. */ default void setSchemaAuthorization(ConnectorSession session, String source, TrinoPrincipal principal) { throw new TrinoException(NOT_SUPPORTED, "This connector does not support setting an owner on a schema"); } /** * Creates a table using the specified table metadata. * * @throws TrinoException with {@code ALREADY_EXISTS} if the table already exists and {@param ignoreExisting} is not set */ default void createTable(ConnectorSession session, ConnectorTableMetadata tableMetadata, boolean ignoreExisting) { throw new TrinoException(NOT_SUPPORTED, "This connector does not support creating tables"); } /** * Drops the specified table * * @throws RuntimeException if the table cannot be dropped or table handle is no longer valid */ default void dropTable(ConnectorSession session, ConnectorTableHandle tableHandle) { throw new TrinoException(NOT_SUPPORTED, "This connector does not support dropping tables"); } /** * Rename the specified table */ default void renameTable(ConnectorSession session, ConnectorTableHandle tableHandle, SchemaTableName newTableName) { throw new TrinoException(NOT_SUPPORTED, "This connector does not support renaming tables"); } /** * Comments to the specified table */ default void setTableComment(ConnectorSession session, ConnectorTableHandle tableHandle, Optional comment) { throw new TrinoException(NOT_SUPPORTED, "This connector does not support setting table comments"); } /** * Comments to the specified column */ default void setColumnComment(ConnectorSession session, ConnectorTableHandle tableHandle, ColumnHandle column, Optional comment) { throw new TrinoException(NOT_SUPPORTED, "This connector does not support setting column comments"); } /** * Add the specified column */ default void addColumn(ConnectorSession session, ConnectorTableHandle tableHandle, ColumnMetadata column) { throw new TrinoException(NOT_SUPPORTED, "This connector does not support adding columns"); } /** * Sets the user/role on the specified table. */ default void setTableAuthorization(ConnectorSession session, SchemaTableName tableName, TrinoPrincipal principal) { throw new TrinoException(NOT_SUPPORTED, "This connector does not support setting an owner on a table"); } /** * Rename the specified column */ default void renameColumn(ConnectorSession session, ConnectorTableHandle tableHandle, ColumnHandle source, String target) { throw new TrinoException(NOT_SUPPORTED, "This connector does not support renaming columns"); } /** * Drop the specified column */ default void dropColumn(ConnectorSession session, ConnectorTableHandle tableHandle, ColumnHandle column) { throw new TrinoException(NOT_SUPPORTED, "This connector does not support dropping columns"); } /** * Get the physical layout for a new table. */ default Optional getNewTableLayout(ConnectorSession session, ConnectorTableMetadata tableMetadata) { return Optional.empty(); } /** * Get the physical layout for a inserting into an existing table. */ default Optional getInsertLayout(ConnectorSession session, ConnectorTableHandle tableHandle) { ConnectorTableProperties properties = getTableProperties(session, tableHandle); return properties.getTablePartitioning() .map(partitioning -> { Map columnNamesByHandle = getColumnHandles(session, tableHandle).entrySet().stream() .collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey)); List partitionColumns = partitioning.getPartitioningColumns().stream() .map(columnNamesByHandle::get) .collect(toList()); return new ConnectorNewTableLayout(partitioning.getPartitioningHandle(), partitionColumns); }); } /** * Describes statistics that must be collected during a write. */ default TableStatisticsMetadata getStatisticsCollectionMetadataForWrite(ConnectorSession session, ConnectorTableMetadata tableMetadata) { return TableStatisticsMetadata.empty(); } /** * Describe statistics that must be collected during a statistics collection */ default TableStatisticsMetadata getStatisticsCollectionMetadata(ConnectorSession session, ConnectorTableMetadata tableMetadata) { throw new TrinoException(GENERIC_INTERNAL_ERROR, "ConnectorMetadata getTableHandleForStatisticsCollection() is implemented without getStatisticsCollectionMetadata()"); } /** * Begin statistics collection */ default ConnectorTableHandle beginStatisticsCollection(ConnectorSession session, ConnectorTableHandle tableHandle) { throw new TrinoException(GENERIC_INTERNAL_ERROR, "ConnectorMetadata getStatisticsCollectionMetadata() is implemented without beginStatisticsCollection()"); } /** * Finish statistics collection */ default void finishStatisticsCollection(ConnectorSession session, ConnectorTableHandle tableHandle, Collection computedStatistics) { throw new TrinoException(GENERIC_INTERNAL_ERROR, "ConnectorMetadata beginStatisticsCollection() is implemented without finishStatisticsCollection()"); } /** * Begin the atomic creation of a table with data. */ default ConnectorOutputTableHandle beginCreateTable(ConnectorSession session, ConnectorTableMetadata tableMetadata, Optional layout) { throw new TrinoException(NOT_SUPPORTED, "This connector does not support creating tables with data"); } /** * Finish a table creation with data after the data is written. */ default Optional finishCreateTable(ConnectorSession session, ConnectorOutputTableHandle tableHandle, Collection fragments, Collection computedStatistics) { throw new TrinoException(GENERIC_INTERNAL_ERROR, "ConnectorMetadata beginCreateTable() is implemented without finishCreateTable()"); } /** * Start a query. This notification is triggered before any other metadata access. */ default void beginQuery(ConnectorSession session) {} /** * Cleanup after a query. This is the very last notification after the query finishes, whether it succeeds or fails. * An exception thrown in this method will not affect the result of the query. */ default void cleanupQuery(ConnectorSession session) {} /** * @deprecated Use {@link #beginInsert(ConnectorSession, ConnectorTableHandle, List)} instead. */ @Deprecated default ConnectorInsertTableHandle beginInsert(ConnectorSession session, ConnectorTableHandle tableHandle) { throw new TrinoException(NOT_SUPPORTED, "This connector does not support inserts"); } /** * Begin insert query */ default ConnectorInsertTableHandle beginInsert(ConnectorSession session, ConnectorTableHandle tableHandle, List columns) { return beginInsert(session, tableHandle); } /** * @return whether connector handles missing columns during insert */ default boolean supportsMissingColumnsOnInsert() { return false; } /** * Finish insert query */ default Optional finishInsert(ConnectorSession session, ConnectorInsertTableHandle insertHandle, Collection fragments, Collection computedStatistics) { throw new TrinoException(GENERIC_INTERNAL_ERROR, "ConnectorMetadata beginInsert() is implemented without finishInsert()"); } /** * Begin materialized view query */ default ConnectorInsertTableHandle beginRefreshMaterializedView(ConnectorSession session, ConnectorTableHandle tableHandle, List sourceTableHandles) { throw new TrinoException(NOT_SUPPORTED, "This connector does not support materialized views"); } /** * Finish materialized view query */ default Optional finishRefreshMaterializedView( ConnectorSession session, ConnectorTableHandle tableHandle, ConnectorInsertTableHandle insertHandle, Collection fragments, Collection computedStatistics, List sourceTableHandles) { throw new TrinoException(GENERIC_INTERNAL_ERROR, "ConnectorMetadata beginRefreshMaterializedView() is implemented without finishRefreshMaterializedView()"); } /** * Get the column handle that will generate row IDs for the delete operation. * These IDs will be passed to the {@code deleteRows()} method of the * {@link io.trino.spi.connector.UpdatablePageSource} that created them. */ default ColumnHandle getUpdateRowIdColumnHandle(ConnectorSession session, ConnectorTableHandle tableHandle) { throw new TrinoException(NOT_SUPPORTED, "This connector does not support updates or deletes"); } /** * Begin delete query */ default ConnectorTableHandle beginDelete(ConnectorSession session, ConnectorTableHandle tableHandle) { throw new TrinoException(NOT_SUPPORTED, "This connector does not support deletes"); } /** * Finish delete query * * @param fragments all fragments returned by {@link io.trino.spi.connector.UpdatablePageSource#finish()} */ default void finishDelete(ConnectorSession session, ConnectorTableHandle tableHandle, Collection fragments) { throw new TrinoException(NOT_SUPPORTED, "This connector does not support deletes"); } /** * Create the specified view. The view definition is intended to * be serialized by the connector for permanent storage. */ default void createView(ConnectorSession session, SchemaTableName viewName, ConnectorViewDefinition definition, boolean replace) { throw new TrinoException(NOT_SUPPORTED, "This connector does not support creating views"); } /** * Rename the specified view */ default void renameView(ConnectorSession session, SchemaTableName source, SchemaTableName target) { throw new TrinoException(NOT_SUPPORTED, "This connector does not support renaming views"); } /** * Sets the user/role on the specified view. */ default void setViewAuthorization(ConnectorSession session, SchemaTableName viewName, TrinoPrincipal principal) { throw new TrinoException(NOT_SUPPORTED, "This connector does not support setting an owner on a view"); } /** * Drop the specified view. */ default void dropView(ConnectorSession session, SchemaTableName viewName) { throw new TrinoException(NOT_SUPPORTED, "This connector does not support dropping views"); } default List listViews(ConnectorSession session, Optional schemaName) { return emptyList(); } /** * Gets the definitions of views, possibly filtered by schema. * This optional method may be implemented by connectors that can support fetching * view data in bulk. It is used to implement {@code information_schema.views}. */ default Map getViews(ConnectorSession session, Optional schemaName) { Map views = new HashMap<>(); for (SchemaTableName name : listViews(session, schemaName)) { getView(session, name).ifPresent(view -> views.put(name, view)); } return views; } /** * Gets the view data for the specified view name. */ default Optional getView(ConnectorSession session, SchemaTableName viewName) { return Optional.empty(); } /** * Gets the schema properties for the specified schema. */ default Map getSchemaProperties(ConnectorSession session, CatalogSchemaName schemaName) { throw new TrinoException(NOT_SUPPORTED, "This connector does not support schema properties"); } /** * Get the schema properties for the specified schema. */ default Optional getSchemaOwner(ConnectorSession session, CatalogSchemaName schemaName) { throw new TrinoException(NOT_SUPPORTED, "This connector does not support schema ownership"); } /** * @return whether delete without table scan is supported */ default boolean supportsMetadataDelete(ConnectorSession session, ConnectorTableHandle tableHandle, ConnectorTableLayoutHandle tableLayoutHandle) { throw new TrinoException(NOT_SUPPORTED, "This connector does not support deletes"); } /** * Delete the provided table layout * * @return number of rows deleted, or null for unknown */ default OptionalLong metadataDelete(ConnectorSession session, ConnectorTableHandle tableHandle, ConnectorTableLayoutHandle tableLayoutHandle) { throw new TrinoException(NOT_SUPPORTED, "This connector does not support deletes"); } /** * Attempt to push down a delete operation into the connector. If a connector * can execute a delete for the table handle on its own, it should return a * table handle, which will be passed back to {@link #executeDelete} during * query executing to actually execute the delete. */ default Optional applyDelete(ConnectorSession session, ConnectorTableHandle handle) { return Optional.empty(); } /** * Execute the delete operation on the handle returned from {@link #applyDelete}. */ default OptionalLong executeDelete(ConnectorSession session, ConnectorTableHandle handle) { throw new TrinoException(GENERIC_INTERNAL_ERROR, "ConnectorMetadata applyDelete() is implemented without executeDelete()"); } /** * Try to locate a table index that can lookup results by indexableColumns and provide the requested outputColumns. */ default Optional resolveIndex(ConnectorSession session, ConnectorTableHandle tableHandle, Set indexableColumns, Set outputColumns, TupleDomain tupleDomain) { return Optional.empty(); } /** * Creates the specified role. * * @param grantor represents the principal specified by WITH ADMIN statement */ default void createRole(ConnectorSession session, String role, Optional grantor) { throw new TrinoException(NOT_SUPPORTED, "This connector does not support create role"); } /** * Drops the specified role. */ default void dropRole(ConnectorSession session, String role) { throw new TrinoException(NOT_SUPPORTED, "This connector does not support drop role"); } /** * List available roles. */ default Set listRoles(ConnectorSession session) { throw new TrinoException(NOT_SUPPORTED, "This connector does not support roles"); } /** * List role grants for a given principal, not recursively. */ default Set listRoleGrants(ConnectorSession session, TrinoPrincipal principal) { throw new TrinoException(NOT_SUPPORTED, "This connector does not support roles"); } /** * List all role grants in the specified catalog, * optionally filtered by passed role, grantee, and limit predicates. */ default Set listAllRoleGrants(ConnectorSession session, Optional> roles, Optional> grantees, OptionalLong limit) { throw new TrinoException(NOT_SUPPORTED, "This connector does not support roles"); } /** * Grants the specified roles to the specified grantees * * @param grantor represents the principal specified by GRANTED BY statement */ default void grantRoles(ConnectorSession connectorSession, Set roles, Set grantees, boolean adminOption, Optional grantor) { throw new TrinoException(NOT_SUPPORTED, "This connector does not support roles"); } /** * Revokes the specified roles from the specified grantees * * @param grantor represents the principal specified by GRANTED BY statement */ default void revokeRoles(ConnectorSession connectorSession, Set roles, Set grantees, boolean adminOption, Optional grantor) { throw new TrinoException(NOT_SUPPORTED, "This connector does not support roles"); } /** * List applicable roles, including the transitive grants, for the specified principal */ default Set listApplicableRoles(ConnectorSession session, TrinoPrincipal principal) { throw new TrinoException(NOT_SUPPORTED, "This connector does not support roles"); } /** * List applicable roles, including the transitive grants, in given session */ default Set listEnabledRoles(ConnectorSession session) { throw new TrinoException(NOT_SUPPORTED, "This connector does not support roles"); } /** * Grants the specified privilege to the specified user on the specified schema */ default void grantSchemaPrivileges(ConnectorSession session, String schemaName, Set privileges, TrinoPrincipal grantee, boolean grantOption) { throw new TrinoException(NOT_SUPPORTED, "This connector does not support grants on schemas"); } /** * Revokes the specified privilege on the specified schema from the specified user */ default void revokeSchemaPrivileges(ConnectorSession session, String schemaName, Set privileges, TrinoPrincipal grantee, boolean grantOption) { throw new TrinoException(NOT_SUPPORTED, "This connector does not support revokes on schemas"); } /** * Grants the specified privilege to the specified user on the specified table */ default void grantTablePrivileges(ConnectorSession session, SchemaTableName tableName, Set privileges, TrinoPrincipal grantee, boolean grantOption) { throw new TrinoException(NOT_SUPPORTED, "This connector does not support grants on tables"); } /** * Revokes the specified privilege on the specified table from the specified user */ default void revokeTablePrivileges(ConnectorSession session, SchemaTableName tableName, Set privileges, TrinoPrincipal grantee, boolean grantOption) { throw new TrinoException(NOT_SUPPORTED, "This connector does not support revokes on tables"); } /** * List the table privileges granted to the specified grantee for the tables that have the specified prefix considering the selected session role */ default List listTablePrivileges(ConnectorSession session, SchemaTablePrefix prefix) { return emptyList(); } /** * Whether the connector uses the legacy Table Layout feature. If this method returns false, * connectors are required to implement the following methods: *
    *
  • {@link #getTableProperties(ConnectorSession session, ConnectorTableHandle table)}
  • *
  • {@link #getInfo(ConnectorTableHandle table)}
  • *
  • {@link ConnectorSplitManager#getSplits(ConnectorTransactionHandle, ConnectorSession, ConnectorTableHandle, ConnectorSplitManager.SplitSchedulingStrategy)}
  • *
*/ default boolean usesLegacyTableLayouts() { return true; } default ConnectorTableProperties getTableProperties(ConnectorSession session, ConnectorTableHandle table) { if (!usesLegacyTableLayouts()) { throw new IllegalStateException("getTableProperties() must be implemented if usesLegacyTableLayouts is false"); } List layouts = getTableLayouts(session, table, Constraint.alwaysTrue(), Optional.empty()); if (layouts.size() != 1) { throw new TrinoException(NOT_SUPPORTED, format("Connector must return a single layout for table %s, but got %s", table, layouts.size())); } return new ConnectorTableProperties(layouts.get(0).getTableLayout()); } /** * Attempt to push down the provided limit into the table. *

* Connectors can indicate whether they don't support limit pushdown or that the action had no effect * by returning {@link Optional#empty()}. Connectors should expect this method to be called multiple times * during the optimization of a given query. *

* Note: it's critical for connectors to return Optional.empty() if calling this method has no effect for that * invocation, even if the connector generally supports limit pushdown. Doing otherwise can cause the optimizer * to loop indefinitely. *

*

* If the connector could benefit from the information but can't guarantee that it will be able to produce * fewer rows than the provided limit, it should return a non-empty result containing a new handle for the * derived table and the "limit guaranteed" flag set to false. *

* If the connector can guarantee it will produce fewer rows than the provided limit, it should return a * non-empty result with the "limit guaranteed" flag set to true. */ default Optional> applyLimit(ConnectorSession session, ConnectorTableHandle handle, long limit) { return Optional.empty(); } /** * Attempt to push down the provided constraint into the table. This method is provided as replacement to * {@link ConnectorMetadata#getTableLayouts(ConnectorSession, ConnectorTableHandle, Constraint, Optional)} to ease * migration for the legacy API. *

* Connectors can indicate whether they don't support predicate pushdown or that the action had no effect * by returning {@link Optional#empty()}. Connectors should expect this method to be called multiple times * during the optimization of a given query. *

* Note: it's critical for connectors to return Optional.empty() if calling this method has no effect for that * invocation, even if the connector generally supports pushdown. Doing otherwise can cause the optimizer * to loop indefinitely. *

*/ default Optional> applyFilter(ConnectorSession session, ConnectorTableHandle handle, Constraint constraint) { return Optional.empty(); } /** * Attempt to push down the provided projections into the table. *

* Connectors can indicate whether they don't support projection pushdown or that the action had no effect * by returning {@link Optional#empty()}. Connectors should expect this method to be called multiple times * during the optimization of a given query. *

* Note: it's critical for connectors to return Optional.empty() if calling this method has no effect for that * invocation, even if the connector generally supports pushdown. Doing otherwise can cause the optimizer * to loop indefinitely. *

*

* If the method returns a result, the list of projections in the result *replaces* the existing ones, and the * list of assignments is the new set of columns exposed by the derived table. *

* As an example, given the following plan: * *

     * - project
     *     x = f1(a, b)
     *     y = f2(a, b)
     *     z = f3(a, b)
     *   - scan (TH0)
     *       a = CH0
     *       b = CH1
     *       c = CH2
     * 
*

* The optimizer would call {@link #applyProjection} with the following arguments: * *

     * handle = TH0
     * projections = [
     *     f1(a, b)
     *     f2(a, b)
     *     f3(a, b)
     * ]
     * assignments = [
     *     a = CH0
     *     b = CH1
     *     c = CH2
     * ]
     * 
*

* Assuming the connector knows how to handle f1(...) and f2(...), it would return: * *

     * handle = TH1
     * projections = [
     *     v2
     *     v3
     *     f3(v0, v1)
     * ]
     * assignments = [
     *     v0 = CH0
     *     v1 = CH1
     *     v2 = CH3  (synthetic column for f1(CH0, CH1))
     *     v3 = CH4  (synthetic column for f2(CH0, CH1))
     * ]
     * 
*/ default Optional> applyProjection(ConnectorSession session, ConnectorTableHandle handle, List projections, Map assignments) { return Optional.empty(); } /** * Attempt to push down the sampling into the table. *

* Connectors can indicate whether they don't support sample pushdown or that the action had no effect * by returning {@link Optional#empty()}. Connectors should expect this method to be called multiple times * during the optimization of a given query. *

* Note: it's critical for connectors to return Optional.empty() if calling this method has no effect for that * invocation, even if the connector generally supports sample pushdown. Doing otherwise can cause the optimizer * to loop indefinitely. *

*/ default Optional applySample(ConnectorSession session, ConnectorTableHandle handle, SampleType sampleType, double sampleRatio) { return Optional.empty(); } /** * Attempt to push down the aggregates into the table. *

* Connectors can indicate whether they don't support aggregate pushdown or that the action had no effect * by returning {@link Optional#empty()}. Connectors should expect this method may be called multiple times. *

* Note: it's critical for connectors to return {@link Optional#empty()} if calling this method has no effect for that * invocation, even if the connector generally supports pushdown. Doing otherwise can cause the optimizer * to loop indefinitely. *

* If the method returns a result, the list of assignments in the result will be merged with existing assignments. The projections * returned by the method must have the same order as the given input list of aggregates. *

* As an example, given the following plan: * *
     *  - aggregation  (GROUP BY c)
     *          variable0 = agg_fn1(a)
     *          variable1 = agg_fn2(b, 2)
     *          variable2 = c
     *          - scan (TH0)
     *              a = CH0
     *              b = CH1
     *              c = CH2
     * 
*

* The optimizer would call this method with the following arguments: * *

     *      handle = TH0
     *      aggregates = [
     *              { functionName=agg_fn1, outputType = «some Trino type» inputs = [{@link Variable} a]} ,
     *              { functionName=agg_fn2, outputType = «some Trino type» inputs = [{@link Variable} b, {@link Constant} 2]}
     *      ]
     *      groupingSets=[[{@link ColumnHandle} CH2]]
     *      assignments = {a = CH0, b = CH1, c = CH2}
     * 
*

* * Assuming the connector knows how to handle {@code agg_fn1(...)} and {@code agg_fn2(...)}, it would return: *
     *
     * {@link AggregationApplicationResult} {
     *      handle = TH1
     *      projections = [{@link Variable} synthetic_name0, {@link Variable} synthetic_name1] -- The order in the list must be same as input list of aggregates
     *      assignments = {
     *          synthetic_name0 = CH3 (synthetic column for agg_fn1(a))
     *          synthetic_name1 = CH4 (synthetic column for agg_fn2(b,2))
     *      }
     * }
     * 
* * if the connector only knows how to handle {@code agg_fn1(...)}, but not {@code agg_fn2}, it should return {@link Optional#empty()}. * *

* Another example is where the connector wants to handle the aggregate function by pointing to a pre-materialized table. * In this case the input can stay same as in the above example and the connector can return *

     * {@link AggregationApplicationResult} {
     *      handle = TH1 (could capture information about which pre-materialized table to use)
     *      projections = [{@link Variable} synthetic_name0, {@link Variable} synthetic_name1] -- The order in the list must be same as input list of aggregates
     *      assignments = {
     *          synthetic_name0 = CH3 (reference to the column in pre-materialized table that has agg_fn1(a) calculated)
     *          synthetic_name1 = CH4 (reference to the column in pre-materialized table that has agg_fn2(b,2) calculated)
     *          synthetic_name2 = CH5 (reference to the column in pre-materialized table that has the group by column c)
     *      }
     *      groupingColumnMapping = {
     *          CH2 -> CH5 (CH2 in the original assignment should now be replaced by CH5 in the new assignment)
     *      }
     * }
     * 
*

*/ default Optional> applyAggregation( ConnectorSession session, ConnectorTableHandle handle, List aggregates, Map assignments, List> groupingSets) { return Optional.empty(); } /** * Attempt to push down the TopN into the table scan. *

* Connectors can indicate whether they don't support topN pushdown or that the action had no effect * by returning {@link Optional#empty()}. Connectors should expect this method may be called multiple times. *

* Note: it's critical for connectors to return {@link Optional#empty()} if calling this method has no effect for that * invocation, even if the connector generally supports topN pushdown. Doing otherwise can cause the optimizer * to loop indefinitely. *

* If the connector can handle TopN Pushdown and guarantee it will produce fewer rows than it should return a * non-empty result with "topN guaranteed" flag set to true. * @return */ default Optional> applyTopN( ConnectorSession session, ConnectorTableHandle handle, long topNCount, List sortItems, Map assignments) { return Optional.empty(); } /** * Allows the connector to reject the table scan produced by the planner. *

* Connectors can choose to reject a query based on the table scan potentially being too expensive, for example * if no filtering is done on a partition column. *

*/ default void validateScan(ConnectorSession session, ConnectorTableHandle handle) {} /** * Create the specified materialized view. The view definition is intended to * be serialized by the connector for permanent storage. * @throws TrinoException with {@code ALREADY_EXISTS} if the object already exists and {@param ignoreExisting} is not set * */ default void createMaterializedView(ConnectorSession session, SchemaTableName viewName, ConnectorMaterializedViewDefinition definition, boolean replace, boolean ignoreExisting) { throw new TrinoException(NOT_SUPPORTED, "This connector does not support creating materialized views"); } /** * Drop the specified materialized view. */ default void dropMaterializedView(ConnectorSession session, SchemaTableName viewName) { throw new TrinoException(NOT_SUPPORTED, "This connector does not support dropping materialized views"); } /** * Gets the materialized view data for the specified materialized view name. */ default Optional getMaterializedView(ConnectorSession session, SchemaTableName viewName) { return Optional.empty(); } /** * The method is used by the engine to determine if a materialized view is current with respect to the tables it depends on. */ default MaterializedViewFreshness getMaterializedViewFreshness(ConnectorSession session, SchemaTableName name) { return new MaterializedViewFreshness(false); } default Optional applyTableScanRedirect(ConnectorSession session, ConnectorTableHandle tableHandle) { return Optional.empty(); } }