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 @@ -356,5 +356,8 @@ private static void validateTableFunction(ConnectorTableFunction tableFunction)
.filter(TableArgumentSpecification::isRowSemantics)
.count();
checkArgument(tableArgumentsWithRowSemantics <= 1, "more than one table argument with row semantics");
// The 'keep when empty' or 'prune when empty' property must not be explicitly specified for a table argument with row semantics.
// Such a table argument is implicitly 'prune when empty'. The TableArgumentSpecification.Builder enforces the 'prune when empty' property
// for a table argument with row semantics.
}
}
175 changes: 174 additions & 1 deletion core/trino-main/src/main/java/io/trino/sql/analyzer/Analysis.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
import io.trino.sql.tree.Offset;
import io.trino.sql.tree.OrderBy;
import io.trino.sql.tree.Parameter;
import io.trino.sql.tree.QualifiedName;
import io.trino.sql.tree.QuantifiedComparisonExpression;
import io.trino.sql.tree.Query;
import io.trino.sql.tree.QuerySpecification;
Expand Down Expand Up @@ -235,6 +236,8 @@ public class Analysis

private Optional<TableExecuteHandle> tableExecuteHandle = 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<>();

public Analysis(@Nullable Statement root, Map<NodeRef<Parameter>, Expression> parameters, QueryType queryType)
Expand Down Expand Up @@ -1219,6 +1222,16 @@ public TableFunctionInvocationAnalysis getTableFunctionAnalysis(TableFunctionInv
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));
}

private boolean isInputTable(Table table)
{
return !(isUpdateTarget(table) || isInsertTarget(table));
Expand Down Expand Up @@ -2028,24 +2041,174 @@ public Optional<Integer> getAtMost()
}
}

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 CatalogHandle catalogHandle;
private final String functionName;
private final Map<String, Argument> arguments;
private final List<TableArgumentAnalysis> tableArgumentAnalyses;
private final List<List<String>> copartitioningLists;
private final ConnectorTableFunctionHandle connectorTableFunctionHandle;
private final ConnectorTransactionHandle transactionHandle;

public TableFunctionInvocationAnalysis(
CatalogHandle catalogHandle,
String functionName,
Map<String, Argument> arguments,
List<TableArgumentAnalysis> tableArgumentAnalyses,
List<List<String>> copartitioningLists,
ConnectorTableFunctionHandle connectorTableFunctionHandle,
ConnectorTransactionHandle transactionHandle)
{
this.catalogHandle = requireNonNull(catalogHandle, "catalogHandle is null");
this.functionName = requireNonNull(functionName, "functionName is null");
this.arguments = requireNonNull(arguments, "arguments is null");
this.arguments = ImmutableMap.copyOf(arguments);
this.tableArgumentAnalyses = ImmutableList.copyOf(tableArgumentAnalyses);
this.copartitioningLists = ImmutableList.copyOf(copartitioningLists);
this.connectorTableFunctionHandle = requireNonNull(connectorTableFunctionHandle, "connectorTableFunctionHandle is null");
this.transactionHandle = requireNonNull(transactionHandle, "transactionHandle is null");
}
Expand All @@ -2065,6 +2228,16 @@ public Map<String, Argument> getArguments()
return arguments;
}

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

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

public ConnectorTableFunctionHandle getConnectorTableFunctionHandle()
{
return connectorTableFunctionHandle;
Expand Down
Loading