Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,9 @@ set(P3_FILES
"src/include/execution/executors/seq_scan_executor.h"
"src/include/execution/executors/external_merge_sort_executor.h"
"src/include/execution/executors/update_executor.h"
"src/include/execution/plans/aggregation_plan.h"
"src/include/storage/page/intermediate_result_page.h"
"src/include/execution/executors/window_function_executor.h"
"src/execution/aggregation_executor.cpp"
"src/execution/delete_executor.cpp"
"src/execution/filter_executor.cpp"
Expand All @@ -346,6 +349,7 @@ set(P3_FILES
"src/execution/seq_scan_executor.cpp"
"src/execution/external_merge_sort_executor.cpp"
"src/execution/update_executor.cpp"
"src/execution/window_function_executor.cpp"
"src/include/execution/execution_common.h"
"src/include/optimizer/optimizer.h"
"src/include/optimizer/optimizer_internal.h"
Expand Down
14 changes: 13 additions & 1 deletion src/binder/bind_select.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -945,8 +945,20 @@ auto Binder::BindSort(duckdb_libpgquery::PGList *list) -> std::vector<std::uniqu
} else {
throw NotImplementedException("unimplemented order by type");
}

OrderByNullType null_order;
if (sort->sortby_nulls == duckdb_libpgquery::PG_SORTBY_NULLS_DEFAULT) {
null_order = OrderByNullType::DEFAULT;
} else if (sort->sortby_nulls == duckdb_libpgquery::PG_SORTBY_NULLS_FIRST) {
null_order = OrderByNullType::NULLS_FIRST;
} else if (sort->sortby_nulls == duckdb_libpgquery::PG_SORTBY_NULLS_LAST) {
null_order = OrderByNullType::NULLS_LAST;
} else {
throw NotImplementedException("unimplemented nulls order type");
}

auto order_expression = BindExpression(target);
order_by.emplace_back(std::make_unique<BoundOrderBy>(type, std::move(order_expression)));
order_by.emplace_back(std::make_unique<BoundOrderBy>(type, null_order, std::move(order_expression)));
} else {
throw NotImplementedException("unsupported order by node");
}
Expand Down
14 changes: 9 additions & 5 deletions src/execution/aggregation_executor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,17 @@ AggregationExecutor::AggregationExecutor(ExecutorContext *exec_ctx, const Aggreg
void AggregationExecutor::Init() { UNIMPLEMENTED("TODO(P3): Add implementation."); }

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

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

/** Do not use or remove this function; otherwise, you will get zero points. */
auto AggregationExecutor::GetChildExecutor() const -> const AbstractExecutor * { return child_executor_.get(); }
Expand Down
10 changes: 6 additions & 4 deletions src/execution/delete_executor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,16 @@ void DeleteExecutor::Init() { UNIMPLEMENTED("TODO(P3): Add implementation."); }

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

Expand Down
10 changes: 6 additions & 4 deletions src/execution/external_merge_sort_executor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,15 @@ void ExternalMergeSortExecutor<K>::Init() {
}

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

Expand Down
62 changes: 53 additions & 9 deletions src/execution/filter_executor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,26 +33,70 @@ void FilterExecutor::Init() {
}

/**
* Yield the next tuple from the filter.
* @param[out] tuple The next tuple produced by the filter
* @param[out] rid The next tuple RID produced by the filter
* Yield the next tuple batch from the filter.
* @param[out] tuple_batch The next tuple batch produced by the filter
* @param[out] rid_batch The next tuple RID batch produced by the filter
* @param batch_size The number of tuples to be included in the batch (default: BUSTUB_BATCH_SIZE)
* @return `true` if a tuple was produced, `false` if there are no more tuples
*/
auto FilterExecutor::Next(Tuple *tuple, RID *rid) -> bool {
auto FilterExecutor::Next(std::vector<bustub::Tuple> *tuple_batch, std::vector<bustub::RID> *rid_batch,
size_t batch_size) -> bool {
tuple_batch->clear();
rid_batch->clear();

auto filter_expr = plan_->GetPredicate();

while (true) {
// Get the next tuple
const auto status = child_executor_->Next(tuple, rid);
// If the child offset is not zero, process remaining tuples in the last fetched batch
if (child_offset_ != 0) {
for (size_t i = child_offset_; i < child_tuples_.size(); ++i) {
auto &tuple = child_tuples_[i];
auto &rid = child_rids_[i];
// Evaluate the filter predicate
auto value = filter_expr->Evaluate(&tuple, child_executor_->GetOutputSchema());
if (filter_expr == nullptr || (!value.IsNull() && value.GetAs<bool>())) {
tuple_batch->push_back(tuple);
rid_batch->push_back(rid);
}
}
}

child_offset_ = 0;

// Get the next tuple batch from the child executor
const auto status = child_executor_->Next(&child_tuples_, &child_rids_, batch_size);

if (!status) {
// If no more tuples and output batch is empty, return false
if (!status && tuple_batch->empty()) {
return false;
}

auto value = filter_expr->Evaluate(tuple, child_executor_->GetOutputSchema());
if (!value.IsNull() && value.GetAs<bool>()) {
// If no more tuples but output batch is not empty, return true
if (!status && !tuple_batch->empty()) {
return true;
}

for (size_t i = 0; i < child_tuples_.size(); ++i) {
auto &tuple = child_tuples_[i];
auto &rid = child_rids_[i];
// Evaluate the filter predicate
auto value = filter_expr->Evaluate(&tuple, child_executor_->GetOutputSchema());
if (filter_expr == nullptr || (!value.IsNull() && value.GetAs<bool>())) {
tuple_batch->push_back(tuple);
rid_batch->push_back(rid);
if (tuple_batch->size() >= batch_size) {
// If we have filled the output batch but not yet reached the end of the current child batch, update the
// offset and return
if (i + 1 < child_tuples_.size()) {
child_offset_ = i + 1;
} else {
child_offset_ = 0;
}

return true;
}
}
}
}
}

Expand Down
14 changes: 9 additions & 5 deletions src/execution/hash_join_executor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,15 @@ HashJoinExecutor::HashJoinExecutor(ExecutorContext *exec_ctx, const HashJoinPlan
void HashJoinExecutor::Init() { UNIMPLEMENTED("TODO(P3): Add implementation."); }

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

} // namespace bustub
5 changes: 4 additions & 1 deletion src/execution/index_scan_executor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ IndexScanExecutor::IndexScanExecutor(ExecutorContext *exec_ctx, const IndexScanP

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

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

} // namespace bustub
15 changes: 10 additions & 5 deletions src/execution/init_check_executor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,19 @@ void InitCheckExecutor::Init() {
}

/**
* Yield the next tuple from the child executor.
* @param[out] tuple The next tuple produced by the child executor
* @param[out] rid The next tuple RID produced by the child executor
* Yield the next tuple batch from the child executor.
* @param[out] tuple_batch The next tuple batch produced by the child executor
* @param[out] rid_batch The next tuple RID batch produced by the child executor
* @param batch_size The number of tuples to be included in the batch (default: BUSTUB_BATCH_SIZE)
* @return `true` if a tuple was produced, `false` if there are no more tuples
*/
auto InitCheckExecutor::Next(Tuple *tuple, RID *rid) -> bool {
auto InitCheckExecutor::Next(std::vector<bustub::Tuple> *tuple_batch, std::vector<bustub::RID> *rid_batch,
size_t batch_size) -> bool {
tuple_batch->clear();
rid_batch->clear();

// Emit the next tuple
auto result = child_executor_->Next(tuple, rid);
auto result = child_executor_->Next(tuple_batch, rid_batch, batch_size);
if (result) {
n_next_++;
}
Expand Down
12 changes: 7 additions & 5 deletions src/execution/insert_executor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,16 @@ void InsertExecutor::Init() { UNIMPLEMENTED("TODO(P3): Add implementation."); }

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

Expand Down
12 changes: 8 additions & 4 deletions src/execution/limit_executor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,15 @@ LimitExecutor::LimitExecutor(ExecutorContext *exec_ctx, const LimitPlanNode *pla
void LimitExecutor::Init() { UNIMPLEMENTED("TODO(P3): Add implementation."); }

/**
* Yield the next tuple from the limit.
* @param[out] tuple The next tuple produced by the limit
* @param[out] rid The next tuple RID produced by the limit
* Yield the next tuple batch from the limit.
* @param[out] tuple_batch The next tuple batch produced by the limit
* @param[out] rid_batch The next tuple RID batch produced by the limit
* @param batch_size The number of tuples to be included in the batch (default: BUSTUB_BATCH_SIZE)
* @return `true` if a tuple was produced, `false` if there are no more tuples
*/
auto LimitExecutor::Next(Tuple *tuple, RID *rid) -> bool { UNIMPLEMENTED("TODO(P3): Add implementation."); }
auto LimitExecutor::Next(std::vector<bustub::Tuple> *tuple_batch, std::vector<bustub::RID> *rid_batch,
size_t batch_size) -> bool {
UNIMPLEMENTED("TODO(P3): Add implementation.");
}

} // namespace bustub
Loading
Loading