Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
98 commits
Select commit Hold shift + click to select a range
08cb57d
Support table function invocation in grammar and AST
mohsaka Mar 5, 2025
bd83df4
Add SPI support for declaring and analyzing TableFunctions
mohsaka Mar 5, 2025
207ed0b
Pass TransactionManager to StatementAnalyzer
mohsaka Mar 5, 2025
e223c54
Register table functions
mohsaka Mar 6, 2025
f1b210f
Analyze table function invocation
mohsaka Mar 6, 2025
7ee4d67
Plan table function invocation as TableFunctionNode
mohsaka Mar 7, 2025
4cfbf58
Add methods for table function pushdown into connector
mohsaka Mar 7, 2025
7222d79
Add rule to push table function invocation into connector
mohsaka Mar 7, 2025
21263fb
Extract transaction manager from JdbcConnector
mohsaka Mar 7, 2025
d5c7de6
Address failing checks
mohsaka Mar 7, 2025
8bcde5a
Add builders for table function arguments
mohsaka Mar 7, 2025
85c911a
Refactor table function analysis
mohsaka Mar 7, 2025
3f08d96
Add argument-less builder methods for boolean values
mohsaka Mar 7, 2025
5a6180c
Refactor ConnectorTableFunction into interface
mohsaka Mar 7, 2025
108a932
Remove unused argument from TableArgumentSpecification.java builder.
mohsaka Mar 7, 2025
e79caca
Support parameters in table function arguments
mohsaka Mar 10, 2025
568b227
Fix and test table functions
mohsaka Mar 11, 2025
c1b2909
Add and run first TVF connector tests
mohsaka Mar 14, 2025
939612e
Support TableFunctionNode in PlanPrinter
mohsaka Mar 14, 2025
b3a8b19
Rename AST nodes to avoid conflicting class names
mohsaka Mar 14, 2025
3765b84
Fix table function argument resolution
mohsaka Mar 14, 2025
47d0297
Refactor empty table treatment into a Node and Fix aliasing table arg…
mohsaka Mar 14, 2025
883c25c
Extract method for analyzing scalar arguments
mohsaka Mar 17, 2025
7b59012
Use variable
mohsaka Mar 17, 2025
39dae91
Enforce the prune when empty property in TableArgumentSpecification
mohsaka Mar 17, 2025
fe7c9ba
Add comment
mohsaka Mar 17, 2025
f19be33
Simplify table argument representation in SPI
mohsaka Mar 17, 2025
e590f78
Record relation names during analysis
mohsaka Mar 17, 2025
b60e00e
Remove descriptor mapping from table function analysis and planning
mohsaka Mar 17, 2025
e53d6ab
Use Optional.orElseThrow()
mohsaka Mar 17, 2025
f85f77a
Add equals() and hashCode() methods for descriptor argument
mohsaka Mar 17, 2025
bc8373b
Add serialization of table function scalar arguments
mohsaka Mar 17, 2025
dc2f02c
Copy a map argument in the constructor
mohsaka Mar 17, 2025
fac7dbc
Analyze table and descriptor arguments
mohsaka Mar 18, 2025
95c9421
Fix error messages as we do not have NodeLocations associated with Qu…
xin-zhang2 Mar 18, 2025
227b077
Validate return type declaration of table function at registration
mohsaka Mar 19, 2025
f5079b1
Analyze the context of table function invocation
xin-zhang2 Mar 19, 2025
06d2261
Analyze aliasing of table function invocation
xin-zhang2 Mar 19, 2025
52db63f
Add columns from input tables to table function returned relation type
xin-zhang2 Mar 19, 2025
7c24b64
Fix formatting of table function table arguments in SqlFormatter
xin-zhang2 Mar 19, 2025
2fb93c5
Pass plan node tag in the context of PlanPrinter
xin-zhang2 Mar 19, 2025
a0ad6d5
Copy arguments in the constructor
xin-zhang2 Mar 19, 2025
cbf9a66
Refactor TestingTableFunctions
xin-zhang2 Mar 19, 2025
779a704
Extract WindowNode.Specification as a separate class
xin-zhang2 Mar 19, 2025
da2eb69
Plan table function invocation with table arguments
mohsaka Mar 19, 2025
152a8ad
Debugging and fixing Presto issues
mohsaka Apr 2, 2025
0878d3c
Add requiredColumns field to TableFunctionAnalysis
mohsaka Mar 24, 2025
af410d8
Analyze table function's required input columns
mohsaka Mar 24, 2025
5a396c2
Require explicit specification of KEEP / PRUNE WHEN EMPTY
xin-zhang2 Mar 24, 2025
585f164
Pass uncoerced partitioning columns from table function source for ou…
mohsaka Mar 25, 2025
93756dd
Add table function's name to TableFunctionHandle
xin-zhang2 Mar 25, 2025
53b7f0c
Pass all necessary pass-through information
xin-zhang2 Mar 25, 2025
7f5ccae
Fix handling of pre-sorted prefix in SymbolMapper
xin-zhang2 Mar 25, 2025
70d44c9
Introduce a PlanNode for table function invocation with prepared source
mohsaka Mar 25, 2025
c16e6e6
Add pre-partitioned and pre-sorted properties to TableFunctionProcess…
mohsaka Mar 26, 2025
db08898
Implement table function source
mohsaka Mar 26, 2025
e32bd4e
Implement table function source
mohsaka Apr 2, 2025
b8f085b
Fix mapping marker symbols in SymbolMapper
xin-zhang2 Mar 31, 2025
291b097
Deduplicate pass-through symbols in SymbolMapper
xin-zhang2 Mar 31, 2025
389b09c
Add comments
xin-zhang2 Mar 31, 2025
d5cd1ad
Support execution by operator for table functions
mohsaka Apr 3, 2025
2d157bf
Introduce TableFunctionSplitProcessor
mohsaka Apr 1, 2025
97a31a6
Support execution by operator for table functions without input
mohsaka Apr 2, 2025
1ddbe51
Fixed some debugging issues.
xin-zhang2 Apr 2, 2025
a3a21ce
Fix some issues.
xin-zhang2 Apr 3, 2025
a7de94f
temporary code for testing
xin-zhang2 Apr 3, 2025
8a91fa0
Formatting
mohsaka Apr 3, 2025
96c0080
Fix jackson serielizer
mohsaka Apr 3, 2025
d8a26dd
Change assignStatsEquivalentPlanNode to be the same as regular node
mohsaka Apr 4, 2025
91c000c
Add visitTableFunctionProcessor in PruneUnreferencedOutputs.java
xin-zhang2 Apr 4, 2025
4c9559c
Add jackson annotations and comment out required columns
mohsaka Apr 4, 2025
993f70f
Replace rowNotDistinctFromRow & positionNotDistinctFromPosition
xin-zhang2 Apr 7, 2025
43d1e4d
Fix requiredColumns issue
xin-zhang2 Apr 7, 2025
70138f9
Add second test in testIdentityFunction
xin-zhang2 Apr 7, 2025
4ba3c6e
Formatting
mohsaka Apr 7, 2025
2440a1b
First working example of table function with non-values table
mohsaka Apr 7, 2025
446f527
Add temporary getTableFunctionProcessorProvider Function in FunctionA…
mohsaka Apr 8, 2025
1a9d476
Optimize plans involving table functions
xin-zhang2 Apr 8, 2025
7126746
Add RepeatFunction and FunctionsReturningEmptyPages tests.
xin-zhang2 Apr 8, 2025
a75306f
Formatting
mohsaka Apr 8, 2025
aede977
Fix getTableFunctionHandleClass
xin-zhang2 Apr 9, 2025
443ef24
Fix graphviz printer
mohsaka Apr 9, 2025
2a531e6
Update Test case
mohsaka Apr 9, 2025
1dec868
Add Table Function Split Resolver to allow for multiple Connector Spl…
mohsaka Apr 10, 2025
e81244d
Fix partitioning cases in testIdentityFunction
xin-zhang2 Apr 10, 2025
52d071e
Fix partition columns issue
mohsaka Apr 11, 2025
7ca5ee8
Fix partitionby and orderby
xin-zhang2 Apr 11, 2025
0c31689
Fix issues in appendHelperSymbolsForCopartitionedNodes
xin-zhang2 Apr 11, 2025
98fe2c2
Fix copartitioning tests expect error
mohsaka Apr 11, 2025
4518897
Fix markerVariables issue
xin-zhang2 Apr 14, 2025
8aea412
Formatting and additional test cases.
mohsaka Apr 15, 2025
bbb539f
Fix testInputPartitioning
xin-zhang2 Apr 16, 2025
180643d
Fix copartitioning
xin-zhang2 Apr 17, 2025
a8bd77e
Formatting
xin-zhang2 Apr 17, 2025
4f3f7e0
Fix is distinct function
mohsaka Apr 17, 2025
e9d52e3
Fix matcher
mohsaka Apr 17, 2025
f518efe
Enable some more tests
mohsaka Apr 18, 2025
fc31072
Fix TestImplementTableFunctionSource
xin-zhang2 Apr 18, 2025
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 @@ -19,13 +19,17 @@
import com.facebook.presto.common.type.Type;
import com.facebook.presto.spi.ColumnHandle;
import com.facebook.presto.spi.ColumnMetadata;
import com.facebook.presto.spi.ConnectorId;
import com.facebook.presto.spi.TableHandle;
import com.facebook.presto.spi.analyzer.AccessControlInfo;
import com.facebook.presto.spi.analyzer.AccessControlInfoForTable;
import com.facebook.presto.spi.analyzer.AccessControlReferences;
import com.facebook.presto.spi.analyzer.AccessControlRole;
import com.facebook.presto.spi.connector.ConnectorTransactionHandle;
import com.facebook.presto.spi.function.FunctionHandle;
import com.facebook.presto.spi.function.FunctionKind;
import com.facebook.presto.spi.function.table.Argument;
import com.facebook.presto.spi.function.table.ConnectorTableFunctionHandle;
import com.facebook.presto.spi.security.AccessControl;
import com.facebook.presto.spi.security.AccessControlContext;
import com.facebook.presto.spi.security.AllowAllAccessControl;
Expand All @@ -43,6 +47,7 @@
import com.facebook.presto.sql.tree.Offset;
import com.facebook.presto.sql.tree.OrderBy;
import com.facebook.presto.sql.tree.Parameter;
import com.facebook.presto.sql.tree.QualifiedName;
import com.facebook.presto.sql.tree.QuantifiedComparisonExpression;
import com.facebook.presto.sql.tree.Query;
import com.facebook.presto.sql.tree.QuerySpecification;
Expand All @@ -51,6 +56,7 @@
import com.facebook.presto.sql.tree.Statement;
import com.facebook.presto.sql.tree.SubqueryExpression;
import com.facebook.presto.sql.tree.Table;
import com.facebook.presto.sql.tree.TableFunctionInvocation;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
Expand Down Expand Up @@ -190,6 +196,12 @@ public class Analysis
// Keeps track of the subquery we are visiting, so we have access to base query information when processing materialized view status
private Optional<QuerySpecification> currentQuerySpecification = Optional.empty();

