Skip to content

Commit deee24f

Browse files
shinyumhs-wangru
andauthored
Project 3 Update (Fall 2025) (#849)
* added nulls first/last * modified fn headers * updated init check * synced mock scan * topn check * p3 updates * small changes * syncing * syncing * some changes * minor changes to test cases * format * clang tidy * random data * clang * remove random in mockscan * bug fix * revert * format --------- Co-authored-by: s-wangru <[email protected]>
1 parent a5e81f9 commit deee24f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+990
-259
lines changed

CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,9 @@ set(P3_FILES
334334
"src/include/execution/executors/seq_scan_executor.h"
335335
"src/include/execution/executors/external_merge_sort_executor.h"
336336
"src/include/execution/executors/update_executor.h"
337+
"src/include/execution/plans/aggregation_plan.h"
338+
"src/include/storage/page/intermediate_result_page.h"
339+
"src/include/execution/executors/window_function_executor.h"
337340
"src/execution/aggregation_executor.cpp"
338341
"src/execution/delete_executor.cpp"
339342
"src/execution/filter_executor.cpp"
@@ -346,6 +349,7 @@ set(P3_FILES
346349
"src/execution/seq_scan_executor.cpp"
347350
"src/execution/external_merge_sort_executor.cpp"
348351
"src/execution/update_executor.cpp"
352+
"src/execution/window_function_executor.cpp"
349353
"src/include/execution/execution_common.h"
350354
"src/include/optimizer/optimizer.h"
351355
"src/include/optimizer/optimizer_internal.h"

src/binder/bind_select.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -945,8 +945,20 @@ auto Binder::BindSort(duckdb_libpgquery::PGList *list) -> std::vector<std::uniqu
945945
} else {
946946
throw NotImplementedException("unimplemented order by type");
947947
}
948+
949+
OrderByNullType null_order;
950+
if (sort->sortby_nulls == duckdb_libpgquery::PG_SORTBY_NULLS_DEFAULT) {
951+
null_order = OrderByNullType::DEFAULT;
952+
} else if (sort->sortby_nulls == duckdb_libpgquery::PG_SORTBY_NULLS_FIRST) {
953+
null_order = OrderByNullType::NULLS_FIRST;
954+
} else if (sort->sortby_nulls == duckdb_libpgquery::PG_SORTBY_NULLS_LAST) {
955+
null_order = OrderByNullType::NULLS_LAST;
956+
} else {
957+
throw NotImplementedException("unimplemented nulls order type");
958+
}
959+
948960
auto order_expression = BindExpression(target);
949-
order_by.emplace_back(std::make_unique<BoundOrderBy>(type, std::move(order_expression)));
961+
order_by.emplace_back(std::make_unique<BoundOrderBy>(type, null_order, std::move(order_expression)));
950962
} else {
951963
throw NotImplementedException("unsupported order by node");
952964
}

src/execution/aggregation_executor.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,17 @@ AggregationExecutor::AggregationExecutor(ExecutorContext *exec_ctx, const Aggreg
3333
void AggregationExecutor::Init() { UNIMPLEMENTED("TODO(P3): Add implementation."); }
3434

3535
/**
36-
* Yield the next tuple from the insert.
37-
* @param[out] tuple The next tuple produced by the aggregation
38-
* @param[out] rid The next tuple RID produced by the aggregation
39-
* @return `true` if a tuple was produced, `false` if there are no more tuples
36+
* Yield the next tuple batch from the aggregation.
37+
* @param[out] tuple_batch The next batch of tuples produced by the aggregation
38+
* @param[out] rid_batch The next batch of tuple RIDs produced by the aggregation
39+
* @param batch_size The number of tuples to be included in the batch (default: BUSTUB_BATCH_SIZE)
40+
* @return `true` if any tuples were produced, `false` if there are no more tuples
4041
*/
4142

42-
auto AggregationExecutor::Next(Tuple *tuple, RID *rid) -> bool { UNIMPLEMENTED("TODO(P3): Add implementation."); }
43+
auto AggregationExecutor::Next(std::vector<bustub::Tuple> *tuple_batch, std::vector<bustub::RID> *rid_batch,
44+
size_t batch_size) -> bool {
45+
UNIMPLEMENTED("TODO(P3): Add implementation.");
46+
}
4347

4448
/** Do not use or remove this function; otherwise, you will get zero points. */
4549
auto AggregationExecutor::GetChildExecutor() const -> const AbstractExecutor * { return child_executor_.get(); }

src/execution/delete_executor.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,16 @@ void DeleteExecutor::Init() { UNIMPLEMENTED("TODO(P3): Add implementation."); }
3434

3535
/**
3636
* Yield the number of rows deleted from the table.
37-
* @param[out] tuple The integer tuple indicating the number of rows deleted from the table
38-
* @param[out] rid The next tuple RID produced by the delete (ignore, not used)
37+
* @param[out] tuple_batch The tuple batch with one integer indicating the number of rows deleted from the table
38+
* @param[out] rid_batch The next tuple RID batch produced by the delete (ignore, not used)
39+
* @param batch_size The number of tuples to be included in the batch (default: BUSTUB_BATCH_SIZE)
3940
* @return `true` if a tuple was produced, `false` if there are no more tuples
4041
*
41-
* NOTE: DeleteExecutor::Next() does not use the `rid` out-parameter.
42+
* NOTE: DeleteExecutor::Next() does not use the `rid_batch` out-parameter.
4243
* NOTE: DeleteExecutor::Next() returns true with the number of deleted rows produced only once.
4344
*/
44-
auto DeleteExecutor::Next([[maybe_unused]] Tuple *tuple, RID *rid) -> bool {
45+
auto DeleteExecutor::Next(std::vector<bustub::Tuple> *tuple_batch, std::vector<bustub::RID> *rid_batch,
46+
size_t batch_size) -> bool {
4547
UNIMPLEMENTED("TODO(P3): Add implementation.");
4648
}
4749

src/execution/external_merge_sort_executor.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,15 @@ void ExternalMergeSortExecutor<K>::Init() {
3131
}
3232

3333
/**
34-
* Yield the next tuple from the external merge sort.
35-
* @param[out] tuple The next tuple produced by the external merge sort.
36-
* @param[out] rid The next tuple RID produced by the external merge sort.
34+
* Yield the next tuple batch from the external merge sort.
35+
* @param[out] tuple_batch The next tuple batch produced by the external merge sort.
36+
* @param[out] rid_batch The next tuple RID batch produced by the external merge sort.
37+
* @param batch_size The number of tuples to be included in the batch (default: BUSTUB_BATCH_SIZE)
3738
* @return `true` if a tuple was produced, `false` if there are no more tuples
3839
*/
3940
template <size_t K>
40-
auto ExternalMergeSortExecutor<K>::Next(Tuple *tuple, RID *rid) -> bool {
41+
auto ExternalMergeSortExecutor<K>::Next(std::vector<bustub::Tuple> *tuple_batch, std::vector<bustub::RID> *rid_batch,
42+
size_t batch_size) -> bool {
4143
UNIMPLEMENTED("TODO(P3): Add implementation.");
4244
}
4345

src/execution/filter_executor.cpp

Lines changed: 53 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,26 +33,70 @@ void FilterExecutor::Init() {
3333
}
3434

3535
/**
36-
* Yield the next tuple from the filter.
37-
* @param[out] tuple The next tuple produced by the filter
38-
* @param[out] rid The next tuple RID produced by the filter
36+
* Yield the next tuple batch from the filter.
37+
* @param[out] tuple_batch The next tuple batch produced by the filter
38+
* @param[out] rid_batch The next tuple RID batch produced by the filter
39+
* @param batch_size The number of tuples to be included in the batch (default: BUSTUB_BATCH_SIZE)
3940
* @return `true` if a tuple was produced, `false` if there are no more tuples
4041
*/
41-
auto FilterExecutor::Next(Tuple *tuple, RID *rid) -> bool {
42+
auto FilterExecutor::Next(std::vector<bustub::Tuple> *tuple_batch, std::vector<bustub::RID> *rid_batch,
43+
size_t batch_size) -> bool {
44+
tuple_batch->clear();
45+
rid_batch->clear();
46+
4247
auto filter_expr = plan_->GetPredicate();
4348

4449
while (true) {
45-
// Get the next tuple
46-
const auto status = child_executor_->Next(tuple, rid);
50+
// If the child offset is not zero, process remaining tuples in the last fetched batch
51+
if (child_offset_ != 0) {
52+
for (size_t i = child_offset_; i < child_tuples_.size(); ++i) {
53+
auto &tuple = child_tuples_[i];
54+
auto &rid = child_rids_[i];
55+
// Evaluate the filter predicate
56+
auto value = filter_expr->Evaluate(&tuple, child_executor_->GetOutputSchema());
57+
if (filter_expr == nullptr || (!value.IsNull() && value.GetAs<bool>())) {
58+
tuple_batch->push_back(tuple);
59+
rid_batch->push_back(rid);
60+
}
61+
}
62+
}
63+
64+
child_offset_ = 0;
65+
66+
// Get the next tuple batch from the child executor
67+
const auto status = child_executor_->Next(&child_tuples_, &child_rids_, batch_size);
4768

48-
if (!status) {
69+
// If no more tuples and output batch is empty, return false
70+
if (!status && tuple_batch->empty()) {
4971
return false;
5072
}
5173

52-
auto value = filter_expr->Evaluate(tuple, child_executor_->GetOutputSchema());
53-
if (!value.IsNull() && value.GetAs<bool>()) {
74+
// If no more tuples but output batch is not empty, return true
75+
if (!status && !tuple_batch->empty()) {
5476
return true;
5577
}
78+
79+
for (size_t i = 0; i < child_tuples_.size(); ++i) {
80+
auto &tuple = child_tuples_[i];
81+
auto &rid = child_rids_[i];
82+
// Evaluate the filter predicate
83+
auto value = filter_expr->Evaluate(&tuple, child_executor_->GetOutputSchema());
84+
if (filter_expr == nullptr || (!value.IsNull() && value.GetAs<bool>())) {
85+
tuple_batch->push_back(tuple);
86+
rid_batch->push_back(rid);
87+
if (tuple_batch->size() >= batch_size) {
88+
// If we have filled the output batch but not yet reached the end of the current child batch, update the
89+
// offset and return
90+
if (i + 1 < child_tuples_.size()) {
91+
child_offset_ = i + 1;
92+
} else {
93+
child_offset_ = 0;
94+
}
95+
96+
return true;
97+
}
98+
}
99+
}
56100
}
57101
}
58102

src/execution/hash_join_executor.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,15 @@ HashJoinExecutor::HashJoinExecutor(ExecutorContext *exec_ctx, const HashJoinPlan
3737
void HashJoinExecutor::Init() { UNIMPLEMENTED("TODO(P3): Add implementation."); }
3838

3939
/**
40-
* Yield the next tuple from the join.
41-
* @param[out] tuple The next tuple produced by the join.
42-
* @param[out] rid The next tuple RID, not used by hash join.
43-
* @return `true` if a tuple was produced, `false` if there are no more tuples.
40+
* Yield the next tuple batch from the hash join.
41+
* @param[out] tuple_batch The next tuple batch produced by the hash join
42+
* @param[out] rid_batch The next tuple RID batch produced by the hash join
43+
* @param batch_size The number of tuples to be included in the batch (default: BUSTUB_BATCH_SIZE)
44+
* @return `true` if a tuple was produced, `false` if there are no more tuples
4445
*/
45-
auto HashJoinExecutor::Next(Tuple *tuple, RID *rid) -> bool { UNIMPLEMENTED("TODO(P3): Add implementation."); }
46+
auto HashJoinExecutor::Next(std::vector<bustub::Tuple> *tuple_batch, std::vector<bustub::RID> *rid_batch,
47+
size_t batch_size) -> bool {
48+
UNIMPLEMENTED("TODO(P3): Add implementation.");
49+
}
4650

4751
} // namespace bustub

src/execution/index_scan_executor.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ IndexScanExecutor::IndexScanExecutor(ExecutorContext *exec_ctx, const IndexScanP
2727

2828
void IndexScanExecutor::Init() { UNIMPLEMENTED("TODO(P3): Add implementation."); }
2929

30-
auto IndexScanExecutor::Next(Tuple *tuple, RID *rid) -> bool { UNIMPLEMENTED("TODO(P3): Add implementation."); }
30+
auto IndexScanExecutor::Next(std::vector<bustub::Tuple> *tuple_batch, std::vector<bustub::RID> *rid_batch,
31+
size_t batch_size) -> bool {
32+
UNIMPLEMENTED("TODO(P3): Add implementation.");
33+
}
3134

3235
} // namespace bustub

src/execution/init_check_executor.cpp

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,19 @@ void InitCheckExecutor::Init() {
3636
}
3737

3838
/**
39-
* Yield the next tuple from the child executor.
40-
* @param[out] tuple The next tuple produced by the child executor
41-
* @param[out] rid The next tuple RID produced by the child executor
39+
* Yield the next tuple batch from the child executor.
40+
* @param[out] tuple_batch The next tuple batch produced by the child executor
41+
* @param[out] rid_batch The next tuple RID batch produced by the child executor
42+
* @param batch_size The number of tuples to be included in the batch (default: BUSTUB_BATCH_SIZE)
4243
* @return `true` if a tuple was produced, `false` if there are no more tuples
4344
*/
44-
auto InitCheckExecutor::Next(Tuple *tuple, RID *rid) -> bool {
45+
auto InitCheckExecutor::Next(std::vector<bustub::Tuple> *tuple_batch, std::vector<bustub::RID> *rid_batch,
46+
size_t batch_size) -> bool {
47+
tuple_batch->clear();
48+
rid_batch->clear();
49+
4550
// Emit the next tuple
46-
auto result = child_executor_->Next(tuple, rid);
51+
auto result = child_executor_->Next(tuple_batch, rid_batch, batch_size);
4752
if (result) {
4853
n_next_++;
4954
}

src/execution/insert_executor.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,16 @@ void InsertExecutor::Init() { UNIMPLEMENTED("TODO(P3): Add implementation."); }
3434

3535
/**
3636
* Yield the number of rows inserted into the table.
37-
* @param[out] tuple The integer tuple indicating the number of rows inserted into the table
38-
* @param[out] rid The next tuple RID produced by the insert (ignore, not used)
37+
* @param[out] tuple_batch The tuple batch with one integer indicating the number of rows inserted into the table
38+
* @param[out] rid_batch The next tuple RID batch produced by the insert (ignore, not used)
39+
* @param batch_size The number of tuples to be included in the batch (default: BUSTUB_BATCH_SIZE)
3940
* @return `true` if a tuple was produced, `false` if there are no more tuples
4041
*
41-
* NOTE: InsertExecutor::Next() does not use the `rid` out-parameter.
42-
* NOTE: InsertExecutor::Next() returns true with number of inserted rows produced only once.
42+
* NOTE: InsertExecutor::Next() does not use the `rid_batch` out-parameter.
43+
* NOTE: InsertExecutor::Next() returns true with the number of inserted rows produced only once.
4344
*/
44-
auto InsertExecutor::Next([[maybe_unused]] Tuple *tuple, RID *rid) -> bool {
45+
auto InsertExecutor::Next(std::vector<bustub::Tuple> *tuple_batch, std::vector<bustub::RID> *rid_batch,
46+
size_t batch_size) -> bool {
4547
UNIMPLEMENTED("TODO(P3): Add implementation.");
4648
}
4749

0 commit comments

Comments
 (0)