void OptimizerTest::setupExpressions() { literal_0_ = E::ScalarLiteral::Create(TypedValue(0), TypeFactory::GetType(kInt, false /* nullable */)); literal_1_ = E::ScalarLiteral::Create(TypedValue(1), TypeFactory::GetType(kInt, false /* nullable */)); alias_0_ = createAlias(literal_0_, "literal_0" /* attribute_name */, "dummy_table" /* relation_name */); alias_1_ = createAlias(literal_1_, "literal_1" /* attribute_name */, "dummy_table" /* relation_name */); attribute_reference_0_ = E::ToRef(alias_0_); attribute_reference_1_ = E::ToRef(alias_1_); filter_predicate_0_ = E::ComparisonExpression::Create( ComparisonFactory::GetComparison(ComparisonID::kNotEqual), relation_attribute_reference_0_0_, relation_attribute_reference_0_2_); filter_predicate_1_ = E::ComparisonExpression::Create( ComparisonFactory::GetComparison(ComparisonID::kGreater), relation_attribute_reference_1_0_, literal_0_); hash_join_predicate_0_1_ = E::ComparisonExpression::Create( ComparisonFactory::GetComparison(ComparisonID::kEqual), relation_attribute_reference_0_0_, relation_attribute_reference_1_0_); non_hash_join_predicate_0_1_ = E::ComparisonExpression::Create( ComparisonFactory::GetComparison(ComparisonID::kGreater), relation_attribute_reference_0_0_, relation_attribute_reference_1_0_); add_literal_0_ = E::BinaryExpression::Create( BinaryOperationFactory::GetBinaryOperation(BinaryOperationID::kAdd), relation_attribute_reference_0_0_, literal_0_); alias_add_literal_0_ = E::Alias::Create( optimizer_context()->nextExprId(), add_literal_0_, "add_literal_0" /* attribute_name */, "add_literal_0" /* attribute_alias */, "" /* relation_name */); }
TEST_F(JoinTest, NestedLoopsJoinOnSelection) { // We pull a any Selection to a NestedLoopsJoin only if it does not have a // filter predicate. // Project -- NestedLoopsJoin -- Project // -- Project -- Filter const E::PredicatePtr join_predicate = E::ComparisonExpression::Create( ComparisonFactory::GetComparison(ComparisonID::kNotEqual), E::ToRef(alias_add_literal_0_), E::ToRef(alias_1_)); const L::NestedLoopsJoinPtr nested_loops_join = L::NestedLoopsJoin::Create( logical_project_0_, logical_project_on_filter_1_, join_predicate); const E::AliasPtr alias_on_alias_reference = E::Alias::Create( optimizer_context()->nextExprId(), E::ToRef(alias_add_literal_0_), "alias_on_alias_reference" /* attribute_name */, "alias_on_alias_reference" /* attribute_alias */, "join_test_relation" /* relation_name */); input_logical_ = L::Project::Create( nested_loops_join, {alias_on_alias_reference} /* project_expressions */); // The top-level project references an attribute created by the left // underlying project of the nested loops join. // The project expression will be rewritten when the left project is merged to // the join. const E::AliasPtr alias_on_alias_reference_after_pullup = std::static_pointer_cast<const E::Alias>(alias_on_alias_reference->copyWithNewChildren( {alias_add_literal_0_->expression()} /* new_children */)); const E::PredicatePtr join_predicate_after_pullup = E::ComparisonExpression::Create( ComparisonFactory::GetComparison(ComparisonID::kNotEqual), std::static_pointer_cast<const E::NamedExpression>(alias_add_literal_0_->expression()), E::ToRef(alias_1_)); expected_physical_ = P::NestedLoopsJoin::Create( physical_table_reference_0_, physical_project_on_filter_1_, join_predicate_after_pullup, {alias_on_alias_reference_after_pullup} /* project_expressions */); EXPECT_CORRECT_PHYSICAL(); }
void OptimizerTextTestRunner::runTestCase(const std::string &input, const std::set<std::string> &options, std::string *output) { CHECK(!options.empty()) << "No options specified"; VLOG(4) << "Test SQL: " << input; sql_parser_.feedNextBuffer(new std::string(input)); ParseResult result = sql_parser_.getNextStatement(); OptimizerContext optimizer_context(tmb::kClientIdNone /* foreman_client_id */, 0 /* query_id */, test_database_loader_.catalog_database(), nullptr /* storage_manager */, nullptr /* TMB */); if (result.condition != ParseResult::kSuccess) { *output = result.error_message; } else { // Number of options specified. int num_options = 0; std::ostringstream out_ss; try { logical::LogicalPtr initial_logical_plan; logical::LogicalPtr optimized_logical_plan; physical::PhysicalPtr physical_plan; const bool output_initial_logical_plan = (options.find(kTestOptions[0]) != options.end()); const bool output_optimized_logical_plan = (options.find(kTestOptions[1]) != options.end()); const bool output_physical_plan = (options.find(kTestOptions[2]) != options.end()); if (output_initial_logical_plan) { initial_logical_plan = resolveParseTree(*result.parsed_statement, &optimizer_context); ++num_options; } if (output_optimized_logical_plan || output_physical_plan) { optimized_logical_plan = generateLogicalPlan(*result.parsed_statement, &optimizer_context); if (output_optimized_logical_plan) { ++num_options; } } if (output_physical_plan) { physical_plan = generatePhysicalPlan(optimized_logical_plan); ++num_options; } if (output_initial_logical_plan) { if (num_options > 1) { out_ss << "[Initial Logical Plan]\n"; } out_ss << initial_logical_plan->toString(); } if (output_optimized_logical_plan) { if (num_options > 1) { out_ss << "[Optimized Logical Plan]\n"; } out_ss << optimized_logical_plan->toString(); } if (output_physical_plan) { if (num_options > 1) { out_ss << "[Physical Plan]\n"; } out_ss << physical_plan->toString(); } *output = out_ss.str(); CHECK(!output->empty()); } catch (const SqlError &error) { *output = error.formatMessage(input); } } }
void CommandExecutorTestRunner::runTestCase( const std::string &input, const std::set<std::string> &options, std::string *output) { // TODO(qzeng): Test multi-threaded query execution when we have a Sort operator. VLOG(4) << "Test SQL(s): " << input; if (options.find(kResetOption) != options.end()) { test_database_loader_.clear(); test_database_loader_.createTestRelation(false /* allow_vchar */); test_database_loader_.loadTestRelation(); } MemStream output_stream; sql_parser_.feedNextBuffer(new std::string(input)); while (true) { ParseResult result = sql_parser_.getNextStatement(); O::OptimizerContext optimizer_context(0 /* query_id */, test_database_loader_.catalog_database(), test_database_loader_.storage_manager()); if (result.condition != ParseResult::kSuccess) { if (result.condition == ParseResult::kError) { *output = result.error_message; } break; } else { std::printf("%s\n", result.parsed_statement->toString().c_str()); try { if (result.parsed_statement->getStatementType() == ParseStatement::kCommand) { quickstep::cli::executeCommand( *result.parsed_statement, *(test_database_loader_.catalog_database()), main_thread_client_id_, foreman_->getBusClientID(), &bus_, test_database_loader_.storage_manager(), nullptr, output_stream.file()); } else { QueryHandle query_handle(optimizer_context.query_id()); O::LogicalGenerator logical_generator(&optimizer_context); O::PhysicalGenerator physical_generator; O::ExecutionGenerator execution_generator(&optimizer_context, &query_handle); const P::PhysicalPtr physical_plan = physical_generator.generatePlan( logical_generator.generatePlan(*result.parsed_statement)); execution_generator.generatePlan(physical_plan); AdmitRequestMessage request_message(&query_handle); TaggedMessage admit_tagged_message( &request_message, sizeof(request_message), kAdmitRequestMessage); QueryExecutionUtil::SendTMBMessage(&bus_, main_thread_client_id_, foreman_->getBusClientID(), std::move(admit_tagged_message)); // Receive workload completion message from Foreman. const AnnotatedMessage annotated_msg = bus_.Receive(main_thread_client_id_, 0, true); const TaggedMessage &tagged_message = annotated_msg.tagged_message; DCHECK_EQ(kWorkloadCompletionMessage, tagged_message.message_type()); const CatalogRelation *query_result_relation = query_handle.getQueryResultRelation(); if (query_result_relation) { PrintToScreen::PrintRelation(*query_result_relation, test_database_loader_.storage_manager(), output_stream.file()); DropRelation::Drop(*query_result_relation, test_database_loader_.catalog_database(), test_database_loader_.storage_manager()); } } } catch (const SqlError &error) { *output = error.formatMessage(input); break; } } } if (output->empty()) { *output = output_stream.str(); } }
void ExecutionGeneratorTestRunner::runTestCase( const std::string &input, const std::set<std::string> &options, std::string *output) { // TODO(qzeng): Test multi-threaded query execution when we have a Sort operator. VLOG(4) << "Test SQL(s): " << input; if (options.find(kResetOption) != options.end()) { test_database_loader_.clear(); test_database_loader_.createTestRelation(false /* allow_vchar */); test_database_loader_.loadTestRelation(); } MemStream output_stream; sql_parser_.feedNextBuffer(new std::string(input)); while (true) { ParseResult result = sql_parser_.getNextStatement(); OptimizerContext optimizer_context(0 /* query_id */, test_database_loader_.catalog_database(), test_database_loader_.storage_manager()); if (result.condition != ParseResult::kSuccess) { if (result.condition == ParseResult::kError) { *output = result.error_message; } break; } else { std::printf("%s\n", result.parsed_statement->toString().c_str()); try { QueryHandle query_handle(optimizer_context.query_id()); LogicalGenerator logical_generator(&optimizer_context); PhysicalGenerator physical_generator; ExecutionGenerator execution_generator(&optimizer_context, &query_handle); const physical::PhysicalPtr physical_plan = physical_generator.generatePlan( logical_generator.generatePlan(*result.parsed_statement)); execution_generator.generatePlan(physical_plan); foreman_->setQueryPlan( query_handle.getQueryPlanMutable()->getQueryPlanDAGMutable()); foreman_->reconstructQueryContextFromProto(query_handle.getQueryContextProto()); foreman_->start(); foreman_->join(); const CatalogRelation *query_result_relation = query_handle.getQueryResultRelation(); if (query_result_relation) { PrintToScreen::PrintRelation(*query_result_relation, test_database_loader_.storage_manager(), output_stream.file()); DropRelation::Drop(*query_result_relation, test_database_loader_.catalog_database(), test_database_loader_.storage_manager()); } } catch (const SqlError &error) { *output = error.formatMessage(input); break; } } } if (output->empty()) { *output = output_stream.str(); } }
TEST_F(JoinTest, HashJoinOnSelection) { // Project -- HashJoin -- Project // -- Project -- Filter const L::HashJoinPtr hash_join = L::HashJoin::Create(logical_project_0_, logical_project_on_filter_1_, {relation_attribute_reference_0_0_}, {relation_attribute_reference_1_0_}, nullptr /* residual_predicate */, L::HashJoin::JoinType::kInnerJoin); // References an attribute created by the left underlying project of the hash // join. const E::AliasPtr alias_on_alias_reference = E::Alias::Create( optimizer_context()->nextExprId(), E::ToRef(alias_add_literal_0_), "alias_on_alias_reference", /* attribute_name */ "alias_on_alias_reference", /* attribute_alias */ "join_test_relation" /* relation_name */); const E::AliasPtr alias_on_alias_reference_after_pullup = std::static_pointer_cast<const E::Alias>(alias_on_alias_reference->copyWithNewChildren( {alias_add_literal_0_->expression()} /* new_children */)); input_logical_ = L::Project::Create( hash_join, {alias_on_alias_reference} /* project_expressions */); // Since the right Selection for the join have a filter, it will not be pulled // up. expected_physical_ = P::HashJoin::Create( physical_table_reference_0_, physical_project_on_filter_1_, {relation_attribute_reference_0_0_}, {relation_attribute_reference_1_0_}, E::PredicatePtr(), E::PredicatePtr(), {alias_on_alias_reference_after_pullup} /* project_expressions */, P::HashJoin::JoinType::kInnerJoin); EXPECT_CORRECT_PHYSICAL(); // HashJoin -- Project // -- Project const E::AliasPtr alias_on_attribute_reference = createAlias(relation_attribute_reference_1_0_, "alias_on_reference", "join_test_relation"); const L::ProjectPtr logical_project_on_attribute_reference = L::Project::Create( logical_table_reference_1_, {alias_on_attribute_reference} /* project_expressions */); const P::PhysicalPtr physical_project_on_attribute_reference = P::Selection::Create( physical_table_reference_1_, logical_project_on_attribute_reference->project_expressions(), E::PredicatePtr()); physical_generator()->setBestPhysicalForLogical( logical_project_on_attribute_reference, physical_project_on_attribute_reference); // The left Project cannot be pulled up, while the right can be. input_logical_ = L::HashJoin::Create(logical_project_0_, logical_project_on_attribute_reference, {E::ToRef(alias_add_literal_0_)}, {relation_attribute_reference_1_0_}, nullptr /* residual_predicate */, L::HashJoin::JoinType::kInnerJoin); std::vector<E::NamedExpressionPtr> project_expressions( E::ToNamedExpressions(physical_project_0_->getOutputAttributes())); project_expressions.push_back(alias_on_attribute_reference); expected_physical_ = P::HashJoin::Create(physical_project_0_, physical_table_reference_1_, {E::ToRef(alias_add_literal_0_)}, {relation_attribute_reference_1_0_}, E::PredicatePtr(), E::PredicatePtr(), project_expressions, P::HashJoin::JoinType::kInnerJoin); EXPECT_CORRECT_PHYSICAL(); }