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/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 new file mode 100644 index 00000000000..2414b9a936b --- /dev/null +++ b/src/executor/explain_executor.cpp @@ -0,0 +1,74 @@ +//===----------------------------------------------------------------------===// +// +// Peloton +// +// explain_executor.cpp +// +// Identification: src/executor/explain_executor.cpp +// +// Copyright (c) 2015-18, Carnegie Mellon University Database Group +// +//===----------------------------------------------------------------------===// + +#include + +#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(); + + parser::SQLStatement *sql_stmt = node.GetSQLStatement(); + + LOG_TRACE("EXPLAIN : %s", sql_stmt->GetInfo().c_str()); + + 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(new optimizer::Optimizer()); + std::unique_ptr 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")}); + std::shared_ptr dest_tile( + storage::TileFactory::GetTempTile(schema, 1)); + std::unique_ptr 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_DEBUG("Explain finished!, plan : %s", plan->GetInfo().c_str()); + return false; +} + +} // namespace executor +} // namespace peloton diff --git a/src/executor/plan_executor.cpp b/src/executor/plan_executor.cpp index 104aff1351c..7d9a0640c8f 100644 --- a/src/executor/plan_executor.cpp +++ b/src/executor/plan_executor.cpp @@ -336,7 +336,10 @@ executor::AbstractExecutor *BuildExecutorTree( child_executor = new executor::PopulateIndexExecutor(plan, executor_context); break; - + 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/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/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/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/network/postgres_protocol_handler.h b/src/include/network/postgres_protocol_handler.h index ef75f0a4cb1..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> 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); @@ -215,9 +207,6 @@ class PostgresProtocolHandler : public ProtocolHandler { // Portals std::unordered_map> 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/optimizer/optimizer.h b/src/include/optimizer/optimizer.h index 82b1d4c9a05..d5de41412b8 100644 --- a/src/include/optimizer/optimizer.h +++ b/src/include/optimizer/optimizer.h @@ -38,12 +38,17 @@ class TransactionContext; } namespace test { - class OptimizerRuleTests_SimpleAssociativeRuleTest_Test; - class OptimizerRuleTests_SimpleAssociativeRuleTest2_Test; -} +class OptimizerRuleTests_SimpleAssociativeRuleTest_Test; +class OptimizerRuleTests_SimpleAssociativeRuleTest2_Test; +} namespace optimizer { +struct UtilPlanStatus { + bool has_plan = false; + std::unique_ptr util_plan; +}; + struct QueryInfo { QueryInfo(std::vector &exprs, std::shared_ptr &props) @@ -60,8 +65,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 +90,26 @@ class Optimizer : public AbstractOptimizer { OptimizerMetadata &GetMetadata() { return metadata_; } /* For test purposes only */ - std::shared_ptr TestInsertQueryTree(parser::SQLStatement *tree, - concurrency::TransactionContext *txn) { + std::shared_ptr 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 root_context) { + std::shared_ptr 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, if the sql type + * is not util statements then return with has_plan set to false */ - std::unique_ptr HandleDDLStatement( - parser::SQLStatement *tree, bool &is_ddl_stmt, - 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 5d3e763f9dc..4a64303f470 100644 --- a/src/include/parser/explain_statement.h +++ b/src/include/parser/explain_statement.h @@ -28,7 +28,17 @@ 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 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 new file mode 100644 index 00000000000..912d28a4ebf --- /dev/null +++ b/src/include/planner/explain_plan.h @@ -0,0 +1,68 @@ + +//===----------------------------------------------------------------------===// +// +// Peloton +// +// explain_plan.h +// +// Identification: src/include/planner/explain_plan.h +// +// Copyright (c) 2015-18, Carnegie Mellon University Database Group +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include "parser/sql_statement.h" +#include "planner/abstract_plan.h" + +#include + +namespace peloton { + +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(std::unique_ptr sql_stmt, + std::string default_database_name) + : sql_stmt_(sql_stmt.release()), + default_database_name_(default_database_name){}; + + explicit ExplainPlan(std::shared_ptr 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(); + } + + inline std::unique_ptr Copy() const { + return std::unique_ptr( + new ExplainPlan(sql_stmt_, default_database_name_)); + } + + parser::SQLStatement *GetSQLStatement() const { return sql_stmt_.get(); } + + std::string GetDatabaseName() const { return default_database_name_; } + + private: + /** + * @brief The SQL statement to explain, the it should be owned by the + * explain ast + */ + std::shared_ptr sql_stmt_; + /** + * @brief The database name to be used in the binder + */ + std::string default_database_name_; +}; + +} // namespace planner +} // namespace peloton diff --git a/src/include/traffic_cop/traffic_cop.h b/src/include/traffic_cop/traffic_cop.h index e324b87fe82..98f6592203d 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, - const std::vector ¶ms, const bool unnamed, - std::shared_ptr param_stats, - const std::vector &result_format, std::vector &result, - size_t thread_id = 0); + ResultType ExecuteStatement(std::shared_ptr param_stats, + const std::vector &result_format, + size_t thread_id); + + ResultType ExecuteStatement(const std::shared_ptr &statement, + const std::vector ¶ms, + std::shared_ptr param_stats, + const std::vector &result_format, + std::vector &result, + size_t thread_id); // Helper to handle txn-specifics for the plan-tree of a statement. executor::ExecutionResult ExecuteHelper( @@ -100,7 +104,6 @@ class TrafficCop { ResultType CommitQueryHelper(); - void ExecuteStatementPlanGetResult(); ResultType ExecuteStatementGetResult(); @@ -131,8 +134,6 @@ class TrafficCop { param_values_ = std::move(param_values); } - std::vector &GetParamVal() { return param_values_; } - std::string &GetErrorMessage() { return error_message_; } void SetQueuing(bool is_queuing) { is_queuing_ = is_queuing; } @@ -145,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_; @@ -156,8 +153,6 @@ class TrafficCop { std::vector param_values_; - std::vector results_; - // This save currnet statement in the traffic cop std::shared_ptr statement_; 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 ffbb786b88e..a989bfedf63 100644 --- a/src/network/postgres_protocol_handler.cpp +++ b/src/network/postgres_protocol_handler.cpp @@ -212,42 +212,34 @@ 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; } ExecQueryMessageGetResult(status); return ProcessResult::COMPLETE; }; - case QueryType::QUERY_EXPLAIN: { - auto status = ExecQueryExplain( - query, static_cast(*sql_stmt)); - ExecQueryMessageGetResult(status); - return ProcessResult::COMPLETE; - } default: { - std::string stmt_name = "unamed"; + std::string stmt_name = ""; std::unique_ptr 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()); - bool unnamed = false; result_format_ = std::vector( 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; } @@ -257,30 +249,6 @@ ProcessResult PostgresProtocolHandler::ExecQueryMessage( } } -ResultType PostgresProtocolHandler::ExecQueryExplain( - const std::string &query, parser::ExplainStatement &explain_stmt) { - std::unique_ptr 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 plan_info = StringUtil::Split( - planner::PlanUtil::GetInfo(stmt->GetPlanTree().get()), '\n'); - const std::vector 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 tuple_descriptor; if (status == ResultType::SUCCESS) { @@ -807,12 +775,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; } @@ -862,7 +829,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/optimizer/optimizer.cpp b/src/optimizer/optimizer.cpp index 62f813ec876..a3cb06e550d 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" @@ -100,13 +101,11 @@ shared_ptr Optimizer::BuildPelotonPlanTree( // TODO: support multi-statement queries auto parse_tree = parse_tree_list->GetStatement(0); - unique_ptr child_plan = nullptr; - + LOG_TRACE("optimizer : %s", parse_tree->GetInfo().c_str()); // 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_status = HandleUtilStatement(parse_tree, txn); + if (util_plan_status.has_plan != false) { + return move(util_plan_status.util_plan); } metadata_.txn = txn; @@ -138,18 +137,17 @@ shared_ptr Optimizer::BuildPelotonPlanTree( void Optimizer::Reset() { metadata_ = OptimizerMetadata(); } -unique_ptr Optimizer::HandleDDLStatement( - parser::SQLStatement *tree, bool &is_ddl_stmt, - concurrency::TransactionContext *txn) { - unique_ptr ddl_plan = nullptr; - is_ddl_stmt = true; +UtilPlanStatus Optimizer::HandleUtilStatement( + parser::SQLStatement *tree, concurrency::TransactionContext *txn) { + 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 drop_plan( new planner::DropPlan((parser::DropStatement *)tree)); - ddl_plan = move(drop_plan); + util_plan_status.util_plan = move(drop_plan); break; } @@ -160,7 +158,7 @@ unique_ptr Optimizer::HandleDDLStatement( auto create_plan = new planner::CreatePlan((parser::CreateStatement *)tree); std::unique_ptr child_CreatePlan(create_plan); - ddl_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; @@ -186,14 +184,14 @@ unique_ptr Optimizer::HandleDDLStatement( std::unique_ptr 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_status.util_plan)); + util_plan_status.util_plan = std::move(child_SeqScanPlan); // Create a plan to add data to index std::unique_ptr child_PopulateIndexPlan( new planner::PopulateIndexPlan(target_table, column_ids)); - child_PopulateIndexPlan->AddChild(std::move(ddl_plan)); + child_PopulateIndexPlan->AddChild(std::move(util_plan_status.util_plan)); create_plan->SetKeyAttrs(column_ids); - ddl_plan = std::move(child_PopulateIndexPlan); + util_plan_status.util_plan = std::move(child_PopulateIndexPlan); } break; } @@ -205,26 +203,41 @@ unique_ptr Optimizer::HandleDDLStatement( unique_ptr create_func_plan( new planner::CreateFunctionPlan( (parser::CreateFunctionStatement *)tree)); - ddl_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 analyze_plan(new planner::AnalyzePlan( static_cast(tree), txn)); - ddl_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(tree); - ddl_plan = util::CreateCopyPlan(copy_parse_tree); + util_plan_status.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 + auto *explain_parse_tree = + reinterpret_cast(tree); + 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(std::move(explain_parse_tree->real_sql_stmt), + explain_parse_tree->default_database_name)); + break; + } + default: { + util_plan_status.has_plan = false; break; } - default: - is_ddl_stmt = false; } - return ddl_plan; + return util_plan_status; } shared_ptr Optimizer::InsertQueryTree( @@ -238,29 +251,29 @@ shared_ptr Optimizer::InsertQueryTree( } QueryInfo Optimizer::GetQueryInfo(parser::SQLStatement *tree) { - auto GetQueryInfoHelper = - [](std::vector> &select_list, - std::unique_ptr &order_info, - std::vector &output_exprs, - std::shared_ptr &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 sort_exprs; - std::vector 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(sort_exprs, sort_ascending)); - } - }; + auto GetQueryInfoHelper = []( + std::vector> &select_list, + std::unique_ptr &order_info, + std::vector &output_exprs, + std::shared_ptr &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 sort_exprs; + std::vector 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(sort_exprs, sort_ascending)); + } + }; std::vector output_exprs; std::shared_ptr physical_props = std::make_shared(); @@ -278,8 +291,7 @@ QueryInfo Optimizer::GetQueryInfo(parser::SQLStatement *tree) { output_exprs, physical_props); break; } - default: - ; + default:; } return QueryInfo(output_exprs, physical_props); 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/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 // diff --git a/src/traffic_cop/traffic_cop.cpp b/src/traffic_cop/traffic_cop.cpp index a87d99c0ac5..592ebe1d076 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); } @@ -137,6 +137,34 @@ ResultType TrafficCop::ExecuteStatementGetResult() { 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 @@ -326,7 +325,8 @@ std::shared_ptr 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); @@ -366,8 +366,8 @@ void TrafficCop::ProcessInvalidStatement() { } bool TrafficCop::BindParamsForCachePlan( - const std::vector> - ¶meters, + const std::vector> & + parameters, const size_t thread_id UNUSED_ATTRIBUTE) { if (tcop_txn_state_.empty()) { single_statement_txn_ = true; @@ -442,7 +442,15 @@ void TrafficCop::GetTableColumns(parser::TableRef *from_table, std::vector TrafficCop::GenerateTupleDescriptor( parser::SQLStatement *sql_stmt) { std::vector 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 @@ -543,9 +551,16 @@ FieldInfo TrafficCop::GetColumnFieldForValueType(std::string column_name, field_size); } +ResultType TrafficCop::ExecuteStatement( + std::shared_ptr param_stats, + const std::vector &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, - const std::vector ¶ms, UNUSED_ATTRIBUTE bool unnamed, + const std::vector ¶ms, std::shared_ptr param_stats, const std::vector &result_format, std::vector &result, size_t thread_id) { 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/network/explain_test.cpp b/test/network/explain_test.cpp new file mode 100644 index 00000000000..2ec6cf8d656 --- /dev/null +++ b/test/network/explain_test.cpp @@ -0,0 +1,100 @@ +//===----------------------------------------------------------------------===// +// +// 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 /* 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( + 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(); + + // Try execute EXPLAIN + pqxx::work txn2(C); + pqxx::result result = txn2.exec("EXPLAIN SELECT * from template;"); + txn2.commit(); + EXPECT_EQ(result.size(), 1); + EXPECT_EQ(std::string(result[0][0].c_str()), std::string("SeqScan()")); + + } 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 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/explain_sql_test.cpp b/test/sql/explain_sql_test.cpp new file mode 100644 index 00000000000..93ecba24071 --- /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 + +#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( + new optimizer::Optimizer()); + const std::string query = "EXPLAIN SELECT * FROM test"; + std::vector result; + std::vector 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], "SeqScan()"); + + // Free the database + txn = txn_manager.BeginTransaction(); + catalog::Catalog::GetInstance()->DropDatabaseWithName(DEFAULT_DB_NAME, txn); + txn_manager.CommitTransaction(txn); +} + +} // namespace test +} // namespace peloton diff --git a/test/sql/testing_sql_util.cpp b/test/sql/testing_sql_util.cpp index 220fa558686..b7546870e51 100644 --- a/test/sql/testing_sql_util.cpp +++ b/test/sql/testing_sql_util.cpp @@ -76,17 +76,18 @@ ResultType TestingSQLUtil::ExecuteSQLQuery( } // ExecuteStatment std::vector param_values; - bool unnamed = false; std::vector 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(); status = traffic_cop_.ExecuteStatementGetResult(); - traffic_cop_.SetQueuing(false); } if (status == ResultType::SUCCESS) { tuple_descriptor = statement->GetTupleDescriptor(); @@ -125,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", @@ -177,17 +178,18 @@ ResultType TestingSQLUtil::ExecuteSQLQuery(const std::string query, } // ExecuteStatment std::vector param_values; - bool unnamed = false; std::vector 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(); status = traffic_cop_.ExecuteStatementGetResult(); - traffic_cop_.SetQueuing(false); } if (status == ResultType::SUCCESS) { tuple_descriptor = statement->GetTupleDescriptor(); @@ -216,18 +218,19 @@ ResultType TestingSQLUtil::ExecuteSQLQuery(const std::string query) { } // ExecuteStatment std::vector param_values; - bool unnamed = false; std::vector 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(); status = traffic_cop_.ExecuteStatementGetResult(); - traffic_cop_.SetQueuing(false); } + if (status == ResultType::SUCCESS) { tuple_descriptor = statement->GetTupleDescriptor(); }