From 5e5d0ae35bc1a4cb082a2d6f941a64a3da592eed Mon Sep 17 00:00:00 2001
From: vagrant <411468452@qq.com>
Date: Sun, 6 May 2018 12:00:27 -0400
Subject: [PATCH 01/13] Handle explain plan in the optimizer

---
 src/include/common/internal_types.h |  1 +
 src/include/optimizer/optimizer.h   | 30 ++++++------
 src/include/planner/explain_plan.h  | 60 ++++++++++++++++++++++++
 src/optimizer/optimizer.cpp         | 71 +++++++++++++++--------------
 4 files changed, 113 insertions(+), 49 deletions(-)
 create mode 100644 src/include/planner/explain_plan.h

diff --git a/src/include/common/internal_types.h b/src/include/common/internal_types.h
index 17020512944..ba35695c2c2 100644
--- a/src/include/common/internal_types.h
+++ b/src/include/common/internal_types.h
@@ -596,6 +596,7 @@ enum class PlanNodeType {
   RESULT = 70,
   COPY = 71,
   CREATE_FUNC = 72,
+  EXPLAIN = 73,
 
   // Test
   MOCK = 80
diff --git a/src/include/optimizer/optimizer.h b/src/include/optimizer/optimizer.h
index 82b1d4c9a05..baeb8720be3 100644
--- a/src/include/optimizer/optimizer.h
+++ b/src/include/optimizer/optimizer.h
@@ -38,9 +38,9 @@ class TransactionContext;
 }
 
 namespace test {
-  class OptimizerRuleTests_SimpleAssociativeRuleTest_Test;
-  class OptimizerRuleTests_SimpleAssociativeRuleTest2_Test;
-} 
+class OptimizerRuleTests_SimpleAssociativeRuleTest_Test;
+class OptimizerRuleTests_SimpleAssociativeRuleTest2_Test;
+}
 
 namespace optimizer {
 
@@ -60,8 +60,10 @@ class Optimizer : public AbstractOptimizer {
   friend class BindingIterator;
   friend class GroupBindingIterator;
 
-  friend class ::peloton::test::OptimizerRuleTests_SimpleAssociativeRuleTest_Test;
-  friend class ::peloton::test::OptimizerRuleTests_SimpleAssociativeRuleTest2_Test; 
+  friend class ::peloton::test::
+      OptimizerRuleTests_SimpleAssociativeRuleTest_Test;
+  friend class ::peloton::test::
+      OptimizerRuleTests_SimpleAssociativeRuleTest2_Test;
 
  public:
   Optimizer(const Optimizer &) = delete;
@@ -83,27 +85,25 @@ class Optimizer : public AbstractOptimizer {
   OptimizerMetadata &GetMetadata() { return metadata_; }
 
   /* For test purposes only */
-  std::shared_ptr<GroupExpression> TestInsertQueryTree(parser::SQLStatement *tree,
-  concurrency::TransactionContext *txn) {
+  std::shared_ptr<GroupExpression> TestInsertQueryTree(
+      parser::SQLStatement *tree, concurrency::TransactionContext *txn) {
     return InsertQueryTree(tree, txn);
   }
   /* For test purposes only */
   void TestExecuteTaskStack(OptimizerTaskStack &task_stack, int root_group_id,
-                        std::shared_ptr<OptimizeContext> root_context) {
+                            std::shared_ptr<OptimizeContext> root_context) {
     return ExecuteTaskStack(task_stack, root_group_id, root_context);
   }
 
  private:
-  /* HandleDDLStatement - Check and handle DDL statment (currently only support
+  /* HandleUtilStatement - Check and handle Util statment (currently only
+   *support
    *CREATE), set
-   * is_ddl_stmt to false if there is no DDL statement.
-   *
    * tree: a peloton query tree representing a select query
-   * return: the DDL plan if it is a DDL statement
+   * return: the util plan if it is a util statement
    */
-  std::unique_ptr<planner::AbstractPlan> HandleDDLStatement(
-      parser::SQLStatement *tree, bool &is_ddl_stmt,
-      concurrency::TransactionContext *txn);
+  std::unique_ptr<planner::AbstractPlan> HandleUtilStatement(
+      parser::SQLStatement *tree, concurrency::TransactionContext *txn);
 
   /* TransformQueryTree - create an initial operator tree for the given query
    * to be used in performing optimization.
diff --git a/src/include/planner/explain_plan.h b/src/include/planner/explain_plan.h
new file mode 100644
index 00000000000..372b491ee2f
--- /dev/null
+++ b/src/include/planner/explain_plan.h
@@ -0,0 +1,60 @@
+
+//===----------------------------------------------------------------------===//
+//
+//                         Peloton
+//
+// explain_plan.h
+//
+// Identification: src/include/planner/analyze_plan.h
+//
+// Copyright (c) 2015-18, Carnegie Mellon University Database Group
+//
+//===----------------------------------------------------------------------===//
+
+#pragma once
+
+#include "planner/abstract_plan.h"
+
+#include <memory>
+
+namespace peloton {
+namespace storage {
+class DataTable;
+}
+namespace parser {
+class AnalyzeStatement;
+}
+namespace catalog {
+class Schema;
+}
+namespace concurrency {
+class TransactionContext;
+}
+
+namespace planner {
+class ExplainPlan : public AbstractPlan {
+ public:
+  ExplainPlan(const ExplainPlan &) = delete;
+  ExplainPlan &operator=(const ExplainPlan &) = delete;
+  ExplainPlan(ExplainPlan &&) = delete;
+  ExplainPlan &operator=(ExplainPlan &&) = delete;
+
+  explicit ExplainPlan(parser::SQLStatement *sql_stmt) : sql_stmt(sql_stmt){};
+
+  inline PlanNodeType GetPlanNodeType() const { return PlanNodeType::EXPLAIN; }
+
+  const std::string GetInfo() const { return "Explain table"; }
+
+  inline std::unique_ptr<AbstractPlan> Copy() const {
+    return std::unique_ptr<AbstractPlan>(new ExplainPlan(sql_stmt));
+  }
+
+ private:
+  /**
+   * @brief The SQL statement to explain (owned by the AST)
+   */
+  parser::SQLStatement *sql_stmt;
+};
+
+}  // namespace planner
+}  // namespace peloton
diff --git a/src/optimizer/optimizer.cpp b/src/optimizer/optimizer.cpp
index 62f813ec876..8a8277fe5de 100644
--- a/src/optimizer/optimizer.cpp
+++ b/src/optimizer/optimizer.cpp
@@ -37,6 +37,7 @@
 #include "planner/create_function_plan.h"
 #include "planner/create_plan.h"
 #include "planner/drop_plan.h"
+#include "planner/explain_plan.h"
 #include "planner/order_by_plan.h"
 #include "planner/populate_index_plan.h"
 #include "planner/projection_plan.h"
@@ -103,10 +104,9 @@ shared_ptr<planner::AbstractPlan> Optimizer::BuildPelotonPlanTree(
   unique_ptr<planner::AbstractPlan> child_plan = nullptr;
 
   // Handle ddl statement
-  bool is_ddl_stmt;
-  auto ddl_plan = HandleDDLStatement(parse_tree, is_ddl_stmt, txn);
-  if (is_ddl_stmt) {
-    return move(ddl_plan);
+  auto util_plan = HandleUtilStatement(parse_tree, txn);
+  if (util_plan != nullptr) {
+    return move(util_plan);
   }
 
   metadata_.txn = txn;
@@ -138,11 +138,9 @@ shared_ptr<planner::AbstractPlan> Optimizer::BuildPelotonPlanTree(
 
 void Optimizer::Reset() { metadata_ = OptimizerMetadata(); }
 
-unique_ptr<planner::AbstractPlan> Optimizer::HandleDDLStatement(
-    parser::SQLStatement *tree, bool &is_ddl_stmt,
-    concurrency::TransactionContext *txn) {
+unique_ptr<planner::AbstractPlan> Optimizer::HandleUtilStatement(
+    parser::SQLStatement *tree, concurrency::TransactionContext *txn) {
   unique_ptr<planner::AbstractPlan> ddl_plan = nullptr;
-  is_ddl_stmt = true;
   auto stmt_type = tree->GetType();
   switch (stmt_type) {
     case StatementType::DROP: {
@@ -221,8 +219,14 @@ unique_ptr<planner::AbstractPlan> Optimizer::HandleDDLStatement(
       ddl_plan = util::CreateCopyPlan(copy_parse_tree);
       break;
     }
+    case StatementType::EXPLAIN: {
+      LOG_TRACE("Adding Explain plan...");
+      // Pass the sql statement to explain to the plan node
+      ddl_plan.reset(new planner::ExplainPlan(
+          static_cast<parser::ExplainStatement *>(tree)->real_sql_stmt.get()));
+    }
     default:
-      is_ddl_stmt = false;
+      break;
   }
   return ddl_plan;
 }
@@ -238,29 +242,29 @@ shared_ptr<GroupExpression> Optimizer::InsertQueryTree(
 }
 
 QueryInfo Optimizer::GetQueryInfo(parser::SQLStatement *tree) {
-  auto GetQueryInfoHelper =
-      [](std::vector<unique_ptr<expression::AbstractExpression>> &select_list,
-         std::unique_ptr<parser::OrderDescription> &order_info,
-         std::vector<expression::AbstractExpression *> &output_exprs,
-         std::shared_ptr<PropertySet> &physical_props) {
-        // Extract output column
-        for (auto &expr : select_list) output_exprs.push_back(expr.get());
-
-        // Extract sort property
-        if (order_info != nullptr) {
-          std::vector<expression::AbstractExpression *> sort_exprs;
-          std::vector<bool> sort_ascending;
-          for (auto &expr : order_info->exprs) {
-            sort_exprs.push_back(expr.get());
-          }
-          for (auto &type : order_info->types) {
-            sort_ascending.push_back(type == parser::kOrderAsc);
-          }
-          if (!sort_exprs.empty())
-            physical_props->AddProperty(
-                std::make_shared<PropertySort>(sort_exprs, sort_ascending));
-        }
-      };
+  auto GetQueryInfoHelper = [](
+      std::vector<unique_ptr<expression::AbstractExpression>> &select_list,
+      std::unique_ptr<parser::OrderDescription> &order_info,
+      std::vector<expression::AbstractExpression *> &output_exprs,
+      std::shared_ptr<PropertySet> &physical_props) {
+    // Extract output column
+    for (auto &expr : select_list) output_exprs.push_back(expr.get());
+
+    // Extract sort property
+    if (order_info != nullptr) {
+      std::vector<expression::AbstractExpression *> sort_exprs;
+      std::vector<bool> sort_ascending;
+      for (auto &expr : order_info->exprs) {
+        sort_exprs.push_back(expr.get());
+      }
+      for (auto &type : order_info->types) {
+        sort_ascending.push_back(type == parser::kOrderAsc);
+      }
+      if (!sort_exprs.empty())
+        physical_props->AddProperty(
+            std::make_shared<PropertySort>(sort_exprs, sort_ascending));
+    }
+  };
 
   std::vector<expression::AbstractExpression *> output_exprs;
   std::shared_ptr<PropertySet> physical_props = std::make_shared<PropertySet>();
@@ -278,8 +282,7 @@ QueryInfo Optimizer::GetQueryInfo(parser::SQLStatement *tree) {
                            output_exprs, physical_props);
       break;
     }
-    default:
-      ;
+    default:;
   }
 
   return QueryInfo(output_exprs, physical_props);

From 7e87de0c2e2124f5438ff29329d46ce96b13068c Mon Sep 17 00:00:00 2001
From: Tianyi Chen <tianyic1@andrew.cmu.edu>
Date: Mon, 7 May 2018 09:45:47 -0400
Subject: [PATCH 02/13] Refactor the execute method interface for traffic cop.

---
 .../network/postgres_protocol_handler.h       |  3 --
 src/include/traffic_cop/traffic_cop.h         | 18 ++++++------
 src/network/postgres_protocol_handler.cpp     | 25 ++++++++---------
 src/traffic_cop/traffic_cop.cpp               | 20 ++++++++-----
 test/sql/testing_sql_util.cpp                 | 28 ++++++++++++-------
 5 files changed, 52 insertions(+), 42 deletions(-)

diff --git a/src/include/network/postgres_protocol_handler.h b/src/include/network/postgres_protocol_handler.h
index ef75f0a4cb1..672ab8c29c6 100644
--- a/src/include/network/postgres_protocol_handler.h
+++ b/src/include/network/postgres_protocol_handler.h
@@ -215,9 +215,6 @@ class PostgresProtocolHandler : public ProtocolHandler {
   //  Portals
   std::unordered_map<std::string, std::shared_ptr<Portal>> portals_;
 
-  // packets ready for read
-  size_t pkt_cntr_;
-
   // Manage parameter types for unnamed statement
   stats::QueryMetric::QueryParamBuf unnamed_stmt_param_types_;
 
diff --git a/src/include/traffic_cop/traffic_cop.h b/src/include/traffic_cop/traffic_cop.h
index e324b87fe82..a4e932558ff 100644
--- a/src/include/traffic_cop/traffic_cop.h
+++ b/src/include/traffic_cop/traffic_cop.h
@@ -65,12 +65,16 @@ class TrafficCop {
   void Reset();
 
   // Execute a statement
-  ResultType ExecuteStatement(
-      const std::shared_ptr<Statement> &statement,
-      const std::vector<type::Value> &params, const bool unnamed,
-      std::shared_ptr<stats::QueryMetric::QueryParams> param_stats,
-      const std::vector<int> &result_format, std::vector<ResultValue> &result,
-      size_t thread_id = 0);
+  ResultType ExecuteStatement(std::shared_ptr<stats::QueryMetric::QueryParams> param_stats,
+                                          const std::vector<int> &result_format,
+                                          size_t thread_id);
+
+  ResultType ExecuteStatement(const std::shared_ptr<Statement> &statement,
+                              const std::vector<type::Value> &params,
+                              std::shared_ptr<stats::QueryMetric::QueryParams> param_stats,
+                              const std::vector<int> &result_format,
+                              std::vector<ResultValue> &result,
+                              size_t thread_id);
 
   // Helper to handle txn-specifics for the plan-tree of a statement.
   executor::ExecutionResult ExecuteHelper(
@@ -156,8 +160,6 @@ class TrafficCop {
 
   std::vector<type::Value> param_values_;
 
-  std::vector<ResultValue> results_;
-
   // This save currnet statement in the traffic cop
   std::shared_ptr<Statement> statement_;
 
diff --git a/src/network/postgres_protocol_handler.cpp b/src/network/postgres_protocol_handler.cpp
index ffbb786b88e..7ddce1f605a 100644
--- a/src/network/postgres_protocol_handler.cpp
+++ b/src/network/postgres_protocol_handler.cpp
@@ -212,10 +212,9 @@ ProcessResult PostgresProtocolHandler::ExecQueryMessage(
         return ProcessResult::COMPLETE;
       }
 
-      bool unnamed = false;
-      auto status = traffic_cop_->ExecuteStatement(
-          traffic_cop_->GetStatement(), traffic_cop_->GetParamVal(), unnamed,
-          nullptr, result_format_, traffic_cop_->GetResult(), thread_id);
+      auto status = traffic_cop_->ExecuteStatement(nullptr,
+                                                   result_format_,
+                                                   thread_id);
       if (traffic_cop_->GetQueuing()) {
         return ProcessResult::PROCESSING;
       }
@@ -229,25 +228,24 @@ ProcessResult PostgresProtocolHandler::ExecQueryMessage(
       return ProcessResult::COMPLETE;
     }
     default: {
-      std::string stmt_name = "unamed";
+      std::string stmt_name = "";
       std::unique_ptr<parser::SQLStatementList> unnamed_sql_stmt_list(
           new parser::SQLStatementList());
       unnamed_sql_stmt_list->PassInStatement(std::move(sql_stmt));
       traffic_cop_->SetStatement(traffic_cop_->PrepareStatement(
           stmt_name, query, std::move(unnamed_sql_stmt_list)));
-      if (traffic_cop_->GetStatement().get() == nullptr) {
+      if (traffic_cop_->GetStatement() == nullptr) {
         SendErrorResponse({{NetworkMessageType::HUMAN_READABLE_ERROR,
                             traffic_cop_->GetErrorMessage()}});
         SendReadyForQuery(NetworkTransactionStateType::IDLE);
         return ProcessResult::COMPLETE;
       }
       traffic_cop_->SetParamVal(std::vector<type::Value>());
-      bool unnamed = false;
       result_format_ = std::vector<int>(
           traffic_cop_->GetStatement()->GetTupleDescriptor().size(), 0);
-      auto status = traffic_cop_->ExecuteStatement(
-          traffic_cop_->GetStatement(), traffic_cop_->GetParamVal(), unnamed,
-          nullptr, result_format_, traffic_cop_->GetResult(), thread_id);
+      auto status = traffic_cop_->ExecuteStatement(nullptr,
+                                                   result_format_,
+                                                   thread_id);
       if (traffic_cop_->GetQueuing()) {
         return ProcessResult::PROCESSING;
       }
@@ -807,12 +805,11 @@ ProcessResult PostgresProtocolHandler::ExecExecuteMessage(
   }
 
   auto statement_name = traffic_cop_->GetStatement()->GetStatementName();
-  bool unnamed = statement_name.empty();
   traffic_cop_->SetParamVal(portal->GetParameters());
 
-  auto status = traffic_cop_->ExecuteStatement(
-      traffic_cop_->GetStatement(), traffic_cop_->GetParamVal(), unnamed,
-      param_stat, result_format_, traffic_cop_->GetResult(), thread_id);
+  auto status = traffic_cop_->ExecuteStatement(param_stat,
+                                               result_format_,
+                                               thread_id);
   if (traffic_cop_->GetQueuing()) {
     return ProcessResult::PROCESSING;
   }
diff --git a/src/traffic_cop/traffic_cop.cpp b/src/traffic_cop/traffic_cop.cpp
index a87d99c0ac5..6e173308c95 100644
--- a/src/traffic_cop/traffic_cop.cpp
+++ b/src/traffic_cop/traffic_cop.cpp
@@ -44,7 +44,7 @@ void TrafficCop::Reset() {
   // clear out the stack
   swap(tcop_txn_state_, new_tcop_txn_state);
   optimizer_->Reset();
-  results_.clear();
+  result_.clear();
   param_values_.clear();
   setRowsAffected(0);
 }
@@ -543,12 +543,18 @@ FieldInfo TrafficCop::GetColumnFieldForValueType(std::string column_name,
                          field_size);
 }
 
-ResultType TrafficCop::ExecuteStatement(
-    const std::shared_ptr<Statement> &statement,
-    const std::vector<type::Value> &params, UNUSED_ATTRIBUTE bool unnamed,
-    std::shared_ptr<stats::QueryMetric::QueryParams> param_stats,
-    const std::vector<int> &result_format, std::vector<ResultValue> &result,
-    size_t thread_id) {
+ResultType TrafficCop::ExecuteStatement(std::shared_ptr<stats::QueryMetric::QueryParams> param_stats,
+                                        const std::vector<int> &result_format,
+                                        size_t thread_id) {
+  return ExecuteStatement(statement_, param_values_, param_stats, result_format, result_, thread_id);
+}
+
+ResultType TrafficCop::ExecuteStatement(const std::shared_ptr<Statement> &statement,
+                                        const std::vector<type::Value> &params,
+                                        std::shared_ptr<stats::QueryMetric::QueryParams> param_stats,
+                                        const std::vector<int> &result_format,
+                                        std::vector<ResultValue> &result,
+                                        size_t thread_id) {
   // TODO(Tianyi) Further simplify this API
   if (static_cast<StatsType>(settings::SettingsManager::GetInt(
           settings::SettingId::stats_mode)) != StatsType::INVALID) {
diff --git a/test/sql/testing_sql_util.cpp b/test/sql/testing_sql_util.cpp
index 220fa558686..b17130d3892 100644
--- a/test/sql/testing_sql_util.cpp
+++ b/test/sql/testing_sql_util.cpp
@@ -76,12 +76,15 @@ ResultType TestingSQLUtil::ExecuteSQLQuery(
   }
   // ExecuteStatment
   std::vector<type::Value> param_values;
-  bool unnamed = false;
   std::vector<int> result_format(statement->GetTupleDescriptor().size(), 0);
   // SetTrafficCopCounter();
   counter_.store(1);
-  auto status = traffic_cop_.ExecuteStatement(statement, param_values, unnamed,
-                                              nullptr, result_format, result);
+  auto status = traffic_cop_.ExecuteStatement(statement,
+                                              param_values,
+                                              nullptr,
+                                              result_format,
+                                              result,
+                                              0);
   if (traffic_cop_.GetQueuing()) {
     ContinueAfterComplete();
     traffic_cop_.ExecuteStatementPlanGetResult();
@@ -177,12 +180,15 @@ ResultType TestingSQLUtil::ExecuteSQLQuery(const std::string query,
   }
   // ExecuteStatment
   std::vector<type::Value> param_values;
-  bool unnamed = false;
   std::vector<int> result_format(statement->GetTupleDescriptor().size(), 0);
   // SetTrafficCopCounter();
   counter_.store(1);
-  auto status = traffic_cop_.ExecuteStatement(statement, param_values, unnamed,
-                                              nullptr, result_format, result);
+  auto status = traffic_cop_.ExecuteStatement(statement,
+                                              param_values,
+                                              nullptr,
+                                              result_format,
+                                              result,
+                                              0);
   if (traffic_cop_.GetQueuing()) {
     ContinueAfterComplete();
     traffic_cop_.ExecuteStatementPlanGetResult();
@@ -216,12 +222,14 @@ ResultType TestingSQLUtil::ExecuteSQLQuery(const std::string query) {
   }
   // ExecuteStatment
   std::vector<type::Value> param_values;
-  bool unnamed = false;
   std::vector<int> result_format(statement->GetTupleDescriptor().size(), 0);
-  // SetTrafficCopCounter();
   counter_.store(1);
-  auto status = traffic_cop_.ExecuteStatement(statement, param_values, unnamed,
-                                              nullptr, result_format, result);
+  auto status = traffic_cop_.ExecuteStatement(statement,
+                                              param_values,
+                                              nullptr,
+                                              result_format,
+                                              result,
+                                              0);
   if (traffic_cop_.GetQueuing()) {
     ContinueAfterComplete();
     traffic_cop_.ExecuteStatementPlanGetResult();

From 5ba06db3a1fb3537ba9f807a0ce29b61a4980140 Mon Sep 17 00:00:00 2001
From: Tianyi Chen <tianyic1@andrew.cmu.edu>
Date: Mon, 7 May 2018 11:03:41 -0400
Subject: [PATCH 03/13] Unify traffic_cop getResult interface

---
 src/include/traffic_cop/traffic_cop.h     |  7 ---
 src/network/connection_handle.cpp         |  1 -
 src/network/postgres_protocol_handler.cpp |  1 -
 src/traffic_cop/traffic_cop.cpp           | 59 +++++++++++------------
 test/binder/binder_test.cpp               |  3 +-
 test/executor/copy_test.cpp               |  3 +-
 test/executor/create_index_test.cpp       |  9 ++--
 test/executor/delete_test.cpp             | 21 +++-----
 test/executor/update_test.cpp             | 15 ++----
 test/optimizer/old_optimizer_test.cpp     |  9 ++--
 test/optimizer/optimizer_test.cpp         | 15 ++----
 test/sql/testing_sql_util.cpp             | 13 ++---
 12 files changed, 58 insertions(+), 98 deletions(-)

diff --git a/src/include/traffic_cop/traffic_cop.h b/src/include/traffic_cop/traffic_cop.h
index a4e932558ff..98f6592203d 100644
--- a/src/include/traffic_cop/traffic_cop.h
+++ b/src/include/traffic_cop/traffic_cop.h
@@ -104,7 +104,6 @@ class TrafficCop {
 
   ResultType CommitQueryHelper();
 
-  void ExecuteStatementPlanGetResult();
 
   ResultType ExecuteStatementGetResult();
 
@@ -135,8 +134,6 @@ class TrafficCop {
     param_values_ = std::move(param_values);
   }
 
-  std::vector<type::Value> &GetParamVal() { return param_values_; }
-
   std::string &GetErrorMessage() { return error_message_; }
 
   void SetQueuing(bool is_queuing) { is_queuing_ = is_queuing; }
@@ -149,10 +146,6 @@ class TrafficCop {
     default_database_name_ = std::move(default_database_name);
   }
 
-  // TODO: this member variable should be in statement_ after parser part
-  // finished
-  std::string query_;
-
  private:
   bool is_queuing_;
 
diff --git a/src/network/connection_handle.cpp b/src/network/connection_handle.cpp
index e79564b5c4d..3b1918e0d36 100644
--- a/src/network/connection_handle.cpp
+++ b/src/network/connection_handle.cpp
@@ -692,7 +692,6 @@ Transition ConnectionHandle::GetResult() {
     PELOTON_ASSERT(false);
   }
   protocol_handler_->GetResult();
-  traffic_cop_.SetQueuing(false);
   return Transition::PROCEED;
 }
 }  // namespace network
diff --git a/src/network/postgres_protocol_handler.cpp b/src/network/postgres_protocol_handler.cpp
index 7ddce1f605a..c3593e027d2 100644
--- a/src/network/postgres_protocol_handler.cpp
+++ b/src/network/postgres_protocol_handler.cpp
@@ -859,7 +859,6 @@ void PostgresProtocolHandler::ExecExecuteMessageGetResult(ResultType status) {
 }
 
 void PostgresProtocolHandler::GetResult() {
-  traffic_cop_->ExecuteStatementPlanGetResult();
   auto status = traffic_cop_->ExecuteStatementGetResult();
   switch (protocol_type_) {
     case NetworkProtocolType::POSTGRES_JDBC:
diff --git a/src/traffic_cop/traffic_cop.cpp b/src/traffic_cop/traffic_cop.cpp
index 6e173308c95..7ba9fe051ac 100644
--- a/src/traffic_cop/traffic_cop.cpp
+++ b/src/traffic_cop/traffic_cop.cpp
@@ -133,10 +133,38 @@ ResultType TrafficCop::AbortQueryHelper() {
 
 ResultType TrafficCop::ExecuteStatementGetResult() {
   LOG_TRACE("Statement executed. Result: %s",
-            ResultTypeToString(p_status_.m_result).c_str());
+          ResultTypeToString(p_status_.m_result).c_str());
   setRowsAffected(p_status_.m_processed);
   LOG_TRACE("rows_changed %d", p_status_.m_processed);
   is_queuing_ = false;
+
+  if (p_status_.m_result == ResultType::FAILURE) return p_status_.m_result;
+
+  auto txn_result = GetCurrentTxnState().first->GetResult();
+  if (single_statement_txn_ || txn_result == ResultType::FAILURE) {
+    LOG_TRACE("About to commit/abort: single stmt: %d,txn_result: %s",
+              single_statement_txn_, ResultTypeToString(txn_result).c_str());
+    switch (txn_result) {
+      case ResultType::SUCCESS:
+        // Commit single statement
+        LOG_TRACE("Commit Transaction");
+        p_status_.m_result = CommitQueryHelper();
+        break;
+
+      case ResultType::FAILURE:
+      default:
+        // Abort
+        LOG_TRACE("Abort Transaction");
+        if (single_statement_txn_) {
+          LOG_TRACE("Tcop_txn_state size: %lu", tcop_txn_state_.size());
+          p_status_.m_result = AbortQueryHelper();
+        } else {
+          tcop_txn_state_.top().second = ResultType::ABORTED;
+          p_status_.m_result = ResultType::ABORTED;
+        }
+    }
+  }
+
   return p_status_.m_result;
 }
 
@@ -203,35 +231,6 @@ executor::ExecutionResult TrafficCop::ExecuteHelper(
   return p_status_;
 }
 
-void TrafficCop::ExecuteStatementPlanGetResult() {
-  if (p_status_.m_result == ResultType::FAILURE) return;
-
-  auto txn_result = GetCurrentTxnState().first->GetResult();
-  if (single_statement_txn_ || txn_result == ResultType::FAILURE) {
-    LOG_TRACE("About to commit/abort: single stmt: %d,txn_result: %s",
-              single_statement_txn_, ResultTypeToString(txn_result).c_str());
-    switch (txn_result) {
-      case ResultType::SUCCESS:
-        // Commit single statement
-        LOG_TRACE("Commit Transaction");
-        p_status_.m_result = CommitQueryHelper();
-        break;
-
-      case ResultType::FAILURE:
-      default:
-        // Abort
-        LOG_TRACE("Abort Transaction");
-        if (single_statement_txn_) {
-          LOG_TRACE("Tcop_txn_state size: %lu", tcop_txn_state_.size());
-          p_status_.m_result = AbortQueryHelper();
-        } else {
-          tcop_txn_state_.top().second = ResultType::ABORTED;
-          p_status_.m_result = ResultType::ABORTED;
-        }
-    }
-  }
-}
-
 /*
  * Prepare a statement based on parse tree. Begin a transaction if necessary.
  * If the query is not issued in a transaction (if txn_stack is empty and it's
diff --git a/test/binder/binder_test.cpp b/test/binder/binder_test.cpp
index b82df1ec72a..7d93c443827 100644
--- a/test/binder/binder_test.cpp
+++ b/test/binder/binder_test.cpp
@@ -91,9 +91,8 @@ void SetupTables(std::string database_name) {
                                             result, result_format);
     if (traffic_cop.GetQueuing()) {
       TestingSQLUtil::ContinueAfterComplete();
-      traffic_cop.ExecuteStatementPlanGetResult();
+      traffic_cop.ExecuteStatementGetResult();
       status = traffic_cop.p_status_;
-      traffic_cop.SetQueuing(false);
     }
     LOG_INFO("Table create result: %s",
              ResultTypeToString(status.m_result).c_str());
diff --git a/test/executor/copy_test.cpp b/test/executor/copy_test.cpp
index 77c1c9eecc9..0274925a93c 100644
--- a/test/executor/copy_test.cpp
+++ b/test/executor/copy_test.cpp
@@ -97,9 +97,8 @@ TEST_F(CopyTests, Copying) {
 
     if (traffic_cop.GetQueuing()) {
       TestingSQLUtil::ContinueAfterComplete();
-      traffic_cop.ExecuteStatementPlanGetResult();
+      traffic_cop.ExecuteStatementGetResult();
       status = traffic_cop.p_status_;
-      traffic_cop.SetQueuing(false);
     }
 
     EXPECT_EQ(status.m_result, peloton::ResultType::SUCCESS);
diff --git a/test/executor/create_index_test.cpp b/test/executor/create_index_test.cpp
index 034eca553fa..68f51456e23 100644
--- a/test/executor/create_index_test.cpp
+++ b/test/executor/create_index_test.cpp
@@ -104,9 +104,8 @@ TEST_F(CreateIndexTests, CreatingIndex) {
 
   if (traffic_cop.GetQueuing()) {
     TestingSQLUtil::ContinueAfterComplete();
-    traffic_cop.ExecuteStatementPlanGetResult();
+    traffic_cop.ExecuteStatementGetResult();
     status = traffic_cop.p_status_;
-    traffic_cop.SetQueuing(false);
   }
 
   LOG_INFO("Statement executed. Result: %s",
@@ -152,9 +151,8 @@ TEST_F(CreateIndexTests, CreatingIndex) {
 
   if (traffic_cop.GetQueuing()) {
     TestingSQLUtil::ContinueAfterComplete();
-    traffic_cop.ExecuteStatementPlanGetResult();
+    traffic_cop.ExecuteStatementGetResult();
     status = traffic_cop.p_status_;
-    traffic_cop.SetQueuing(false);
   }
   LOG_INFO("Statement executed. Result: %s",
            ResultTypeToString(status.m_result).c_str());
@@ -194,9 +192,8 @@ TEST_F(CreateIndexTests, CreatingIndex) {
 
   if (traffic_cop.GetQueuing()) {
     TestingSQLUtil::ContinueAfterComplete();
-    traffic_cop.ExecuteStatementPlanGetResult();
+    traffic_cop.ExecuteStatementGetResult();
     status = traffic_cop.p_status_;
-    traffic_cop.SetQueuing(false);
   }
   LOG_INFO("Statement executed. Result: %s",
            ResultTypeToString(status.m_result).c_str());
diff --git a/test/executor/delete_test.cpp b/test/executor/delete_test.cpp
index f081b766720..1fa29a6a70c 100644
--- a/test/executor/delete_test.cpp
+++ b/test/executor/delete_test.cpp
@@ -84,9 +84,8 @@ void ShowTable(std::string database_name, std::string table_name) {
                                      result_format);
   if (traffic_cop.GetQueuing()) {
     TestingSQLUtil::ContinueAfterComplete();
-    traffic_cop.ExecuteStatementPlanGetResult();
+    traffic_cop.ExecuteStatementGetResult();
     status = traffic_cop.p_status_;
-    traffic_cop.SetQueuing(false);
   }
   traffic_cop.CommitQueryHelper();
 }
@@ -165,9 +164,8 @@ TEST_F(DeleteTests, VariousOperations) {
       statement->GetPlanTree(), params, result, result_format);
   if (traffic_cop.GetQueuing()) {
     TestingSQLUtil::ContinueAfterComplete();
-    traffic_cop.ExecuteStatementPlanGetResult();
+    traffic_cop.ExecuteStatementGetResult();
     status = traffic_cop.p_status_;
-    traffic_cop.SetQueuing(false);
   }
   LOG_INFO("Statement executed. Result: %s",
            ResultTypeToString(status.m_result).c_str());
@@ -206,9 +204,8 @@ TEST_F(DeleteTests, VariousOperations) {
                                      result_format);
   if (traffic_cop.GetQueuing()) {
     TestingSQLUtil::ContinueAfterComplete();
-    traffic_cop.ExecuteStatementPlanGetResult();
+    traffic_cop.ExecuteStatementGetResult();
     status = traffic_cop.p_status_;
-    traffic_cop.SetQueuing(false);
   }
   LOG_INFO("Statement executed. Result: %s",
            ResultTypeToString(status.m_result).c_str());
@@ -247,9 +244,8 @@ TEST_F(DeleteTests, VariousOperations) {
                                      result_format);
   if (traffic_cop.GetQueuing()) {
     TestingSQLUtil::ContinueAfterComplete();
-    traffic_cop.ExecuteStatementPlanGetResult();
+    traffic_cop.ExecuteStatementGetResult();
     status = traffic_cop.p_status_;
-    traffic_cop.SetQueuing(false);
   }
   LOG_INFO("Statement executed. Result: %s",
            ResultTypeToString(status.m_result).c_str());
@@ -290,9 +286,8 @@ TEST_F(DeleteTests, VariousOperations) {
                                      result_format);
   if (traffic_cop.GetQueuing()) {
     TestingSQLUtil::ContinueAfterComplete();
-    traffic_cop.ExecuteStatementPlanGetResult();
+    traffic_cop.ExecuteStatementGetResult();
     status = traffic_cop.p_status_;
-    traffic_cop.SetQueuing(false);
   }
   LOG_INFO("Statement executed. Result: %s",
            ResultTypeToString(status.m_result).c_str());
@@ -328,9 +323,8 @@ TEST_F(DeleteTests, VariousOperations) {
                                      result_format);
   if (traffic_cop.GetQueuing()) {
     TestingSQLUtil::ContinueAfterComplete();
-    traffic_cop.ExecuteStatementPlanGetResult();
+    traffic_cop.ExecuteStatementGetResult();
     status = traffic_cop.p_status_;
-    traffic_cop.SetQueuing(false);
   }
   LOG_INFO("Statement executed. Result: %s",
            ResultTypeToString(status.m_result).c_str());
@@ -368,9 +362,8 @@ TEST_F(DeleteTests, VariousOperations) {
                                      result_format);
   if (traffic_cop.GetQueuing()) {
     TestingSQLUtil::ContinueAfterComplete();
-    traffic_cop.ExecuteStatementPlanGetResult();
+    traffic_cop.ExecuteStatementGetResult();
     status = traffic_cop.p_status_;
-    traffic_cop.SetQueuing(false);
   }
   LOG_INFO("Statement executed. Result: %s",
            ResultTypeToString(status.m_result).c_str());
diff --git a/test/executor/update_test.cpp b/test/executor/update_test.cpp
index f8f3c12d0a2..3c16ae8b532 100644
--- a/test/executor/update_test.cpp
+++ b/test/executor/update_test.cpp
@@ -231,9 +231,8 @@ TEST_F(UpdateTests, UpdatingOld) {
       statement->GetPlanTree(), params, result, result_format);
   if (traffic_cop.GetQueuing()) {
     TestingSQLUtil::ContinueAfterComplete();
-    traffic_cop.ExecuteStatementPlanGetResult();
+    traffic_cop.ExecuteStatementGetResult();
     status = traffic_cop.p_status_;
-    traffic_cop.SetQueuing(false);
   }
   LOG_INFO("Statement executed. Result: %s",
            ResultTypeToString(status.m_result).c_str());
@@ -275,9 +274,8 @@ TEST_F(UpdateTests, UpdatingOld) {
                                      result_format);
   if (traffic_cop.GetQueuing()) {
     TestingSQLUtil::ContinueAfterComplete();
-    traffic_cop.ExecuteStatementPlanGetResult();
+    traffic_cop.ExecuteStatementGetResult();
     status = traffic_cop.p_status_;
-    traffic_cop.SetQueuing(false);
   }
   LOG_INFO("Statement executed. Result: %s",
            ResultTypeToString(status.m_result).c_str());
@@ -320,9 +318,8 @@ TEST_F(UpdateTests, UpdatingOld) {
                                      result_format);
   if (traffic_cop.GetQueuing()) {
     TestingSQLUtil::ContinueAfterComplete();
-    traffic_cop.ExecuteStatementPlanGetResult();
+    traffic_cop.ExecuteStatementGetResult();
     status = traffic_cop.p_status_;
-    traffic_cop.SetQueuing(false);
   }
   LOG_INFO("Statement executed. Result: %s",
            ResultTypeToString(status.m_result).c_str());
@@ -359,9 +356,8 @@ TEST_F(UpdateTests, UpdatingOld) {
                                      result_format);
   if (traffic_cop.GetQueuing()) {
     TestingSQLUtil::ContinueAfterComplete();
-    traffic_cop.ExecuteStatementPlanGetResult();
+    traffic_cop.ExecuteStatementGetResult();
     status = traffic_cop.p_status_;
-    traffic_cop.SetQueuing(false);
   }
   LOG_INFO("Statement executed. Result: %s",
            ResultTypeToString(status.m_result).c_str());
@@ -401,9 +397,8 @@ TEST_F(UpdateTests, UpdatingOld) {
                                      result_format);
   if (traffic_cop.GetQueuing()) {
     TestingSQLUtil::ContinueAfterComplete();
-    traffic_cop.ExecuteStatementPlanGetResult();
+    traffic_cop.ExecuteStatementGetResult();
     status = traffic_cop.p_status_;
-    traffic_cop.SetQueuing(false);
   }
   LOG_INFO("Statement executed. Result: %s",
            ResultTypeToString(status.m_result).c_str());
diff --git a/test/optimizer/old_optimizer_test.cpp b/test/optimizer/old_optimizer_test.cpp
index 1069ab87909..b1060503812 100644
--- a/test/optimizer/old_optimizer_test.cpp
+++ b/test/optimizer/old_optimizer_test.cpp
@@ -91,9 +91,8 @@ TEST_F(OldOptimizerTests, UpdateDelWithIndexScanTest) {
       statement->GetPlanTree(), params, result, result_format);
   if (traffic_cop.GetQueuing()) {
     TestingSQLUtil::ContinueAfterComplete();
-    traffic_cop.ExecuteStatementPlanGetResult();
+    traffic_cop.ExecuteStatementGetResult();
     status = traffic_cop.p_status_;
-    traffic_cop.SetQueuing(false);
   }
   LOG_TRACE("Statement executed. Result: %s",
             ResultTypeToString(status.m_result).c_str());
@@ -128,9 +127,8 @@ TEST_F(OldOptimizerTests, UpdateDelWithIndexScanTest) {
                                      result_format);
   if (traffic_cop.GetQueuing()) {
     TestingSQLUtil::ContinueAfterComplete();
-    traffic_cop.ExecuteStatementPlanGetResult();
+    traffic_cop.ExecuteStatementGetResult();
     status = traffic_cop.p_status_;
-    traffic_cop.SetQueuing(false);
   }
   LOG_TRACE("Statement executed. Result: %s",
             ResultTypeToString(status.m_result).c_str());
@@ -160,9 +158,8 @@ TEST_F(OldOptimizerTests, UpdateDelWithIndexScanTest) {
                                      result_format);
   if (traffic_cop.GetQueuing()) {
     TestingSQLUtil::ContinueAfterComplete();
-    traffic_cop.ExecuteStatementPlanGetResult();
+    traffic_cop.ExecuteStatementGetResult();
     status = traffic_cop.p_status_;
-    traffic_cop.SetQueuing(false);
   }
   LOG_TRACE("Statement executed. Result: %s",
             ResultTypeToString(status.m_result).c_str());
diff --git a/test/optimizer/optimizer_test.cpp b/test/optimizer/optimizer_test.cpp
index dae410999d6..09acba53398 100644
--- a/test/optimizer/optimizer_test.cpp
+++ b/test/optimizer/optimizer_test.cpp
@@ -110,9 +110,8 @@ TEST_F(OptimizerTests, HashJoinTest) {
       statement->GetPlanTree(), params, result, result_format);
   if (traffic_cop.GetQueuing()) {
     TestingSQLUtil::ContinueAfterComplete();
-    traffic_cop.ExecuteStatementPlanGetResult();
+    traffic_cop.ExecuteStatementGetResult();
     status = traffic_cop.p_status_;
-    traffic_cop.SetQueuing(false);
   }
   LOG_INFO("Statement executed. Result: %s",
            ResultTypeToString(status.m_result).c_str());
@@ -146,9 +145,8 @@ TEST_F(OptimizerTests, HashJoinTest) {
                                      result_format);
   if (traffic_cop.GetQueuing()) {
     TestingSQLUtil::ContinueAfterComplete();
-    traffic_cop.ExecuteStatementPlanGetResult();
+    traffic_cop.ExecuteStatementGetResult();
     status = traffic_cop.p_status_;
-    traffic_cop.SetQueuing(false);
   }
   LOG_INFO("Statement executed. Result: %s",
            ResultTypeToString(status.m_result).c_str());
@@ -182,9 +180,8 @@ TEST_F(OptimizerTests, HashJoinTest) {
                                      result_format);
   if (traffic_cop.GetQueuing()) {
     TestingSQLUtil::ContinueAfterComplete();
-    traffic_cop.ExecuteStatementPlanGetResult();
+    traffic_cop.ExecuteStatementGetResult();
     status = traffic_cop.p_status_;
-    traffic_cop.SetQueuing(false);
   }
   LOG_INFO("Statement executed. Result: %s",
            ResultTypeToString(status.m_result).c_str());
@@ -212,9 +209,8 @@ TEST_F(OptimizerTests, HashJoinTest) {
                                      result_format);
   if (traffic_cop.GetQueuing()) {
     TestingSQLUtil::ContinueAfterComplete();
-    traffic_cop.ExecuteStatementPlanGetResult();
+    traffic_cop.ExecuteStatementGetResult();
     status = traffic_cop.p_status_;
-    traffic_cop.SetQueuing(false);
   }
   LOG_INFO("Statement executed. Result: %s",
            ResultTypeToString(status.m_result).c_str());
@@ -241,9 +237,8 @@ TEST_F(OptimizerTests, HashJoinTest) {
                                      result_format);
   if (traffic_cop.GetQueuing()) {
     TestingSQLUtil::ContinueAfterComplete();
-    traffic_cop.ExecuteStatementPlanGetResult();
+    traffic_cop.ExecuteStatementGetResult();
     status = traffic_cop.p_status_;
-    traffic_cop.SetQueuing(false);
   }
   LOG_INFO("Statement executed. Result: %s",
            ResultTypeToString(status.m_result).c_str());
diff --git a/test/sql/testing_sql_util.cpp b/test/sql/testing_sql_util.cpp
index b17130d3892..b7546870e51 100644
--- a/test/sql/testing_sql_util.cpp
+++ b/test/sql/testing_sql_util.cpp
@@ -87,9 +87,7 @@ ResultType TestingSQLUtil::ExecuteSQLQuery(
                                               0);
   if (traffic_cop_.GetQueuing()) {
     ContinueAfterComplete();
-    traffic_cop_.ExecuteStatementPlanGetResult();
     status = traffic_cop_.ExecuteStatementGetResult();
-    traffic_cop_.SetQueuing(false);
   }
   if (status == ResultType::SUCCESS) {
     tuple_descriptor = statement->GetTupleDescriptor();
@@ -128,11 +126,11 @@ ResultType TestingSQLUtil::ExecuteSQLQueryWithOptimizer(
     counter_.store(1);
     auto status =
         traffic_cop_.ExecuteHelper(plan, params, result, result_format);
+
     if (traffic_cop_.GetQueuing()) {
-      TestingSQLUtil::ContinueAfterComplete();
-      traffic_cop_.ExecuteStatementPlanGetResult();
+      ContinueAfterComplete();
+      traffic_cop_.ExecuteStatementGetResult();
       status = traffic_cop_.p_status_;
-      traffic_cop_.SetQueuing(false);
     }
     rows_changed = status.m_processed;
     LOG_INFO("Statement executed. Result: %s",
@@ -191,9 +189,7 @@ ResultType TestingSQLUtil::ExecuteSQLQuery(const std::string query,
                                               0);
   if (traffic_cop_.GetQueuing()) {
     ContinueAfterComplete();
-    traffic_cop_.ExecuteStatementPlanGetResult();
     status = traffic_cop_.ExecuteStatementGetResult();
-    traffic_cop_.SetQueuing(false);
   }
   if (status == ResultType::SUCCESS) {
     tuple_descriptor = statement->GetTupleDescriptor();
@@ -232,10 +228,9 @@ ResultType TestingSQLUtil::ExecuteSQLQuery(const std::string query) {
                                               0);
   if (traffic_cop_.GetQueuing()) {
     ContinueAfterComplete();
-    traffic_cop_.ExecuteStatementPlanGetResult();
     status = traffic_cop_.ExecuteStatementGetResult();
-    traffic_cop_.SetQueuing(false);
   }
+
   if (status == ResultType::SUCCESS) {
     tuple_descriptor = statement->GetTupleDescriptor();
   }

From d0b9ae247be7f95094d357d8a418ab705a1cd3a9 Mon Sep 17 00:00:00 2001
From: Tianyi Chen <tianyic1@andrew.cmu.edu>
Date: Mon, 7 May 2018 16:05:57 -0400
Subject: [PATCH 04/13] Naming fix

---
 src/include/planner/explain_plan.h |  2 +-
 src/optimizer/optimizer.cpp        | 24 ++++++++++++------------
 2 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/src/include/planner/explain_plan.h b/src/include/planner/explain_plan.h
index 372b491ee2f..1de7f65b55c 100644
--- a/src/include/planner/explain_plan.h
+++ b/src/include/planner/explain_plan.h
@@ -5,7 +5,7 @@
 //
 // explain_plan.h
 //
-// Identification: src/include/planner/analyze_plan.h
+// Identification: src/include/planner/explain_plan.h
 //
 // Copyright (c) 2015-18, Carnegie Mellon University Database Group
 //
diff --git a/src/optimizer/optimizer.cpp b/src/optimizer/optimizer.cpp
index 8a8277fe5de..35fdfacc4a4 100644
--- a/src/optimizer/optimizer.cpp
+++ b/src/optimizer/optimizer.cpp
@@ -140,14 +140,14 @@ void Optimizer::Reset() { metadata_ = OptimizerMetadata(); }
 
 unique_ptr<planner::AbstractPlan> Optimizer::HandleUtilStatement(
     parser::SQLStatement *tree, concurrency::TransactionContext *txn) {
-  unique_ptr<planner::AbstractPlan> ddl_plan = nullptr;
+  unique_ptr<planner::AbstractPlan> util_plan = nullptr;
   auto stmt_type = tree->GetType();
   switch (stmt_type) {
     case StatementType::DROP: {
       LOG_TRACE("Adding Drop plan...");
       unique_ptr<planner::AbstractPlan> drop_plan(
           new planner::DropPlan((parser::DropStatement *)tree));
-      ddl_plan = move(drop_plan);
+      util_plan = move(drop_plan);
       break;
     }
 
@@ -158,7 +158,7 @@ unique_ptr<planner::AbstractPlan> Optimizer::HandleUtilStatement(
       auto create_plan =
           new planner::CreatePlan((parser::CreateStatement *)tree);
       std::unique_ptr<planner::AbstractPlan> child_CreatePlan(create_plan);
-      ddl_plan = move(child_CreatePlan);
+      util_plan = move(child_CreatePlan);
 
       if (create_plan->GetCreateType() == peloton::CreateType::INDEX) {
         auto create_stmt = (parser::CreateStatement *)tree;
@@ -184,14 +184,14 @@ unique_ptr<planner::AbstractPlan> Optimizer::HandleUtilStatement(
         std::unique_ptr<planner::SeqScanPlan> child_SeqScanPlan(
             new planner::SeqScanPlan(target_table, nullptr, column_ids, false));
 
-        child_SeqScanPlan->AddChild(std::move(ddl_plan));
-        ddl_plan = std::move(child_SeqScanPlan);
+        child_SeqScanPlan->AddChild(std::move(util_plan));
+        util_plan = std::move(child_SeqScanPlan);
         // Create a plan to add data to index
         std::unique_ptr<planner::AbstractPlan> child_PopulateIndexPlan(
             new planner::PopulateIndexPlan(target_table, column_ids));
-        child_PopulateIndexPlan->AddChild(std::move(ddl_plan));
+        child_PopulateIndexPlan->AddChild(std::move(util_plan));
         create_plan->SetKeyAttrs(column_ids);
-        ddl_plan = std::move(child_PopulateIndexPlan);
+        util_plan = std::move(child_PopulateIndexPlan);
       }
       break;
     }
@@ -203,32 +203,32 @@ unique_ptr<planner::AbstractPlan> Optimizer::HandleUtilStatement(
       unique_ptr<planner::AbstractPlan> create_func_plan(
           new planner::CreateFunctionPlan(
               (parser::CreateFunctionStatement *)tree));
-      ddl_plan = move(create_func_plan);
+      util_plan = move(create_func_plan);
     } break;
     case StatementType::ANALYZE: {
       LOG_TRACE("Adding Analyze plan...");
       unique_ptr<planner::AbstractPlan> analyze_plan(new planner::AnalyzePlan(
           static_cast<parser::AnalyzeStatement *>(tree), txn));
-      ddl_plan = move(analyze_plan);
+      util_plan = move(analyze_plan);
       break;
     }
     case StatementType::COPY: {
       LOG_TRACE("Adding Copy plan...");
       parser::CopyStatement *copy_parse_tree =
           static_cast<parser::CopyStatement *>(tree);
-      ddl_plan = util::CreateCopyPlan(copy_parse_tree);
+      util_plan = util::CreateCopyPlan(copy_parse_tree);
       break;
     }
     case StatementType::EXPLAIN: {
       LOG_TRACE("Adding Explain plan...");
       // Pass the sql statement to explain to the plan node
-      ddl_plan.reset(new planner::ExplainPlan(
+      util_plan.reset(new planner::ExplainPlan(
           static_cast<parser::ExplainStatement *>(tree)->real_sql_stmt.get()));
     }
     default:
       break;
   }
-  return ddl_plan;
+  return util_plan;
 }
 
 shared_ptr<GroupExpression> Optimizer::InsertQueryTree(

From 5d8919d3fa8caad61b32445dec5e8a20a7db2146 Mon Sep 17 00:00:00 2001
From: vagrant <411468452@qq.com>
Date: Mon, 7 May 2018 23:30:50 -0400
Subject: [PATCH 05/13] Add explain support in executor, not tested yet

---
 src/binder/bind_node_visitor.cpp        |  4 +-
 src/executor/explain_executor.cpp       | 72 +++++++++++++++++++++++++
 src/executor/plan_executor.cpp          |  3 ++
 src/include/binder/bind_node_visitor.h  |  1 +
 src/include/executor/executors.h        |  1 +
 src/include/executor/explain_executor.h | 46 ++++++++++++++++
 src/include/parser/explain_statement.h  |  6 +++
 src/include/planner/explain_plan.h      | 17 ++++--
 src/optimizer/optimizer.cpp             |  6 ++-
 src/planner/analyze_plan.cpp            |  2 +-
 10 files changed, 151 insertions(+), 7 deletions(-)
 create mode 100644 src/executor/explain_executor.cpp
 create mode 100644 src/include/executor/explain_executor.h

diff --git a/src/binder/bind_node_visitor.cpp b/src/binder/bind_node_visitor.cpp
index a6ffe17b322..3aca3f9071d 100644
--- a/src/binder/bind_node_visitor.cpp
+++ b/src/binder/bind_node_visitor.cpp
@@ -191,7 +191,9 @@ void BindNodeVisitor::Visit(parser::AnalyzeStatement *node) {
   node->TryBindDatabaseName(default_database_name_);
 }
 
-// void BindNodeVisitor::Visit(const parser::ConstantValueExpression *) {}
+void BindNodeVisitor::Visit(parser::ExplainStatement *node) {
+  node->default_database_name = default_database_name_;
+}
 
 void BindNodeVisitor::Visit(expression::TupleValueExpression *expr) {
   if (!expr->GetIsBound()) {
diff --git a/src/executor/explain_executor.cpp b/src/executor/explain_executor.cpp
new file mode 100644
index 00000000000..4bc7ceb9880
--- /dev/null
+++ b/src/executor/explain_executor.cpp
@@ -0,0 +1,72 @@
+//===----------------------------------------------------------------------===//
+//
+//                         Peloton
+//
+// explain_executor.cpp
+//
+// Identification: src/executor/explain_executor.cpp
+//
+// Copyright (c) 2015-18, Carnegie Mellon University Database Group
+//
+//===----------------------------------------------------------------------===//
+
+#include <vector>
+
+#include "binder/bind_node_visitor.h"
+#include "catalog/catalog.h"
+#include "catalog/column.h"
+#include "catalog/schema.h"
+#include "concurrency/transaction_manager_factory.h"
+#include "common/logger.h"
+#include "executor/explain_executor.h"
+#include "executor/executor_context.h"
+#include "executor/logical_tile_factory.h"
+#include "optimizer/optimizer.h"
+#include "storage/tile.h"
+#include "type/type.h"
+
+namespace peloton {
+namespace executor {
+
+bool ExplainExecutor::DInit() {
+  LOG_TRACE("Initializing explain executor...");
+  LOG_TRACE("Explain executor initialized!");
+  return true;
+}
+
+bool ExplainExecutor::DExecute() {
+  LOG_TRACE("Executing Explain...");
+
+  const planner::ExplainPlan &node = GetPlanNode<planner::ExplainPlan>();
+
+  parser::SQLStatement *sql_stmt = node.GetSQLStatement();
+
+  // LOG_TRACE("Analyzing column size %lu", target_columns.size());
+
+  auto current_txn = executor_context_->GetTransaction();
+
+  auto bind_node_visitor =
+      binder::BindNodeVisitor(current_txn, node.GetDatabaseName());
+
+  // Bind, optimize and return the plan as a string
+  bind_node_visitor.BindNameToNode(sql_stmt);
+  std::unique_ptr<optimizer::Optimizer> optimizer(new optimizer::Optimizer());
+  std::unique_ptr<parser::SQLStatementList> stmt_list(
+      new parser::SQLStatementList(sql_stmt));
+  auto plan = optimizer->BuildPelotonPlanTree(stmt_list, current_txn);
+  const catalog::Schema schema({catalog::Column(
+      type::TypeId::VARCHAR, type::Type::GetTypeSize(type::TypeId::VARCHAR),
+      "Query Plan")});
+  std::shared_ptr<storage::Tile> dest_tile(
+      storage::TileFactory::GetTempTile(schema, 1));
+  std::unique_ptr<storage::Tuple> buffer(new storage::Tuple(&schema, true));
+  buffer->SetValue(0, type::ValueFactory::GetVarcharValue(plan->GetInfo()));
+  dest_tile->InsertTuple(0, buffer.get());
+  SetOutput(LogicalTileFactory::WrapTiles({dest_tile}));
+
+  LOG_TRACE("Explain finished!");
+  return false;
+}
+
+}  // namespace executor
+}  // namespace peloton
diff --git a/src/executor/plan_executor.cpp b/src/executor/plan_executor.cpp
index 104aff1351c..9191fbf83bc 100644
--- a/src/executor/plan_executor.cpp
+++ b/src/executor/plan_executor.cpp
@@ -336,6 +336,9 @@ executor::AbstractExecutor *BuildExecutorTree(
       child_executor =
           new executor::PopulateIndexExecutor(plan, executor_context);
       break;
+    case PlanNodeType::EXPLAIN:
+      child_executor = 
+          new executor::ExplainExecutor(plan, executor_context);
 
     default:
       LOG_ERROR("Unsupported plan node type : %s",
diff --git a/src/include/binder/bind_node_visitor.h b/src/include/binder/bind_node_visitor.h
index 9ca09c68693..5f24ea27563 100644
--- a/src/include/binder/bind_node_visitor.h
+++ b/src/include/binder/bind_node_visitor.h
@@ -67,6 +67,7 @@ class BindNodeVisitor : public SqlNodeVisitor {
   void Visit(parser::UpdateStatement *) override;
   void Visit(parser::CopyStatement *) override;
   void Visit(parser::AnalyzeStatement *) override;
+  void Visit(parser::ExplainStatement *) override;
 
   void Visit(expression::CaseExpression *expr) override;
   void Visit(expression::SubqueryExpression *expr) override;
diff --git a/src/include/executor/executors.h b/src/include/executor/executors.h
index 16614120444..fbfb77860d2 100644
--- a/src/include/executor/executors.h
+++ b/src/include/executor/executors.h
@@ -21,6 +21,7 @@
 #include "executor/copy_executor.h"
 #include "executor/create_executor.h"
 #include "executor/create_function_executor.h"
+#include "executor/explain_executor.h"
 #include "executor/delete_executor.h"
 #include "executor/drop_executor.h"
 #include "executor/hash_executor.h"
diff --git a/src/include/executor/explain_executor.h b/src/include/executor/explain_executor.h
new file mode 100644
index 00000000000..f5e6bb4f2ae
--- /dev/null
+++ b/src/include/executor/explain_executor.h
@@ -0,0 +1,46 @@
+//===----------------------------------------------------------------------===//
+//
+//                         Peloton
+//
+// explain_executor.h
+//
+// Identification: src/include/executor/explain_executor.h
+//
+// Copyright (c) 2015-18, Carnegie Mellon University Database Group
+//
+//===----------------------------------------------------------------------===//
+
+#pragma once
+
+#include "executor/abstract_executor.h"
+#include "planner/explain_plan.h"
+
+namespace peloton {
+
+namespace storage {
+class DataTable;
+}
+
+namespace executor {
+
+class ExplainExecutor : public AbstractExecutor {
+ public:
+  ExplainExecutor(const ExplainExecutor &) = delete;
+  ExplainExecutor &operator=(const ExplainExecutor &) = delete;
+  ExplainExecutor(ExplainExecutor &&) = delete;
+  ExplainExecutor &operator=(ExplainExecutor &&) = delete;
+
+  ExplainExecutor(const planner::AbstractPlan *node,
+                  ExecutorContext *executor_context)
+      : AbstractExecutor(node, executor_context) {}
+
+  ~ExplainExecutor() {}
+
+ protected:
+  bool DInit();
+
+  bool DExecute();
+};
+
+}  // namespace executor
+}  // namespace peloton
diff --git a/src/include/parser/explain_statement.h b/src/include/parser/explain_statement.h
index 5d3e763f9dc..e0497a60484 100644
--- a/src/include/parser/explain_statement.h
+++ b/src/include/parser/explain_statement.h
@@ -29,6 +29,12 @@ class ExplainStatement : public SQLStatement {
   void Accept(SqlNodeVisitor *v) override { v->Visit(this); }
 
   std::unique_ptr<parser::SQLStatement> real_sql_stmt;
+
+  /**
+   * @brief Should be set by the binder, used in the executor to bind the stmt
+   * being explained
+   */
+  std::string default_database_name;
 };
 
 }  // namespace parser
diff --git a/src/include/planner/explain_plan.h b/src/include/planner/explain_plan.h
index 1de7f65b55c..b517809535f 100644
--- a/src/include/planner/explain_plan.h
+++ b/src/include/planner/explain_plan.h
@@ -39,21 +39,32 @@ class ExplainPlan : public AbstractPlan {
   ExplainPlan(ExplainPlan &&) = delete;
   ExplainPlan &operator=(ExplainPlan &&) = delete;
 
-  explicit ExplainPlan(parser::SQLStatement *sql_stmt) : sql_stmt(sql_stmt){};
+  explicit ExplainPlan(parser::SQLStatement *sql_stmt,
+                       std::string default_database_name)
+      : sql_stmt_(sql_stmt), default_database_name_(default_database_name){};
 
   inline PlanNodeType GetPlanNodeType() const { return PlanNodeType::EXPLAIN; }
 
   const std::string GetInfo() const { return "Explain table"; }
 
   inline std::unique_ptr<AbstractPlan> Copy() const {
-    return std::unique_ptr<AbstractPlan>(new ExplainPlan(sql_stmt));
+    return std::unique_ptr<AbstractPlan>(
+        new ExplainPlan(sql_stmt_, default_database_name_));
   }
 
+  parser::SQLStatement *GetSQLStatement() const { return sql_stmt_; }
+
+  std::string GetDatabaseName() const { return default_database_name_; }
+
  private:
   /**
    * @brief The SQL statement to explain (owned by the AST)
    */
-  parser::SQLStatement *sql_stmt;
+  parser::SQLStatement *sql_stmt_;
+  /**
+   * @brief The database name to be used in the binder
+   */
+  std::string default_database_name_;
 };
 
 }  // namespace planner
diff --git a/src/optimizer/optimizer.cpp b/src/optimizer/optimizer.cpp
index 35fdfacc4a4..76195ae7193 100644
--- a/src/optimizer/optimizer.cpp
+++ b/src/optimizer/optimizer.cpp
@@ -222,8 +222,10 @@ unique_ptr<planner::AbstractPlan> Optimizer::HandleUtilStatement(
     case StatementType::EXPLAIN: {
       LOG_TRACE("Adding Explain plan...");
       // Pass the sql statement to explain to the plan node
-      util_plan.reset(new planner::ExplainPlan(
-          static_cast<parser::ExplainStatement *>(tree)->real_sql_stmt.get()));
+      auto *explain_parse_tree = static_cast<parser::ExplainStatement *>(tree);
+      util_plan.reset(
+          new planner::ExplainPlan(explain_parse_tree->real_sql_stmt.get(),
+                                   explain_parse_tree->default_database_name));
     }
     default:
       break;
diff --git a/src/planner/analyze_plan.cpp b/src/planner/analyze_plan.cpp
index 5de53476b14..07c200d2b98 100644
--- a/src/planner/analyze_plan.cpp
+++ b/src/planner/analyze_plan.cpp
@@ -4,7 +4,7 @@
 //
 // analyze_plan.cpp
 //
-// Identification: src/planner/Analyze_plan.cpp
+// Identification: src/planner/analyze_plan.cpp
 //
 // Copyright (c) 2015-16, Carnegie Mellon University Database Group
 //

From f4fdd3994f2bb1f8f6cb10457a844784b9c15d0a Mon Sep 17 00:00:00 2001
From: vagrant <411468452@qq.com>
Date: Tue, 8 May 2018 14:23:11 -0400
Subject: [PATCH 06/13] Add a test and fix several bugs, still breaking because
 the ownership of the sql statement's not correctly set

---
 src/common/internal_types.cpp      |  3 ++
 src/executor/explain_executor.cpp  |  4 +-
 src/executor/plan_executor.cpp     |  2 +-
 src/include/planner/explain_plan.h | 24 +++++-----
 src/optimizer/optimizer.cpp        |  5 ++-
 src/traffic_cop/traffic_cop.cpp    | 33 +++++++++-----
 test/sql/explain_sql_test.cpp      | 72 ++++++++++++++++++++++++++++++
 7 files changed, 113 insertions(+), 30 deletions(-)
 create mode 100644 test/sql/explain_sql_test.cpp

diff --git a/src/common/internal_types.cpp b/src/common/internal_types.cpp
index 6d95bf1a35c..3899daad63e 100644
--- a/src/common/internal_types.cpp
+++ b/src/common/internal_types.cpp
@@ -1391,6 +1391,9 @@ std::string PlanNodeTypeToString(PlanNodeType type) {
     case PlanNodeType::ANALYZE: {
       return ("ANALYZE");
     }
+    case PlanNodeType::EXPLAIN: {
+      return ("EXPLAIN");
+    }
     default: {
       throw ConversionException(
           StringUtil::Format("No string conversion for PlanNodeType value '%d'",
diff --git a/src/executor/explain_executor.cpp b/src/executor/explain_executor.cpp
index 4bc7ceb9880..d190117b760 100644
--- a/src/executor/explain_executor.cpp
+++ b/src/executor/explain_executor.cpp
@@ -41,7 +41,7 @@ bool ExplainExecutor::DExecute() {
 
   parser::SQLStatement *sql_stmt = node.GetSQLStatement();
 
-  // LOG_TRACE("Analyzing column size %lu", target_columns.size());
+  LOG_TRACE("EXPLAIN : %s", sql_stmt->GetInfo().c_str());
 
   auto current_txn = executor_context_->GetTransaction();
 
@@ -65,7 +65,7 @@ bool ExplainExecutor::DExecute() {
   SetOutput(LogicalTileFactory::WrapTiles({dest_tile}));
 
   LOG_TRACE("Explain finished!");
-  return false;
+  return true;
 }
 
 }  // namespace executor
diff --git a/src/executor/plan_executor.cpp b/src/executor/plan_executor.cpp
index 9191fbf83bc..7d9a0640c8f 100644
--- a/src/executor/plan_executor.cpp
+++ b/src/executor/plan_executor.cpp
@@ -339,7 +339,7 @@ executor::AbstractExecutor *BuildExecutorTree(
     case PlanNodeType::EXPLAIN:
       child_executor = 
           new executor::ExplainExecutor(plan, executor_context);
-
+      break;
     default:
       LOG_ERROR("Unsupported plan node type : %s",
                 PlanNodeTypeToString(plan_node_type).c_str());
diff --git a/src/include/planner/explain_plan.h b/src/include/planner/explain_plan.h
index b517809535f..30d9dfd8c28 100644
--- a/src/include/planner/explain_plan.h
+++ b/src/include/planner/explain_plan.h
@@ -13,20 +13,12 @@
 
 #pragma once
 
+#include "parser/sql_statement.h"
 #include "planner/abstract_plan.h"
 
 #include <memory>
 
 namespace peloton {
-namespace storage {
-class DataTable;
-}
-namespace parser {
-class AnalyzeStatement;
-}
-namespace catalog {
-class Schema;
-}
 namespace concurrency {
 class TransactionContext;
 }
@@ -39,20 +31,26 @@ class ExplainPlan : public AbstractPlan {
   ExplainPlan(ExplainPlan &&) = delete;
   ExplainPlan &operator=(ExplainPlan &&) = delete;
 
-  explicit ExplainPlan(parser::SQLStatement *sql_stmt,
+  explicit ExplainPlan(std::unique_ptr<parser::SQLStatement> sql_stmt,
+                       std::string default_database_name)
+      : sql_stmt_(sql_stmt.release()),
+        default_database_name_(default_database_name){};
+
+  explicit ExplainPlan(std::shared_ptr<parser::SQLStatement> sql_stmt,
                        std::string default_database_name)
       : sql_stmt_(sql_stmt), default_database_name_(default_database_name){};
 
   inline PlanNodeType GetPlanNodeType() const { return PlanNodeType::EXPLAIN; }
 
-  const std::string GetInfo() const { return "Explain table"; }
+  const std::string GetInfo() const { return std::string("Explain") + sql_stmt_->GetInfo(); }
 
   inline std::unique_ptr<AbstractPlan> Copy() const {
+    // FIXME: support deep copy for sql statement, then use a unique_ptr here
     return std::unique_ptr<AbstractPlan>(
         new ExplainPlan(sql_stmt_, default_database_name_));
   }
 
-  parser::SQLStatement *GetSQLStatement() const { return sql_stmt_; }
+  parser::SQLStatement *GetSQLStatement() const { return sql_stmt_.get(); }
 
   std::string GetDatabaseName() const { return default_database_name_; }
 
@@ -60,7 +58,7 @@ class ExplainPlan : public AbstractPlan {
   /**
    * @brief The SQL statement to explain (owned by the AST)
    */
-  parser::SQLStatement *sql_stmt_;
+  std::shared_ptr<parser::SQLStatement> sql_stmt_;
   /**
    * @brief The database name to be used in the binder
    */
diff --git a/src/optimizer/optimizer.cpp b/src/optimizer/optimizer.cpp
index 76195ae7193..30ea3072915 100644
--- a/src/optimizer/optimizer.cpp
+++ b/src/optimizer/optimizer.cpp
@@ -222,9 +222,10 @@ unique_ptr<planner::AbstractPlan> Optimizer::HandleUtilStatement(
     case StatementType::EXPLAIN: {
       LOG_TRACE("Adding Explain plan...");
       // Pass the sql statement to explain to the plan node
-      auto *explain_parse_tree = static_cast<parser::ExplainStatement *>(tree);
+      auto *explain_parse_tree =
+          reinterpret_cast<parser::ExplainStatement *>(tree);
       util_plan.reset(
-          new planner::ExplainPlan(explain_parse_tree->real_sql_stmt.get(),
+          new planner::ExplainPlan(std::move(explain_parse_tree->real_sql_stmt),
                                    explain_parse_tree->default_database_name));
     }
     default:
diff --git a/src/traffic_cop/traffic_cop.cpp b/src/traffic_cop/traffic_cop.cpp
index 7ba9fe051ac..fe47dd2a78f 100644
--- a/src/traffic_cop/traffic_cop.cpp
+++ b/src/traffic_cop/traffic_cop.cpp
@@ -133,7 +133,7 @@ ResultType TrafficCop::AbortQueryHelper() {
 
 ResultType TrafficCop::ExecuteStatementGetResult() {
   LOG_TRACE("Statement executed. Result: %s",
-          ResultTypeToString(p_status_.m_result).c_str());
+            ResultTypeToString(p_status_.m_result).c_str());
   setRowsAffected(p_status_.m_processed);
   LOG_TRACE("rows_changed %d", p_status_.m_processed);
   is_queuing_ = false;
@@ -441,7 +441,15 @@ void TrafficCop::GetTableColumns(parser::TableRef *from_table,
 std::vector<FieldInfo> TrafficCop::GenerateTupleDescriptor(
     parser::SQLStatement *sql_stmt) {
   std::vector<FieldInfo> tuple_descriptor;
-  if (sql_stmt->GetType() != StatementType::SELECT) return tuple_descriptor;
+  // EXPLAIN returns a the query plan string as a tuple
+  if (sql_stmt->GetType() == StatementType::EXPLAIN) {
+    tuple_descriptor.push_back(
+        GetColumnFieldForValueType("Query Plan", type::TypeId::VARCHAR));
+    return tuple_descriptor;
+  }
+  if (sql_stmt->GetType() != StatementType::SELECT) {
+    return tuple_descriptor;
+  }
   auto select_stmt = (parser::SelectStatement *)sql_stmt;
 
   // TODO: this is a hack which I don't have time to fix now
@@ -542,18 +550,19 @@ FieldInfo TrafficCop::GetColumnFieldForValueType(std::string column_name,
                          field_size);
 }
 
-ResultType TrafficCop::ExecuteStatement(std::shared_ptr<stats::QueryMetric::QueryParams> param_stats,
-                                        const std::vector<int> &result_format,
-                                        size_t thread_id) {
-  return ExecuteStatement(statement_, param_values_, param_stats, result_format, result_, thread_id);
+ResultType TrafficCop::ExecuteStatement(
+    std::shared_ptr<stats::QueryMetric::QueryParams> param_stats,
+    const std::vector<int> &result_format, size_t thread_id) {
+  return ExecuteStatement(statement_, param_values_, param_stats, result_format,
+                          result_, thread_id);
 }
 
-ResultType TrafficCop::ExecuteStatement(const std::shared_ptr<Statement> &statement,
-                                        const std::vector<type::Value> &params,
-                                        std::shared_ptr<stats::QueryMetric::QueryParams> param_stats,
-                                        const std::vector<int> &result_format,
-                                        std::vector<ResultValue> &result,
-                                        size_t thread_id) {
+ResultType TrafficCop::ExecuteStatement(
+    const std::shared_ptr<Statement> &statement,
+    const std::vector<type::Value> &params,
+    std::shared_ptr<stats::QueryMetric::QueryParams> param_stats,
+    const std::vector<int> &result_format, std::vector<ResultValue> &result,
+    size_t thread_id) {
   // TODO(Tianyi) Further simplify this API
   if (static_cast<StatsType>(settings::SettingsManager::GetInt(
           settings::SettingId::stats_mode)) != StatsType::INVALID) {
diff --git a/test/sql/explain_sql_test.cpp b/test/sql/explain_sql_test.cpp
new file mode 100644
index 00000000000..09c91bf42b5
--- /dev/null
+++ b/test/sql/explain_sql_test.cpp
@@ -0,0 +1,72 @@
+//===----------------------------------------------------------------------===//
+//
+//                         Peloton
+//
+// explain_sql_test.cpp
+//
+// Identification: test/sql/explain_sql_test.cpp
+//
+// Copyright (c) 2015-18, Carnegie Mellon University Database Group
+//
+//===----------------------------------------------------------------------===//
+
+#include <memory>
+
+#include "catalog/catalog.h"
+#include "catalog/column_stats_catalog.h"
+#include "common/harness.h"
+#include "common/internal_types.h"
+#include "concurrency/transaction_manager_factory.h"
+#include "executor/create_executor.h"
+#include "optimizer/optimizer.h"
+#include "planner/create_plan.h"
+#include "sql/testing_sql_util.h"
+
+namespace peloton {
+namespace test {
+
+class ExplainSQLTests : public PelotonTest {};
+
+void CreateAndLoadTable() {
+  // Create a table first
+  TestingSQLUtil::ExecuteSQLQuery(
+      "CREATE TABLE test(a INT PRIMARY KEY, b INT, c INT, d VARCHAR);");
+
+  // Insert tuples into table
+  TestingSQLUtil::ExecuteSQLQuery(
+      "INSERT INTO test VALUES (1, 22, 333, 'abcd');");
+  TestingSQLUtil::ExecuteSQLQuery(
+      "INSERT INTO test VALUES (2, 22, 333, 'abc');");
+  TestingSQLUtil::ExecuteSQLQuery(
+      "INSERT INTO test VALUES (3, 11, 222, 'abcd');");
+}
+
+TEST_F(ExplainSQLTests, ExplainSelectTest) {
+  auto &txn_manager = concurrency::TransactionManagerFactory::GetInstance();
+  auto txn = txn_manager.BeginTransaction();
+  catalog::Catalog::GetInstance()->CreateDatabase(DEFAULT_DB_NAME, txn);
+  txn_manager.CommitTransaction(txn);
+
+  CreateAndLoadTable();
+  std::unique_ptr<optimizer::AbstractOptimizer> optimizer(
+      new optimizer::Optimizer());
+  const std::string query = "EXPLAIN SELECT * FROM test";
+  std::vector<ResultValue> result;
+  std::vector<FieldInfo> tuple_descriptor;
+  int rows_changed;
+  std::string error_message;
+  // Execute explain
+  TestingSQLUtil::ExecuteSQLQueryWithOptimizer(
+      optimizer, query, result, tuple_descriptor, rows_changed, error_message);
+
+  EXPECT_EQ(result.size(), 1);
+  EXPECT_EQ(result[0], "");
+
+  // Free the database
+  txn = txn_manager.BeginTransaction();
+  catalog::Catalog::GetInstance()->DropDatabaseWithName(DEFAULT_DB_NAME, txn);
+  txn_manager.CommitTransaction(txn);
+}
+
+}  // namespace test
+}  // namespace peloton

From fa2f942cb04347f832cf53d26f6f6a81f5db41f5 Mon Sep 17 00:00:00 2001
From: vagrant <411468452@qq.com>
Date: Wed, 9 May 2018 21:50:55 -0400
Subject: [PATCH 07/13] Fix double delete in the test case, the cause is not
 clear though

---
 src/executor/explain_executor.cpp  |  4 ++--
 src/include/planner/explain_plan.h | 22 ++++++++--------------
 src/optimizer/optimizer.cpp        |  5 ++++-
 test/sql/explain_sql_test.cpp      |  2 +-
 4 files changed, 15 insertions(+), 18 deletions(-)

diff --git a/src/executor/explain_executor.cpp b/src/executor/explain_executor.cpp
index d190117b760..30dd4283c4f 100644
--- a/src/executor/explain_executor.cpp
+++ b/src/executor/explain_executor.cpp
@@ -64,8 +64,8 @@ bool ExplainExecutor::DExecute() {
   dest_tile->InsertTuple(0, buffer.get());
   SetOutput(LogicalTileFactory::WrapTiles({dest_tile}));
 
-  LOG_TRACE("Explain finished!");
-  return true;
+  LOG_TRACE("Explain finished!, plan : %s", plan->GetInfo().c_str());
+  return false;
 }
 
 }  // namespace executor
diff --git a/src/include/planner/explain_plan.h b/src/include/planner/explain_plan.h
index 30d9dfd8c28..98390508d5e 100644
--- a/src/include/planner/explain_plan.h
+++ b/src/include/planner/explain_plan.h
@@ -19,9 +19,6 @@
 #include <memory>
 
 namespace peloton {
-namespace concurrency {
-class TransactionContext;
-}
 
 namespace planner {
 class ExplainPlan : public AbstractPlan {
@@ -31,34 +28,31 @@ class ExplainPlan : public AbstractPlan {
   ExplainPlan(ExplainPlan &&) = delete;
   ExplainPlan &operator=(ExplainPlan &&) = delete;
 
-  explicit ExplainPlan(std::unique_ptr<parser::SQLStatement> sql_stmt,
-                       std::string default_database_name)
-      : sql_stmt_(sql_stmt.release()),
-        default_database_name_(default_database_name){};
-
-  explicit ExplainPlan(std::shared_ptr<parser::SQLStatement> sql_stmt,
+  explicit ExplainPlan(parser::SQLStatement *sql_stmt,
                        std::string default_database_name)
       : sql_stmt_(sql_stmt), default_database_name_(default_database_name){};
 
   inline PlanNodeType GetPlanNodeType() const { return PlanNodeType::EXPLAIN; }
 
-  const std::string GetInfo() const { return std::string("Explain") + sql_stmt_->GetInfo(); }
+  const std::string GetInfo() const {
+    return std::string("Explain") + sql_stmt_->GetInfo();
+  }
 
   inline std::unique_ptr<AbstractPlan> Copy() const {
-    // FIXME: support deep copy for sql statement, then use a unique_ptr here
     return std::unique_ptr<AbstractPlan>(
         new ExplainPlan(sql_stmt_, default_database_name_));
   }
 
-  parser::SQLStatement *GetSQLStatement() const { return sql_stmt_.get(); }
+  parser::SQLStatement *GetSQLStatement() const { return sql_stmt_; }
 
   std::string GetDatabaseName() const { return default_database_name_; }
 
  private:
   /**
-   * @brief The SQL statement to explain (owned by the AST)
+   * @brief The SQL statement to explain, the it should be owned by the
+   * explain ast
    */
-  std::shared_ptr<parser::SQLStatement> sql_stmt_;
+  parser::SQLStatement *sql_stmt_;
   /**
    * @brief The database name to be used in the binder
    */
diff --git a/src/optimizer/optimizer.cpp b/src/optimizer/optimizer.cpp
index 30ea3072915..5a2fb2bc434 100644
--- a/src/optimizer/optimizer.cpp
+++ b/src/optimizer/optimizer.cpp
@@ -225,7 +225,10 @@ unique_ptr<planner::AbstractPlan> Optimizer::HandleUtilStatement(
       auto *explain_parse_tree =
           reinterpret_cast<parser::ExplainStatement *>(tree);
       util_plan.reset(
-          new planner::ExplainPlan(std::move(explain_parse_tree->real_sql_stmt),
+          // TODO(boweic): not releasing this unique_ptr here would cause a
+          // double delete which I still don't know why is happening.
+          // I believe no one should take the ownership of the pointer here
+          new planner::ExplainPlan(explain_parse_tree->real_sql_stmt.release(),
                                    explain_parse_tree->default_database_name));
     }
     default:
diff --git a/test/sql/explain_sql_test.cpp b/test/sql/explain_sql_test.cpp
index 09c91bf42b5..93ecba24071 100644
--- a/test/sql/explain_sql_test.cpp
+++ b/test/sql/explain_sql_test.cpp
@@ -60,7 +60,7 @@ TEST_F(ExplainSQLTests, ExplainSelectTest) {
       optimizer, query, result, tuple_descriptor, rows_changed, error_message);
 
   EXPECT_EQ(result.size(), 1);
-  EXPECT_EQ(result[0], "");
+  EXPECT_EQ(result[0], "SeqScan()");
 
   // Free the database
   txn = txn_manager.BeginTransaction();

From 3f67dcef32176f2c08dc38c8ae7b85bbe42a0539 Mon Sep 17 00:00:00 2001
From: vagrant <411468452@qq.com>
Date: Wed, 9 May 2018 21:56:53 -0400
Subject: [PATCH 08/13] Remove explain hack in the protocol handler

---
 .../network/postgres_protocol_handler.h       |  8 -----
 src/network/postgres_protocol_handler.cpp     | 30 -------------------
 2 files changed, 38 deletions(-)

diff --git a/src/include/network/postgres_protocol_handler.h b/src/include/network/postgres_protocol_handler.h
index 672ab8c29c6..b225aa4123d 100644
--- a/src/include/network/postgres_protocol_handler.h
+++ b/src/include/network/postgres_protocol_handler.h
@@ -31,10 +31,6 @@
 
 namespace peloton {
 
-namespace parser {
-class ExplainStatement;
-}  // namespace parser
-
 namespace network {
 
 typedef std::vector<std::unique_ptr<OutputPacket>> ResponseBuffer;
@@ -165,10 +161,6 @@ class PostgresProtocolHandler : public ProtocolHandler {
   /* Execute a Simple query protocol message */
   ProcessResult ExecQueryMessage(InputPacket *pkt, const size_t thread_id);
 
-  /* Execute a EXPLAIN query message */
-  ResultType ExecQueryExplain(const std::string &query,
-                              parser::ExplainStatement &explain_stmt);
-
   /* Process the PARSE message of the extended query protocol */
   void ExecParseMessage(InputPacket *pkt);
 
diff --git a/src/network/postgres_protocol_handler.cpp b/src/network/postgres_protocol_handler.cpp
index c3593e027d2..a989bfedf63 100644
--- a/src/network/postgres_protocol_handler.cpp
+++ b/src/network/postgres_protocol_handler.cpp
@@ -221,12 +221,6 @@ ProcessResult PostgresProtocolHandler::ExecQueryMessage(
       ExecQueryMessageGetResult(status);
       return ProcessResult::COMPLETE;
     };
-    case QueryType::QUERY_EXPLAIN: {
-      auto status = ExecQueryExplain(
-          query, static_cast<parser::ExplainStatement &>(*sql_stmt));
-      ExecQueryMessageGetResult(status);
-      return ProcessResult::COMPLETE;
-    }
     default: {
       std::string stmt_name = "";
       std::unique_ptr<parser::SQLStatementList> unnamed_sql_stmt_list(
@@ -255,30 +249,6 @@ ProcessResult PostgresProtocolHandler::ExecQueryMessage(
   }
 }
 
-ResultType PostgresProtocolHandler::ExecQueryExplain(
-    const std::string &query, parser::ExplainStatement &explain_stmt) {
-  std::unique_ptr<parser::SQLStatementList> unnamed_sql_stmt_list(
-      new parser::SQLStatementList());
-  unnamed_sql_stmt_list->PassInStatement(std::move(explain_stmt.real_sql_stmt));
-  auto stmt = traffic_cop_->PrepareStatement(
-      "explain", query, std::move(unnamed_sql_stmt_list));
-  ResultType status = ResultType::UNKNOWN;
-  if (stmt != nullptr) {
-    traffic_cop_->SetStatement(stmt);
-    std::vector<std::string> plan_info = StringUtil::Split(
-        planner::PlanUtil::GetInfo(stmt->GetPlanTree().get()), '\n');
-    const std::vector<FieldInfo> tuple_descriptor = {
-        traffic_cop_->GetColumnFieldForValueType("Query plan",
-                                                 type::TypeId::VARCHAR)};
-    stmt->SetTupleDescriptor(tuple_descriptor);
-    traffic_cop_->SetResult(plan_info);
-    status = ResultType::SUCCESS;
-  } else {
-    status = ResultType::FAILURE;
-  }
-  return status;
-}
-
 void PostgresProtocolHandler::ExecQueryMessageGetResult(ResultType status) {
   std::vector<FieldInfo> tuple_descriptor;
   if (status == ResultType::SUCCESS) {

From 2a3813e368f02d68670a11d8d410f062f41159a7 Mon Sep 17 00:00:00 2001
From: Tianyi Chen <tianyic1@andrew.cmu.edu>
Date: Fri, 11 May 2018 00:21:55 -0400
Subject: [PATCH 09/13] Add Explain for query descriptor

---
 src/traffic_cop/traffic_cop.cpp | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/src/traffic_cop/traffic_cop.cpp b/src/traffic_cop/traffic_cop.cpp
index fe47dd2a78f..592ebe1d076 100644
--- a/src/traffic_cop/traffic_cop.cpp
+++ b/src/traffic_cop/traffic_cop.cpp
@@ -325,7 +325,8 @@ std::shared_ptr<Statement> TrafficCop::PrepareStatement(
         planner::PlanUtil::GetTablesReferenced(plan.get());
     statement->SetReferencedTables(table_oids);
 
-    if (query_type == QueryType::QUERY_SELECT) {
+    if (query_type == QueryType::QUERY_SELECT ||
+        query_type == QueryType::QUERY_EXPLAIN) {
       auto tuple_descriptor = GenerateTupleDescriptor(
           statement->GetStmtParseTreeList()->GetStatement(0));
       statement->SetTupleDescriptor(tuple_descriptor);
@@ -365,8 +366,8 @@ void TrafficCop::ProcessInvalidStatement() {
 }
 
 bool TrafficCop::BindParamsForCachePlan(
-    const std::vector<std::unique_ptr<expression::AbstractExpression>>
-        &parameters,
+    const std::vector<std::unique_ptr<expression::AbstractExpression>> &
+        parameters,
     const size_t thread_id UNUSED_ATTRIBUTE) {
   if (tcop_txn_state_.empty()) {
     single_statement_txn_ = true;

From ac7185a9b7420156db9a197b1af73d96a84d579c Mon Sep 17 00:00:00 2001
From: vagrant <411468452@qq.com>
Date: Thu, 10 May 2018 12:11:14 -0400
Subject: [PATCH 10/13] Add a network test for EXPLAIN

---
 src/executor/explain_executor.cpp |   2 +-
 test/network/explain_test.cpp     | 105 ++++++++++++++++++++++++++++++
 2 files changed, 106 insertions(+), 1 deletion(-)
 create mode 100644 test/network/explain_test.cpp

diff --git a/src/executor/explain_executor.cpp b/src/executor/explain_executor.cpp
index 30dd4283c4f..88e4fac38b4 100644
--- a/src/executor/explain_executor.cpp
+++ b/src/executor/explain_executor.cpp
@@ -64,7 +64,7 @@ bool ExplainExecutor::DExecute() {
   dest_tile->InsertTuple(0, buffer.get());
   SetOutput(LogicalTileFactory::WrapTiles({dest_tile}));
 
-  LOG_TRACE("Explain finished!, plan : %s", plan->GetInfo().c_str());
+  LOG_DEBUG("Explain finished!, plan : %s", plan->GetInfo().c_str());
   return false;
 }
 
diff --git a/test/network/explain_test.cpp b/test/network/explain_test.cpp
new file mode 100644
index 00000000000..b6d7f193b7d
--- /dev/null
+++ b/test/network/explain_test.cpp
@@ -0,0 +1,105 @@
+//===----------------------------------------------------------------------===//
+//
+//                         Peloton
+//
+// explain_test.cpp
+//
+// Identification: test/network/explain_test.cpp
+//
+// Copyright (c) 2016-18, Carnegie Mellon University Database Group
+//
+//===----------------------------------------------------------------------===//
+
+#include "common/harness.h"
+#include "gtest/gtest.h"
+#include "common/logger.h"
+#include "network/peloton_server.h"
+#include "network/protocol_handler_factory.h"
+#include "network/connection_handle_factory.h"
+#include "util/string_util.h"
+#include <pqxx/pqxx> /* libpqxx is used to instantiate C++ client */
+#include "network/postgres_protocol_handler.h"
+
+namespace peloton {
+namespace test {
+
+//===--------------------------------------------------------------------===//
+// Explain Tests
+//===--------------------------------------------------------------------===//
+
+class ExplainTests : public PelotonTest {};
+
+/**
+ * Explain Test
+ * Test how the network layer handle explain
+ */
+void *ExplainTest(int port) {
+  try {
+    // forcing the factory to generate psql protocol handler
+    pqxx::connection C(
+        StringUtil::Format("host=127.0.0.1 port=%d user=default_database "
+                           "sslmode=disable application_name=psql",
+                           port));
+    pqxx::work txn1(C);
+    peloton::network::ConnectionHandle *conn =
+        peloton::network::ConnectionHandleFactory::GetInstance()
+            .ConnectionHandleAt(peloton::network::PelotonServer::recent_connfd)
+            .get();
+
+    network::PostgresProtocolHandler *handler =
+        dynamic_cast<network::PostgresProtocolHandler *>(
+            conn->GetProtocolHandler().get());
+    EXPECT_NE(handler, nullptr);
+
+    // create table and insert some data
+    txn1.exec("DROP TABLE IF EXISTS template;");
+    txn1.exec("CREATE TABLE template(id INT);");
+    txn1.commit();
+
+    // Execute EXPLAIN directly
+    pqxx::work txn2(C);
+    pqxx::result result1 = txn2.exec("EXPLAIN SELECT * from template;");
+    txn2.commit();
+    EXPECT_EQ(result1.size(), 1);
+
+    // Execute EXPLAIN through PREPARE statement
+    pqxx::work txn3(C);
+    txn3.exec("PREPARE func AS EXPLAIN SELECT * from template;");
+    pqxx::result result2 = txn3.exec("EXECUTE func");
+    txn3.commit();
+    EXPECT_EQ(result2.size(), 1);
+  } catch (const std::exception &e) {
+    LOG_INFO("[ExplainTest] Exception occurred: %s", e.what());
+    EXPECT_TRUE(false);
+  }
+
+  LOG_INFO("[ExplainTest] Client has closed");
+  return NULL;
+}
+
+TEST_F(ExplainTests, ExplainTest) {
+  peloton::PelotonInit::Initialize();
+  LOG_INFO("Server initialized");
+  peloton::network::PelotonServer server;
+
+  int port = 15721;
+  try {
+    server.SetPort(port);
+    server.SetupServer();
+  } catch (peloton::ConnectionException &exception) {
+    LOG_INFO("[LaunchServer] exception when launching server");
+  }
+  std::thread serverThread([&]() { server.ServerLoop(); });
+
+  // server & client running correctly
+  ExplainTest(port);
+
+  server.Close();
+  serverThread.join();
+  LOG_INFO("Peloton is shutting down");
+  peloton::PelotonInit::Shutdown();
+  LOG_INFO("Peloton has shut down");
+}
+
+}  // namespace test
+}  // namespace peloton

From ae8f0380e46c4f682cb599c0071f0020681bc868 Mon Sep 17 00:00:00 2001
From: vagrant <411468452@qq.com>
Date: Thu, 10 May 2018 14:00:59 -0400
Subject: [PATCH 11/13] Fix the newly added test

---
 src/include/optimizer/optimizer.h      | 12 ++++++--
 src/include/parser/explain_statement.h |  4 +++
 src/optimizer/optimizer.cpp            | 41 ++++++++++++++------------
 src/parser/explain_statement.cpp       | 37 +++++++++++++++++++++++
 test/network/explain_test.cpp          | 13 +++-----
 5 files changed, 76 insertions(+), 31 deletions(-)
 create mode 100644 src/parser/explain_statement.cpp

diff --git a/src/include/optimizer/optimizer.h b/src/include/optimizer/optimizer.h
index baeb8720be3..d5de41412b8 100644
--- a/src/include/optimizer/optimizer.h
+++ b/src/include/optimizer/optimizer.h
@@ -44,6 +44,11 @@ class OptimizerRuleTests_SimpleAssociativeRuleTest2_Test;
 
 namespace optimizer {
 
+struct UtilPlanStatus {
+  bool has_plan = false;
+  std::unique_ptr<planner::AbstractPlan> util_plan;
+};
+
 struct QueryInfo {
   QueryInfo(std::vector<expression::AbstractExpression *> &exprs,
             std::shared_ptr<PropertySet> &props)
@@ -100,10 +105,11 @@ class Optimizer : public AbstractOptimizer {
    *support
    *CREATE), set
    * tree: a peloton query tree representing a select query
-   * return: the util plan if it is a util statement
+   * return: the util plan if it is a util statement, if the sql type
+   * is not util statements then return with has_plan set to false
    */
-  std::unique_ptr<planner::AbstractPlan> HandleUtilStatement(
-      parser::SQLStatement *tree, concurrency::TransactionContext *txn);
+  UtilPlanStatus HandleUtilStatement(parser::SQLStatement *tree,
+                                     concurrency::TransactionContext *txn);
 
   /* TransformQueryTree - create an initial operator tree for the given query
    * to be used in performing optimization.
diff --git a/src/include/parser/explain_statement.h b/src/include/parser/explain_statement.h
index e0497a60484..4a64303f470 100644
--- a/src/include/parser/explain_statement.h
+++ b/src/include/parser/explain_statement.h
@@ -28,6 +28,10 @@ class ExplainStatement : public SQLStatement {
 
   void Accept(SqlNodeVisitor *v) override { v->Visit(this); }
 
+  const std::string GetInfo(int num_indent) const override;
+
+  const std::string GetInfo() const override;
+
   std::unique_ptr<parser::SQLStatement> real_sql_stmt;
 
   /**
diff --git a/src/optimizer/optimizer.cpp b/src/optimizer/optimizer.cpp
index 5a2fb2bc434..bc0dcf3894d 100644
--- a/src/optimizer/optimizer.cpp
+++ b/src/optimizer/optimizer.cpp
@@ -101,12 +101,11 @@ shared_ptr<planner::AbstractPlan> Optimizer::BuildPelotonPlanTree(
   // TODO: support multi-statement queries
   auto parse_tree = parse_tree_list->GetStatement(0);
 
-  unique_ptr<planner::AbstractPlan> child_plan = nullptr;
-
+  LOG_DEBUG("optimizer : %s", parse_tree->GetInfo().c_str());
   // Handle ddl statement
-  auto util_plan = HandleUtilStatement(parse_tree, txn);
-  if (util_plan != nullptr) {
-    return move(util_plan);
+  auto util_plan_status = HandleUtilStatement(parse_tree, txn);
+  if (util_plan_status.has_plan != false) {
+    return move(util_plan_status.util_plan);
   }
 
   metadata_.txn = txn;
@@ -138,16 +137,17 @@ shared_ptr<planner::AbstractPlan> Optimizer::BuildPelotonPlanTree(
 
 void Optimizer::Reset() { metadata_ = OptimizerMetadata(); }
 
-unique_ptr<planner::AbstractPlan> Optimizer::HandleUtilStatement(
+UtilPlanStatus Optimizer::HandleUtilStatement(
     parser::SQLStatement *tree, concurrency::TransactionContext *txn) {
-  unique_ptr<planner::AbstractPlan> util_plan = nullptr;
+  UtilPlanStatus util_plan_status;
+  util_plan_status.has_plan = true;
   auto stmt_type = tree->GetType();
   switch (stmt_type) {
     case StatementType::DROP: {
       LOG_TRACE("Adding Drop plan...");
       unique_ptr<planner::AbstractPlan> drop_plan(
           new planner::DropPlan((parser::DropStatement *)tree));
-      util_plan = move(drop_plan);
+      util_plan_status.util_plan = move(drop_plan);
       break;
     }
 
@@ -158,7 +158,7 @@ unique_ptr<planner::AbstractPlan> Optimizer::HandleUtilStatement(
       auto create_plan =
           new planner::CreatePlan((parser::CreateStatement *)tree);
       std::unique_ptr<planner::AbstractPlan> child_CreatePlan(create_plan);
-      util_plan = move(child_CreatePlan);
+      util_plan_status.util_plan = move(child_CreatePlan);
 
       if (create_plan->GetCreateType() == peloton::CreateType::INDEX) {
         auto create_stmt = (parser::CreateStatement *)tree;
@@ -184,14 +184,14 @@ unique_ptr<planner::AbstractPlan> Optimizer::HandleUtilStatement(
         std::unique_ptr<planner::SeqScanPlan> child_SeqScanPlan(
             new planner::SeqScanPlan(target_table, nullptr, column_ids, false));
 
-        child_SeqScanPlan->AddChild(std::move(util_plan));
-        util_plan = std::move(child_SeqScanPlan);
+        child_SeqScanPlan->AddChild(std::move(util_plan_status.util_plan));
+        util_plan_status.util_plan = std::move(child_SeqScanPlan);
         // Create a plan to add data to index
         std::unique_ptr<planner::AbstractPlan> child_PopulateIndexPlan(
             new planner::PopulateIndexPlan(target_table, column_ids));
-        child_PopulateIndexPlan->AddChild(std::move(util_plan));
+        child_PopulateIndexPlan->AddChild(std::move(util_plan_status.util_plan));
         create_plan->SetKeyAttrs(column_ids);
-        util_plan = std::move(child_PopulateIndexPlan);
+        util_plan_status.util_plan = std::move(child_PopulateIndexPlan);
       }
       break;
     }
@@ -203,20 +203,20 @@ unique_ptr<planner::AbstractPlan> Optimizer::HandleUtilStatement(
       unique_ptr<planner::AbstractPlan> create_func_plan(
           new planner::CreateFunctionPlan(
               (parser::CreateFunctionStatement *)tree));
-      util_plan = move(create_func_plan);
+      util_plan_status.util_plan = move(create_func_plan);
     } break;
     case StatementType::ANALYZE: {
       LOG_TRACE("Adding Analyze plan...");
       unique_ptr<planner::AbstractPlan> analyze_plan(new planner::AnalyzePlan(
           static_cast<parser::AnalyzeStatement *>(tree), txn));
-      util_plan = move(analyze_plan);
+      util_plan_status.util_plan = move(analyze_plan);
       break;
     }
     case StatementType::COPY: {
       LOG_TRACE("Adding Copy plan...");
       parser::CopyStatement *copy_parse_tree =
           static_cast<parser::CopyStatement *>(tree);
-      util_plan = util::CreateCopyPlan(copy_parse_tree);
+      util_plan_status.util_plan = util::CreateCopyPlan(copy_parse_tree);
       break;
     }
     case StatementType::EXPLAIN: {
@@ -224,17 +224,20 @@ unique_ptr<planner::AbstractPlan> Optimizer::HandleUtilStatement(
       // Pass the sql statement to explain to the plan node
       auto *explain_parse_tree =
           reinterpret_cast<parser::ExplainStatement *>(tree);
-      util_plan.reset(
+      util_plan_status.util_plan.reset(
           // TODO(boweic): not releasing this unique_ptr here would cause a
           // double delete which I still don't know why is happening.
           // I believe no one should take the ownership of the pointer here
           new planner::ExplainPlan(explain_parse_tree->real_sql_stmt.release(),
                                    explain_parse_tree->default_database_name));
+      break;
     }
-    default:
+    default: {
+      util_plan_status.has_plan = false;
       break;
+    }
   }
-  return util_plan;
+  return util_plan_status;
 }
 
 shared_ptr<GroupExpression> Optimizer::InsertQueryTree(
diff --git a/src/parser/explain_statement.cpp b/src/parser/explain_statement.cpp
new file mode 100644
index 00000000000..bd78593debf
--- /dev/null
+++ b/src/parser/explain_statement.cpp
@@ -0,0 +1,37 @@
+//===----------------------------------------------------------------------===//
+//
+//                         Peloton
+//
+// explain_statement.cpp
+//
+// Identification: src/parser/explain_statement.cpp
+//
+// Copyright (c) 2015-18, Carnegie Mellon University Database Group
+//
+//===----------------------------------------------------------------------===//
+
+#include "parser/explain_statement.h"
+#include "parser/select_statement.h"
+
+namespace peloton {
+namespace parser {
+
+const std::string ExplainStatement::GetInfo(int num_indent) const {
+  std::ostringstream os;
+  os << StringUtil::Indent(num_indent) << "ExplainStatement:\n";
+  os << real_sql_stmt->GetInfo(num_indent + 1);
+  return os.str();
+}
+
+const std::string ExplainStatement::GetInfo() const {
+  std::ostringstream os;
+
+  os << "SQLStatement[EXPLAIN]\n";
+
+  os << GetInfo(1);
+
+  return os.str();
+}
+
+}  // namespace parser
+}  // namespace peloton
diff --git a/test/network/explain_test.cpp b/test/network/explain_test.cpp
index b6d7f193b7d..2ec6cf8d656 100644
--- a/test/network/explain_test.cpp
+++ b/test/network/explain_test.cpp
@@ -56,18 +56,13 @@ void *ExplainTest(int port) {
     txn1.exec("CREATE TABLE template(id INT);");
     txn1.commit();
 
-    // Execute EXPLAIN directly
+    // Try execute EXPLAIN 
     pqxx::work txn2(C);
-    pqxx::result result1 = txn2.exec("EXPLAIN SELECT * from template;");
+    pqxx::result result = txn2.exec("EXPLAIN SELECT * from template;");
     txn2.commit();
-    EXPECT_EQ(result1.size(), 1);
+    EXPECT_EQ(result.size(), 1);
+    EXPECT_EQ(std::string(result[0][0].c_str()), std::string("SeqScan()"));
 
-    // Execute EXPLAIN through PREPARE statement
-    pqxx::work txn3(C);
-    txn3.exec("PREPARE func AS EXPLAIN SELECT * from template;");
-    pqxx::result result2 = txn3.exec("EXECUTE func");
-    txn3.commit();
-    EXPECT_EQ(result2.size(), 1);
   } catch (const std::exception &e) {
     LOG_INFO("[ExplainTest] Exception occurred: %s", e.what());
     EXPECT_TRUE(false);

From 3b0143ce5a14ceaa351daa3d0de1ef7c74d126eb Mon Sep 17 00:00:00 2001
From: Tianyi Chen <tianyic1@andrew.cmu.edu>
Date: Sat, 12 May 2018 11:31:19 -0400
Subject: [PATCH 12/13] reduce log size by changing parse tree printing level
 to trace

---
 src/optimizer/optimizer.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/optimizer/optimizer.cpp b/src/optimizer/optimizer.cpp
index bc0dcf3894d..265cec4c431 100644
--- a/src/optimizer/optimizer.cpp
+++ b/src/optimizer/optimizer.cpp
@@ -101,7 +101,7 @@ shared_ptr<planner::AbstractPlan> Optimizer::BuildPelotonPlanTree(
   // TODO: support multi-statement queries
   auto parse_tree = parse_tree_list->GetStatement(0);
 
-  LOG_DEBUG("optimizer : %s", parse_tree->GetInfo().c_str());
+  LOG_TRACE("optimizer : %s", parse_tree->GetInfo().c_str());
   // Handle ddl statement
   auto util_plan_status = HandleUtilStatement(parse_tree, txn);
   if (util_plan_status.has_plan != false) {

From 21385b2b0f80575874d267ffce4246f305c60ba3 Mon Sep 17 00:00:00 2001
From: vagrant <411468452@qq.com>
Date: Wed, 16 May 2018 01:45:50 -0400
Subject: [PATCH 13/13] Fix memory leak

---
 src/executor/explain_executor.cpp  |  2 ++
 src/include/planner/explain_plan.h | 11 ++++++++---
 src/optimizer/optimizer.cpp        |  2 +-
 3 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/src/executor/explain_executor.cpp b/src/executor/explain_executor.cpp
index 88e4fac38b4..2414b9a936b 100644
--- a/src/executor/explain_executor.cpp
+++ b/src/executor/explain_executor.cpp
@@ -54,6 +54,8 @@ bool ExplainExecutor::DExecute() {
   std::unique_ptr<parser::SQLStatementList> stmt_list(
       new parser::SQLStatementList(sql_stmt));
   auto plan = optimizer->BuildPelotonPlanTree(stmt_list, current_txn);
+  // Release the ptr to prevent double delete
+  stmt_list->PassOutStatement(0).release();
   const catalog::Schema schema({catalog::Column(
       type::TypeId::VARCHAR, type::Type::GetTypeSize(type::TypeId::VARCHAR),
       "Query Plan")});
diff --git a/src/include/planner/explain_plan.h b/src/include/planner/explain_plan.h
index 98390508d5e..912d28a4ebf 100644
--- a/src/include/planner/explain_plan.h
+++ b/src/include/planner/explain_plan.h
@@ -28,7 +28,12 @@ class ExplainPlan : public AbstractPlan {
   ExplainPlan(ExplainPlan &&) = delete;
   ExplainPlan &operator=(ExplainPlan &&) = delete;
 
-  explicit ExplainPlan(parser::SQLStatement *sql_stmt,
+  explicit ExplainPlan(std::unique_ptr<parser::SQLStatement> sql_stmt,
+                       std::string default_database_name)
+      : sql_stmt_(sql_stmt.release()),
+        default_database_name_(default_database_name){};
+
+  explicit ExplainPlan(std::shared_ptr<parser::SQLStatement> sql_stmt,
                        std::string default_database_name)
       : sql_stmt_(sql_stmt), default_database_name_(default_database_name){};
 
@@ -43,7 +48,7 @@ class ExplainPlan : public AbstractPlan {
         new ExplainPlan(sql_stmt_, default_database_name_));
   }
 
-  parser::SQLStatement *GetSQLStatement() const { return sql_stmt_; }
+  parser::SQLStatement *GetSQLStatement() const { return sql_stmt_.get(); }
 
   std::string GetDatabaseName() const { return default_database_name_; }
 
@@ -52,7 +57,7 @@ class ExplainPlan : public AbstractPlan {
    * @brief The SQL statement to explain, the it should be owned by the
    * explain ast
    */
-  parser::SQLStatement *sql_stmt_;
+  std::shared_ptr<parser::SQLStatement> sql_stmt_;
   /**
    * @brief The database name to be used in the binder
    */
diff --git a/src/optimizer/optimizer.cpp b/src/optimizer/optimizer.cpp
index 265cec4c431..a3cb06e550d 100644
--- a/src/optimizer/optimizer.cpp
+++ b/src/optimizer/optimizer.cpp
@@ -228,7 +228,7 @@ UtilPlanStatus Optimizer::HandleUtilStatement(
           // TODO(boweic): not releasing this unique_ptr here would cause a
           // double delete which I still don't know why is happening.
           // I believe no one should take the ownership of the pointer here
-          new planner::ExplainPlan(explain_parse_tree->real_sql_stmt.release(),
+          new planner::ExplainPlan(std::move(explain_parse_tree->real_sql_stmt),
                                    explain_parse_tree->default_database_name));
       break;
     }