This is an automated email from the ASF dual-hosted git repository.
alsuliman pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/asterixdb.git
The following commit(s) were added to refs/heads/master by this push:
new 0e31085648 [ASTERIXDB-3224] Added support for printing logical plan in
DOT format
0e31085648 is described below
commit 0e310856484a45a5a2d1d639eabccfde61873ed2
Author: Suryaa <[email protected]>
AuthorDate: Thu Mar 13 17:22:57 2025 -0700
[ASTERIXDB-3224] Added support for printing logical plan in DOT format
- Added support in UI and API(s)
Change-Id: Ia6e37080a581292744ddd9030b294936513c15ac
Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/19390
Tested-by: Jenkins <[email protected]>
Integration-Tests: Jenkins <[email protected]>
Reviewed-by: Ian Maxon <[email protected]>
---
.../translator/ExecutionPlansJsonPrintUtil.java | 3 ++
.../apache/asterix/translator/SessionConfig.java | 44 ++++++++++++++++++++--
.../apache/asterix/api/common/APIFramework.java | 24 +++++++++++-
.../apache/asterix/api/http/server/ApiServlet.java | 7 +++-
.../api/http/server/QueryResultApiServlet.java | 5 ++-
.../http/server/QueryServiceRequestParameters.java | 19 +++++++++-
.../api/http/server/QueryServiceServlet.java | 2 +
.../apache/asterix/api/java/AsterixJavaClient.java | 3 +-
.../asterix/app/result/fields/PlansPrinter.java | 1 +
.../src/main/resources/webui/querytemplate.html | 1 +
.../api/compileonly/compileonly.6.plans.sqlpp | 27 +++++++++++++
.../api/compileonly/compileonly.7.plans.sqlpp | 27 +++++++++++++
.../api/compileonly/compileonly.8.plans.sqlpp | 27 +++++++++++++
.../api/compileonly/compileonly.6.regexjson | 3 ++
.../api/compileonly/compileonly.7.regexjson | 3 ++
.../results/api/compileonly/compileonly.8.regex | 1 +
.../src/app/dashboard/query/input.component.html | 1 +
17 files changed, 187 insertions(+), 11 deletions(-)
diff --git
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/ExecutionPlansJsonPrintUtil.java
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/ExecutionPlansJsonPrintUtil.java
index ad89ad68c0..bf010c5af4 100644
---
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/ExecutionPlansJsonPrintUtil.java
+++
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/ExecutionPlansJsonPrintUtil.java
@@ -66,6 +66,9 @@ public class ExecutionPlansJsonPrintUtil {
case STRING:
JSONUtil.quoteAndEscape(builder, value);
break;
+ case DOT:
+ JSONUtil.quoteAndEscape(builder, value);
+ break;
default:
throw new IllegalStateException("Unrecognized plan format:
" + format);
}
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 4e294ecf12..b7eb98b13f 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
@@ -59,7 +59,8 @@ public class SessionConfig implements Serializable {
public enum PlanFormat {
JSON,
- STRING;
+ STRING,
+ DOT;
public static PlanFormat get(String fmtString, String label,
PlanFormat defaultFmt, Logger logger) {
try {
if (fmtString != null) {
@@ -79,6 +80,24 @@ public class SessionConfig implements Serializable {
JDBC
}
+ /**
+ * Used to specify the format for Hyracks Job
+ */
+ public enum HyracksJobFormat {
+ JSON,
+ DOT;
+ public static HyracksJobFormat get(String fmtString, String label,
HyracksJobFormat defaultFmt, Logger logger) {
+ try {
+ if (fmtString != null) {
+ return HyracksJobFormat.valueOf(fmtString.toUpperCase());
+ }
+ } catch (IllegalArgumentException e) {
+ logger.log(Level.INFO, fmtString + ": unsupported " + label +
", using " + defaultFmt + "instead", e);
+ }
+ return defaultFmt;
+ }
+ }
+
/**
* Produce out-of-band output for Hyracks Job.
*/
@@ -140,6 +159,7 @@ public class SessionConfig implements Serializable {
// Output format.
private OutputFormat fmt;
private PlanFormat planFormat;
+ private HyracksJobFormat hyracksJobFormat;
// Standard execution flags.
private boolean executeQuery;
@@ -155,7 +175,11 @@ public class SessionConfig implements Serializable {
}
public SessionConfig(OutputFormat fmt, PlanFormat planFormat) {
- this(fmt, true, true, true, planFormat);
+ this(fmt, true, true, true, planFormat, HyracksJobFormat.JSON);
+ }
+
+ public SessionConfig(OutputFormat fmt, PlanFormat planFormat,
HyracksJobFormat jobFormat) {
+ this(fmt, true, true, true, planFormat, jobFormat);
}
/**
@@ -173,11 +197,11 @@ public class SessionConfig implements Serializable {
* Whether to generate the Hyracks job specification (if
*/
public SessionConfig(OutputFormat fmt, boolean optimize, boolean
executeQuery, boolean generateJobSpec) {
- this(fmt, optimize, executeQuery, generateJobSpec, PlanFormat.STRING);
+ this(fmt, optimize, executeQuery, generateJobSpec, PlanFormat.STRING,
HyracksJobFormat.DOT);
}
public SessionConfig(OutputFormat fmt, boolean optimize, boolean
executeQuery, boolean generateJobSpec,
- PlanFormat planFormat) {
+ PlanFormat planFormat, HyracksJobFormat jobFormat) {
this.fmt = fmt;
this.optimize = optimize;
this.executeQuery = executeQuery;
@@ -185,6 +209,7 @@ public class SessionConfig implements Serializable {
this.flags = new HashMap<>();
this.planFormat = planFormat;
this.clientType = ClientType.ASTERIX;
+ this.hyracksJobFormat = jobFormat;
}
/**
@@ -220,6 +245,17 @@ public class SessionConfig implements Serializable {
this.planFormat = planFormat;
}
+ /**
+ * Retrieve the HyracksJobFormat for this execution.
+ */
+ public HyracksJobFormat getHyracksJobFormat() {
+ return this.hyracksJobFormat;
+ }
+
+ public void setHyracksJobFormat(HyracksJobFormat hyracksJobFormat) {
+ this.hyracksJobFormat = hyracksJobFormat;
+ }
+
/**
* Retrieve the maximum number of warnings to be reported.
*/
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 c5fc39527c..06c8c5d7a0 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
@@ -98,6 +98,7 @@ import
org.apache.hyracks.algebricks.core.algebra.prettyprint.IPlanPrettyPrinter
import
org.apache.hyracks.algebricks.core.algebra.prettyprint.PlanPrettyPrinter;
import
org.apache.hyracks.algebricks.core.rewriter.base.IOptimizationContextFactory;
import
org.apache.hyracks.algebricks.core.rewriter.base.PhysicalOptimizationConfig;
+import org.apache.hyracks.algebricks.core.utils.DotFormatGenerator;
import org.apache.hyracks.algebricks.data.IPrinterFactoryProvider;
import
org.apache.hyracks.algebricks.runtime.serializer.ResultSerializerFactoryProvider;
import org.apache.hyracks.algebricks.runtime.writers.PrinterBasedWriterFactory;
@@ -388,7 +389,7 @@ public class APIFramework {
}
if (isQuery && conf.is(SessionConfig.OOB_HYRACKS_JOB)) {
- generateJob(spec);
+ generateJob(spec, output.config().getHyracksJobFormat());
}
return spec;
@@ -580,12 +581,22 @@ public class APIFramework {
private void generateLogicalPlan(ILogicalPlan plan,
SessionConfig.PlanFormat format,
boolean printOptimizerEstimates) throws AlgebricksException {
+ if (format.equals(SessionConfig.PlanFormat.DOT)) {
+ DotFormatGenerator planGenerator = new DotFormatGenerator();
+ executionPlans.setLogicalPlan(planGenerator.generate(plan, true));
+ return;
+ }
executionPlans
.setLogicalPlan(getPrettyPrintVisitor(format).printPlan(plan,
printOptimizerEstimates).toString());
}
private void generateOptimizedLogicalPlan(ILogicalPlan plan, Map<Object,
String> log2phys,
SessionConfig.PlanFormat format, boolean printOptimizerEstimates)
throws AlgebricksException {
+ if (format.equals(SessionConfig.PlanFormat.DOT)) {
+ DotFormatGenerator planGenerator = new DotFormatGenerator();
+
executionPlans.setOptimizedLogicalPlan(planGenerator.generate(plan, true));
+ return;
+ }
executionPlans.setOptimizedLogicalPlan(
getPrettyPrintVisitor(format).printPlan(plan, log2phys,
printOptimizerEstimates).toString());
}
@@ -606,11 +617,20 @@ public class APIFramework {
private void generateOptimizedLogicalPlan(ILogicalPlan plan,
SessionConfig.PlanFormat format,
boolean printOptimizerEstimates) throws AlgebricksException {
+ if (format.equals(SessionConfig.PlanFormat.DOT)) {
+ DotFormatGenerator planGenerator = new DotFormatGenerator();
+
executionPlans.setOptimizedLogicalPlan(planGenerator.generate(plan, true));
+ return;
+ }
executionPlans.setOptimizedLogicalPlan(
getPrettyPrintVisitor(format).printPlan(plan,
printOptimizerEstimates).toString());
}
- private void generateJob(JobSpecification spec) {
+ private void generateJob(JobSpecification spec,
SessionConfig.HyracksJobFormat format) {
+ if (format.equals(SessionConfig.HyracksJobFormat.DOT)) {
+
executionPlans.setJob(org.apache.hyracks.api.util.DotFormatGenerator.generate(spec));
+ return;
+ }
final StringWriter stringWriter = new StringWriter();
try (PrintWriter writer = new PrintWriter(stringWriter)) {
writer.println(OBJECT_WRITER.writeValueAsString(spec.toJSON()));
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 56ad88e4c6..53abe1baaf 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
@@ -50,6 +50,7 @@ import org.apache.asterix.translator.IStatementExecutor;
import org.apache.asterix.translator.IStatementExecutorFactory;
import org.apache.asterix.translator.ResultProperties;
import org.apache.asterix.translator.SessionConfig;
+import org.apache.asterix.translator.SessionConfig.HyracksJobFormat;
import org.apache.asterix.translator.SessionConfig.OutputFormat;
import org.apache.asterix.translator.SessionConfig.PlanFormat;
import org.apache.asterix.translator.SessionOutput;
@@ -121,7 +122,8 @@ public class ApiServlet extends AbstractServlet {
}
PlanFormat planFormat =
PlanFormat.get(request.getParameter("plan-format"), "plan
format", PlanFormat.STRING, LOGGER);
-
+ HyracksJobFormat hyracksJobFormat =
HyracksJobFormat.get(request.getParameter("hyracks-job-format"),
+ "hyracks-job-format", HyracksJobFormat.JSON, LOGGER);
String query = request.getParameter("query");
String wrapperArray = request.getParameter("wrapper-array");
String printExprParam = request.getParameter("print-expr-tree");
@@ -137,7 +139,8 @@ public class ApiServlet extends AbstractServlet {
IResultSet resultSet = ServletUtil.getResultSet(appCtx, ctx);
IParser parser = parserFactory.createParser(query);
List<Statement> statements = parser.parse();
- SessionConfig sessionConfig = new SessionConfig(format, true,
isSet(executeQuery), true, planFormat);
+ SessionConfig sessionConfig =
+ new SessionConfig(format, true, isSet(executeQuery), true,
planFormat, hyracksJobFormat);
sessionConfig.set(SessionConfig.FORMAT_HTML, true);
sessionConfig.set(SessionConfig.FORMAT_CSV_HEADER, csvAndHeader);
sessionConfig.set(SessionConfig.FORMAT_WRAPPER_ARRAY,
isSet(wrapperArray));
diff --git
a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryResultApiServlet.java
b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryResultApiServlet.java
index 77846d541b..3b0e031690 100644
---
a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryResultApiServlet.java
+++
b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryResultApiServlet.java
@@ -146,10 +146,13 @@ public class QueryResultApiServlet extends
AbstractQueryApiServlet {
}
SessionConfig.PlanFormat planFormat =
SessionConfig.PlanFormat.get(request.getParameter("plan-format"),
"plan format", SessionConfig.PlanFormat.STRING, LOGGER);
+ SessionConfig.HyracksJobFormat hyracksJobFormat =
+
SessionConfig.HyracksJobFormat.get(request.getParameter("hyracks-job-format"),
"hyracks-job-format",
+ SessionConfig.HyracksJobFormat.JSON, LOGGER);
SessionOutput.ResultAppender appendHandle = (app, handle) ->
app.append("{ \"").append("handle")
.append("\":" + " \"").append(handle).append("\" }");
- SessionConfig sessionConfig = new SessionConfig(format, planFormat);
+ SessionConfig sessionConfig = new SessionConfig(format, planFormat,
hyracksJobFormat);
// 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/http/server/QueryServiceRequestParameters.java
b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryServiceRequestParameters.java
index 563f49864f..e8cb86d307 100644
---
a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryServiceRequestParameters.java
+++
b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryServiceRequestParameters.java
@@ -36,6 +36,7 @@ import
org.apache.asterix.common.exceptions.RuntimeDataException;
import org.apache.asterix.translator.IStatementExecutor.ResultDelivery;
import org.apache.asterix.translator.IStatementExecutor.Stats.ProfileType;
import org.apache.asterix.translator.SessionConfig.ClientType;
+import org.apache.asterix.translator.SessionConfig.HyracksJobFormat;
import org.apache.asterix.translator.SessionConfig.OutputFormat;
import org.apache.asterix.translator.SessionConfig.PlanFormat;
import org.apache.commons.lang3.StringUtils;
@@ -70,6 +71,7 @@ public class QueryServiceRequestParameters {
MODE("mode"),
TIMEOUT("timeout"),
PLAN_FORMAT("plan-format"),
+ HYRACKS_JOB_FORMAT("hyracks-job-format"),
MAX_RESULT_READS("max-result-reads"),
EXPRESSION_TREE("expression-tree"),
REWRITTEN_EXPRESSION_TREE("rewritten-expression-tree"),
@@ -114,7 +116,9 @@ public class QueryServiceRequestParameters {
}
private static final Map<String, PlanFormat> planFormats =
ImmutableMap.of(HttpUtil.ContentType.JSON,
- PlanFormat.JSON, "clean_json", PlanFormat.JSON, "string",
PlanFormat.STRING);
+ PlanFormat.JSON, "clean_json", PlanFormat.JSON, "string",
PlanFormat.STRING, "dot", PlanFormat.DOT);
+ private static final Map<String, HyracksJobFormat> hyracksJobFormats =
+ ImmutableMap.of(HttpUtil.ContentType.JSON, HyracksJobFormat.JSON,
"dot", HyracksJobFormat.DOT);
private static final Map<String, ClientType> clientTypes =
ImmutableMap.of("asterix", ClientType.ASTERIX, "jdbc",
ClientType.JDBC);
private static final Map<String, Boolean> booleanValues =
@@ -134,6 +138,7 @@ public class QueryServiceRequestParameters {
private OutputFormat format = OutputFormat.CLEAN_JSON;
private ResultDelivery mode = ResultDelivery.IMMEDIATE;
private PlanFormat planFormat = PlanFormat.JSON;
+ private HyracksJobFormat hyracksJobFormat = HyracksJobFormat.JSON;
private ProfileType profileType = ProfileType.COUNTS;
private Map<String, String> optionalParams = null;
private Map<String, JsonNode> statementParams = null;
@@ -265,6 +270,15 @@ public class QueryServiceRequestParameters {
this.planFormat = planFormat;
}
+ public HyracksJobFormat getHyracksJobFormat() {
+ return hyracksJobFormat;
+ }
+
+ public void setHyracksJobFormat(HyracksJobFormat hyracksJobFormat) {
+ Objects.requireNonNull(hyracksJobFormat);
+ this.hyracksJobFormat = hyracksJobFormat;
+ }
+
public Map<String, String> getOptionalParams() {
return optionalParams;
}
@@ -489,6 +503,9 @@ public class QueryServiceRequestParameters {
setFormatIfExists(req, acceptHeader, Parameter.FORMAT.str(),
valGetter);
setMode(parseIfExists(req, Parameter.MODE.str(), valGetter, getMode(),
ResultDelivery::fromName));
setPlanFormat(parseIfExists(req, Parameter.PLAN_FORMAT.str(),
valGetter, getPlanFormat(), planFormats::get));
+ setHyracksJobFormat(parseIfExists(req,
Parameter.HYRACKS_JOB_FORMAT.str(), valGetter, getHyracksJobFormat(),
+ hyracksJobFormats::get));
+
setProfileType(parseIfExists(req, Parameter.PROFILE.str(), valGetter,
getProfileType(), ProfileType::fromName));
setTimeout(parseTime(req, Parameter.TIMEOUT.str(), valGetter,
getTimeout()));
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 07d9632b38..12859fb14a 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
@@ -492,9 +492,11 @@ public class QueryServiceServlet extends
AbstractQueryApiServlet {
SessionConfig.ClientType clientType = param.getClientType();
SessionConfig.OutputFormat format = param.getFormat();
SessionConfig.PlanFormat planFormat = param.getPlanFormat();
+ SessionConfig.HyracksJobFormat hyracksJobFormat =
param.getHyracksJobFormat();
sessionConfig.setClientType(clientType);
sessionConfig.setFmt(format);
sessionConfig.setPlanFormat(planFormat);
+ sessionConfig.setHyracksJobFormat(hyracksJobFormat);
sessionConfig.setMaxWarnings(param.getMaxWarnings());
sessionConfig.setExecuteQuery(!param.isCompileOnly());
sessionConfig.set(SessionConfig.FORMAT_WRAPPER_ARRAY, true);
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 4b70f95454..81dcac02e5 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
@@ -124,7 +124,8 @@ public class AsterixJavaClient {
List<Statement> statements = parser.parse();
MetadataManager.INSTANCE.init();
- SessionConfig conf = new SessionConfig(OutputFormat.ADM, optimize,
true, generateBinaryRuntime, pformat);
+ SessionConfig conf = new SessionConfig(OutputFormat.ADM, optimize,
true, generateBinaryRuntime, pformat,
+ SessionConfig.HyracksJobFormat.JSON);
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/app/result/fields/PlansPrinter.java
b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/result/fields/PlansPrinter.java
index 40219567f4..1935d3fe53 100644
---
a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/result/fields/PlansPrinter.java
+++
b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/result/fields/PlansPrinter.java
@@ -42,6 +42,7 @@ public class PlansPrinter implements IResponseFieldPrinter {
pw.print(FIELD_NAME);
pw.print("\":");
switch (planFormat) {
+ case DOT:
case JSON:
case STRING:
pw.print(ExecutionPlansJsonPrintUtil.asJson(executionPlans,
planFormat));
diff --git a/asterixdb/asterix-app/src/main/resources/webui/querytemplate.html
b/asterixdb/asterix-app/src/main/resources/webui/querytemplate.html
index cd803cf836..e212f11c14 100644
--- a/asterixdb/asterix-app/src/main/resources/webui/querytemplate.html
+++ b/asterixdb/asterix-app/src/main/resources/webui/querytemplate.html
@@ -305,6 +305,7 @@ $(document).ready(function() {
<option selected value="JSON">JSON</option>
<option value="CLEAN_JSON">JSON
(formatted)</option>
<option value="STRING">String</option>
+ <option value="DOT">DOT</option>
</select>
</label>
<label class="optlabel"><input type="checkbox"
name="wrapper-array" value="true"/> Wrap results
diff --git
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/api/compileonly/compileonly.6.plans.sqlpp
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/api/compileonly/compileonly.6.plans.sqlpp
new file mode 100644
index 0000000000..409cf06d68
--- /dev/null
+++
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/api/compileonly/compileonly.6.plans.sqlpp
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+/*
+ * Test additional information returned when client-type=jdbc (update
statement)
+ */
+
+-- param compile-only:string=true
+-- param logical-plan:string=true
+-- param plan-format:string=DOT
+select value v from range(1,2) v where v > ?;
\ No newline at end of file
diff --git
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/api/compileonly/compileonly.7.plans.sqlpp
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/api/compileonly/compileonly.7.plans.sqlpp
new file mode 100644
index 0000000000..949cc09ca6
--- /dev/null
+++
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/api/compileonly/compileonly.7.plans.sqlpp
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+/*
+ * Test additional information returned when client-type=jdbc (update
statement)
+ */
+
+-- param compile-only:string=true
+-- param job:string=true
+-- param hyracks-job-format:string=DOT
+select value v from range(1,2) v where v > ?;
\ No newline at end of file
diff --git
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/api/compileonly/compileonly.8.plans.sqlpp
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/api/compileonly/compileonly.8.plans.sqlpp
new file mode 100644
index 0000000000..7c6b7303e4
--- /dev/null
+++
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/api/compileonly/compileonly.8.plans.sqlpp
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+/*
+ * Test additional information returned when client-type=jdbc (update
statement)
+ */
+
+-- param compile-only:string=true
+-- param optimized-logical-plan:string=true
+-- param plan-format:string=DOT
+select value v from range(1,2) v where v > ?;
\ No newline at end of file
diff --git
a/asterixdb/asterix-app/src/test/resources/runtimets/results/api/compileonly/compileonly.6.regexjson
b/asterixdb/asterix-app/src/test/resources/runtimets/results/api/compileonly/compileonly.6.regexjson
new file mode 100644
index 0000000000..0cf39ff7df
--- /dev/null
+++
b/asterixdb/asterix-app/src/test/resources/runtimets/results/api/compileonly/compileonly.6.regexjson
@@ -0,0 +1,3 @@
+{
+ "logicalPlan":"R{(?s).*digraph.*\\{.*distribute result.*\\}}"
+}
\ No newline at end of file
diff --git
a/asterixdb/asterix-app/src/test/resources/runtimets/results/api/compileonly/compileonly.7.regexjson
b/asterixdb/asterix-app/src/test/resources/runtimets/results/api/compileonly/compileonly.7.regexjson
new file mode 100644
index 0000000000..532708a269
--- /dev/null
+++
b/asterixdb/asterix-app/src/test/resources/runtimets/results/api/compileonly/compileonly.7.regexjson
@@ -0,0 +1,3 @@
+{
+ "job": "R{(?s).*digraph \"JobSpecification\"
\\{.*ResultWriterOperatorDescriptor@[a-f0-9]+-ResultWriterOperatorDescriptor.*RangeDescriptor\\$1@[a-f0-9]+.*GreaterThanDescriptor\\$2@[a-f0-9]+.*}"
+}
diff --git
a/asterixdb/asterix-app/src/test/resources/runtimets/results/api/compileonly/compileonly.8.regex
b/asterixdb/asterix-app/src/test/resources/runtimets/results/api/compileonly/compileonly.8.regex
new file mode 100644
index 0000000000..e791a9f897
--- /dev/null
+++
b/asterixdb/asterix-app/src/test/resources/runtimets/results/api/compileonly/compileonly.8.regex
@@ -0,0 +1 @@
+/(?s)digraph\s+"Plan"\s*\{.*?ONE_TO_ONE_EXCHANGE.*?\}/
\ No newline at end of file
diff --git
a/asterixdb/asterix-dashboard/src/node/src/app/dashboard/query/input.component.html
b/asterixdb/asterix-dashboard/src/node/src/app/dashboard/query/input.component.html
index 549615f43d..db86574761 100755
---
a/asterixdb/asterix-dashboard/src/node/src/app/dashboard/query/input.component.html
+++
b/asterixdb/asterix-dashboard/src/node/src/app/dashboard/query/input.component.html
@@ -37,6 +37,7 @@ limitations under the License.
<mat-select id="plan-format" placeholder="PLAN FORMAT"
[(ngModel)]="formatOptions">
<mat-option value="JSON">JSON</mat-option>
<mat-option value="STRING">STRING</mat-option>
+ <mat-option value="DOT">DOT</mat-option>
</mat-select>
</mat-form-field>
</div>