4949import com .facebook .presto .sql .tree .Offset ;
5050import com .facebook .presto .sql .tree .OrderBy ;
5151import com .facebook .presto .sql .tree .Parameter ;
52+ import com .facebook .presto .sql .tree .QualifiedName ;
5253import com .facebook .presto .sql .tree .QuantifiedComparisonExpression ;
5354import com .facebook .presto .sql .tree .Query ;
5455import com .facebook .presto .sql .tree .QuerySpecification ;
@@ -214,7 +215,11 @@ public class Analysis
214215
215216 private Optional <List <OutputColumnMetadata >> updatedSourceColumns = Optional .empty ();
216217
218+ // names of tables and aliased relations. All names are resolved case-insensitive.
219+ private final Map <NodeRef <Relation >, QualifiedName > relationNames = new LinkedHashMap <>();
217220 private final Map <NodeRef <TableFunctionInvocation >, TableFunctionInvocationAnalysis > tableFunctionAnalyses = new LinkedHashMap <>();
221+ private final Set <NodeRef <Relation >> aliasedRelations = new LinkedHashSet <>();
222+ private final Set <NodeRef <TableFunctionInvocation >> polymorphicTableFunctions = new LinkedHashSet <>();
218223
219224 public Analysis (@ Nullable Statement root , Map <NodeRef <Parameter >, Expression > parameters , boolean isDescribe )
220225 {
@@ -1120,6 +1125,36 @@ public TableFunctionInvocationAnalysis getTableFunctionAnalysis(TableFunctionInv
11201125 return tableFunctionAnalyses .get (NodeRef .of (node ));
11211126 }
11221127
1128+ public void setRelationName (Relation relation , QualifiedName name )
1129+ {
1130+ relationNames .put (NodeRef .of (relation ), name );
1131+ }
1132+
1133+ public QualifiedName getRelationName (Relation relation )
1134+ {
1135+ return relationNames .get (NodeRef .of (relation ));
1136+ }
1137+
1138+ public void addAliased (Relation relation )
1139+ {
1140+ aliasedRelations .add (NodeRef .of (relation ));
1141+ }
1142+
1143+ public boolean isAliased (Relation relation )
1144+ {
1145+ return aliasedRelations .contains (NodeRef .of (relation ));
1146+ }
1147+
1148+ public void addPolymorphicTableFunction (TableFunctionInvocation invocation )
1149+ {
1150+ polymorphicTableFunctions .add (NodeRef .of (invocation ));
1151+ }
1152+
1153+ public boolean isPolymorphicTableFunction (TableFunctionInvocation invocation )
1154+ {
1155+ return polymorphicTableFunctions .contains (NodeRef .of (invocation ));
1156+ }
1157+
11231158 @ Immutable
11241159 public static final class Insert
11251160 {
@@ -1371,23 +1406,229 @@ public int hashCode()
13711406 }
13721407 }
13731408
1409+ public static class TableArgumentAnalysis
1410+ {
1411+ private final String argumentName ;
1412+ private final Optional <QualifiedName > name ;
1413+ private final Relation relation ;
1414+ private final Optional <List <Expression >> partitionBy ; // it is allowed to partition by empty list
1415+ private final Optional <OrderBy > orderBy ;
1416+ private final boolean pruneWhenEmpty ;
1417+ private final boolean rowSemantics ;
1418+ private final boolean passThroughColumns ;
1419+
1420+ private TableArgumentAnalysis (
1421+ String argumentName ,
1422+ Optional <QualifiedName > name ,
1423+ Relation relation ,
1424+ Optional <List <Expression >> partitionBy ,
1425+ Optional <OrderBy > orderBy ,
1426+ boolean pruneWhenEmpty ,
1427+ boolean rowSemantics ,
1428+ boolean passThroughColumns )
1429+ {
1430+ this .argumentName = requireNonNull (argumentName , "argumentName is null" );
1431+ this .name = requireNonNull (name , "name is null" );
1432+ this .relation = requireNonNull (relation , "relation is null" );
1433+ this .partitionBy = requireNonNull (partitionBy , "partitionBy is null" ).map (ImmutableList ::copyOf );
1434+ this .orderBy = requireNonNull (orderBy , "orderBy is null" );
1435+ this .pruneWhenEmpty = pruneWhenEmpty ;
1436+ this .rowSemantics = rowSemantics ;
1437+ this .passThroughColumns = passThroughColumns ;
1438+ }
1439+
1440+ public String getArgumentName ()
1441+ {
1442+ return argumentName ;
1443+ }
1444+
1445+ public Optional <QualifiedName > getName ()
1446+ {
1447+ return name ;
1448+ }
1449+
1450+ public Relation getRelation ()
1451+ {
1452+ return relation ;
1453+ }
1454+
1455+ public Optional <List <Expression >> getPartitionBy ()
1456+ {
1457+ return partitionBy ;
1458+ }
1459+
1460+ public Optional <OrderBy > getOrderBy ()
1461+ {
1462+ return orderBy ;
1463+ }
1464+
1465+ public boolean isPruneWhenEmpty ()
1466+ {
1467+ return pruneWhenEmpty ;
1468+ }
1469+
1470+ public boolean isRowSemantics ()
1471+ {
1472+ return rowSemantics ;
1473+ }
1474+
1475+ public boolean isPassThroughColumns ()
1476+ {
1477+ return passThroughColumns ;
1478+ }
1479+
1480+ public static Builder builder ()
1481+ {
1482+ return new Builder ();
1483+ }
1484+
1485+ public static final class Builder
1486+ {
1487+ private String argumentName ;
1488+ private Optional <QualifiedName > name = Optional .empty ();
1489+ private Relation relation ;
1490+ private Optional <List <Expression >> partitionBy = Optional .empty ();
1491+ private Optional <OrderBy > orderBy = Optional .empty ();
1492+ private boolean pruneWhenEmpty ;
1493+ private boolean rowSemantics ;
1494+ private boolean passThroughColumns ;
1495+
1496+ private Builder () {}
1497+
1498+ public Builder withArgumentName (String argumentName )
1499+ {
1500+ this .argumentName = argumentName ;
1501+ return this ;
1502+ }
1503+
1504+ public Builder withName (QualifiedName name )
1505+ {
1506+ this .name = Optional .of (name );
1507+ return this ;
1508+ }
1509+
1510+ public Builder withRelation (Relation relation )
1511+ {
1512+ this .relation = relation ;
1513+ return this ;
1514+ }
1515+
1516+ public Builder withPartitionBy (List <Expression > partitionBy )
1517+ {
1518+ this .partitionBy = Optional .of (partitionBy );
1519+ return this ;
1520+ }
1521+
1522+ public Builder withOrderBy (OrderBy orderBy )
1523+ {
1524+ this .orderBy = Optional .of (orderBy );
1525+ return this ;
1526+ }
1527+
1528+ public Builder withPruneWhenEmpty (boolean pruneWhenEmpty )
1529+ {
1530+ this .pruneWhenEmpty = pruneWhenEmpty ;
1531+ return this ;
1532+ }
1533+
1534+ public Builder withRowSemantics (boolean rowSemantics )
1535+ {
1536+ this .rowSemantics = rowSemantics ;
1537+ return this ;
1538+ }
1539+
1540+ public Builder withPassThroughColumns (boolean passThroughColumns )
1541+ {
1542+ this .passThroughColumns = passThroughColumns ;
1543+ return this ;
1544+ }
1545+
1546+ public TableArgumentAnalysis build ()
1547+ {
1548+ return new TableArgumentAnalysis (argumentName , name , relation , partitionBy , orderBy , pruneWhenEmpty , rowSemantics , passThroughColumns );
1549+ }
1550+ }
1551+ }
1552+
13741553 /**
13751554 * Encapsulates the result of analyzing a table function invocation.
13761555 * Includes the connector ID, function name, argument bindings, and the
13771556 * connector-specific table function handle needed for planning and execution.
1557+ *
1558+ * Example of a TableFunctionInvocationAnalysis for a table function
1559+ * with two table arguments, required columns, and co-partitioning
1560+ * implemented by {@link TestingTableFunctions.TwoTableArgumentsFunction}
1561+ *
1562+ * SQL:
1563+ * SELECT * FROM TABLE(system.two_table_arguments_function(
1564+ * input1 => TABLE(t1) PARTITION BY (a, b),
1565+ * input2 => TABLE(SELECT 1, 2) t1(x, y) PARTITION BY (x, y)
1566+ * COPARTITION(t1, s1.t1)))
1567+ *
1568+ * Table Function:
1569+ * super(
1570+ * SCHEMA_NAME,
1571+ * "two_table_arguments_function",
1572+ * ImmutableList.of(
1573+ * TableArgumentSpecification.builder()
1574+ * .name("INPUT1")
1575+ * .build(),
1576+ * TableArgumentSpecification.builder()
1577+ * .name("INPUT2")
1578+ * .build()),
1579+ * GENERIC_TABLE);
1580+ *
1581+ * analyze:
1582+ * return TableFunctionAnalysis.builder()
1583+ * .handle(HANDLE)
1584+ * .returnedType(new Descriptor(ImmutableList.of(new Descriptor.Field(COLUMN_NAME, Optional.of(BOOLEAN)))))
1585+ * .requiredColumns("INPUT1", ImmutableList.of(0))
1586+ * .requiredColumns("INPUT2", ImmutableList.of(0))
1587+ * .build();
1588+ *
1589+ * Example values:
1590+ * connectorId = "tpch"
1591+ * functionName = "two_table_arguments_function"
1592+ * arguments = {
1593+ * "input1" -> row(a bigint,b bigint,c bigint,d bigint),
1594+ * "input2" -> row(x integer,y integer)
1595+ * }
1596+ * tableArgumentAnalyses = [
1597+ * { argumentName="INPUT1", relation=Table{t1}, partitionBy=[a, b], orderBy=[], pruneWhenEmpty=false },
1598+ * { argumentName="INPUT2", relation=AliasedRelation{SELECT 1, 2 AS x, y}, partitionBy=[x, y], orderBy=[], pruneWhenEmpty=false }
1599+ * ]
1600+ * requiredColumns = {
1601+ * "INPUT1" -> [0],
1602+ * "INPUT2" -> [0]
1603+ * }
1604+ * copartitioningLists = [
1605+ * ["INPUT2", "INPUT1"]
1606+ * ]
1607+ * properColumnsCount = 1
1608+ * connectorTableFunctionHandle = TestingTableFunctionPushdownHandle
1609+ * transactionHandle = AbstractAnalyzerTest$1$1
1610+ *
13781611 */
13791612 public static class TableFunctionInvocationAnalysis
13801613 {
13811614 private final ConnectorId connectorId ;
13821615 private final String functionName ;
13831616 private final Map <String , Argument > arguments ;
1617+ private final List <TableArgumentAnalysis > tableArgumentAnalyses ;
1618+ private final Map <String , List <Integer >> requiredColumns ;
1619+ private final List <List <String >> copartitioningLists ;
1620+ private final int properColumnsCount ;
13841621 private final ConnectorTableFunctionHandle connectorTableFunctionHandle ;
13851622 private final ConnectorTransactionHandle transactionHandle ;
13861623
13871624 public TableFunctionInvocationAnalysis (
13881625 ConnectorId connectorId ,
13891626 String functionName ,
13901627 Map <String , Argument > arguments ,
1628+ List <TableArgumentAnalysis > tableArgumentAnalyses ,
1629+ Map <String , List <Integer >> requiredColumns ,
1630+ List <List <String >> copartitioningLists ,
1631+ int properColumnsCount ,
13911632 ConnectorTableFunctionHandle connectorTableFunctionHandle ,
13921633 ConnectorTransactionHandle transactionHandle )
13931634 {
@@ -1396,6 +1637,11 @@ public TableFunctionInvocationAnalysis(
13961637 this .arguments = ImmutableMap .copyOf (arguments );
13971638 this .connectorTableFunctionHandle = requireNonNull (connectorTableFunctionHandle , "connectorTableFunctionHandle is null" );
13981639 this .transactionHandle = requireNonNull (transactionHandle , "transactionHandle is null" );
1640+ this .tableArgumentAnalyses = ImmutableList .copyOf (tableArgumentAnalyses );
1641+ this .requiredColumns = requiredColumns .entrySet ().stream ()
1642+ .collect (toImmutableMap (Map .Entry ::getKey , entry -> ImmutableList .copyOf (entry .getValue ())));
1643+ this .copartitioningLists = ImmutableList .copyOf (copartitioningLists );
1644+ this .properColumnsCount = properColumnsCount ;
13991645 }
14001646
14011647 public ConnectorId getConnectorId ()
@@ -1413,6 +1659,31 @@ public Map<String, Argument> getArguments()
14131659 return arguments ;
14141660 }
14151661
1662+ public List <TableArgumentAnalysis > getTableArgumentAnalyses ()
1663+ {
1664+ return tableArgumentAnalyses ;
1665+ }
1666+
1667+ public Map <String , List <Integer >> getRequiredColumns ()
1668+ {
1669+ return requiredColumns ;
1670+ }
1671+
1672+ public List <List <String >> getCopartitioningLists ()
1673+ {
1674+ return copartitioningLists ;
1675+ }
1676+
1677+ /**
1678+ * Proper columns are the columns produced by the table function, as opposed to pass-through columns from input tables.
1679+ * Proper columns should be considered the actual result of the table function.
1680+ * @return the number of table function's proper columns
1681+ */
1682+ public int getProperColumnsCount ()
1683+ {
1684+ return properColumnsCount ;
1685+ }
1686+
14161687 public ConnectorTableFunctionHandle getConnectorTableFunctionHandle ()
14171688 {
14181689 return connectorTableFunctionHandle ;
0 commit comments