// names of tables and aliased relations. All names are resolved case-insensitive.
private final Map<NodeRef<Relation>, QualifiedName> relationNames = new LinkedHashMap<>();
private final Map<NodeRef<TableFunctionInvocation>, TableFunctionInvocationAnalysis> tableFunctionAnalyses = new LinkedHashMap<>();
private final Set<NodeRef<Relation>> aliasedRelations = new LinkedHashSet<>();
private final Set<NodeRef<TableFunctionInvocation>> polymorphicTableFunctions = new LinkedHashSet<>();

public Analysis(@Nullable Statement root, Map<NodeRef<Parameter>, Expression> parameters, boolean isDescribe)
{
this.root = root;
Expand Down Expand Up @@ -994,6 +1006,46 @@ public Map<FunctionKind, Set<String>> getInvokedFunctions()
return functionMap.entrySet().stream().collect(toImmutableMap(Map.Entry::getKey, entry -> ImmutableSet.copyOf(entry.getValue())));
}

public void setTableFunctionAnalysis(TableFunctionInvocation node, TableFunctionInvocationAnalysis analysis)
{
tableFunctionAnalyses.put(NodeRef.of(node), analysis);
}

public TableFunctionInvocationAnalysis getTableFunctionAnalysis(TableFunctionInvocation node)
{
return tableFunctionAnalyses.get(NodeRef.of(node));
}

