org.apache.hadoop.hive.ql.parse.PTFInvocationSpec Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.hadoop.hive.ql.parse;
import java.util.ArrayList;
import java.util.List;
import org.apache.hadoop.hive.ql.exec.PTFUtils;
public class PTFInvocationSpec {
PartitionedTableFunctionSpec function;
public PartitionedTableFunctionSpec getFunction() {
return function;
}
public void setFunction(PartitionedTableFunctionSpec function) {
this.function = function;
}
public PartitionedTableFunctionSpec getStartOfChain() {
return function == null ? null : function.getStartOfChain();
}
public String getQueryInputName() {
return function == null ? null : function.getQueryInputName();
}
public PTFQueryInputSpec getQueryInput() {
return function == null ? null : function.getQueryInput();
}
/*
* A PTF Input represents the input to a PTF Function. An Input can be a Hive SubQuery or Table
* or another PTF Function. An Input instance captures the ASTNode that this instance was created from.
*/
public abstract static class PTFInputSpec {
ASTNode astNode;
public ASTNode getAstNode() {
return astNode;
}
public void setAstNode(ASTNode astNode) {
this.astNode = astNode;
}
public abstract PTFInputSpec getInput();
public abstract String getQueryInputName();
public abstract PTFQueryInputSpec getQueryInput();
}
public static enum PTFQueryInputType {
TABLE,
SUBQUERY,
PTFCOMPONENT,
WINDOWING;
}
/*
* A PTF input that represents a source in the overall Query. This could be a Table or a SubQuery.
* If a PTF chain requires execution by multiple PTF Operators;
* then the original Invocation object is decomposed into a set of Component Invocations.
* Every component Invocation but the first one ends in a PTFQueryInputSpec instance.
* During the construction of the Operator plan a PTFQueryInputSpec object in the chain implies connect the PTF Operator to the
* 'input' i.e. has been generated so far.
*/
public static class PTFQueryInputSpec extends PTFInputSpec {
String source;
PTFQueryInputType type;
public String getSource() {
return source;
}
public void setSource(String source) {
this.source = source;
}
public PTFQueryInputType getType() {
return type;
}
public void setType(PTFQueryInputType type) {
this.type = type;
}
@Override
public PTFInputSpec getInput() {
return null;
}
@Override
public String getQueryInputName() {
return getSource();
}
@Override
public PTFQueryInputSpec getQueryInput() {
return this;
}
}
/*
* Represents a PTF Invocation. Captures:
* - function name and alias
* - the Partitioning details about its input
* - its arguments. The ASTNodes representing the arguments are captured here.
* - a reference to its Input
*/
public static class PartitionedTableFunctionSpec extends PTFInputSpec {
String name;
String alias;
List args;
PartitioningSpec partitioning;
PTFInputSpec input;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAlias() {
return alias;
}
public void setAlias(String alias) {
this.alias = alias;
}
public List getArgs() {
return args;
}
public void setArgs(List args) {
this.args = args;
}
public PartitioningSpec getPartitioning() {
return partitioning;
}
public void setPartitioning(PartitioningSpec partitioning) {
this.partitioning = partitioning;
}
@Override
public PTFInputSpec getInput() {
return input;
}
public void setInput(PTFInputSpec input) {
this.input = input;
}
public PartitionSpec getPartition() {
return getPartitioning() == null ? null : getPartitioning().getPartSpec();
}
public void setPartition(PartitionSpec partSpec) {
partitioning = partitioning == null ? new PartitioningSpec() : partitioning;
partitioning.setPartSpec(partSpec);
}
public OrderSpec getOrder() {
return getPartitioning() == null ? null : getPartitioning().getOrderSpec();
}
public void setOrder(OrderSpec orderSpec) {
partitioning = partitioning == null ? new PartitioningSpec() : partitioning;
partitioning.setOrderSpec(orderSpec);
}
public void addArg(ASTNode arg)
{
args = args == null ? new ArrayList() : args;
args.add(arg);
}
public PartitionedTableFunctionSpec getStartOfChain() {
if ( input instanceof PartitionedTableFunctionSpec ) {
return ((PartitionedTableFunctionSpec)input).getStartOfChain();
}
return this;
}
@Override
public String getQueryInputName() {
return input.getQueryInputName();
}
@Override
public PTFQueryInputSpec getQueryInput() {
return input.getQueryInput();
}
}
/*
* Captures how the Input to a PTF Function should be partitioned and
* ordered. Refers to a /Partition/ and /Order/ instance.
*/
public static class PartitioningSpec {
PartitionSpec partSpec;
OrderSpec orderSpec;
public PartitionSpec getPartSpec() {
return partSpec;
}
public void setPartSpec(PartitionSpec partSpec) {
this.partSpec = partSpec;
}
public OrderSpec getOrderSpec() {
return orderSpec;
}
public void setOrderSpec(OrderSpec orderSpec) {
this.orderSpec = orderSpec;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((orderSpec == null) ? 0 : orderSpec.hashCode());
result = prime * result + ((partSpec == null) ? 0 : partSpec.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
PartitioningSpec other = (PartitioningSpec) obj;
if (orderSpec == null) {
if (other.orderSpec != null) {
return false;
}
} else if (!orderSpec.equals(other.orderSpec)) {
return false;
}
if (partSpec == null) {
if (other.partSpec != null) {
return false;
}
} else if (!partSpec.equals(other.partSpec)) {
return false;
}
return true;
}
@Override
public String toString() {
return String.format("PartitioningSpec=[%s%s]",
partSpec == null ? "" : partSpec,
orderSpec == null ? "" : orderSpec);
}
}
/*
* Captures how an Input should be Partitioned. This is captured as a
* list of ASTNodes that are the expressions in the Distribute/Cluster
* by clause specifying the partitioning applied for a PTF invocation.
*/
public static class PartitionSpec {
ArrayList expressions;
public ArrayList getExpressions()
{
return expressions;
}
public void setExpressions(ArrayList columns)
{
this.expressions = columns;
}
public void addExpression(PartitionExpression c)
{
expressions = expressions == null ? new ArrayList() : expressions;
expressions.add(c);
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((expressions == null) ? 0 : expressions.hashCode());
return result;
}
@Override
public boolean equals(Object obj)
{
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
PartitionSpec other = (PartitionSpec) obj;
if (expressions == null)
{
if (other.expressions != null) {
return false;
}
}
else if (!expressions.equals(other.expressions)) {
return false;
}
return true;
}
@Override
public String toString()
{
return String.format("partitionColumns=%s",PTFUtils.toString(expressions));
}
}
public static class PartitionExpression
{
ASTNode expression;
public PartitionExpression() {}
public PartitionExpression(PartitionExpression peSpec)
{
expression = peSpec.getExpression();
}
public ASTNode getExpression() {
return expression;
}
public void setExpression(ASTNode expression) {
this.expression = expression;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((expression == null) ? 0 : expression.toStringTree().hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!getClass().isAssignableFrom(obj.getClass())) {
return false;
}
PartitionExpression other = (PartitionExpression) obj;
if (expression == null) {
if (other.expression != null) {
return false;
}
} else if (!expression.toStringTree().equals(other.expression.toStringTree())) {
return false;
}
return true;
}
@Override
public String toString()
{
return expression.toStringTree();
}
}
/*
* Captures how the Input should be Ordered. This is captured as a list
* of ASTNodes that are the expressions in the Sort By clause in a
* PTF invocation.
*/
public static class OrderSpec
{
ArrayList expressions;
public OrderSpec() {}
public OrderSpec(PartitionSpec pSpec)
{
for(PartitionExpression peSpec : pSpec.getExpressions())
{
addExpression(new OrderExpression(peSpec));
}
}
public ArrayList getExpressions()
{
return expressions;
}
public void setExpressions(ArrayList columns)
{
this.expressions = columns;
}
/**
* Add order expressions from the list of expressions in the format of ASTNode
* @param nodes
*/
public void addExpressions(ArrayList nodes) {
for (int i = 0; i < nodes.size(); i++) {
OrderExpression expr = new OrderExpression();
expr.setExpression(nodes.get(i));
addExpression(expr);
}
}
public void addExpression(OrderExpression c)
{
expressions = expressions == null ? new ArrayList() : expressions;
expressions.add(c);
}
protected boolean isPrefixedBy(PartitionSpec pSpec) {
if ( pSpec == null || pSpec.getExpressions() == null) {
return true;
}
int pExprCnt = pSpec.getExpressions().size();
int exprCnt = getExpressions() == null ? 0 : getExpressions().size();
if ( exprCnt < pExprCnt ) {
return false;
}
for(int i=0; i < pExprCnt; i++) {
if ( !pSpec.getExpressions().get(i).equals(getExpressions().get(i)) ) {
return false;
}
}
return true;
}
protected void prefixBy(PartitionSpec pSpec) {
if ( pSpec == null || pSpec.getExpressions() == null) {
return;
}
if ( expressions == null ) {
expressions = new ArrayList();
}
for(int i = pSpec.getExpressions().size() - 1; i >= 0; i--) {
expressions.add(0, new OrderExpression(pSpec.getExpressions().get(i)));
}
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((expressions == null) ? 0 : expressions.hashCode());
return result;
}
@Override
public boolean equals(Object obj)
{
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
OrderSpec other = (OrderSpec) obj;
if (expressions == null)
{
if (other.expressions != null) {
return false;
}
}
else if (!expressions.equals(other.expressions)) {
return false;
}
return true;
}
@Override
public String toString()
{
return String.format("orderColumns=%s",PTFUtils.toString(expressions));
}
}
public static enum Order
{
ASC,
DESC;
}
public static enum NullOrder
{
NULLS_FIRST,
NULLS_LAST;
}
public static class OrderExpression extends PartitionExpression
{
Order order;
NullOrder nullOrder;
public OrderExpression() {
order = Order.ASC;
nullOrder = NullOrder.NULLS_FIRST;
}
public OrderExpression(PartitionExpression peSpec)
{
super(peSpec);
order = Order.ASC;
nullOrder = NullOrder.NULLS_FIRST;
}
public Order getOrder()
{
return order;
}
public void setOrder(Order order)
{
this.order = order;
}
public NullOrder getNullOrder()
{
return nullOrder;
}
public void setNullOrder(NullOrder nullOrder)
{
this.nullOrder = nullOrder;
}
@Override
public int hashCode()
{
final int prime = 31;
int result = super.hashCode();
result = prime * result + ((order == null) ? 0 : order.hashCode());
result = prime * result + ((nullOrder == null) ? 0 : nullOrder.hashCode());
return result;
}
@Override
public boolean equals(Object obj)
{
if (this == obj) {
return true;
}
if (!super.equals(obj)) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
OrderExpression other = (OrderExpression) obj;
if (order != other.order) {
return false;
}
if (nullOrder != other.nullOrder) {
return false;
}
return true;
}
@Override
public String toString()
{
return String.format("%s %s %s", super.toString(), order, nullOrder);
}
}
}