Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
import io.trino.spi.ptf.ScalarArgument;
import io.trino.spi.ptf.ScalarArgumentSpecification;
import io.trino.spi.ptf.TableArgumentSpecification;
import io.trino.spi.ptf.TableFunctionAnalysis;
import io.trino.spi.security.AccessDeniedException;
import io.trino.spi.security.GroupProvider;
import io.trino.spi.security.Identity;
Expand Down Expand Up @@ -1488,7 +1489,7 @@ protected Scope visitTableFunctionInvocation(TableFunctionInvocation node, Optio
ConnectorTransactionHandle transactionHandle = transactionManager.getConnectorTransaction(
session.getRequiredTransactionId(),
getRequiredCatalogHandle(metadata, session, node, catalogName.getCatalogName()));
ConnectorTableFunction.Analysis functionAnalysis = function.analyze(session.toConnectorSession(catalogName), transactionHandle, passedArguments);
TableFunctionAnalysis functionAnalysis = function.analyze(session.toConnectorSession(catalogName), transactionHandle, passedArguments);
analysis.setTableFunctionAnalysis(node, new TableFunctionInvocationAnalysis(catalogName, functionName.toString(), passedArguments, functionAnalysis.getHandle(), transactionHandle));

// TODO handle the DescriptorMapping descriptorsToTables mapping from the TableFunction.Analysis:
Expand All @@ -1501,7 +1502,7 @@ protected Scope visitTableFunctionInvocation(TableFunctionInvocation node, Optio
// 4. at this point, the Identifier should be recorded as a column reference to the appropriate table
// 5. record the mapping NameAndPosition -> Identifier
// ... later translate Identifier to Symbol in Planner, and eventually translate it to channel before execution
if (!functionAnalysis.getDescriptorsToTables().isEmpty()) {
if (!functionAnalysis.getDescriptorMapping().isEmpty()) {
throw semanticException(NOT_SUPPORTED, node, "Table arguments are not yet supported for table functions");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

import static java.util.Objects.requireNonNull;
Expand Down Expand Up @@ -79,7 +78,7 @@ public ReturnTypeSpecification getReturnTypeSpecification()
* 3. Perform function-specific validation and pre-processing of the input arguments.
* As part of function-specific validation, the Table Function's author might want to:
* - check if the descriptors which reference input tables contain a correct number of column references
* - check if the referenced input columns have appropriate types to fit the function's logic // TODO return request for coercions to the Analyzer in the Analysis object
* - check if the referenced input columns have appropriate types to fit the function's logic // TODO return request for coercions to the Analyzer in the TableFunctionAnalysis object
* - if there is a descriptor which describes the function's output, check if it matches the shape of the actual function's output
* - for table arguments, check the number and types of ordering columns
* <p>
Expand All @@ -88,57 +87,7 @@ public ReturnTypeSpecification getReturnTypeSpecification()
*
* @param arguments actual invocation arguments, mapped by argument names
*/
public Analysis analyze(ConnectorSession session, ConnectorTransactionHandle transaction, Map<String, Argument> arguments)
{
throw new UnsupportedOperationException("analyze method not implemented for Table Function " + name);
}

/**
* The `analyze()` method should produce an object of this class, containing all the analysis results:
* <p>
* The `returnedType` field is used to inform the Analyzer of the proper columns returned by the Table
* Function, that is, the columns produced by the function, as opposed to the columns passed from the
* input tables. The `returnedType` should only be set if the declared returned type is GENERIC_TABLE.
* <p>
* The `descriptorsToTables` field is used to inform the Analyzer of the semantics of descriptor arguments.
* Some descriptor arguments (or some of their fields) might be references to columns of the input tables.
* In such case, the Analyzer must be informed of those dependencies. It allows to pass the right values
* (input channels) to the Table Function during execution. It also allows to prune unused input columns
* during the optimization phase.
* <p>
* The `handle` field can be used to carry all information necessary to execute the table function,
* gathered at analysis time. Typically, these are the values of the constant arguments, and results
* of pre-processing arguments.
*/
public static class Analysis
{
private final Optional<Descriptor> returnedType;
private final DescriptorMapping descriptorsToTables;
private final ConnectorTableFunctionHandle handle;

public Analysis(Optional<Descriptor> returnedType, DescriptorMapping descriptorsToTables, ConnectorTableFunctionHandle handle)
{
this.returnedType = requireNonNull(returnedType, "returnedType is null");
returnedType.ifPresent(descriptor -> checkArgument(descriptor.isTyped(), "field types not specified"));
this.descriptorsToTables = requireNonNull(descriptorsToTables, "descriptorsToTables is null");
this.handle = requireNonNull(handle, "handle is null");
}

public Optional<Descriptor> getReturnedType()
{
return returnedType;
}

public DescriptorMapping getDescriptorsToTables()
{
return descriptorsToTables;
}

public ConnectorTableFunctionHandle getHandle()
{
return handle;
}
}
public abstract TableFunctionAnalysis analyze(ConnectorSession session, ConnectorTransactionHandle transaction, Map<String, Argument> arguments);

static String checkNotNullOrEmpty(String value, String name)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
* 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.ptf;

import java.util.Optional;

import static io.trino.spi.ptf.ConnectorTableFunction.checkArgument;
import static io.trino.spi.ptf.DescriptorMapping.EMPTY_MAPPING;
import static java.util.Objects.requireNonNull;

/**
* An object of this class is produced by the `analyze()` method of a `ConnectorTableFunction`
* implementation. It contains all the analysis results:
* <p>
* The `returnedType` field is used to inform the Analyzer of the proper columns returned by the Table
* Function, that is, the columns produced by the function, as opposed to the columns passed from the
* input tables. The `returnedType` should only be set if the declared returned type is GENERIC_TABLE.
* <p>
* The `descriptorMapping` field is used to inform the Analyzer of the semantics of descriptor arguments.
* Some descriptor arguments (or some of their fields) might be references to columns of the input tables.
* In such case, the Analyzer must be informed of those dependencies. It allows to pass the right values
* (input channels) to the Table Function during execution. It also allows to prune unused input columns
* during the optimization phase.
* <p>
* The `handle` field can be used to carry all information necessary to execute the table function,
* gathered at analysis time. Typically, these are the values of the constant arguments, and results
* of pre-processing arguments.
*/
public final class TableFunctionAnalysis
{
private final Optional<Descriptor> returnedType;
private final DescriptorMapping descriptorMapping;
private final ConnectorTableFunctionHandle handle;

private TableFunctionAnalysis(Optional<Descriptor> returnedType, DescriptorMapping descriptorMapping, ConnectorTableFunctionHandle handle)
{
this.returnedType = requireNonNull(returnedType, "returnedType is null");
returnedType.ifPresent(descriptor -> checkArgument(descriptor.isTyped(), "field types not specified"));
this.descriptorMapping = requireNonNull(descriptorMapping, "descriptorMapping is null");
this.handle = requireNonNull(handle, "handle is null");
}

public Optional<Descriptor> getReturnedType()
{
return returnedType;
}

public DescriptorMapping getDescriptorMapping()
{
return descriptorMapping;
}

public ConnectorTableFunctionHandle getHandle()
{
return handle;
}

public static Builder builder()
{
return new Builder();
}

public static final class Builder
{
private Descriptor returnedType;
private DescriptorMapping descriptorMapping = EMPTY_MAPPING;
private ConnectorTableFunctionHandle handle = new ConnectorTableFunctionHandle() {};

private Builder() {}

public Builder returnedType(Descriptor returnedType)
{
this.returnedType = returnedType;
return this;
}

public Builder descriptorMapping(DescriptorMapping descriptorMapping)
{
this.descriptorMapping = descriptorMapping;
return this;
}

public Builder handle(ConnectorTableFunctionHandle handle)
{
this.handle = handle;
return this;
}

public TableFunctionAnalysis build()
{
return new TableFunctionAnalysis(Optional.ofNullable(returnedType), descriptorMapping, handle);
}
}
}