public void setRelationName(Relation relation, QualifiedName name)
{
relationNames.put(NodeRef.of(relation), name);
}

public QualifiedName getRelationName(Relation relation)
{
return relationNames.get(NodeRef.of(relation));
}

public void addAliased(Relation relation)
{
aliasedRelations.add(NodeRef.of(relation));
}

public boolean isAliased(Relation relation)
{
return aliasedRelations.contains(NodeRef.of(relation));
}

public void addPolymorphicTableFunction(TableFunctionInvocation invocation)
{
polymorphicTableFunctions.add(NodeRef.of(invocation));
}

public boolean isPolymorphicTableFunction(TableFunctionInvocation invocation)
{
return polymorphicTableFunctions.contains(NodeRef.of(invocation));
}

@Immutable
public static final class Insert
{
Expand Down Expand Up @@ -1177,4 +1229,242 @@ public boolean isFromView()
return isFromView;
}
}

public static class TableArgumentAnalysis
{
private final String argumentName;
private final Optional<QualifiedName> name;
private final Relation relation;
private final Optional<List<Expression>> partitionBy; // it is allowed to partition by empty list
private final Optional<OrderBy> orderBy;
private final boolean pruneWhenEmpty;
private final boolean rowSemantics;
private final boolean passThroughColumns;

private TableArgumentAnalysis(
String argumentName,
Optional<QualifiedName> name,
Relation relation,
Optional<List<Expression>> partitionBy,
Optional<OrderBy> orderBy,
boolean pruneWhenEmpty,
boolean rowSemantics,
boolean passThroughColumns)
{
this.argumentName = requireNonNull(argumentName, "argumentName is null");
this.name = requireNonNull(name, "name is null");
this.relation = requireNonNull(relation, "relation is null");
this.partitionBy = requireNonNull(partitionBy, "partitionBy is null").map(ImmutableList::copyOf);
this.orderBy = requireNonNull(orderBy, "orderBy is null");
this.pruneWhenEmpty = pruneWhenEmpty;
this.rowSemantics = rowSemantics;
this.passThroughColumns = passThroughColumns;
}

public String getArgumentName()
{
return argumentName;
}

public Optional<QualifiedName> getName()
{
return name;
}

public Relation getRelation()
{
return relation;
}

public Optional<List<Expression>> getPartitionBy()
{
return partitionBy;
}

public Optional<OrderBy> getOrderBy()
{
return orderBy;
}

public boolean isPruneWhenEmpty()
{
return pruneWhenEmpty;
}

public boolean isRowSemantics()
{
return rowSemantics;
}

public boolean isPassThroughColumns()
{
return passThroughColumns;
}

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

public static final class Builder
{
private String argumentName;
private Optional<QualifiedName> name = Optional.empty();
private Relation relation;
private Optional<List<Expression>> partitionBy = Optional.empty();
private Optional<OrderBy> orderBy = Optional.empty();
private boolean pruneWhenEmpty;
private boolean rowSemantics;
private boolean passThroughColumns;

private Builder() {}

public Builder withArgumentName(String argumentName)
{
this.argumentName = argumentName;
return this;
}

public Builder withName(QualifiedName name)
{
this.name = Optional.of(name);
return this;
}

public Builder withRelation(Relation relation)
{
this.relation = relation;
return this;
}

public Builder withPartitionBy(List<Expression> partitionBy)
{
this.partitionBy = Optional.of(partitionBy);
return this;
}

public Builder withOrderBy(OrderBy orderBy)
{
this.orderBy = Optional.of(orderBy);
return this;
}

public Builder withPruneWhenEmpty(boolean pruneWhenEmpty)
{
this.pruneWhenEmpty = pruneWhenEmpty;
return this;
}

public Builder withRowSemantics(boolean rowSemantics)
{
this.rowSemantics = rowSemantics;
return this;
}

public Builder withPassThroughColumns(boolean passThroughColumns)
{
this.passThroughColumns = passThroughColumns;
return this;
}

public TableArgumentAnalysis build()
{
return new TableArgumentAnalysis(argumentName, name, relation, partitionBy, orderBy, pruneWhenEmpty, rowSemantics, passThroughColumns);
}
}
}

