/** * @brief Convenience function to pass a single logical tile through an * executor which has only one child. * @param executor Executor to pass logical tile through. * @param source_logical_tile Logical tile to pass through executor. * @param check the value of logical tiles * * @return Pointer to processed logical tile. */ executor::LogicalTile *ExecutorTestsUtil::ExecuteTile( executor::AbstractExecutor *executor, executor::LogicalTile *source_logical_tile) { MockExecutor child_executor; executor->AddChild(&child_executor); // Uneventful init... EXPECT_CALL(child_executor, DInit()).WillOnce(Return(true)); EXPECT_TRUE(executor->Init()); // Where the main work takes place... EXPECT_CALL(child_executor, DExecute()) .WillOnce(Return(true)) .WillOnce(Return(false)); EXPECT_CALL(child_executor, GetOutput()) .WillOnce(Return(source_logical_tile)); EXPECT_TRUE(executor->Execute()); std::unique_ptr<executor::LogicalTile> result_logical_tile( executor->GetOutput()); EXPECT_THAT(result_logical_tile, NotNull()); EXPECT_THAT(executor->Execute(), false); return result_logical_tile.release(); }
/** * @brief Returns next tile processed by this executor. * * This function is the backbone of the tile-based volcano-style execution * model we are using. * * @return Pointer to the logical tile processed by this executor. */ bool AbstractExecutor::Execute() { // TODO In the future, we might want to pass some kind of executor state to // GetNextTile. e.g. params for prepared plans. bool status = DExecute(); return status; }
TEST_F(ProjectionTests, BasicTest) { MockExecutor child_executor; EXPECT_CALL(child_executor, DInit()).WillOnce(Return(true)); EXPECT_CALL(child_executor, DExecute()) .WillOnce(Return(true)) .WillOnce(Return(false)); size_t tile_size = 5; // Create a table and wrap it in logical tile auto &txn_manager = concurrency::TransactionManagerFactory::GetInstance(); auto txn = txn_manager.BeginTransaction(); std::unique_ptr<storage::DataTable> data_table( ExecutorTestsUtil::CreateTable(tile_size)); ExecutorTestsUtil::PopulateTable(txn, data_table.get(), tile_size, false, false, false); txn_manager.CommitTransaction(); std::unique_ptr<executor::LogicalTile> source_logical_tile1( executor::LogicalTileFactory::WrapTileGroup(data_table->GetTileGroup(0))); EXPECT_CALL(child_executor, GetOutput()) .WillOnce(Return(source_logical_tile1.release())); // Create the plan node planner::ProjectInfo::TargetList target_list; planner::ProjectInfo::DirectMapList direct_map_list; ///////////////////////////////////////////////////////// // PROJECTION 0 ///////////////////////////////////////////////////////// // construct schema std::vector<catalog::Column> columns; auto orig_schema = data_table.get()->GetSchema(); columns.push_back(orig_schema->GetColumn(0)); std::shared_ptr<const catalog::Schema> schema(new catalog::Schema(columns)); // direct map planner::ProjectInfo::DirectMap direct_map = std::make_pair(0, std::make_pair(0, 0)); direct_map_list.push_back(direct_map); std::unique_ptr<const planner::ProjectInfo> project_info( new planner::ProjectInfo(std::move(target_list), std::move(direct_map_list))); planner::ProjectionPlan node(std::move(project_info), schema); // Create and set up executor executor::ProjectionExecutor executor(&node, nullptr); executor.AddChild(&child_executor); RunTest(executor, 1); }
// Insert a logical tile into a table TEST_F(MutateTests, InsertTest) { auto &txn_manager = concurrency::OptimisticTxnManager::GetInstance(); // We are going to insert a tile group into a table in this test std::unique_ptr<storage::DataTable> source_data_table( ExecutorTestsUtil::CreateAndPopulateTable()); std::unique_ptr<storage::DataTable> dest_data_table( ExecutorTestsUtil::CreateTable()); const std::vector<storage::Tuple *> tuples; EXPECT_EQ(source_data_table->GetTileGroupCount(), 3); EXPECT_EQ(dest_data_table->GetTileGroupCount(), 1); auto txn = txn_manager.BeginTransaction(); std::unique_ptr<executor::ExecutorContext> context( new executor::ExecutorContext(txn)); planner::InsertPlan node(dest_data_table.get(), nullptr); executor::InsertExecutor executor(&node, context.get()); MockExecutor child_executor; executor.AddChild(&child_executor); // Uneventful init... EXPECT_CALL(child_executor, DInit()).WillOnce(Return(true)); // Will return one tile. EXPECT_CALL(child_executor, DExecute()) .WillOnce(Return(true)) .WillOnce(Return(false)); // Construct input logical tile auto physical_tile_group = source_data_table->GetTileGroup(0); auto tile_count = physical_tile_group->GetTileCount(); std::vector<std::shared_ptr<storage::Tile> > physical_tile_refs; for (oid_t tile_itr = 0; tile_itr < tile_count; tile_itr++) physical_tile_refs.push_back( physical_tile_group->GetTileReference(tile_itr)); std::unique_ptr<executor::LogicalTile> source_logical_tile( executor::LogicalTileFactory::WrapTiles(physical_tile_refs)); EXPECT_CALL(child_executor, GetOutput()) .WillOnce(Return(source_logical_tile.release())); EXPECT_TRUE(executor.Init()); EXPECT_TRUE(executor.Execute()); EXPECT_FALSE(executor.Execute()); txn_manager.CommitTransaction(); // We have inserted all the tuples in this logical tile EXPECT_EQ(dest_data_table->GetTileGroupCount(), 1); }
TEST_F(ProjectionTests, BasicTargetTest) { MockExecutor child_executor; EXPECT_CALL(child_executor, DInit()).WillOnce(Return(true)); EXPECT_CALL(child_executor, DExecute()) .WillOnce(Return(true)) .WillOnce(Return(false)); size_t tile_size = 5; // Create a table and wrap it in logical tile auto &txn_manager = concurrency::TransactionManagerFactory::GetInstance(); auto txn = txn_manager.BeginTransaction(); std::unique_ptr<storage::DataTable> data_table( TestingExecutorUtil::CreateTable(tile_size)); TestingExecutorUtil::PopulateTable(data_table.get(), tile_size, false, false, false, txn); txn_manager.CommitTransaction(txn); std::unique_ptr<executor::LogicalTile> source_logical_tile1( executor::LogicalTileFactory::WrapTileGroup(data_table->GetTileGroup(0))); EXPECT_CALL(child_executor, GetOutput()) .WillOnce(Return(source_logical_tile1.release())); // Create the plan node TargetList target_list; DirectMapList direct_map_list; ///////////////////////////////////////////////////////// // PROJECTION 0, TARGET 0 + 20 ///////////////////////////////////////////////////////// // construct schema std::vector<catalog::Column> columns; auto orig_schema = data_table.get()->GetSchema(); columns.push_back(orig_schema->GetColumn(0)); columns.push_back(orig_schema->GetColumn(0)); std::shared_ptr<const catalog::Schema> schema(new catalog::Schema(columns)); // direct map DirectMap direct_map = std::make_pair(0, std::make_pair(0, 0)); direct_map_list.push_back(direct_map); // target list auto const_val = new expression::ConstantValueExpression( type::ValueFactory::GetIntegerValue(20)); auto tuple_value_expr = expression::ExpressionUtil::TupleValueFactory(type::Type::INTEGER, 0, 0); expression::AbstractExpression *expr = expression::ExpressionUtil::OperatorFactory(ExpressionType::OPERATOR_PLUS, type::Type::INTEGER, tuple_value_expr, const_val); Target target = std::make_pair(1, expr); target_list.push_back(target); std::unique_ptr<const planner::ProjectInfo> project_info( new planner::ProjectInfo(std::move(target_list), std::move(direct_map_list))); planner::ProjectionPlan node(std::move(project_info), schema); // Create and set up executor executor::ProjectionExecutor executor(&node, nullptr); executor.AddChild(&child_executor); RunTest(executor, 1); }
void ExecuteJoinTest(PlanNodeType join_algorithm, PelotonJoinType join_type, oid_t join_test_type) { //===--------------------------------------------------------------------===// // Mock table scan executors //===--------------------------------------------------------------------===// MockExecutor left_table_scan_executor, right_table_scan_executor; // Create a table and wrap it in logical tile size_t tile_group_size = TESTS_TUPLES_PER_TILEGROUP; size_t left_table_tile_group_count = 3; size_t right_table_tile_group_count = 2; auto &txn_manager = concurrency::TransactionManager::GetInstance(); auto txn = txn_manager.BeginTransaction(); auto txn_id = txn->GetTransactionId(); // Left table has 3 tile groups std::unique_ptr<storage::DataTable> left_table( ExecutorTestsUtil::CreateTable(tile_group_size)); ExecutorTestsUtil::PopulateTable( txn, left_table.get(), tile_group_size * left_table_tile_group_count, false, false, false); // Right table has 2 tile groups std::unique_ptr<storage::DataTable> right_table( ExecutorTestsUtil::CreateTable(tile_group_size)); ExecutorTestsUtil::PopulateTable( txn, right_table.get(), tile_group_size * right_table_tile_group_count, false, false, false); txn_manager.CommitTransaction(); //std::cout << (*left_table); //std::cout << (*right_table); // Wrap the input tables with logical tiles std::unique_ptr<executor::LogicalTile> left_table_logical_tile1( executor::LogicalTileFactory::WrapTileGroup(left_table->GetTileGroup(0), txn_id)); std::unique_ptr<executor::LogicalTile> left_table_logical_tile2( executor::LogicalTileFactory::WrapTileGroup(left_table->GetTileGroup(1), txn_id)); std::unique_ptr<executor::LogicalTile> left_table_logical_tile3( executor::LogicalTileFactory::WrapTileGroup(left_table->GetTileGroup(2), txn_id)); std::unique_ptr<executor::LogicalTile> right_table_logical_tile1( executor::LogicalTileFactory::WrapTileGroup( right_table->GetTileGroup(0), txn_id)); std::unique_ptr<executor::LogicalTile> right_table_logical_tile2( executor::LogicalTileFactory::WrapTileGroup( right_table->GetTileGroup(1), txn_id)); // Left scan executor returns logical tiles from the left table EXPECT_CALL(left_table_scan_executor, DInit()).WillOnce(Return(true)); //===--------------------------------------------------------------------===// // Setup left table //===--------------------------------------------------------------------===// if(join_test_type == BASIC_TEST) { EXPECT_CALL(left_table_scan_executor, DExecute()) .WillOnce(Return(true)) .WillOnce(Return(true)) .WillOnce(Return(true)) .WillOnce(Return(false)); EXPECT_CALL(left_table_scan_executor, GetOutput()) .WillOnce(Return(left_table_logical_tile1.release())) .WillOnce(Return(left_table_logical_tile2.release())) .WillOnce(Return(left_table_logical_tile3.release())); } // Right scan executor returns logical tiles from the right table EXPECT_CALL(right_table_scan_executor, DInit()).WillOnce(Return(true)); //===--------------------------------------------------------------------===// // Setup right table //===--------------------------------------------------------------------===// if(join_test_type == BASIC_TEST) { EXPECT_CALL(right_table_scan_executor, DExecute()) .WillOnce(Return(true)) .WillOnce(Return(true)) .WillOnce(Return(false)); EXPECT_CALL(right_table_scan_executor, GetOutput()) .WillOnce(Return(right_table_logical_tile1.release())) .WillOnce(Return(right_table_logical_tile2.release())); } //===--------------------------------------------------------------------===// // Setup join plan nodes and executors and run them //===--------------------------------------------------------------------===// oid_t result_tuple_count = 0; oid_t tuples_with_null = 0; auto projection = JoinTestsUtil::CreateProjection(); // Construct predicate expression::AbstractExpression *predicate = JoinTestsUtil::CreateJoinPredicate(); // Differ based on join algorithm switch (join_algorithm) { case PLAN_NODE_TYPE_NESTLOOP: { // Create nested loop join plan node. planner::NestedLoopJoinPlan nested_loop_join_node(join_type, predicate, projection); // Run the nested loop join executor executor::NestedLoopJoinExecutor nested_loop_join_executor( &nested_loop_join_node, nullptr); // Construct the executor tree nested_loop_join_executor.AddChild(&left_table_scan_executor); nested_loop_join_executor.AddChild(&right_table_scan_executor); // Run the nested loop join executor EXPECT_TRUE(nested_loop_join_executor.Init()); while (nested_loop_join_executor.Execute() == true) { std::unique_ptr<executor::LogicalTile> result_logical_tile( nested_loop_join_executor.GetOutput()); if (result_logical_tile != nullptr) { result_tuple_count += result_logical_tile->GetTupleCount(); tuples_with_null += CountTuplesWithNullFields(result_logical_tile.get()); //std::cout << (*result_logical_tile); } } } break; case PLAN_NODE_TYPE_MERGEJOIN: { // Create join clauses std::vector<planner::MergeJoinPlan::JoinClause> join_clauses; join_clauses = CreateJoinClauses(); // Create merge join plan node planner::MergeJoinPlan merge_join_node(join_type, predicate, projection, join_clauses); // Construct the merge join executor executor::MergeJoinExecutor merge_join_executor(&merge_join_node, nullptr); // Construct the executor tree merge_join_executor.AddChild(&left_table_scan_executor); merge_join_executor.AddChild(&right_table_scan_executor); // Run the merge join executor EXPECT_TRUE(merge_join_executor.Init()); while (merge_join_executor.Execute() == true) { std::unique_ptr<executor::LogicalTile> result_logical_tile( merge_join_executor.GetOutput()); if (result_logical_tile != nullptr) { result_tuple_count += result_logical_tile->GetTupleCount(); tuples_with_null += CountTuplesWithNullFields(result_logical_tile.get()); //std::cout << (*result_logical_tile); } } } break; case PLAN_NODE_TYPE_HASHJOIN: { // Create hash plan node expression::AbstractExpression *right_table_attr_1 = new expression::TupleValueExpression(1, 1); std::vector<std::unique_ptr<const expression::AbstractExpression> > hash_keys; hash_keys.emplace_back(right_table_attr_1); // Create hash plan node planner::HashPlan hash_plan_node(hash_keys); // Construct the hash executor executor::HashExecutor hash_executor(&hash_plan_node, nullptr); // Create hash join plan node. planner::HashJoinPlan hash_join_plan_node(join_type, predicate, projection); // Construct the hash join executor executor::HashJoinExecutor hash_join_executor(&hash_join_plan_node, nullptr); // Construct the executor tree hash_join_executor.AddChild(&left_table_scan_executor); hash_join_executor.AddChild(&hash_executor); hash_executor.AddChild(&right_table_scan_executor); // Run the hash_join_executor EXPECT_TRUE(hash_join_executor.Init()); while (hash_join_executor.Execute() == true) { std::unique_ptr<executor::LogicalTile> result_logical_tile( hash_join_executor.GetOutput()); if (result_logical_tile != nullptr) { result_tuple_count += result_logical_tile->GetTupleCount(); tuples_with_null += CountTuplesWithNullFields(result_logical_tile.get()); // std::cout << (*result_logical_tile); } } } break; default: throw Exception("Unsupported join algorithm : " + std::to_string(join_algorithm)); break; } //===--------------------------------------------------------------------===// // Execute test //===--------------------------------------------------------------------===// if(join_test_type == BASIC_TEST) { // Check output switch (join_type) { case JOIN_TYPE_INNER: EXPECT_EQ(result_tuple_count, 10); EXPECT_EQ(tuples_with_null, 0); break; case JOIN_TYPE_LEFT: EXPECT_EQ(result_tuple_count, 15); EXPECT_EQ(tuples_with_null, 5); break; case JOIN_TYPE_RIGHT: EXPECT_EQ(result_tuple_count, 10); EXPECT_EQ(tuples_with_null, 0); break; case JOIN_TYPE_OUTER: EXPECT_EQ(result_tuple_count, 15); EXPECT_EQ(tuples_with_null, 5); break; default: throw Exception("Unsupported join type : " + std::to_string(join_type)); break; } } }
/** * @brief Creates logical tiles from the two input logical tiles after applying * join predicate. * @return true on success, false otherwise. */ bool MergeJoinExecutor::DExecute() { LOG_INFO( "********** Merge Join executor :: 2 children " "left:: start: %lu, end: %lu, done: %d " "right:: start: %lu, end: %lu, done: %d", left_start_row, left_end_row, left_child_done_, right_start_row, right_end_row, right_child_done_); // Build outer join output when done if (right_child_done_ && left_child_done_) { return BuildOuterJoinOutput(); } //===--------------------------------------------------------------------===// // Pick right and left tiles //===--------------------------------------------------------------------===// // Try to get next tile from RIGHT child if (((right_child_done_ == false) && (right_start_row == right_end_row)) || (left_child_done_ == true)) { if (children_[1]->Execute() == false) { LOG_TRACE("Did not get right tile "); right_child_done_ = true; // Try again return DExecute(); } LOG_TRACE("Got right tile "); auto right_tile = children_[1]->GetOutput(); BufferRightTile(right_tile); right_start_row = 0; right_end_row = Advance(right_tile, right_start_row, false); LOG_TRACE("size of right tiles: %lu", right_result_tiles_.size()); } // Try to get next tile from LEFT child if (((left_child_done_ == false) && (left_start_row == left_end_row)) || (right_child_done_ == true)) { if (children_[0]->Execute() == false) { LOG_TRACE("Did not get left tile "); left_child_done_ = true; // Try again return DExecute(); } LOG_TRACE("Got left tile "); auto left_tile = children_[0]->GetOutput(); BufferLeftTile(left_tile); left_start_row = 0; left_end_row = Advance(left_tile, left_start_row, true); LOG_TRACE("size of left tiles: %lu", left_result_tiles_.size()); } // Check if we have logical tiles to process if(left_result_tiles_.empty() || right_result_tiles_.empty()) { return false; } LogicalTile *left_tile = left_result_tiles_.back().get(); LogicalTile *right_tile = right_result_tiles_.back().get(); //===--------------------------------------------------------------------===// // Build Join Tile //===--------------------------------------------------------------------===// // Build output logical tile auto output_tile = BuildOutputLogicalTile(left_tile, right_tile); // Build position lists LogicalTile::PositionListsBuilder pos_lists_builder(left_tile, right_tile); while ((left_end_row > left_start_row) && (right_end_row > right_start_row)) { expression::ContainerTuple<executor::LogicalTile> left_tuple( left_tile, left_start_row); expression::ContainerTuple<executor::LogicalTile> right_tuple( right_tile, right_start_row); bool not_matching_tuple_pair = false; // Evaluate and compare the join clauses for (auto &clause : *join_clauses_) { auto left_value = clause.left_->Evaluate(&left_tuple, &right_tuple, nullptr); auto right_value = clause.right_->Evaluate(&left_tuple, &right_tuple, nullptr); // Compare the values int comparison = left_value.Compare(right_value); // Left key < Right key, advance left if (comparison < 0) { LOG_TRACE("left < right, advance left "); left_start_row = left_end_row; left_end_row = Advance(left_tile, left_start_row, true); not_matching_tuple_pair = true; break; } // Left key > Right key, advance right else if (comparison > 0) { LOG_TRACE("left > right, advance right "); right_start_row = right_end_row; right_end_row = Advance(right_tile, right_start_row, false); not_matching_tuple_pair = true; break; } // Left key == Right key, go and check next join clause } // Atleast one of the join clauses don't match // One of the tile has been advanced if (not_matching_tuple_pair) { continue; } // Join clauses matched, try to match predicate LOG_TRACE("one pair of tuples matches join clause "); // Join predicate exists if (predicate_ != nullptr) { if (predicate_->Evaluate(&left_tuple, &right_tuple, executor_context_) .IsFalse()) { // Join predicate is false. Advance both. left_start_row = left_end_row; left_end_row = Advance(left_tile, left_start_row, true); right_start_row = right_end_row; right_end_row = Advance(right_tile, right_start_row, false); } } // Sub tile matched, do a Cartesian product // Go over every pair of tuples in left and right logical tiles for (size_t left_tile_row_itr = left_start_row; left_tile_row_itr < left_end_row; left_tile_row_itr++) { for (size_t right_tile_row_itr = right_start_row; right_tile_row_itr < right_end_row; right_tile_row_itr++) { // Insert a tuple into the output logical tile pos_lists_builder.AddRow(left_tile_row_itr, right_tile_row_itr); RecordMatchedLeftRow(left_result_tiles_.size() - 1, left_tile_row_itr); RecordMatchedRightRow(right_result_tiles_.size() - 1, right_tile_row_itr); } } // Then, advance both left_start_row = left_end_row; left_end_row = Advance(left_tile, left_start_row, true); right_start_row = right_end_row; right_end_row = Advance(right_tile, right_start_row, false); } // Check if we have any join tuples. if (pos_lists_builder.Size() > 0) { output_tile->SetPositionListsAndVisibility(pos_lists_builder.Release()); SetOutput(output_tile.release()); return true; } // Try again else { // If we are out of any more pairs of child tiles to examine, // then we will return false earlier in this function // So, no need to return false here DExecute(); } return true; }
TEST(AggregateTests, PlainSumCountDistinctTest) { /* * SELECT SUM(a), COUNT(b), COUNT(DISTINCT b) from table */ const int tuple_count = TESTS_TUPLES_PER_TILEGROUP; // Create a table and wrap it in logical tiles auto &txn_manager = concurrency::TransactionManager::GetInstance(); auto txn = txn_manager.BeginTransaction(); auto txn_id = txn->GetTransactionId(); std::unique_ptr<storage::DataTable> data_table( ExecutorTestsUtil::CreateTable(tuple_count, false)); ExecutorTestsUtil::PopulateTable(txn, data_table.get(), 2 * tuple_count, false, true, true); txn_manager.CommitTransaction(); std::unique_ptr<executor::LogicalTile> source_logical_tile1( executor::LogicalTileFactory::WrapTileGroup(data_table->GetTileGroup(0), txn_id)); std::unique_ptr<executor::LogicalTile> source_logical_tile2( executor::LogicalTileFactory::WrapTileGroup(data_table->GetTileGroup(1), txn_id)); // (1-5) Setup plan node // 1) Set up group-by columns std::vector<oid_t> group_by_columns; // 2) Set up project info planner::ProjectInfo::DirectMapList direct_map_list = { {0, {1, 0}}, {1, {1, 1}}, {2, {1, 2}}}; auto proj_info = new planner::ProjectInfo(planner::ProjectInfo::TargetList(), std::move(direct_map_list)); // 3) Set up unique aggregates std::vector<planner::AggregatePlan::AggTerm> agg_terms; planner::AggregatePlan::AggTerm sumA(EXPRESSION_TYPE_AGGREGATE_SUM, expression::TupleValueFactory(0, 0), false); planner::AggregatePlan::AggTerm countB(EXPRESSION_TYPE_AGGREGATE_COUNT, expression::TupleValueFactory(0, 1), false); // Flag distinct planner::AggregatePlan::AggTerm countDistinctB( EXPRESSION_TYPE_AGGREGATE_COUNT, expression::TupleValueFactory(0, 1), true); // Flag distinct agg_terms.push_back(sumA); agg_terms.push_back(countB); agg_terms.push_back(countDistinctB); // 4) Set up predicate (empty) expression::AbstractExpression* predicate = nullptr; // 5) Create output table schema auto data_table_schema = data_table.get()->GetSchema(); std::vector<oid_t> set = {0, 1, 1}; std::vector<catalog::Column> columns; for (auto column_index : set) { columns.push_back(data_table_schema->GetColumn(column_index)); } auto output_table_schema = new catalog::Schema(columns); // OK) Create the plan node planner::AggregatePlan node(proj_info, predicate, std::move(agg_terms), std::move(group_by_columns), output_table_schema, AGGREGATE_TYPE_PLAIN); // Create and set up executor auto txn2 = txn_manager.BeginTransaction(); std::unique_ptr<executor::ExecutorContext> context( new executor::ExecutorContext(txn2)); executor::AggregateExecutor executor(&node, context.get()); MockExecutor child_executor; executor.AddChild(&child_executor); EXPECT_CALL(child_executor, DInit()).WillOnce(Return(true)); EXPECT_CALL(child_executor, DExecute()) .WillOnce(Return(true)) .WillOnce(Return(true)) .WillOnce(Return(false)); EXPECT_CALL(child_executor, GetOutput()) .WillOnce(Return(source_logical_tile1.release())) .WillOnce(Return(source_logical_tile2.release())); EXPECT_TRUE(executor.Init()); EXPECT_TRUE(executor.Execute()); txn_manager.CommitTransaction(); /* Verify result */ std::unique_ptr<executor::LogicalTile> result_tile(executor.GetOutput()); EXPECT_TRUE(result_tile.get() != nullptr); EXPECT_TRUE(result_tile->GetValue(0, 0) .OpEquals(ValueFactory::GetIntegerValue(50)) .IsTrue()); EXPECT_TRUE(result_tile->GetValue(0, 1) .OpEquals(ValueFactory::GetIntegerValue(10)) .IsTrue()); EXPECT_TRUE(result_tile->GetValue(0, 2) .OpLessThanOrEqual(ValueFactory::GetIntegerValue(3)) .IsTrue()); }
TEST(AggregateTests, HashDistinctTest) { /* * SELECT d, a, b, c FROM table GROUP BY a, b, c, d; */ const int tuple_count = TESTS_TUPLES_PER_TILEGROUP; // Create a table and wrap it in logical tiles auto &txn_manager = concurrency::TransactionManager::GetInstance(); auto txn = txn_manager.BeginTransaction(); auto txn_id = txn->GetTransactionId(); std::unique_ptr<storage::DataTable> data_table( ExecutorTestsUtil::CreateTable(tuple_count, false)); ExecutorTestsUtil::PopulateTable(txn, data_table.get(), 2 * tuple_count, false, true, true); // let it be random txn_manager.CommitTransaction(); std::unique_ptr<executor::LogicalTile> source_logical_tile1( executor::LogicalTileFactory::WrapTileGroup(data_table->GetTileGroup(0), txn_id)); std::unique_ptr<executor::LogicalTile> source_logical_tile2( executor::LogicalTileFactory::WrapTileGroup(data_table->GetTileGroup(1), txn_id)); // (1-5) Setup plan node // 1) Set up group-by columns std::vector<oid_t> group_by_columns = {0, 1, 2, 3}; // 2) Set up project info planner::ProjectInfo::DirectMapList direct_map_list = { {0, {0, 3}}, {1, {0, 0}}, {2, {0, 1}}, {3, {0, 2}}}; auto proj_info = new planner::ProjectInfo(planner::ProjectInfo::TargetList(), std::move(direct_map_list)); // 3) Set up unique aggregates (empty) std::vector<planner::AggregatePlan::AggTerm> agg_terms; // 4) Set up predicate (empty) expression::AbstractExpression* predicate = nullptr; // 5) Create output table schema auto data_table_schema = data_table.get()->GetSchema(); std::vector<oid_t> set = {3, 0, 1, 2}; std::vector<catalog::Column> columns; for (auto column_index : set) { columns.push_back(data_table_schema->GetColumn(column_index)); } auto output_table_schema = new catalog::Schema(columns); // OK) Create the plan node planner::AggregatePlan node(proj_info, predicate, std::move(agg_terms), std::move(group_by_columns), output_table_schema, AGGREGATE_TYPE_HASH); // Create and set up executor auto txn2 = txn_manager.BeginTransaction(); std::unique_ptr<executor::ExecutorContext> context( new executor::ExecutorContext(txn2)); executor::AggregateExecutor executor(&node, context.get()); MockExecutor child_executor; executor.AddChild(&child_executor); EXPECT_CALL(child_executor, DInit()).WillOnce(Return(true)); EXPECT_CALL(child_executor, DExecute()) .WillOnce(Return(true)) .WillOnce(Return(true)) .WillOnce(Return(false)); EXPECT_CALL(child_executor, GetOutput()) .WillOnce(Return(source_logical_tile1.release())) .WillOnce(Return(source_logical_tile2.release())); EXPECT_TRUE(executor.Init()); EXPECT_TRUE(executor.Execute()); txn_manager.CommitTransaction(); /* Verify result */ std::unique_ptr<executor::LogicalTile> result_tile(executor.GetOutput()); EXPECT_TRUE(result_tile.get() != nullptr); for (auto tuple_id : *result_tile) { int colA = ValuePeeker::PeekAsInteger(result_tile->GetValue(tuple_id, 1)); (void)colA; } }