diff --git a/core/trino-main/src/main/java/io/trino/sql/analyzer/StatementAnalyzer.java b/core/trino-main/src/main/java/io/trino/sql/analyzer/StatementAnalyzer.java index 0f8ac9a2540e..fdcb6f8432e9 100644 --- a/core/trino-main/src/main/java/io/trino/sql/analyzer/StatementAnalyzer.java +++ b/core/trino-main/src/main/java/io/trino/sql/analyzer/StatementAnalyzer.java @@ -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; @@ -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: @@ -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"); } diff --git a/core/trino-spi/src/main/java/io/trino/spi/ptf/ConnectorTableFunction.java b/core/trino-spi/src/main/java/io/trino/spi/ptf/ConnectorTableFunction.java index d61622bd0cb4..fac48b61eef9 100644 --- a/core/trino-spi/src/main/java/io/trino/spi/ptf/ConnectorTableFunction.java +++ b/core/trino-spi/src/main/java/io/trino/spi/ptf/ConnectorTableFunction.java @@ -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; @@ -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 *

@@ -88,57 +87,7 @@ public ReturnTypeSpecification getReturnTypeSpecification() * * @param arguments actual invocation arguments, mapped by argument names */ - public Analysis analyze(ConnectorSession session, ConnectorTransactionHandle transaction, Map 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: - *

- * 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. - *

- * 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. - *

- * 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 returnedType; - private final DescriptorMapping descriptorsToTables; - private final ConnectorTableFunctionHandle handle; - - public Analysis(Optional 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 getReturnedType() - { - return returnedType; - } - - public DescriptorMapping getDescriptorsToTables() - { - return descriptorsToTables; - } - - public ConnectorTableFunctionHandle getHandle() - { - return handle; - } - } + public abstract TableFunctionAnalysis analyze(ConnectorSession session, ConnectorTransactionHandle transaction, Map arguments); static String checkNotNullOrEmpty(String value, String name) { diff --git a/core/trino-spi/src/main/java/io/trino/spi/ptf/TableFunctionAnalysis.java b/core/trino-spi/src/main/java/io/trino/spi/ptf/TableFunctionAnalysis.java new file mode 100644 index 000000000000..cfe20e97b2bc --- /dev/null +++ b/core/trino-spi/src/main/java/io/trino/spi/ptf/TableFunctionAnalysis.java @@ -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: + *

+ * 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. + *

+ * 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. + *

+ * 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 returnedType; + private final DescriptorMapping descriptorMapping; + private final ConnectorTableFunctionHandle handle; + + private TableFunctionAnalysis(Optional 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 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); + } + } +}