[UI] Allow logical plan to be viewed as JSON / formatted JSON
- user model changes: no
- storage format changes: no
- interface changes: enhancements to the web interface
details:
Added drop-down menu for printing logical plan and optimized
logical plan in string,json, and clean-json.
Change-Id: I4dd62e355048a5b8a02e074049fe41e73e74e357
Reviewed-on: https://asterix-gerrit.ics.uci.edu/1885
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Contrib: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Till Westmann <tillw@apache.org>
Reviewed-by: Ian Maxon <imaxon@apache.org>
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SessionConfig.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SessionConfig.java
index cfd4e87..6e67612 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SessionConfig.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SessionConfig.java
@@ -21,6 +21,9 @@
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
/**
* SessionConfig captures several different parameters for controlling
@@ -36,7 +39,6 @@
* <li>It allows you to specify output format-specific parameters.
*/
public class SessionConfig implements Serializable {
-
private static final long serialVersionUID = 1L;
/**
@@ -50,6 +52,29 @@
};
/**
+ * Used to specify the format for logical plan and optimized logical plan.
+ */
+
+ public enum PlanFormat {
+ JSON,
+ STRING;
+ public static PlanFormat get(String fmtString, String label, PlanFormat defaultFmt, Logger logger) {
+ try {
+ if (fmtString != null) {
+ String format =
+ ("JSON".equalsIgnoreCase(fmtString) || "CLEAN_JSON".equalsIgnoreCase(fmtString))
+ ? "JSON"
+ : fmtString;
+ return PlanFormat.valueOf(format);
+ }
+ } catch (IllegalArgumentException e) {
+ logger.log(Level.INFO, fmtString + ": unsupported " + label + ", using " + defaultFmt + "instead", e);
+ }
+ return defaultFmt;
+ }
+ };
+
+ /**
* Produce out-of-band output for Hyracks Job.
*/
public static final String OOB_HYRACKS_JOB = "oob-hyracks-job";
@@ -106,6 +131,7 @@
// Output format.
private final OutputFormat fmt;
+ private final PlanFormat lpfmt;
// Standard execution flags.
private final boolean executeQuery;
@@ -116,13 +142,18 @@
private final Map<String, Boolean> flags;
public SessionConfig(OutputFormat fmt) {
- this(fmt, true, true, true);
+ this(fmt, PlanFormat.STRING);
+ }
+
+ public SessionConfig(OutputFormat fmt, PlanFormat lpfmt) {
+ this(fmt, true, true, true, lpfmt);
}
/**
* Create a SessionConfig object with all optional values set to defaults:
* - All format flags set to "false".
* - All out-of-band outputs set to "false".
+ *
* @param fmt
* Output format for execution output.
* @param optimize
@@ -131,13 +162,20 @@
* Whether to execute the query or not.
* @param generateJobSpec
* Whether to generate the Hyracks job specification (if
+ * @param lpfmt
+ * Plan format for logical plan.
*/
public SessionConfig(OutputFormat fmt, boolean optimize, boolean executeQuery, boolean generateJobSpec) {
+ this(fmt, optimize, executeQuery, generateJobSpec, PlanFormat.STRING);
+ }
+ public SessionConfig(OutputFormat fmt, boolean optimize, boolean executeQuery, boolean generateJobSpec,
+ PlanFormat lpfmt) {
this.fmt = fmt;
this.optimize = optimize;
this.executeQuery = executeQuery;
this.generateJobSpec = generateJobSpec;
this.flags = new HashMap<>();
+ this.lpfmt = lpfmt;
}
/**
@@ -148,6 +186,13 @@
}
/**
+ * Retrieve the PlanFormat for this execution.
+ */
+ public PlanFormat getLpfmt() {
+ return this.lpfmt;
+ }
+
+ /**
* Retrieve the value of the "execute query" flag.
*/
public boolean isExecuteQuery() {
diff --git a/asterixdb/asterix-app/pom.xml b/asterixdb/asterix-app/pom.xml
index ee733d9..b039071 100644
--- a/asterixdb/asterix-app/pom.xml
+++ b/asterixdb/asterix-app/pom.xml
@@ -279,6 +279,10 @@
</profiles>
<dependencies>
<dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-databind</artifactId>
+ </dependency>
+ <dependency>
<groupId>org.apache.hyracks</groupId>
<artifactId>hyracks-control-cc</artifactId>
</dependency>
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/common/APIFramework.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/common/APIFramework.java
index 567d587..8290446 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/common/APIFramework.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/common/APIFramework.java
@@ -84,8 +84,10 @@
import org.apache.hyracks.algebricks.core.algebra.expressions.IExpressionTypeComputer;
import org.apache.hyracks.algebricks.core.algebra.expressions.IMergeAggregationExpressionFactory;
import org.apache.hyracks.algebricks.core.algebra.expressions.IMissableTypeComputer;
+import org.apache.hyracks.algebricks.core.algebra.prettyprint.AbstractLogicalOperatorPrettyPrintVisitor;
import org.apache.hyracks.algebricks.core.algebra.prettyprint.AlgebricksAppendable;
import org.apache.hyracks.algebricks.core.algebra.prettyprint.LogicalOperatorPrettyPrintVisitor;
+import org.apache.hyracks.algebricks.core.algebra.prettyprint.LogicalOperatorPrettyPrintVisitorJson;
import org.apache.hyracks.algebricks.core.algebra.prettyprint.PlanPrettyPrinter;
import org.apache.hyracks.algebricks.core.rewriter.base.AlgebricksOptimizationContext;
import org.apache.hyracks.algebricks.core.rewriter.base.IOptimizationContextFactory;
@@ -111,6 +113,8 @@
private static final int MIN_FRAME_LIMIT_FOR_SORT = 3;
private static final int MIN_FRAME_LIMIT_FOR_GROUP_BY = 4;
private static final int MIN_FRAME_LIMIT_FOR_JOIN = 5;
+ private static final String LPLAN = "Logical plan";
+ private static final String OPLAN = "Optimized logical plan";
// A white list of supported configurable parameters.
private static final Set<String> CONFIGURABLE_PARAMETER_NAMES =
@@ -156,7 +160,13 @@
private void printPlanPrefix(SessionOutput output, String planName) {
if (output.config().is(SessionConfig.FORMAT_HTML)) {
output.out().println("<h4>" + planName + ":</h4>");
- output.out().println("<pre>");
+ if (LPLAN.equalsIgnoreCase(planName)) {
+ output.out().println("<pre class = query-plan>");
+ } else if (OPLAN.equalsIgnoreCase(planName)) {
+ output.out().println("<pre class = query-optimized-plan>");
+ } else {
+ output.out().println("<pre>");
+ }
} else {
output.out().println("----------" + planName + ":");
}
@@ -219,7 +229,13 @@
printPlanPrefix(output, "Logical plan");
if (rwQ != null || (statement != null && statement.getKind() == Statement.Kind.LOAD)) {
- LogicalOperatorPrettyPrintVisitor pvisitor = new LogicalOperatorPrettyPrintVisitor(output.out());
+ AbstractLogicalOperatorPrettyPrintVisitor pvisitor;
+ if (output.config().getLpfmt().equals(SessionConfig.PlanFormat.JSON)) {
+ pvisitor = new LogicalOperatorPrettyPrintVisitorJson(output.out());
+ } else {
+ pvisitor = new LogicalOperatorPrettyPrintVisitor(output.out());
+
+ }
PlanPrettyPrinter.printPlan(plan, pvisitor, 0);
}
printPlanPostfix(output);
@@ -273,8 +289,13 @@
} else {
printPlanPrefix(output, "Optimized logical plan");
if (rwQ != null || (statement != null && statement.getKind() == Statement.Kind.LOAD)) {
- LogicalOperatorPrettyPrintVisitor pvisitor =
- new LogicalOperatorPrettyPrintVisitor(output.out());
+ AbstractLogicalOperatorPrettyPrintVisitor pvisitor;
+ if (output.config().getLpfmt().equals(SessionConfig.PlanFormat.JSON)) {
+ pvisitor = new LogicalOperatorPrettyPrintVisitorJson(output.out());
+
+ } else {
+ pvisitor = new LogicalOperatorPrettyPrintVisitor(output.out());
+ }
PlanPrettyPrinter.printPlan(plan, pvisitor, 0);
}
printPlanPostfix(output);
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ApiServlet.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ApiServlet.java
index fbe5852..a29d869 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ApiServlet.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ApiServlet.java
@@ -52,6 +52,7 @@
import org.apache.asterix.translator.IStatementExecutorFactory;
import org.apache.asterix.translator.SessionConfig;
import org.apache.asterix.translator.SessionConfig.OutputFormat;
+import org.apache.asterix.translator.SessionConfig.PlanFormat;
import org.apache.asterix.translator.SessionOutput;
import org.apache.hyracks.api.client.IHyracksClientConnection;
import org.apache.hyracks.api.dataset.IHyracksDataset;
@@ -67,7 +68,6 @@
import io.netty.handler.codec.http.HttpResponseStatus;
public class ApiServlet extends AbstractServlet {
-
private static final Logger LOGGER = Logger.getLogger(ApiServlet.class.getName());
public static final String HTML_STATEMENT_SEPARATOR = "<!-- BEGIN -->";
@@ -88,18 +88,20 @@
this.componentProvider = componentProvider;
}
- @Override
- protected void post(IServletRequest request, IServletResponse response) {
+ @Override protected void post(IServletRequest request, IServletResponse response) {
// Query language
- ILangCompilationProvider compilationProvider = "AQL".equals(request.getParameter("query-language"))
- ? aqlCompilationProvider : sqlppCompilationProvider;
+ ILangCompilationProvider compilationProvider = "AQL".equals(request.getParameter("query-language")) ?
+ aqlCompilationProvider :
+ sqlppCompilationProvider;
IParserFactory parserFactory = compilationProvider.getParserFactory();
// Output format.
PrintWriter out = response.writer();
OutputFormat format;
+
boolean csvAndHeader = false;
String output = request.getParameter("output-format");
+
if ("CSV-Header".equals(output)) {
output = "CSV";
csvAndHeader = true;
@@ -112,6 +114,8 @@
// Default output format
format = OutputFormat.CLEAN_JSON;
}
+ PlanFormat planFormat =
+ PlanFormat.get(request.getParameter("plan-format"), "plan format", PlanFormat.STRING, LOGGER);
String query = request.getParameter("query");
String wrapperArray = request.getParameter("wrapper-array");
@@ -144,12 +148,14 @@
}
IParser parser = parserFactory.createParser(query);
List<Statement> aqlStatements = parser.parse();
- SessionConfig sessionConfig = new SessionConfig(format, true, isSet(executeQuery), true);
+ SessionConfig sessionConfig =
+ new SessionConfig(format, true, isSet(executeQuery), true, planFormat);
sessionConfig.set(SessionConfig.FORMAT_HTML, true);
sessionConfig.set(SessionConfig.FORMAT_CSV_HEADER, csvAndHeader);
sessionConfig.set(SessionConfig.FORMAT_WRAPPER_ARRAY, isSet(wrapperArray));
- sessionConfig.setOOBData(isSet(printExprParam), isSet(printRewrittenExprParam),
- isSet(printLogicalPlanParam), isSet(printOptimizedLogicalPlanParam), isSet(printJob));
+ sessionConfig
+ .setOOBData(isSet(printExprParam), isSet(printRewrittenExprParam), isSet(printLogicalPlanParam),
+ isSet(printOptimizedLogicalPlanParam), isSet(printJob));
SessionOutput sessionOutput = new SessionOutput(sessionConfig, out);
MetadataManager.INSTANCE.init();
IStatementExecutor translator = statementExectorFactory.create(appCtx, aqlStatements, sessionOutput,
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryServiceServlet.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryServiceServlet.java
index 6a92a26..f8f5c18 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryServiceServlet.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryServiceServlet.java
@@ -114,7 +114,8 @@
CLIENT_ID("client_context_id"),
PRETTY("pretty"),
MODE("mode"),
- TIMEOUT("timeout");
+ TIMEOUT("timeout"),
+ PLAN_FORMAT("plan-format");
private final String str;
@@ -236,6 +237,7 @@
SessionOutput.ResultAppender appendStatus = ResultUtil.createResultStatusAppender();
SessionConfig.OutputFormat format = getFormat(param.format);
+ //TODO:get the parameters from UI.Currently set to clean_json.
SessionConfig sessionConfig = new SessionConfig(format);
sessionConfig.set(SessionConfig.FORMAT_WRAPPER_ARRAY, true);
sessionConfig.set(SessionConfig.FORMAT_INDENT_JSON, param.pretty);
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/RestApiServlet.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/RestApiServlet.java
index 3d00d88..117d7fb 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/RestApiServlet.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/RestApiServlet.java
@@ -46,6 +46,7 @@
import org.apache.asterix.translator.IStatementExecutorFactory;
import org.apache.asterix.translator.SessionConfig;
import org.apache.asterix.translator.SessionConfig.OutputFormat;
+import org.apache.asterix.translator.SessionConfig.PlanFormat;
import org.apache.asterix.translator.SessionOutput;
import org.apache.hyracks.api.client.IHyracksClientConnection;
import org.apache.hyracks.api.dataset.IHyracksDataset;
@@ -107,6 +108,8 @@
format = OutputFormat.CSV;
}
}
+ PlanFormat planFormat =
+ PlanFormat.get(request.getParameter("plan-format"), "plan format", PlanFormat.STRING, LOGGER);
// If it's JSON, check for the "lossless" flag
@@ -117,7 +120,7 @@
SessionOutput.ResultAppender appendHandle = (app, handle) -> app.append("{ \"").append("handle")
.append("\":" + " \"").append(handle).append("\" }");
- SessionConfig sessionConfig = new SessionConfig(format);
+ SessionConfig sessionConfig = new SessionConfig(format, planFormat);
// If it's JSON or ADM, check for the "wrapper-array" flag. Default is
// "true" for JSON and "false" for ADM. (Not applicable for CSV.)
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/java/AsterixJavaClient.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/java/AsterixJavaClient.java
index 675bb9b..58a7f09 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/java/AsterixJavaClient.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/java/AsterixJavaClient.java
@@ -37,6 +37,7 @@
import org.apache.asterix.translator.IStatementExecutorFactory;
import org.apache.asterix.translator.SessionConfig;
import org.apache.asterix.translator.SessionConfig.OutputFormat;
+import org.apache.asterix.translator.SessionConfig.PlanFormat;
import org.apache.asterix.translator.SessionOutput;
import org.apache.hyracks.api.client.IHyracksClientConnection;
import org.apache.hyracks.api.job.JobSpecification;
@@ -80,12 +81,20 @@
}
public void compile() throws Exception {
- compile(true, false, false, false, false, false, false);
+ compile(true, false, true, false, false, false, false);
}
public void compile(boolean optimize, boolean printRewrittenExpressions, boolean printLogicalPlan,
boolean printOptimizedPlan, boolean printPhysicalOpsOnly, boolean generateBinaryRuntime, boolean printJob)
throws Exception {
+ compile(optimize, printRewrittenExpressions, printLogicalPlan, printOptimizedPlan, printPhysicalOpsOnly,
+ generateBinaryRuntime, printJob, PlanFormat.STRING);
+ }
+
+ public void compile(boolean optimize, boolean printRewrittenExpressions, boolean printLogicalPlan,
+ boolean printOptimizedPlan, boolean printPhysicalOpsOnly, boolean generateBinaryRuntime, boolean printJob,
+ PlanFormat pformat)
+ throws Exception {
queryJobSpec = null;
dmlJobs = null;
@@ -101,7 +110,7 @@
List<Statement> statements = parser.parse();
MetadataManager.INSTANCE.init();
- SessionConfig conf = new SessionConfig(OutputFormat.ADM, optimize, true, generateBinaryRuntime);
+ SessionConfig conf = new SessionConfig(OutputFormat.ADM, optimize, true, generateBinaryRuntime, pformat);
conf.setOOBData(false, printRewrittenExpressions, printLogicalPlan, printOptimizedPlan, printJob);
if (printPhysicalOpsOnly) {
conf.set(SessionConfig.FORMAT_ONLY_PHYSICAL_OPS, true);
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/drivers/AsterixClientDriver.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/drivers/AsterixClientDriver.java
index ba44833..14a5fe0 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/drivers/AsterixClientDriver.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/drivers/AsterixClientDriver.java
@@ -53,8 +53,8 @@
}
boolean exec = new Boolean(acc.execute);
IHyracksClientConnection hcc = exec ? new HyracksConnection("localhost", acc.hyracksPort) : null;
- AsterixJavaClient q = compileQuery(hcc, acc.getArguments().get(0), new Boolean(acc.optimize),
- new Boolean(acc.onlyPhysical), exec || new Boolean(acc.hyracksJob));
+ AsterixJavaClient q = compileQuery(hcc, acc.getArguments().get(0), new Boolean(acc.optimize), false,
+ exec || new Boolean(acc.hyracksJob));
if (exec) {
q.execute();
}
@@ -64,8 +64,9 @@
boolean onlyPhysical, boolean createBinaryRuntime) throws Exception {
ILangCompilationProvider compilationProvider = new AqlCompilationProvider();
FileReader reader = new FileReader(filename);
- AsterixJavaClient q = new AsterixJavaClient(null, hcc, reader, compilationProvider,
- new DefaultStatementExecutorFactory(), new StorageComponentProvider());
+ AsterixJavaClient q =
+ new AsterixJavaClient(null, hcc, reader, compilationProvider, new DefaultStatementExecutorFactory(),
+ new StorageComponentProvider());
q.compile(optimize, true, true, true, onlyPhysical, createBinaryRuntime, createBinaryRuntime);
return q;
}
diff --git a/asterixdb/asterix-app/src/main/resources/webui/querytemplate.html b/asterixdb/asterix-app/src/main/resources/webui/querytemplate.html
index 383754e..1157c27 100644
--- a/asterixdb/asterix-app/src/main/resources/webui/querytemplate.html
+++ b/asterixdb/asterix-app/src/main/resources/webui/querytemplate.html
@@ -19,24 +19,24 @@
<!DOCTYPE html>
<html lang="en">
<head>
-<meta name="description" content="ASTERIX WEB PAGE" />
-<meta name="viewport" content="width=device-width, initial-scale=1.0">
-<link
- href='http://fonts.googleapis.com/css?family=Bitter|PT+Sans+Caption|Open+Sans'
- rel='stylesheet' type='text/css'>
-<script src="/webui/static/js/jquery.min.js"></script>
+ <meta name="description" content="ASTERIX WEB PAGE" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <link
+ href='http://fonts.googleapis.com/css?family=Bitter|PT+Sans+Caption|Open+Sans'
+ rel='stylesheet' type='text/css'>
+ <script src="/webui/static/js/jquery.min.js"></script>
-<link href="/webui/static/css/bootstrap.min.css" rel="stylesheet"
- type="text/css" />
-<link href="/webui/static/css/bootstrap-responsive.min.css"
- rel="stylesheet" type="text/css" />
+ <link href="/webui/static/css/bootstrap.min.css" rel="stylesheet"
+ type="text/css" />
+ <link href="/webui/static/css/bootstrap-responsive.min.css"
+ rel="stylesheet" type="text/css" />
-<script src="/webui/static/js/bootstrap.min.js"></script>
+ <script src="/webui/static/js/bootstrap.min.js"></script>
-<link href="/webui/static/css/style.css" rel="stylesheet"
- type="text/css" />
-<script src="/webui/static/js/jquery.json-viewer.js"></script>
-<link href="/webui/static/css/jquery.json-viewer.css" type="text/css" rel="stylesheet" />
+ <link href="/webui/static/css/style.css" rel="stylesheet"
+ type="text/css" />
+ <script src="/webui/static/js/jquery.json-viewer.js"></script>
+ <link href="/webui/static/css/jquery.json-viewer.css" type="text/css" rel="stylesheet" />
<script type="text/javascript">
$(document).ready(function() {
@@ -169,13 +169,13 @@
}
}
- /* Handling Pretty JSON */
+ /* Handling Pretty JSON-query result */
var resultFormat = $('#output-format option:checked').text();
if ( resultFormat == 'JSON (formatted)') {
$('.result-content').each(
function(idx) {
var results = $(this).text().split('\n');
- $(this).css('padding-left', '20px');
+ $(this).css('padding-left', '20px');
$(this).text('');
for (var iter1 = 0; iter1 < results.length - 1; iter1++) {
if (results[iter1].length < 1) {
@@ -183,13 +183,39 @@
}
var resultJSON = $.parseJSON(results[iter1]);
$(this).append($('<div/>').attr("id", "json-record"+idx+"-"+iter1));
- $('#json-record'+idx+"-"+iter1).jsonViewer(resultJSON, {collapsed: true, level: 1});
+ $('#json-record'+idx+"-"+iter1).jsonViewer(resultJSON, {collapsed: true, level: 10});
}
}
);
}
+ /* Handling Pretty JSON-logical plan */
+ var planFormat = $('#plan-format option:checked').text();
+ $('.query-plan').addClass("outer");
+ $('.query-optimized-plan').addClass("outer");
+ if ( planFormat == 'JSON (formatted)') {
+ $('.query-plan').each(
+ function() {
+ var planSt = $(this).text();
+ $(this).text('');
+ var planJSON = $.parseJSON(planSt);
+ $(this).append($('<div/>').attr("id", "json-queryPlan"));
+ $('#json-queryPlan').jsonViewer(planJSON, {collapsed: false, level: 10});
+ }
+ );
+ $('.query-optimized-plan').each(
+ function() {
+ var opPlanSt = $(this).text();
+ $(this).text('');
+ var opPlanJSON = $.parseJSON(opPlanSt);
+ $(this).append($('<div/>').attr("id", "json-queryOptimizedPlan").attr("class","inner"));
+ $('#json-queryOptimizedPlan').jsonViewer(opPlanJSON, {collapsed: false, level: 10});
+ }
+ );
+ }
+
+
var contentString = data.toString();
if (contentString.indexOf(durPattern) != -1) {
$('<div/>')
@@ -203,106 +229,129 @@
});
</script>
-<meta charset=utf-8 />
-<title>AsterixDB Web Interface</title>
+ <meta charset=utf-8 />
+ <title>AsterixDB Web Interface</title>
</head>
<body>
- <div class="navbar navbar-fixed-top">
- <div class="navbar-inner">
- <div class="container">
- <a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
- <span class="icon-bar"></span>
- <span class="icon-bar"></span>
- <span class="icon-bar"></span>
- </a>
+<div class="navbar navbar-fixed-top">
+ <div class="navbar-inner">
+ <div class="container">
+ <a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ </a>
- <!-- Temporary logo placeholder -->
- <a class="brand" href="#"><img src="/webui/static/img/finalasterixlogo.png"></a>
+ <!-- Temporary logo placeholder -->
+ <a class="brand" href="#"><img src="/webui/static/img/finalasterixlogo.png"></a>
- <div class="nav-collapse collapse">
- <ul class="nav">
- <li><a href="https://asterixdb.apache.org/" target="_blank">
- Open source<img class="extarget" src="/webui/static/img/targetlink.png"/></a></li>
- <li><a href="https://issues.apache.org/jira/browse/ASTERIXDB" target="_blank">
- File issues<img class="extarget" src="/webui/static/img/targetlink.png"/></a></li>
- <li><a href="https://ci.apache.org/projects/asterixdb/index.html" target="_blank">
- Documentation<img class="extarget" src="/webui/static/img/targetlink.png"/></a></li>
- <li><a href="https://asterixdb.apache.org/community.html" target="_blank">
- Contact<img class="extarget" src="/webui/static/img/targetlink.png"/></a></li>
- </ul>
- </div><!--/.nav-collapse -->
- </div>
+ <div class="nav-collapse collapse">
+ <ul class="nav">
+ <li><a href="https://asterixdb.apache.org/" target="_blank">
+ Open source<img class="extarget" src="/webui/static/img/targetlink.png"/></a></li>
+ <li><a href="https://issues.apache.org/jira/browse/ASTERIXDB" target="_blank">
+ File issues<img class="extarget" src="/webui/static/img/targetlink.png"/></a></li>
+ <li><a href="https://ci.apache.org/projects/asterixdb/index.html" target="_blank">
+ Documentation<img class="extarget" src="/webui/static/img/targetlink.png"/></a></li>
+ <li><a href="https://asterixdb.apache.org/community.html" target="_blank">
+ Contact<img class="extarget" src="/webui/static/img/targetlink.png"/></a></li>
+ </ul>
+ </div><!--/.nav-collapse -->
</div>
</div>
+</div>
- <div class="content">
+<div class="content">
<div class="container">
- <div class="row-fluid">
+ <div class="row-fluid">
- <div class="span6">
+ <div class="span6">
- <form id="queryform" class="form-horizontal" method="post">
- <div style="margin-bottom: 1em;">
- <label class="query">Query</label>
- <textarea rows="10" id="qry" name="query" class="query" value="%s" placeholder="Type your query ..."></textarea>
+ <form id="queryform" class="form-horizontal" method="post">
+ <div style="margin-bottom: 1em;">
+ <label class="query">Query</label>
+ <textarea rows="10" id="qry" name="query" class="query" value="%s"
+ placeholder="Type your query ..."></textarea>
+ </div>
+
+ <div class="btn-group">
+ <button id="checkboxes-on" class="btn">
+ <i id="opts" class="icon-ok" style="display:none;"></i>Select Options
+ </button>
+ <button id="clear-query-button" class="btn">Clear Query</button>
+ <!-- <button id="checkboxes-off" class="btn">Clear All Options</button> -->
+ <button type="submit" id="run-btn" class="btn btn-custom-darken">Run</button>
+ </div>
+
+ <div>
+ <label id="query-language" class="optlabel"> Query Language:<br/>
+ <select name="query-language" class="btn btn-width">
+ <option selected value="SQLPP">SQL++</option>
+ <option value="AQL">AQL</option>
+ </select>
+ </label>
+ <label id="output-format" class="optlabel"> Output Format:<br/>
+ <select name="output-format" class="btn btn-width">
+ <option selected value="CLEAN_JSON">JSON</option>
+ <option value="CLEAN_JSON">JSON (formatted)</option>
+ <option value="ADM">ADM</option>
+ <option value="CSV">CSV (no header)</option>
+ <option value="CSV-Header">CSV (with header)</option>
+ <option value="LOSSLESS_JSON">JSON (lossless)</option>
+ </select>
+ </label>
+ <label id="plan-format" class="optlabel"> Plan Format:<br/>
+ <select name="plan-format" class="btn btn-width">
+ <option selected value="JSON">JSON</option>
+ <option value="CLEAN_JSON">JSON (formatted)</option>
+ <option value="STRING">String</option>
+ </select>
+ </label>
+ <label class="optlabel"><input type="checkbox" name="wrapper-array" value="true"/> Wrap results
+ in outer array</label>
+ <label class="checkbox optlabel"><input type="checkbox" name="print-expr-tree" value="true"/>
+ Print parsed expressions</label>
+ <label class="checkbox optlabel"><input type="checkbox" name="print-rewritten-expr-tree"
+ value="true"/> Print rewritten expressions</label>
+ <div><label class="checkbox optlabel"><input type="checkbox"
+ name="print-logical-plan"
+ value="true"/> Print logical
+ plan</label></div>
+
+ <div><label class="checkbox optlabel"><input type="checkbox"
+ name="print-optimized-logical-plan"
+ value="true"/> Print optimized
+ logical plan</label></div>
+
+ <label class="checkbox optlabel"><input type="checkbox" name="print-job" value="true"/> Print
+ Hyracks job</label>
+ <label class="optlabel"><input type="checkbox" name="execute-query" value="true" checked/>
+ Execute query</label>
+ </div>
+ </form>
</div>
- <div class="btn-group">
- <button id="checkboxes-on" class="btn">
- <i id="opts" class="icon-ok" style="display:none;"></i>Select Options</button>
- <button id="clear-query-button" class="btn">Clear Query</button>
- <!-- <button id="checkboxes-off" class="btn">Clear All Options</button> -->
- <button type="submit" id="run-btn" class="btn btn-custom-darken">Run</button>
+ <div class="span6">
+ <div class="output">
+ <label id="output-heading" class="heading">Output</label>
+ <div id="output-message" class="message">
+ </div>
+ </div>
</div>
-
- <div>
- <label id="query-language" class="optlabel"> Query Language:<br/>
- <select name="query-language" class="btn">
- <option selected value="SQLPP">SQL++</option>
- <option value="AQL">AQL</option>
- </select>
- </label>
- <label id="output-format" class="optlabel"> Output Format:<br/>
- <select name="output-format" class="btn">
- <option selected value="CLEAN_JSON">JSON</option>
- <option value="CLEAN_JSON">JSON (formatted)</option>
- <option value="ADM">ADM</option>
- <option value="CSV">CSV (no header)</option>
- <option value="CSV-Header">CSV (with header)</option>
- <option value="LOSSLESS_JSON">JSON (lossless)</option>
- </select>
- </label>
- <label class="optlabel"><input type="checkbox" name="wrapper-array" value="true" /> Wrap results in outer array</label>
- <label class="checkbox optlabel"><input type="checkbox" name="print-expr-tree" value="true" /> Print parsed expressions</label>
- <label class="checkbox optlabel"><input type="checkbox" name="print-rewritten-expr-tree" value="true" /> Print rewritten expressions</label>
- <label class="checkbox optlabel"><input type="checkbox" name="print-logical-plan" value="true" /> Print logical plan</label>
- <label class="checkbox optlabel"><input type="checkbox" name="print-optimized-logical-plan" value="true" /> Print optimized logical plan</label>
- <label class="checkbox optlabel"><input type="checkbox" name="print-job" value="true" /> Print Hyracks job</label>
- <label class="optlabel"><input type="checkbox" name="execute-query" value="true" checked/> Execute query</label>
- </div>
- </form>
- </div>
-
- <div class="span6">
- <div class="output">
- <label id="output-heading" class="heading">Output</label>
- <div id="output-message" class="message">
- </div>
- </div>
- </div>
-
- </div>
+ </div>
</div>
</div>
- <div class="footer">
- <section class="line"><hr></section>
- <section class="content">
- <section class="left">
- </section>
- <section class="right">
- </section>
+<div class="footer">
+ <section class="line">
+ <hr>
</section>
- </div>
+ <section class="content">
+ <section class="left">
+ </section>
+ <section class="right">
+ </section>
+ </section>
+</div>
</body>
</html>
diff --git a/asterixdb/asterix-app/src/main/resources/webui/static/css/style.css b/asterixdb/asterix-app/src/main/resources/webui/static/css/style.css
index b9b733c..1982e3a 100644
--- a/asterixdb/asterix-app/src/main/resources/webui/static/css/style.css
+++ b/asterixdb/asterix-app/src/main/resources/webui/static/css/style.css
@@ -230,3 +230,33 @@
.span6 {
padding: 24px;
}
+
+.inline-half {
+ display: inline-block;
+ width: 50%;
+ float:left;
+}
+.inline-btn-width{
+ display: inline-block;
+ width: 58%;
+}
+
+.btn-width{
+ width: 30%;
+}
+.inner{
+ float : none;
+}
+
+pre.outer {
+ padding-left :20px;
+ overflow-x : scroll !important;
+ overflow-y : scroll !important;
+ word-wrap : normal !important;
+ word-break : normal !important;
+}
+
+.wrapper {
+ overflow: hidden;
+}
+
diff --git a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/jsonplan/JsonLogicalPlanTest.java b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/jsonplan/JsonLogicalPlanTest.java
new file mode 100644
index 0000000..77d0130
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/jsonplan/JsonLogicalPlanTest.java
@@ -0,0 +1 @@
+/*
* 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.asterix.test.jsonplan;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.logging.Logger;
import org.apache.asterix.api.common.AsterixHyracksIntegrationUtil;
import org.apache.asterix.api.java.AsterixJavaClient;
import org.apache.asterix.app.translator.DefaultStatementExecutorFactory;
import org.apache.asterix.common.config.GlobalConfig;
import org.apache.asterix.common.context.IStorageComponentProvider;
import org.apache.asterix.common.dataflow.ICcApplicationContext;
import org.apache.asterix.common.exceptions.AsterixException;
import org.apache.asterix.compiler.provider.AqlCompilationProvider;
import org.apache.asterix.compiler.provider.ILangCompilationProvider;
import org.apache.asterix.compiler.provider.SqlppCompilationProvider;
import org.apache.asterix.external.util.ExternalDataConstants;
import org.apache.asterix.external.util.IdentitiyResolverFactory;
import org.apache.asterix.file.StorageComponentProvider;
import org.apache.asterix.test.base.AsterixTestHelper;
import org.apache.asterix.test.common.TestHelper;
import org.apache.asterix.test.runtime.HDFSCluster;
import org.apache.asterix.translator.IStatementExecutorFactory;
import org.apache.asterix.translator.SessionConfig.PlanFormat;
import org.apache.hyracks.api.client.IHyracksClientConnection;
import org.junit.AfterClass;
import org.junit.Assume;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.internal.AssumptionViolatedException;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.ObjectMapper;
@RunWith(Parameterized.class)
public class JsonLogicalPlanTest {
private static final Logger LOGGER =
Logger.getLogger(org.apache.asterix.test.jsonplan.JsonLogicalPlanTest.class.getName());
protected static final String SEPARATOR = File.separator;
private static final String EXTENSION_AQL = "aql";
private static final String EXTENSION_SQLPP = "sqlpp";
private static final String EXTENSION_RESULT = "plan";
private static final String FILENAME_IGNORE = "ignore.txt";
private static final String FILENAME_ONLY = "only.txt";
private static final String PATH_BASE =
"src" + SEPARATOR + "test" + SEPARATOR + "resources" + SEPARATOR + "optimizerts" + SEPARATOR;
private static final String PATH_QUERIES = PATH_BASE + "queries" + SEPARATOR;
protected static String PATH_ACTUAL = "target" + File.separator + "jplantest" + SEPARATOR;
protected static boolean optimized = false;
private static final ArrayList<String> ignore = AsterixTestHelper.readTestListFile(FILENAME_IGNORE, PATH_BASE);
private static final ArrayList<String> only = AsterixTestHelper.readTestListFile(FILENAME_ONLY, PATH_BASE);
protected static String TEST_CONFIG_FILE_NAME = "asterix-build-configuration.xml";
private static final ILangCompilationProvider aqlCompilationProvider = new AqlCompilationProvider();
private static final ILangCompilationProvider sqlppCompilationProvider = new SqlppCompilationProvider();
protected static ILangCompilationProvider extensionLangCompilationProvider = null;
protected static IStatementExecutorFactory statementExecutorFactory = new DefaultStatementExecutorFactory();
protected static IStorageComponentProvider storageComponentProvider = new StorageComponentProvider();
protected static AsterixHyracksIntegrationUtil integrationUtil = new AsterixHyracksIntegrationUtil();
@BeforeClass
public static void setUp() throws Exception {
System.setProperty(GlobalConfig.CONFIG_FILE_PROPERTY, TEST_CONFIG_FILE_NAME);
final File outdir = new File(PATH_ACTUAL);
outdir.mkdirs();
HDFSCluster.getInstance().setup();
integrationUtil.init(true);
// Set the node resolver to be the identity resolver that expects node names
// to be node controller ids; a valid assumption in test environment.
System.setProperty(ExternalDataConstants.NODE_RESOLVER_FACTORY_PROPERTY,
IdentitiyResolverFactory.class.getName());
}
@AfterClass
public static void tearDown() throws Exception {
File outdir = new File(PATH_ACTUAL);
File[] files = outdir.listFiles();
if (files == null || files.length == 0) {
outdir.delete();
}
HDFSCluster.getInstance().cleanup();
integrationUtil.deinit(true);
}
private static void suiteBuildPerFile(File file, Collection<Object[]> testArgs, String path) {
if (file.isDirectory() && !file.getName().startsWith(".")) {
for (File innerfile : file.listFiles()) {
String subdir = innerfile.isDirectory() ? path + innerfile.getName() + SEPARATOR : path;
suiteBuildPerFile(innerfile, testArgs, subdir);
}
}
if (file.isFile() && (file.getName().endsWith(EXTENSION_AQL) || file.getName().endsWith(EXTENSION_SQLPP))) {
String resultFileName = AsterixTestHelper.extToResExt(file.getName(), EXTENSION_RESULT);
File actualFile = new File(PATH_ACTUAL + SEPARATOR + path + resultFileName);
testArgs.add(new Object[] { file, actualFile });
}
}
@Parameters(name = "JsonLogicalPlanTest {index}: {0}")
public static Collection<Object[]> tests() {
Collection<Object[]> testArgs = new ArrayList<>();
if (only.isEmpty()) {
suiteBuildPerFile(new File(PATH_QUERIES), testArgs, "");
} else {
for (String path : only) {
suiteBuildPerFile(new File(PATH_QUERIES + path), testArgs,
path.lastIndexOf(SEPARATOR) < 0 ? "" : path.substring(0, path.lastIndexOf(SEPARATOR) + 1));
}
}
return testArgs;
}
private final File actualFile;
private final File queryFile;
public JsonLogicalPlanTest(final File queryFile, final File actualFile) {
this.queryFile = queryFile;
this.actualFile = actualFile;
}
@Test
public void test() throws Exception {
try {
String queryFileShort =
queryFile.getPath().substring(PATH_QUERIES.length()).replace(SEPARATOR.charAt(0), '/');
if (!only.isEmpty()) {
boolean toRun = TestHelper.isInPrefixList(only, queryFileShort);
if (!toRun) {
LOGGER.info("SKIP TEST: \"" + queryFile.getPath()
+ "\" \"only.txt\" not empty and not in \"only.txt\".");
}
Assume.assumeTrue(toRun);
}
boolean skipped = TestHelper.isInPrefixList(ignore, queryFileShort);
if (skipped) {
LOGGER.info("SKIP TEST: \"" + queryFile.getPath() + "\" in \"ignore.txt\".");
}
Assume.assumeTrue(!skipped);
LOGGER.info("RUN TEST: \"" + queryFile.getPath() + "\"");
Reader query = new BufferedReader(new InputStreamReader(new FileInputStream(queryFile), "UTF-8"));
// Forces the creation of actualFile.
actualFile.getParentFile().mkdirs();
PrintWriter plan = new PrintWriter(actualFile);
ILangCompilationProvider provider =
queryFile.getName().endsWith("aql") ? aqlCompilationProvider : sqlppCompilationProvider;
if (extensionLangCompilationProvider != null) {
provider = extensionLangCompilationProvider;
}
IHyracksClientConnection hcc = integrationUtil.getHyracksClientConnection();
AsterixJavaClient asterix =
new AsterixJavaClient((ICcApplicationContext) integrationUtil.cc.getApplicationContext(), hcc,
query, plan, provider, statementExecutorFactory, storageComponentProvider);
try {
asterix.compile(true, false, !optimized, optimized, false, false, false, PlanFormat.JSON);
} catch (AsterixException e) {
plan.close();
query.close();
throw new Exception("Compile ERROR for " + queryFile + ": " + e.getMessage(), e);
}
plan.close();
query.close();
BufferedReader readerActual =
new BufferedReader(new InputStreamReader(new FileInputStream(actualFile), "UTF-8"));
String lineActual, objectActual = "";
boolean firstPlan = false;
while ((lineActual = readerActual.readLine()) != null) {
if (lineActual.contains("--")) {
if (firstPlan) {
break;
}
firstPlan = true;
} else {
objectActual = objectActual + lineActual;
}
}
try {
final JsonParser parser = new ObjectMapper().getJsonFactory().createJsonParser(objectActual);
while (parser.nextToken() != null) {
}
} finally {
readerActual.close();
}
} catch (Exception e) {
if (!(e instanceof AssumptionViolatedException)) {
LOGGER.severe("Test \"" + queryFile.getPath() + "\" FAILED!");
throw new Exception("Test \"" + queryFile.getPath() + "\" FAILED!", e);
} else {
throw e;
}
}
}
}
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/jsonplan/JsonOptimizedLogicalPlanTest.java b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/jsonplan/JsonOptimizedLogicalPlanTest.java
new file mode 100644
index 0000000..b8e4595
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/jsonplan/JsonOptimizedLogicalPlanTest.java
@@ -0,0 +1,39 @@
+/*
+ * 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.asterix.test.jsonplan;
+
+import java.io.File;
+import java.util.logging.Logger;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class JsonOptimizedLogicalPlanTest extends JsonLogicalPlanTest {
+
+ private static final Logger LOGGER =
+ Logger.getLogger(org.apache.asterix.test.jsonplan.JsonOptimizedLogicalPlanTest.class.getName());
+
+ public JsonOptimizedLogicalPlanTest(File queryFile, File actualFile) {
+ super(queryFile, actualFile);
+ optimized = true;
+ PATH_ACTUAL = "target" + File.separator + "joptplantest" + SEPARATOR;
+ }
+}
\ No newline at end of file
diff --git a/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/AbstractLogicalOperator.java b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/AbstractLogicalOperator.java
index 4686f32..8b38a2b 100644
--- a/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/AbstractLogicalOperator.java
+++ b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/AbstractLogicalOperator.java
@@ -19,7 +19,7 @@
package org.apache.hyracks.algebricks.core.algebra.operators.logical;
import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
@@ -63,7 +63,7 @@
private AbstractLogicalOperator.ExecutionMode mode = AbstractLogicalOperator.ExecutionMode.UNPARTITIONED;
protected IPhysicalOperator physicalOperator;
- private final Map<String, Object> annotations = new HashMap<>();
+ private final Map<String, Object> annotations = new IdentityHashMap<String, Object>();
private boolean bJobGenEnabled = true;
protected final List<Mutable<ILogicalOperator>> inputs;
diff --git a/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/prettyprint/AbstractLogicalOperatorPrettyPrintVisitor.java b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/prettyprint/AbstractLogicalOperatorPrettyPrintVisitor.java
new file mode 100644
index 0000000..140ba80
--- /dev/null
+++ b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/prettyprint/AbstractLogicalOperatorPrettyPrintVisitor.java
@@ -0,0 +1,113 @@
+/*
+ * 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 org.apache.commons.lang3.mutable.Mutable;
+import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalPlan;
+import org.apache.hyracks.algebricks.core.algebra.base.IPhysicalOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractLogicalOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractOperatorWithNestedPlans;
+import org.apache.hyracks.algebricks.core.algebra.visitors.ILogicalExpressionVisitor;
+import org.apache.hyracks.algebricks.core.algebra.visitors.ILogicalOperatorVisitor;
+
+public abstract class AbstractLogicalOperatorPrettyPrintVisitor implements ILogicalOperatorVisitor<Void, Integer> {
+ ILogicalExpressionVisitor<String, Integer> exprVisitor;
+ AlgebricksAppendable buffer;
+
+ public AbstractLogicalOperatorPrettyPrintVisitor() {
+ this(new AlgebricksAppendable());
+ }
+
+ public AbstractLogicalOperatorPrettyPrintVisitor(Appendable app) {
+ this(new AlgebricksAppendable(app), new LogicalExpressionPrettyPrintVisitor());
+ }
+
+ public AbstractLogicalOperatorPrettyPrintVisitor(AlgebricksAppendable buffer) {
+ this(buffer, new LogicalExpressionPrettyPrintVisitor());
+ }
+
+ public AbstractLogicalOperatorPrettyPrintVisitor(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);
+ }
+
+ protected static void appendln(AlgebricksAppendable buf, String s) throws AlgebricksException {
+ buf.append(s);
+ buf.append("\n");
+ }
+
+ protected static void append(AlgebricksAppendable buf, String s) throws AlgebricksException {
+ buf.append(s);
+ }
+
+ protected static void pad(AlgebricksAppendable buf, int indent) throws AlgebricksException {
+ for (int i = 0; i < indent; ++i) {
+ buf.append(' ');
+ }
+ }
+
+ public static void printPhysicalOperator(AbstractLogicalOperator op, int indent, AlgebricksAppendable out)
+ throws AlgebricksException {
+ IPhysicalOperator pOp = op.getPhysicalOperator();
+ pad(out, indent);
+ appendln(out, "-- " + pOp.toString() + " |" + op.getExecutionMode() + "|");
+ if (op.hasNestedPlans()) {
+ AbstractOperatorWithNestedPlans opNest = (AbstractOperatorWithNestedPlans) op;
+ for (ILogicalPlan p : opNest.getNestedPlans()) {
+ pad(out, indent + 8);
+ appendln(out, "{");
+ printPhysicalOps(p, out, indent + 10);
+ pad(out, indent + 8);
+ appendln(out, "}");
+ }
+ }
+ for (Mutable<ILogicalOperator> i : op.getInputs()) {
+ printPhysicalOperator((AbstractLogicalOperator) i.getValue(), indent + 2, out);
+ }
+ }
+
+ public static void printPhysicalOps(ILogicalPlan plan, AlgebricksAppendable out, int indent)
+ throws AlgebricksException {
+ for (Mutable<ILogicalOperator> root : plan.getRoots()) {
+ printPhysicalOperator((AbstractLogicalOperator) root.getValue(), indent, out);
+ }
+ }
+}
diff --git a/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/prettyprint/LogicalOperatorPrettyPrintVisitor.java b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/prettyprint/LogicalOperatorPrettyPrintVisitor.java
index 2139627..fe63b89 100644
--- a/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/prettyprint/LogicalOperatorPrettyPrintVisitor.java
+++ b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/prettyprint/LogicalOperatorPrettyPrintVisitor.java
@@ -25,18 +25,21 @@
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.ILogicalOperator;
import org.apache.hyracks.algebricks.core.algebra.base.ILogicalPlan;
+import org.apache.hyracks.algebricks.core.algebra.base.IPhysicalOperator;
import org.apache.hyracks.algebricks.core.algebra.base.LogicalVariable;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractLogicalOperator;
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.DelegateOperator;
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.DelegateOperator;
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;
@@ -65,48 +68,50 @@
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.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 class LogicalOperatorPrettyPrintVisitor extends AbstractLogicalOperatorPrettyPrintVisitor {
public LogicalOperatorPrettyPrintVisitor() {
- this(new AlgebricksAppendable());
- }
-
- public LogicalOperatorPrettyPrintVisitor(Appendable app) {
- this(new AlgebricksAppendable(app), new LogicalExpressionPrettyPrintVisitor());
- }
-
- public LogicalOperatorPrettyPrintVisitor(AlgebricksAppendable buffer) {
- this(buffer, new LogicalExpressionPrettyPrintVisitor());
+ super();
}
public LogicalOperatorPrettyPrintVisitor(AlgebricksAppendable buffer,
ILogicalExpressionVisitor<String, Integer> exprVisitor) {
- reset(buffer);
- this.exprVisitor = exprVisitor;
+ super(buffer, exprVisitor);
}
- public AlgebricksAppendable reset(AlgebricksAppendable buffer) {
- AlgebricksAppendable old = this.buffer;
- this.buffer = buffer;
- return old;
+ public LogicalOperatorPrettyPrintVisitor(AlgebricksAppendable buffer) {
+ super(buffer);
}
- public AlgebricksAppendable get() {
- return buffer;
+ public LogicalOperatorPrettyPrintVisitor(Appendable app) {
+ super(app);
}
- @Override
- public String toString() {
- return buffer.toString();
+ public static void printPlan(ILogicalPlan plan, LogicalOperatorPrettyPrintVisitor pvisitor, int indent)
+ throws AlgebricksException {
+ for (Mutable<ILogicalOperator> root : plan.getRoots()) {
+ printOperator((AbstractLogicalOperator) root.getValue(), pvisitor, indent);
+ }
}
- CharSequence str(Object o) {
- return String.valueOf(o);
+ public static void printOperator(AbstractLogicalOperator op, LogicalOperatorPrettyPrintVisitor pvisitor, int indent)
+ throws AlgebricksException {
+ final AlgebricksAppendable out = pvisitor.get();
+ op.accept(pvisitor, indent);
+ IPhysicalOperator pOp = op.getPhysicalOperator();
+
+ if (pOp != null) {
+ out.append("\n");
+ pad(out, indent);
+ appendln(out, "-- " + pOp.toString() + " |" + op.getExecutionMode() + "|");
+ } else {
+ appendln(out, " -- |" + op.getExecutionMode() + "|");
+ }
+
+ for (Mutable<ILogicalOperator> i : op.getInputs()) {
+ printOperator((AbstractLogicalOperator) i.getValue(), pvisitor, indent + 2);
+ }
}
@Override
@@ -480,7 +485,7 @@
} else {
addIndent(indent).append(" {\n");
}
- PlanPrettyPrinter.printPlan(p, this, indent + 10);
+ printPlan(p, this, indent + 10);
addIndent(indent).append(" }");
}
}
diff --git a/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/prettyprint/LogicalOperatorPrettyPrintVisitorJson.java b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/prettyprint/LogicalOperatorPrettyPrintVisitorJson.java
new file mode 100644
index 0000000..fefb1e9
--- /dev/null
+++ b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/prettyprint/LogicalOperatorPrettyPrintVisitorJson.java
@@ -0,0 +1,748 @@
+/*
+ * 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.Deque;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+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.ILogicalOperator;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalPlan;
+import org.apache.hyracks.algebricks.core.algebra.base.IPhysicalOperator;
+import org.apache.hyracks.algebricks.core.algebra.base.LogicalVariable;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractLogicalOperator;
+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.DelegateOperator;
+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.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.InsertDeleteUpsertOperator.Kind;
+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.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.SplitOperator;
+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.visitors.ILogicalExpressionVisitor;
+
+public class LogicalOperatorPrettyPrintVisitorJson extends AbstractLogicalOperatorPrettyPrintVisitor {
+ Map<AbstractLogicalOperator, String> operatorIdentity = new HashMap<>();
+
+ public LogicalOperatorPrettyPrintVisitorJson(Appendable app) {
+ super(app);
+ }
+
+ IdCounter idCounter = new IdCounter();
+
+ public class IdCounter {
+ private int id;
+ private Deque<Integer> prefix;
+
+ public IdCounter() {
+ prefix = new LinkedList<Integer>();
+ prefix.add(1);
+ this.id = 0;
+ }
+
+ public void previousPrefix() {
+ this.id = prefix.removeLast();
+ }
+
+ public void nextPrefix() {
+ prefix.add(this.id);
+ this.id = 0;
+ }
+
+ public String printOperatorId(AbstractLogicalOperator op) {
+ String stringPrefix = "";
+ Object[] values = this.prefix.toArray();
+ for (Object val : values) {
+ stringPrefix = stringPrefix.isEmpty() ? val.toString() : stringPrefix + "." + val.toString();
+ }
+ if (!operatorIdentity.containsKey(op)) {
+ String opId = stringPrefix.isEmpty() ? "" + Integer.toString(++id)
+ : stringPrefix + "." + Integer.toString(++id);
+ operatorIdentity.put(op, opId);
+ }
+ return operatorIdentity.get(op);
+ }
+ }
+
+ public static void printPlanJson(ILogicalPlan plan, LogicalOperatorPrettyPrintVisitorJson pvisitor, int indent)
+ throws AlgebricksException {
+ for (Mutable<ILogicalOperator> root : plan.getRoots()) {
+ printOperatorJson((AbstractLogicalOperator) root.getValue(), pvisitor, indent);
+ }
+ }
+
+ public static void printOperatorJson(AbstractLogicalOperator op, LogicalOperatorPrettyPrintVisitorJson pvisitor,
+ int indent) throws AlgebricksException {
+ int currentIndent = indent;
+ final AlgebricksAppendable out = pvisitor.get();
+ pad(out, currentIndent);
+ appendln(out, "{");
+ currentIndent++;
+ op.accept(pvisitor, currentIndent);
+ appendln(out, ",");
+ pad(out, currentIndent);
+ append(out, "\"operatorId\" : \"" + pvisitor.idCounter.printOperatorId(op) + "\"");
+ IPhysicalOperator pOp = op.getPhysicalOperator();
+ if (pOp != null) {
+ appendln(out, ",");
+ pad(out, currentIndent);
+ String pOperator = "\"physical-operator\":\"" + pOp.toString() + "\"";
+ append(out, pOperator);
+ }
+ appendln(out, ",");
+ pad(out, currentIndent);
+ append(out, "\"execution-mode\":\"" + op.getExecutionMode() + '"');
+ if (!op.getInputs().isEmpty()) {
+ appendln(out, ",");
+ pad(out, currentIndent);
+ appendln(out, "\"inputs\":[");
+ boolean moreInputes = false;
+ for (Mutable<ILogicalOperator> k : op.getInputs()) {
+ if (moreInputes) {
+ append(out, ",");
+ }
+ printOperatorJson((AbstractLogicalOperator) k.getValue(), pvisitor, currentIndent + 4);
+ moreInputes = true;
+ }
+ pad(out, currentIndent + 2);
+ appendln(out, "]");
+ }
+ out.append("\n");
+ pad(out, currentIndent - 1);
+ appendln(out, "}");
+ }
+
+ public void variablePrintHelper(List<LogicalVariable> variables, Integer indent) throws AlgebricksException {
+ if (!variables.isEmpty()) {
+ addIndent(0).append(",\n");
+ addIndent(indent).append("\"variables\" :[");
+ boolean first = true;
+ for (LogicalVariable v : variables) {
+ if (!first) {
+ buffer.append(",");
+ }
+ buffer.append("\"" + str(v) + "\"");
+ first = false;
+ }
+ buffer.append("]");
+ }
+ }
+
+ @Override
+ public Void visitAggregateOperator(AggregateOperator op, Integer indent) throws AlgebricksException {
+ addIndent(indent).append("\"operator\":\"aggregate\"");
+ variablePrintHelper(op.getVariables(), indent);
+
+ return null;
+ }
+
+ @Override
+ public Void visitRunningAggregateOperator(RunningAggregateOperator op, Integer indent) throws AlgebricksException {
+ addIndent(indent).append("\"operator\":\"running-aggregate\"");
+ variablePrintHelper(op.getVariables(), indent);
+ if (!op.getExpressions().isEmpty()) {
+ addIndent(0).append(",\n");
+ pprintExprList(op.getExpressions(), indent);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitEmptyTupleSourceOperator(EmptyTupleSourceOperator op, Integer indent) throws AlgebricksException {
+ addIndent(indent).append("\"operator\":\"empty-tuple-source\"");
+ return null;
+ }
+
+ @Override
+ public Void visitGroupByOperator(GroupByOperator op, Integer indent) throws AlgebricksException {
+ addIndent(indent).append("\"operator\":\"group-by\"");
+
+ if (op.isGroupAll()) {
+ buffer.append(",\n");
+ addIndent(indent).append("\"option\":\"all\"");
+ }
+ if (!op.getGroupByList().isEmpty()) {
+ buffer.append(",\n");
+ addIndent(indent).append("\"group-by-list\":");
+ pprintVeList(op.getGroupByList(), indent);
+ }
+ if (!op.getDecorList().isEmpty()) {
+ buffer.append(",\n");
+ addIndent(indent).append("\"decor-list\":");
+ pprintVeList(op.getDecorList(), indent);
+ }
+ if (!op.getNestedPlans().isEmpty()) {
+ buffer.append(",\n");
+ addIndent(indent).append("\"subplan\":");
+ printNestedPlans(op, indent);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitDistinctOperator(DistinctOperator op, Integer indent) throws AlgebricksException {
+ addIndent(indent).append("\"operator\":\"distinct\"");
+ if (!op.getExpressions().isEmpty()) {
+ addIndent(0).append(",\n");
+ pprintExprList(op.getExpressions(), indent);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitInnerJoinOperator(InnerJoinOperator op, Integer indent) throws AlgebricksException {
+ addIndent(indent).append("\"operator\":\"join\",\n");
+ addIndent(indent)
+ .append("\"condition\":" + "\"" + op.getCondition().getValue().accept(exprVisitor, indent) + "\"");
+ return null;
+ }
+
+ @Override
+ public Void visitLeftOuterJoinOperator(LeftOuterJoinOperator op, Integer indent) throws AlgebricksException {
+ addIndent(indent).append("\"operator\":\"left-outer-join\",\n");
+ addIndent(indent)
+ .append("\"condition\":" + "\"" + op.getCondition().getValue().accept(exprVisitor, indent) + "\"");
+ return null;
+ }
+
+ @Override
+ public Void visitNestedTupleSourceOperator(NestedTupleSourceOperator op, Integer indent)
+ throws AlgebricksException {
+ addIndent(indent).append("\"operator\":\"nested-tuple-source\"");
+ return null;
+ }
+
+ @Override
+ public Void visitOrderOperator(OrderOperator op, Integer indent) throws AlgebricksException {
+ addIndent(indent).append("\"operator\":\"order\"");
+ for (Pair<OrderOperator.IOrder, Mutable<ILogicalExpression>> p : op.getOrderExpressions()) {
+ buffer.append(",\n");
+ if (op.getTopK() != -1) {
+ addIndent(indent).append("\"topK\":\"" + op.getTopK() + "\",\n");
+ }
+ String fst = getOrderString(p.first);
+ addIndent(indent).append("\"first\":" + fst + ",\n");
+ addIndent(indent)
+ .append("\"second\":\"" + p.second.getValue().accept(exprVisitor, indent).replace('"', ' ') + "\"");
+ }
+ 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("\"operator\":\"assign\"");
+ variablePrintHelper(op.getVariables(), indent);
+ if (!op.getExpressions().isEmpty()) {
+ addIndent(0).append(",\n");
+ pprintExprList(op.getExpressions(), indent);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitWriteOperator(WriteOperator op, Integer indent) throws AlgebricksException {
+ addIndent(indent).append("\"operator\":\"write\"");
+ if (!op.getExpressions().isEmpty()) {
+ addIndent(0).append(",\n");
+ pprintExprList(op.getExpressions(), indent);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitDistributeResultOperator(DistributeResultOperator op, Integer indent) throws AlgebricksException {
+ addIndent(indent).append("\"operator\":\"distribute-result\"");
+ if (!op.getExpressions().isEmpty()) {
+ addIndent(0).append(",\n");
+ pprintExprList(op.getExpressions(), indent);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitWriteResultOperator(WriteResultOperator op, Integer indent) throws AlgebricksException {
+ addIndent(indent).append("\"operator\":\"load\",\n");
+ addIndent(indent).append(str(op.getDataSource())).append("\"from\":")
+ .append(op.getPayloadExpression().getValue().accept(exprVisitor, indent) + ",\n");
+ addIndent(indent).append("\"partitioned-by\":{");
+ pprintExprList(op.getKeyExpressions(), indent);
+ addIndent(indent).append("}");
+ return null;
+ }
+
+ @Override
+ public Void visitSelectOperator(SelectOperator op, Integer indent) throws AlgebricksException {
+ addIndent(indent).append("\"operator\":\"select\",\n");
+ addIndent(indent).append("\"expressions\":\""
+ + op.getCondition().getValue().accept(exprVisitor, indent).replace('"', ' ') + "\"");
+ return null;
+ }
+
+ @Override
+ public Void visitProjectOperator(ProjectOperator op, Integer indent) throws AlgebricksException {
+ addIndent(indent).append("\"operator\":\"project\"");
+ variablePrintHelper(op.getVariables(), indent);
+ return null;
+ }
+
+ @Override
+ public Void visitSubplanOperator(SubplanOperator op, Integer indent) throws AlgebricksException {
+ if (!op.getNestedPlans().isEmpty()) {
+ addIndent(indent).append("\"subplan\":");
+ printNestedPlans(op, indent);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitUnionOperator(UnionAllOperator op, Integer indent) throws AlgebricksException {
+ addIndent(indent).append("\"operator\":\"union\"");
+ for (Triple<LogicalVariable, LogicalVariable, LogicalVariable> v : op.getVariableMappings()) {
+ buffer.append(",\n");
+ addIndent(indent)
+ .append("\"values\":[" + "\"" + v.first + "\"," + "\"" + v.second + "\"," + "\"" + v.third + "\"]");
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitIntersectOperator(IntersectOperator op, Integer indent) throws AlgebricksException {
+ addIndent(indent).append("\"operator\":\"intersect\",\n");
+
+ addIndent(indent).append("\"output-variables\":[");
+ for (int i = 0; i < op.getOutputVars().size(); i++) {
+ if (i > 0) {
+ buffer.append(", ");
+ }
+ buffer.append("\"" + str(op.getOutputVars().get(i)) + "\"");
+ }
+ buffer.append("],");
+ addIndent(indent).append("\"input_variables\":[");
+ for (int i = 0; i < op.getNumInput(); i++) {
+ if (i > 0) {
+ buffer.append(",\n");
+ }
+ 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("\"operator\":\"unnest\"");
+ variablePrintHelper(op.getVariables(), indent);
+ if (op.getPositionalVariable() != null) {
+ buffer.append(",\n");
+ addIndent(indent).append("\"position\":\"" + op.getPositionalVariable() + "\"");
+ }
+ buffer.append(",\n");
+ addIndent(indent).append("\"expressions\":\""
+ + op.getExpressionRef().getValue().accept(exprVisitor, indent).replace('"', ' ') + "\"");
+ return null;
+ }
+
+ @Override
+ public Void visitLeftOuterUnnestOperator(LeftOuterUnnestOperator op, Integer indent) throws AlgebricksException {
+ addIndent(indent).append("\"operator\":\"outer-unnest\",\n");
+ addIndent(indent).append("\"variables\":[\"" + op.getVariable() + "\"]");
+ if (op.getPositionalVariable() != null) {
+ buffer.append(",\n");
+ addIndent(indent).append("\"position\":" + op.getPositionalVariable());
+ }
+ buffer.append(",\n");
+ addIndent(indent).append("\"expressions\":\""
+ + op.getExpressionRef().getValue().accept(exprVisitor, indent).replace('"', ' ') + "\"");
+ 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 {
+ AlgebricksAppendable plan = addIndent(indent).append("\"operator\":\"" + opSignature + "\"");
+ variablePrintHelper(op.getVariables(), indent);
+ buffer.append(",\n");
+ addIndent(indent).append("\"expressions\":\""
+ + op.getExpressionRef().getValue().accept(exprVisitor, indent).replace('"', ' ') + "\"");
+ appendFilterInformation(plan, op.getMinFilterVars(), op.getMaxFilterVars(), indent);
+ return null;
+ }
+
+ @Override
+ public Void visitDataScanOperator(DataSourceScanOperator op, Integer indent) throws AlgebricksException {
+ AlgebricksAppendable plan = addIndent(indent).append("\"operator\":\"data-scan\"");
+ if (!op.getProjectVariables().isEmpty()) {
+ addIndent(0).append(",\n");
+ addIndent(indent).append("\"project-variables\":[");
+ boolean first = true;
+ for (LogicalVariable v : op.getProjectVariables()) {
+ if (!first) {
+ buffer.append(",");
+ }
+ buffer.append("\"" + str(v) + "\"");
+ first = false;
+ }
+ buffer.append("]");
+ }
+ variablePrintHelper(op.getVariables(), indent);
+ if (op.getDataSource() != null) {
+ addIndent(0).append(",\n");
+ addIndent(indent).append("\"data-source\":\"" + op.getDataSource() + "\"");
+ }
+ appendFilterInformation(plan, op.getMinFilterVars(), op.getMaxFilterVars(), indent);
+ return null;
+ }
+
+ private Void appendFilterInformation(AlgebricksAppendable plan, List<LogicalVariable> minFilterVars,
+ List<LogicalVariable> maxFilterVars, Integer indent) throws AlgebricksException {
+ if (minFilterVars != null || maxFilterVars != null) {
+ plan.append(",\n");
+ addIndent(indent);
+ plan.append("\"with-filter-on\":{");
+ }
+ if (minFilterVars != null) {
+ buffer.append("\n");
+ addIndent(indent).append("\"min\":[");
+ boolean first = true;
+ for (LogicalVariable v : minFilterVars) {
+ if (!first) {
+ buffer.append(",");
+ }
+ buffer.append("\"" + str(v) + "\"");
+ first = false;
+ }
+ buffer.append("]");
+ }
+ if (minFilterVars != null && maxFilterVars != null) {
+ buffer.append(",");
+ }
+ if (maxFilterVars != null) {
+ buffer.append("\n");
+ addIndent(indent).append("\"max\":[");
+ boolean first = true;
+ for (LogicalVariable v : maxFilterVars) {
+ if (!first) {
+ buffer.append(",");
+ }
+ buffer.append("\"" + str(v) + "\"");
+ first = false;
+ }
+ buffer.append("]");
+ }
+ if (minFilterVars != null || maxFilterVars != null) {
+ plan.append("\n");
+ addIndent(indent).append("}");
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitLimitOperator(LimitOperator op, Integer indent) throws AlgebricksException {
+ addIndent(indent).append("\"operator\":\"limit\",\n");
+ addIndent(indent).append("\"value\":\"" + op.getMaxObjects().getValue().accept(exprVisitor, indent) + "\"");
+ ILogicalExpression offset = op.getOffset().getValue();
+ if (offset != null) {
+ buffer.append(",\n");
+ addIndent(indent).append("\"offset\":\"" + offset.accept(exprVisitor, indent) + "\"");
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitExchangeOperator(ExchangeOperator op, Integer indent) throws AlgebricksException {
+ addIndent(indent).append("\"operator\":\"exchange\"");
+ return null;
+ }
+
+ @Override
+ public Void visitScriptOperator(ScriptOperator op, Integer indent) throws AlgebricksException {
+ addIndent(indent).append("\"operator\":\"script\"");
+ if (!op.getInputVariables().isEmpty()) {
+ addIndent(0).append(",\n");
+ addIndent(indent).append("\"in\":[");
+ boolean first = true;
+ for (LogicalVariable v : op.getInputVariables()) {
+ if (!first) {
+ buffer.append(",");
+ }
+ buffer.append("\"" + str(v) + "\"");
+ first = false;
+ }
+ buffer.append("]");
+ }
+ if (!op.getOutputVariables().isEmpty()) {
+ addIndent(0).append(",\n");
+ addIndent(indent).append("\"out\":[");
+ boolean first = true;
+ for (LogicalVariable v : op.getOutputVariables()) {
+ if (!first) {
+ buffer.append(",");
+ }
+ buffer.append("\"" + str(v) + "\"");
+ first = false;
+ }
+ buffer.append("]");
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitReplicateOperator(ReplicateOperator op, Integer indent) throws AlgebricksException {
+ addIndent(indent).append("\"operator\":\"replicate\"");
+ return null;
+ }
+
+ @Override
+ public Void visitSplitOperator(SplitOperator op, Integer indent) throws AlgebricksException {
+ Mutable<ILogicalExpression> branchingExpression = op.getBranchingExpression();
+ addIndent(indent).append("\"operator\":\"split\",\n");
+ addIndent(indent).append("\"" + branchingExpression.getValue().accept(exprVisitor, indent) + "\"");
+ return null;
+ }
+
+ @Override
+ public Void visitMaterializeOperator(MaterializeOperator op, Integer indent) throws AlgebricksException {
+ addIndent(indent).append("\"operator\":\"materialize\"");
+ return null;
+ }
+
+ @Override
+ public Void visitInsertDeleteUpsertOperator(InsertDeleteUpsertOperator op, Integer indent)
+ throws AlgebricksException {
+ String header = "\"operator\":\"" + getIndexOpString(op.getOperation()) + "\",\n";
+ addIndent(indent).append(header);
+ addIndent(indent).append(str("\"data-source\":\"" + op.getDataSource() + "\",\n"));
+ addIndent(indent).append("\"from-record\":\"")
+ .append(op.getPayloadExpression().getValue().accept(exprVisitor, indent) + "\"");
+ if (op.getAdditionalNonFilteringExpressions() != null) {
+ buffer.append(",\n\"meta\":\"");
+ pprintExprList(op.getAdditionalNonFilteringExpressions(), 0);
+ buffer.append("\"");
+ }
+ buffer.append(",\n");
+ addIndent(indent).append("\"partitioned-by\":{");
+ pprintExprList(op.getPrimaryKeyExpressions(), 0);
+ buffer.append("}");
+ if (op.getOperation() == Kind.UPSERT) {
+ addIndent(indent).append(",\n\"out\":{\n");
+ addIndent(indent).append("\"record-before-upsert\":\"" + op.getBeforeOpRecordVar() + "\"");
+ if (op.getBeforeOpAdditionalNonFilteringVars() != null) {
+ buffer.append(",\n");
+ addIndent(indent)
+ .append("\"additional-before-upsert\":\"" + op.getBeforeOpAdditionalNonFilteringVars() + "\"");
+ }
+ addIndent(indent).append("}");
+ }
+ if (op.isBulkload()) {
+ buffer.append(",\n");
+ addIndent(indent).append("\"bulkload\":\"true\"");
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitIndexInsertDeleteUpsertOperator(IndexInsertDeleteUpsertOperator op, Integer indent)
+ throws AlgebricksException {
+ String header = getIndexOpString(op.getOperation());
+ addIndent(indent).append("\"operator\":\"" + header + "\",\n");
+ addIndent(indent).append("\"index\":\"" + op.getIndexName() + "\",\n");
+ addIndent(indent).append("\"on\":\"").append(str(op.getDataSourceIndex().getDataSource()) + "\",\n");
+ addIndent(indent).append("\"from\":{");
+
+ if (op.getOperation() == Kind.UPSERT) {
+
+ addIndent(indent).append("[\"replace\":\"");
+ pprintExprList(op.getPrevSecondaryKeyExprs(), 0);
+ buffer.append("\",\n");
+ addIndent(indent).append("\"with\":\"");
+ pprintExprList(op.getSecondaryKeyExpressions(), 0);
+ buffer.append("\"}");
+ } else {
+ pprintExprList(op.getSecondaryKeyExpressions(), 0);
+ }
+ buffer.append("\n");
+ addIndent(indent).append("}");
+ if (op.isBulkload()) {
+ buffer.append(",\n");
+ buffer.append("\"bulkload\":\"true\"");
+ }
+ 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("\"operator\":\"tokenize\"");
+ variablePrintHelper(op.getTokenizeVars(), indent);
+ if (!op.getSecondaryKeyExpressions().isEmpty()) {
+ addIndent(0).append(",\n");
+ pprintExprList(op.getSecondaryKeyExpressions(), indent);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitSinkOperator(SinkOperator op, Integer indent) throws AlgebricksException {
+ addIndent(indent).append("\"operator\":\"sink\"");
+ return null;
+ }
+
+ @Override
+ public Void visitDelegateOperator(DelegateOperator op, Integer indent) throws AlgebricksException {
+ addIndent(indent).append("\"operator\":\"" + 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 {
+ idCounter.nextPrefix();
+ buffer.append("[\n");
+ boolean first = true;
+ for (ILogicalPlan p : op.getNestedPlans()) {
+ if (!first) {
+ buffer.append(",");
+ }
+ printPlanJson(p, this, indent + 4);
+ first = false;
+
+ }
+ addIndent(indent).append("]");
+ idCounter.previousPrefix();
+ }
+
+ //Done--Look for exprRef
+ protected void pprintExprList(List<Mutable<ILogicalExpression>> expressions, Integer indent)
+ throws AlgebricksException {
+ addIndent(indent);
+ buffer.append("\"expressions\":\"");
+ boolean first = true;
+ for (Mutable<ILogicalExpression> exprRef : expressions) {
+ if (first) {
+ first = false;
+ } else {
+ buffer.append(", ");
+ }
+ buffer.append(exprRef.getValue().accept(exprVisitor, indent).replace('"', ' '));
+ }
+ 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("{\"variable\":\"" + ve.first.toString().replace('"', ' ') + "\"," + "\"expression\":\""
+ + ve.second.toString().replace('"', ' ') + "\"}");
+ } else {
+ buffer.append("{\"expression\":\"" + ve.second.getValue().accept(exprVisitor, indent).replace('"', ' ')
+ + "\"}");
+ }
+ }
+ buffer.append("]");
+ }
+
+}
diff --git a/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/prettyprint/PlanPrettyPrinter.java b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/prettyprint/PlanPrettyPrinter.java
index 9a55f11..cf99d3b 100644
--- a/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/prettyprint/PlanPrettyPrinter.java
+++ b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/prettyprint/PlanPrettyPrinter.java
@@ -18,76 +18,42 @@
*/
package org.apache.hyracks.algebricks.core.algebra.prettyprint;
-import org.apache.commons.lang3.mutable.Mutable;
import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
-import org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator;
import org.apache.hyracks.algebricks.core.algebra.base.ILogicalPlan;
-import org.apache.hyracks.algebricks.core.algebra.base.IPhysicalOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractLogicalOperator;
-import org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractOperatorWithNestedPlans;
public class PlanPrettyPrinter {
- public static void printPlan(ILogicalPlan plan, LogicalOperatorPrettyPrintVisitor pvisitor, int indent)
- throws AlgebricksException {
- for (Mutable<ILogicalOperator> root : plan.getRoots()) {
- printOperator((AbstractLogicalOperator) root.getValue(), pvisitor, indent);
+ @FunctionalInterface
+ public interface print<T1, T2, T3> {
+ void apply(T1 arg1, T2 arg2, T3 arg3) throws AlgebricksException;
+ }
+
+ public static void printOperator(AbstractLogicalOperator op, LogicalOperatorPrettyPrintVisitor pvisitor,
+ int indent) throws AlgebricksException {
+ print<AbstractLogicalOperator, LogicalOperatorPrettyPrintVisitor, Integer> printOperator =
+ LogicalOperatorPrettyPrintVisitor::printOperator;
+ printOperator.apply(op, pvisitor, indent);
+ }
+
+ public static <T extends AbstractLogicalOperatorPrettyPrintVisitor> void printPlan(ILogicalPlan plan,
+ T pvisitor, int indent) throws AlgebricksException {
+ if (pvisitor.getClass().equals(LogicalOperatorPrettyPrintVisitor.class)) {
+ print<ILogicalPlan, LogicalOperatorPrettyPrintVisitor, Integer> printPlan =
+ LogicalOperatorPrettyPrintVisitor::printPlan;
+ printPlan.apply(plan,(LogicalOperatorPrettyPrintVisitor) pvisitor, indent);
}
+ else if (pvisitor.getClass().equals(LogicalOperatorPrettyPrintVisitorJson.class)) {
+ print<ILogicalPlan, LogicalOperatorPrettyPrintVisitorJson, Integer> printPlan =
+ LogicalOperatorPrettyPrintVisitorJson::printPlanJson;
+ printPlan.apply(plan, (LogicalOperatorPrettyPrintVisitorJson)pvisitor, indent);
+ }
+
}
public static void printPhysicalOps(ILogicalPlan plan, AlgebricksAppendable out, int indent)
throws AlgebricksException {
- for (Mutable<ILogicalOperator> root : plan.getRoots()) {
- printPhysicalOperator((AbstractLogicalOperator) root.getValue(), indent, out);
- }
- }
-
- public static void printOperator(AbstractLogicalOperator op, LogicalOperatorPrettyPrintVisitor pvisitor, int indent)
- throws AlgebricksException {
- final AlgebricksAppendable out = pvisitor.get();
- op.accept(pvisitor, indent);
- IPhysicalOperator pOp = op.getPhysicalOperator();
-
- if (pOp != null) {
- out.append("\n");
- pad(out, indent);
- appendln(out, "-- " + pOp.toString() + " |" + op.getExecutionMode() + "|");
- } else {
- appendln(out, " -- |" + op.getExecutionMode() + "|");
- }
-
- for (Mutable<ILogicalOperator> i : op.getInputs()) {
- printOperator((AbstractLogicalOperator) i.getValue(), pvisitor, indent + 2);
- }
- }
-
- private static void printPhysicalOperator(AbstractLogicalOperator op, int indent, AlgebricksAppendable out)
- throws AlgebricksException {
- IPhysicalOperator pOp = op.getPhysicalOperator();
- pad(out, indent);
- appendln(out, "-- " + pOp.toString() + " |" + op.getExecutionMode() + "|");
- if (op.hasNestedPlans()) {
- AbstractOperatorWithNestedPlans opNest = (AbstractOperatorWithNestedPlans) op;
- for (ILogicalPlan p : opNest.getNestedPlans()) {
- pad(out, indent + 8);
- appendln(out, "{");
- printPhysicalOps(p, out, indent + 10);
- pad(out, indent + 8);
- appendln(out, "}");
- }
- }
- for (Mutable<ILogicalOperator> i : op.getInputs()) {
- printPhysicalOperator((AbstractLogicalOperator) i.getValue(), indent + 2, out);
- }
- }
-
- private static void appendln(AlgebricksAppendable buf, String s) throws AlgebricksException {
- buf.append(s);
- buf.append("\n");
- }
-
- private static void pad(AlgebricksAppendable buf, int indent) throws AlgebricksException {
- for (int i = 0; i < indent; ++i) {
- buf.append(' ');
- }
+ print<ILogicalPlan, AlgebricksAppendable, Integer> printOperator =
+ AbstractLogicalOperatorPrettyPrintVisitor::printPhysicalOps;
+ printOperator.apply(plan, out, indent);
}
}
diff --git a/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/visitors/ILogicalOperatorVisitor.java b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/visitors/ILogicalOperatorVisitor.java
index 8da41e2..deb98b0 100644
--- a/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/visitors/ILogicalOperatorVisitor.java
+++ b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/visitors/ILogicalOperatorVisitor.java
@@ -22,11 +22,11 @@
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.DelegateOperator;
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.DelegateOperator;
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;