blob: fe8e0441e4c82e7399924c33a0d351092330c1d9 [file] [log] [blame]
/*
* 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.hyracks.algebricks.core.algebra.prettyprint;
import java.util.List;
import org.apache.commons.lang3.mutable.Mutable;
import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
import org.apache.hyracks.algebricks.common.utils.Pair;
import org.apache.hyracks.algebricks.common.utils.Triple;
import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;
import org.apache.hyracks.algebricks.core.algebra.base.ILogicalPlan;
import org.apache.hyracks.algebricks.core.algebra.base.LogicalVariable;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractOperatorWithNestedPlans;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractUnnestMapOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.AggregateOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.AssignOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.DataSourceScanOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.DistinctOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.DistributeResultOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.EmptyTupleSourceOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.ExchangeOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.ExtensionOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.GroupByOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.IndexInsertDeleteUpsertOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.InnerJoinOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.InsertDeleteUpsertOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.IntersectOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.LeftOuterJoinOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.LeftOuterUnnestMapOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.LeftOuterUnnestOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.LimitOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.MaterializeOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.NestedTupleSourceOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.OrderOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.PartitioningSplitOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.ProjectOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.ReplicateOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.RunningAggregateOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.ScriptOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.SelectOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.SinkOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.SubplanOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.TokenizeOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.UnionAllOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.UnnestMapOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.UnnestOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.WriteOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.WriteResultOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.InsertDeleteUpsertOperator.Kind;
import org.apache.hyracks.algebricks.core.algebra.visitors.ILogicalExpressionVisitor;
import org.apache.hyracks.algebricks.core.algebra.visitors.ILogicalOperatorVisitor;
public class LogicalOperatorPrettyPrintVisitor implements ILogicalOperatorVisitor<Void, Integer> {
ILogicalExpressionVisitor<String, Integer> exprVisitor;
AlgebricksAppendable buffer;
public LogicalOperatorPrettyPrintVisitor() {
this(new AlgebricksAppendable());
}
public LogicalOperatorPrettyPrintVisitor(Appendable app) {
this(new AlgebricksAppendable(app), new LogicalExpressionPrettyPrintVisitor());
}
public LogicalOperatorPrettyPrintVisitor(AlgebricksAppendable buffer) {
this(buffer, new LogicalExpressionPrettyPrintVisitor());
}
public LogicalOperatorPrettyPrintVisitor(AlgebricksAppendable buffer,
ILogicalExpressionVisitor<String, Integer> exprVisitor) {
reset(buffer);
this.exprVisitor = exprVisitor;
}
public AlgebricksAppendable reset(AlgebricksAppendable buffer) {
AlgebricksAppendable old = this.buffer;
this.buffer = buffer;
return old;
}
public AlgebricksAppendable get() {
return buffer;
}
@Override
public String toString() {
return buffer.toString();
}
CharSequence str(Object o) {
return String.valueOf(o);
}
@Override
public Void visitAggregateOperator(AggregateOperator op, Integer indent) throws AlgebricksException {
addIndent(indent).append("aggregate ").append(str(op.getVariables())).append(" <- ");
pprintExprList(op.getExpressions(), indent);
return null;
}
@Override
public Void visitRunningAggregateOperator(RunningAggregateOperator op, Integer indent) throws AlgebricksException {
addIndent(indent).append("running-aggregate ").append(str(op.getVariables())).append(" <- ");
pprintExprList(op.getExpressions(), indent);
return null;
}
@Override
public Void visitEmptyTupleSourceOperator(EmptyTupleSourceOperator op, Integer indent) throws AlgebricksException {
addIndent(indent).append("empty-tuple-source");
return null;
}
@Override
public Void visitGroupByOperator(GroupByOperator op, Integer indent) throws AlgebricksException {
addIndent(indent).append("group by (");
pprintVeList(op.getGroupByList(), indent);
buffer.append(") decor (");
pprintVeList(op.getDecorList(), indent);
buffer.append(") {");
printNestedPlans(op, indent);
return null;
}
@Override
public Void visitDistinctOperator(DistinctOperator op, Integer indent) throws AlgebricksException {
addIndent(indent).append("distinct (");
pprintExprList(op.getExpressions(), indent);
buffer.append(")");
return null;
}
@Override
public Void visitInnerJoinOperator(InnerJoinOperator op, Integer indent) throws AlgebricksException {
addIndent(indent).append("join (").append(op.getCondition().getValue().accept(exprVisitor, indent)).append(")");
return null;
}
@Override
public Void visitLeftOuterJoinOperator(LeftOuterJoinOperator op, Integer indent) throws AlgebricksException {
addIndent(indent).append("left outer join (").append(op.getCondition().getValue().accept(exprVisitor, indent))
.append(")");
return null;
}
@Override
public Void visitNestedTupleSourceOperator(NestedTupleSourceOperator op, Integer indent)
throws AlgebricksException {
addIndent(indent).append("nested tuple source");
return null;
}
@Override
public Void visitOrderOperator(OrderOperator op, Integer indent) throws AlgebricksException {
addIndent(indent).append("order ");
for (Pair<OrderOperator.IOrder, Mutable<ILogicalExpression>> p : op.getOrderExpressions()) {
if (op.getTopK() != -1) {
buffer.append("(topK: " + op.getTopK() + ") ");
}
String fst = getOrderString(p.first);
buffer.append("(" + fst + ", " + p.second.getValue().accept(exprVisitor, indent) + ") ");
}
return null;
}
private String getOrderString(OrderOperator.IOrder first) {
switch (first.getKind()) {
case ASC:
return "ASC";
case DESC:
return "DESC";
default:
return first.getExpressionRef().toString();
}
}
@Override
public Void visitAssignOperator(AssignOperator op, Integer indent) throws AlgebricksException {
addIndent(indent).append("assign ").append(str(op.getVariables())).append(" <- ");
pprintExprList(op.getExpressions(), indent);
return null;
}
@Override
public Void visitWriteOperator(WriteOperator op, Integer indent) throws AlgebricksException {
addIndent(indent).append("write ");
pprintExprList(op.getExpressions(), indent);
return null;
}
@Override
public Void visitDistributeResultOperator(DistributeResultOperator op, Integer indent) throws AlgebricksException {
addIndent(indent).append("distribute result ");
pprintExprList(op.getExpressions(), indent);
return null;
}
@Override
public Void visitWriteResultOperator(WriteResultOperator op, Integer indent) throws AlgebricksException {
addIndent(indent).append("load ").append(str(op.getDataSource())).append(" from ")
.append(op.getPayloadExpression().getValue().accept(exprVisitor, indent)).append(" partitioned by ");
pprintExprList(op.getKeyExpressions(), indent);
return null;
}
@Override
public Void visitSelectOperator(SelectOperator op, Integer indent) throws AlgebricksException {
addIndent(indent).append("select (").append(op.getCondition().getValue().accept(exprVisitor, indent))
.append(")");
return null;
}
@Override
public Void visitProjectOperator(ProjectOperator op, Integer indent) throws AlgebricksException {
addIndent(indent).append("project " + "(" + op.getVariables() + ")");
return null;
}
@Override
public Void visitPartitioningSplitOperator(PartitioningSplitOperator op, Integer indent)
throws AlgebricksException {
addIndent(indent).append("partitioning-split (");
pprintExprList(op.getExpressions(), indent);
buffer.append(")");
return null;
}
@Override
public Void visitSubplanOperator(SubplanOperator op, Integer indent) throws AlgebricksException {
addIndent(indent).append("subplan {");
printNestedPlans(op, indent);
return null;
}
@Override
public Void visitUnionOperator(UnionAllOperator op, Integer indent) throws AlgebricksException {
addIndent(indent).append("union");
for (Triple<LogicalVariable, LogicalVariable, LogicalVariable> v : op.getVariableMappings()) {
buffer.append(" (" + v.first + ", " + v.second + ", " + v.third + ")");
}
return null;
}
@Override
public Void visitIntersectOperator(IntersectOperator op, Integer indent) throws AlgebricksException {
addIndent(indent).append("intersect (");
buffer.append('[');
for (int i = 0; i < op.getOutputVars().size(); i++) {
if (i > 0) {
buffer.append(", ");
}
buffer.append(str(op.getOutputVars().get(i)));
}
buffer.append("] <- [");
for (int i = 0; i < op.getNumInput(); i++) {
if (i > 0) {
buffer.append(", ");
}
buffer.append('[');
for (int j = 0; j < op.getInputVariables(i).size(); j++) {
if (j > 0) {
buffer.append(", ");
}
buffer.append(str(op.getInputVariables(i).get(j)));
}
buffer.append(']');
}
buffer.append("])");
return null;
}
@Override
public Void visitUnnestOperator(UnnestOperator op, Integer indent) throws AlgebricksException {
addIndent(indent).append("unnest " + op.getVariable());
if (op.getPositionalVariable() != null) {
buffer.append(" at " + op.getPositionalVariable());
}
buffer.append(" <- " + op.getExpressionRef().getValue().accept(exprVisitor, indent));
return null;
}
@Override
public Void visitLeftOuterUnnestOperator(LeftOuterUnnestOperator op, Integer indent) throws AlgebricksException {
addIndent(indent).append("outer-unnest " + op.getVariable());
if (op.getPositionalVariable() != null) {
buffer.append(" at " + op.getPositionalVariable());
}
buffer.append(" <- " + op.getExpressionRef().getValue().accept(exprVisitor, indent));
return null;
}
@Override
public Void visitUnnestMapOperator(UnnestMapOperator op, Integer indent) throws AlgebricksException {
return printAbstractUnnestMapOperator(op, indent, "unnest-map");
}
@Override
public Void visitLeftOuterUnnestMapOperator(LeftOuterUnnestMapOperator op, Integer indent)
throws AlgebricksException {
return printAbstractUnnestMapOperator(op, indent, "left-outer-unnest-map");
}
private Void printAbstractUnnestMapOperator(AbstractUnnestMapOperator op, Integer indent, String opSignature)
throws AlgebricksException {
addIndent(indent).append(opSignature + " " + op.getVariables() + " <- "
+ op.getExpressionRef().getValue().accept(exprVisitor, indent));
return null;
}
@Override
public Void visitDataScanOperator(DataSourceScanOperator op, Integer indent) throws AlgebricksException {
addIndent(indent).append(
"data-scan " + op.getProjectVariables() + "<-" + op.getVariables() + " <- " + op.getDataSource());
return null;
}
@Override
public Void visitLimitOperator(LimitOperator op, Integer indent) throws AlgebricksException {
addIndent(indent).append("limit " + op.getMaxObjects().getValue().accept(exprVisitor, indent));
ILogicalExpression offset = op.getOffset().getValue();
if (offset != null) {
buffer.append(", " + offset.accept(exprVisitor, indent));
}
return null;
}
@Override
public Void visitExchangeOperator(ExchangeOperator op, Integer indent) throws AlgebricksException {
addIndent(indent).append("exchange");
return null;
}
@Override
public Void visitScriptOperator(ScriptOperator op, Integer indent) throws AlgebricksException {
addIndent(indent).append("script (in: " + op.getInputVariables() + ") (out: " + op.getOutputVariables() + ")");
return null;
}
@Override
public Void visitReplicateOperator(ReplicateOperator op, Integer indent) throws AlgebricksException {
addIndent(indent).append("replicate");
return null;
}
@Override
public Void visitMaterializeOperator(MaterializeOperator op, Integer indent) throws AlgebricksException {
addIndent(indent).append("materialize");
return null;
}
@Override
public Void visitInsertDeleteUpsertOperator(InsertDeleteUpsertOperator op, Integer indent)
throws AlgebricksException {
String header = getIndexOpString(op.getOperation());
addIndent(indent).append(header).append(str(op.getDataSource())).append(" from record: ")
.append(op.getPayloadExpression().getValue().accept(exprVisitor, indent));
if (op.getAdditionalNonFilteringExpressions() != null) {
buffer.append(", meta: ");
pprintExprList(op.getAdditionalNonFilteringExpressions(), indent);
}
buffer.append(" partitioned by ");
pprintExprList(op.getPrimaryKeyExpressions(), indent);
if (op.getOperation() == Kind.UPSERT) {
buffer.append(
" out: ([record-before-upsert:" + op.getPrevRecordVar()
+ ((op.getPrevAdditionalNonFilteringVars() != null)
? (", additional-before-upsert: " + op.getPrevAdditionalNonFilteringVars()) : "")
+ "]) ");
}
if (op.isBulkload()) {
buffer.append(" [bulkload]");
}
return null;
}
@Override
public Void visitIndexInsertDeleteUpsertOperator(IndexInsertDeleteUpsertOperator op, Integer indent)
throws AlgebricksException {
String header = getIndexOpString(op.getOperation());
addIndent(indent).append(header).append(op.getIndexName()).append(" on ")
.append(str(op.getDataSourceIndex().getDataSource())).append(" from ");
if (op.getOperation() == Kind.UPSERT) {
buffer.append(" replace:");
pprintExprList(op.getPrevSecondaryKeyExprs(), indent);
buffer.append(" with:");
pprintExprList(op.getSecondaryKeyExpressions(), indent);
} else {
pprintExprList(op.getSecondaryKeyExpressions(), indent);
}
if (op.isBulkload()) {
buffer.append(" [bulkload]");
}
return null;
}
public String getIndexOpString(Kind opKind) {
switch (opKind) {
case DELETE:
return "delete from ";
case INSERT:
return "insert into ";
case UPSERT:
return "upsert into ";
}
return null;
}
@Override
public Void visitTokenizeOperator(TokenizeOperator op, Integer indent) throws AlgebricksException {
addIndent(indent).append("tokenize ").append(str(op.getTokenizeVars())).append(" <- ");
pprintExprList(op.getSecondaryKeyExpressions(), indent);
return null;
}
@Override
public Void visitSinkOperator(SinkOperator op, Integer indent) throws AlgebricksException {
addIndent(indent).append("sink");
return null;
}
@Override
public Void visitExtensionOperator(ExtensionOperator op, Integer indent) throws AlgebricksException {
addIndent(indent).append(op.toString());
return null;
}
protected AlgebricksAppendable addIndent(int level) throws AlgebricksException {
for (int i = 0; i < level; ++i) {
buffer.append(' ');
}
return buffer;
}
protected void printNestedPlans(AbstractOperatorWithNestedPlans op, Integer indent) throws AlgebricksException {
boolean first = true;
if (op.getNestedPlans().isEmpty()) {
buffer.append("}");
} else {
for (ILogicalPlan p : op.getNestedPlans()) {
// PrettyPrintUtil.indent(buffer, level + 10).append("var " +
// p.first + ":\n");
buffer.append("\n");
if (first) {
first = false;
} else {
addIndent(indent).append(" {\n");
}
PlanPrettyPrinter.printPlan(p, this, indent + 10);
addIndent(indent).append(" }");
}
}
}
protected void pprintExprList(List<Mutable<ILogicalExpression>> expressions, Integer indent)
throws AlgebricksException {
buffer.append("[");
boolean first = true;
for (Mutable<ILogicalExpression> exprRef : expressions) {
if (first) {
first = false;
} else {
buffer.append(", ");
}
buffer.append(exprRef.getValue().accept(exprVisitor, indent));
}
buffer.append("]");
}
protected void pprintVeList(List<Pair<LogicalVariable, Mutable<ILogicalExpression>>> vePairList, Integer indent)
throws AlgebricksException {
buffer.append("[");
boolean fst = true;
for (Pair<LogicalVariable, Mutable<ILogicalExpression>> ve : vePairList) {
if (fst) {
fst = false;
} else {
buffer.append("; ");
}
if (ve.first != null) {
buffer.append(ve.first + " := " + ve.second);
} else {
buffer.append(ve.second.getValue().accept(exprVisitor, indent));
}
}
buffer.append("]");
}
}