You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@asterixdb.apache.org by im...@apache.org on 2017/10/31 21:26:17 UTC

[2/2] asterixdb git commit: [UI] Allow logical plan to be viewed as JSON / formatted JSON

[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 <je...@fulliautomatix.ics.uci.edu>
Tested-by: Jenkins <je...@fulliautomatix.ics.uci.edu>
Contrib: Jenkins <je...@fulliautomatix.ics.uci.edu>
Reviewed-by: Till Westmann <ti...@apache.org>
Reviewed-by: Ian Maxon <im...@apache.org>


Project: http://git-wip-us.apache.org/repos/asf/asterixdb/repo
Commit: http://git-wip-us.apache.org/repos/asf/asterixdb/commit/a22ca7bf
Tree: http://git-wip-us.apache.org/repos/asf/asterixdb/tree/a22ca7bf
Diff: http://git-wip-us.apache.org/repos/asf/asterixdb/diff/a22ca7bf

Branch: refs/heads/master
Commit: a22ca7bf8b69ee3a747947be42d2895f82ffae48
Parents: 7ea8489
Author: Shiva <sh...@uci.edu>
Authored: Thu Oct 26 20:35:59 2017 -0700
Committer: Ian Maxon <im...@apache.org>
Committed: Tue Oct 31 14:25:41 2017 -0700

----------------------------------------------------------------------
 .../asterix/translator/SessionConfig.java       |  49 +-
 asterixdb/asterix-app/pom.xml                   |   4 +
 .../apache/asterix/api/common/APIFramework.java |  29 +-
 .../asterix/api/http/server/ApiServlet.java     |  22 +-
 .../api/http/server/QueryServiceServlet.java    |   4 +-
 .../asterix/api/http/server/RestApiServlet.java |   5 +-
 .../asterix/api/java/AsterixJavaClient.java     |  13 +-
 .../asterix/drivers/AsterixClientDriver.java    |   9 +-
 .../src/main/resources/webui/querytemplate.html | 259 ++++---
 .../main/resources/webui/static/css/style.css   |  30 +
 .../test/jsonplan/JsonLogicalPlanTest.java      |   1 +
 .../jsonplan/JsonOptimizedLogicalPlanTest.java  |  39 +
 .../logical/AbstractLogicalOperator.java        |   4 +-
 ...stractLogicalOperatorPrettyPrintVisitor.java | 113 +++
 .../LogicalOperatorPrettyPrintVisitor.java      |  63 +-
 .../LogicalOperatorPrettyPrintVisitorJson.java  | 748 +++++++++++++++++++
 .../algebra/prettyprint/PlanPrettyPrinter.java  |  80 +-
 .../visitors/ILogicalOperatorVisitor.java       |   2 +-
 18 files changed, 1258 insertions(+), 216 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/asterixdb/blob/a22ca7bf/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SessionConfig.java
----------------------------------------------------------------------
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 @@ package org.apache.asterix.translator;
 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 @@ import java.util.Map;
  * <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 @@ public class SessionConfig implements Serializable {
     };
 
     /**
+     * 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 @@ public class SessionConfig implements Serializable {
 
     // Output format.
     private final OutputFormat fmt;
+    private final PlanFormat lpfmt;
 
     // Standard execution flags.
     private final boolean executeQuery;
@@ -116,13 +142,18 @@ public class SessionConfig implements Serializable {
     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 @@ public class SessionConfig implements Serializable {
      *            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 @@ public class SessionConfig implements Serializable {
     }
 
     /**
+     * Retrieve the PlanFormat for this execution.
+     */
+    public PlanFormat getLpfmt() {
+        return this.lpfmt;
+    }
+
+    /**
      * Retrieve the value of the "execute query" flag.
      */
     public boolean isExecuteQuery() {

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/a22ca7bf/asterixdb/asterix-app/pom.xml
----------------------------------------------------------------------
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>

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/a22ca7bf/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/common/APIFramework.java
----------------------------------------------------------------------
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.IExpressionEvalSiz
 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 @@ public class APIFramework {
     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 @@ public class APIFramework {
     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 @@ public class APIFramework {
 
             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 @@ public class APIFramework {
                 } 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);

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/a22ca7bf/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ApiServlet.java
----------------------------------------------------------------------
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.IStatementExecutor;
 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 org.apache.hyracks.http.server.utils.HttpUtil.Encoding;
 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 @@ public class ApiServlet extends AbstractServlet {
         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 @@ public class ApiServlet extends AbstractServlet {
             // 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 @@ public class ApiServlet extends AbstractServlet {
             }
             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,

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/a22ca7bf/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryServiceServlet.java
----------------------------------------------------------------------
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 @@ public class QueryServiceServlet extends AbstractQueryApiServlet {
         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 @@ public class QueryServiceServlet extends AbstractQueryApiServlet {
         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);

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/a22ca7bf/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/RestApiServlet.java
----------------------------------------------------------------------
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.IStatementExecutor.ResultDelivery;
 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 @@ public abstract class RestApiServlet extends AbstractServlet {
                 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 @@ public abstract class RestApiServlet extends AbstractServlet {
 
         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.)

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/a22ca7bf/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/java/AsterixJavaClient.java
----------------------------------------------------------------------
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.IStatementExecutor;
 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 class AsterixJavaClient {
     }
 
     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 @@ public class AsterixJavaClient {
         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);

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/a22ca7bf/asterixdb/asterix-app/src/main/java/org/apache/asterix/drivers/AsterixClientDriver.java
----------------------------------------------------------------------
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 @@ public class AsterixClientDriver {
         }
         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 @@ public class AsterixClientDriver {
             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;
     }

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/a22ca7bf/asterixdb/asterix-app/src/main/resources/webui/querytemplate.html
----------------------------------------------------------------------
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 @@ $(document).ready(function() {
                 }
             }
 
-            /* 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 @@ $(document).ready(function() {
                       }
                       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 @@ $(document).ready(function() {
 });
 </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>
-
-        <!-- 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="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>
+
+      <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="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>
-            </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="row-fluid">
+
+            <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>
+                    </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>
-              <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 class="span6">
+                <div class="output">
+                    <label id="output-heading" class="heading">Output</label>
+                    <div id="output-message" class="message">
+                    </div>
+                </div>
             </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>
+<div class="footer">
+    <section class="line">
+        <hr>
+    </section>
     <section class="content">
-      <section class="left">
-      </section>
-      <section class="right">
-      </section>
+        <section class="left">
+        </section>
+        <section class="right">
+        </section>
     </section>
-  </div>
+</div>
 </body>
 </html>

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/a22ca7bf/asterixdb/asterix-app/src/main/resources/webui/static/css/style.css
----------------------------------------------------------------------
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 @@ div.output .message pre.error {
 .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;
+}
+

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/a22ca7bf/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/jsonplan/JsonLogicalPlanTest.java
----------------------------------------------------------------------
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.Asterix
 TestHelper;
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 EXTEN
 SION_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 ILangCompilationProvi
 der 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 nod
 e 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.getN
 ame().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 J
 sonLogicalPlanTest(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

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/a22ca7bf/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/jsonplan/JsonOptimizedLogicalPlanTest.java
----------------------------------------------------------------------
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

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/a22ca7bf/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/AbstractLogicalOperator.java
----------------------------------------------------------------------
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 @@ public abstract class AbstractLogicalOperator implements ILogicalOperator {
 
     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;

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/a22ca7bf/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/prettyprint/AbstractLogicalOperatorPrettyPrintVisitor.java
----------------------------------------------------------------------
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);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/a22ca7bf/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/prettyprint/LogicalOperatorPrettyPrintVisitor.java
----------------------------------------------------------------------
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.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.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.UnnestOperat
 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 @@ public class LogicalOperatorPrettyPrintVisitor implements ILogicalOperatorVisito
                 } else {
                     addIndent(indent).append("       {\n");
                 }
-                PlanPrettyPrinter.printPlan(p, this, indent + 10);
+                printPlan(p, this, indent + 10);
                 addIndent(indent).append("       }");
             }
         }