public static class TableFunctionInvocationAnalysis
{
private final ConnectorId connectorId;
private final String schemaName;
private final String functionName;
private final Map<String, Argument> arguments;
private final List<TableArgumentAnalysis> tableArgumentAnalyses;
private final List<List<String>> copartitioningLists;
private final Map<String, List<Integer>> requiredColumns;
private final int properColumnsCount;
private final ConnectorTableFunctionHandle connectorTableFunctionHandle;
private final ConnectorTransactionHandle transactionHandle;

public TableFunctionInvocationAnalysis(
ConnectorId connectorId,
String schemaName,
String functionName,
Map<String, Argument> arguments,
List<TableArgumentAnalysis> tableArgumentAnalyses,
Map<String, List<Integer>> requiredColumns,
List<List<String>> copartitioningLists,
int properColumnsCount,
ConnectorTableFunctionHandle connectorTableFunctionHandle,
ConnectorTransactionHandle transactionHandle)
{
this.connectorId = requireNonNull(connectorId, "connectorId is null");
this.schemaName = requireNonNull(schemaName, "schemaName is null");
this.functionName = requireNonNull(functionName, "functionName is null");
this.arguments = ImmutableMap.copyOf(arguments);
this.connectorTableFunctionHandle = requireNonNull(connectorTableFunctionHandle, "connectorTableFunctionHandle is null");
this.transactionHandle = requireNonNull(transactionHandle, "transactionHandle is null");
this.tableArgumentAnalyses = ImmutableList.copyOf(tableArgumentAnalyses);
this.requiredColumns = requiredColumns.entrySet().stream()
.collect(toImmutableMap(Map.Entry::getKey, entry -> ImmutableList.copyOf(entry.getValue())));
this.copartitioningLists = ImmutableList.copyOf(copartitioningLists);
this.properColumnsCount = properColumnsCount;
}

public ConnectorId getConnectorId()
{
return connectorId;
}

public String getSchemaName()
{
return schemaName;
}

public String getFunctionName()
{
return functionName;
}

public Map<String, Argument> getArguments()
{
return arguments;
}

public List<TableArgumentAnalysis> getTableArgumentAnalyses()
{
return tableArgumentAnalyses;
}

public Map<String, List<Integer>> getRequiredColumns()
{
return requiredColumns;
}

public List<List<String>> getCopartitioningLists()
{
return copartitioningLists;
}

/**
* Proper columns are the columns produced by the table function, as opposed to pass-through columns from input tables.
* Proper columns should be considered the actual result of the table function.
* @return the number of table function's proper columns
*/
public int getProperColumnsCount()
{
return properColumnsCount;
}

public ConnectorTableFunctionHandle getConnectorTableFunctionHandle()
{
return connectorTableFunctionHandle;
}

public ConnectorTransactionHandle getTransactionHandle()
{
return transactionHandle;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,14 @@ public Field(Optional<NodeLocation> nodeLocation, Optional<QualifiedName> relati
this.aliased = aliased;
}

public static Field newUnqualified(Optional<String> name, Type type)
{
requireNonNull(name, "name is null");
requireNonNull(type, "type is null");

return new Field(Optional.empty(), Optional.empty(), name, type, false, Optional.empty(), Optional.empty(), false);
}

public Optional<NodeLocation> getNodeLocation()
{
return nodeLocation;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,13 @@ public enum SemanticErrorCode
FUNCTION_NOT_FOUND,
INVALID_FUNCTION_NAME,
DUPLICATE_PARAMETER_NAME,
FUNCTION_IMPLEMENTATION_ERROR,

MISSING_RETURN_TYPE,
AMBIGUOUS_RETURN_TYPE,
MISSING_ARGUMENT,
INVALID_FUNCTION_ARGUMENT,
INVALID_ARGUMENTS,

ORDER_BY_MUST_BE_IN_SELECT,
ORDER_BY_MUST_BE_IN_AGGREGATE,
Expand Down Expand Up @@ -111,4 +118,9 @@ public enum SemanticErrorCode
TOO_MANY_GROUPING_SETS,

INVALID_OFFSET_ROW_COUNT,
INVALID_COPARTITIONING,
INVALID_TABLE_FUNCTION_INVOCATION,
DUPLICATE_RANGE_VARIABLE,
INVALID_COLUMN_REFERENCE,
COLUMN_NOT_FOUND
}
Loading
Loading