Skip to content
Merged
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
3 changes: 3 additions & 0 deletions src/binder/statement/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub struct BoundSelect {
pub limit: Option<BoundExpr>,
pub offset: Option<BoundExpr>,
pub order_by: Vec<BoundOrderBy>,
pub select_distinct: bool,
}

#[derive(Debug, Clone, PartialEq, Eq)]
Expand Down Expand Up @@ -61,6 +62,7 @@ impl Binder {
}
}
}
let select_distinct = select.distinct;

// bind where clause
let where_clause = select
Expand Down Expand Up @@ -109,6 +111,7 @@ impl Binder {
limit,
offset,
order_by,
select_distinct,
})
}

Expand Down
30 changes: 30 additions & 0 deletions src/planner/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,22 @@ mod planner_test {
};
use crate::optimizer::PlanNodeType;

fn build_test_select_distinct_stmt() -> BoundStatement {
let c1 = build_bound_column_ref("t", "c1");
let t = build_table_ref("t", vec!["c1", "c2"]);

BoundStatement::Select(BoundSelect {
select_list: vec![c1],
from_table: Some(t),
where_clause: None,
group_by: vec![],
limit: None,
offset: None,
order_by: vec![],
select_distinct: true,
})
}

fn build_test_select_stmt() -> BoundStatement {
let c1 = build_bound_column_ref("t", "c1");
let t = build_table_ref("t", vec!["c1", "c2"]);
Expand All @@ -49,6 +65,7 @@ mod planner_test {
limit: Some(BoundExpr::Constant(10.into())),
offset: None,
order_by: vec![],
select_distinct: false,
})
}

Expand Down Expand Up @@ -83,6 +100,7 @@ mod planner_test {
limit: None,
offset: None,
order_by: vec![],
select_distinct: false,
})
}

Expand Down Expand Up @@ -152,4 +170,16 @@ mod planner_test {

dbg!(plan_ref);
}

#[test]
fn test_plan_select_distinct_works() {
let stmt = build_test_select_distinct_stmt();
let p = Planner {};
let node = p.plan(stmt);
assert!(node.is_ok());
let plan_ref = node.unwrap();
assert_eq!(plan_ref.node_type(), PlanNodeType::LogicalProject);
assert_eq!(plan_ref.children()[0].node_type(), PlanNodeType::LogicalAgg);
dbg!(plan_ref);
}
}
5 changes: 5 additions & 0 deletions src/planner/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ impl Planner {
plan = Arc::new(LogicalAgg::new(agg, stmt.group_by, plan));
}

if stmt.select_distinct {
// convert distinct to groupby with no aggregations
plan = Arc::new(LogicalAgg::new(vec![], stmt.select_list.clone(), plan));
}

// LogicalOrder should be below LogicalProject in tree due to it could contains column_ref
if !stmt.order_by.is_empty() {
plan = Arc::new(LogicalOrder::new(stmt.order_by, plan));
Expand Down
15 changes: 15 additions & 0 deletions tests/slt/select.slt
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,18 @@ Bill CA 1 12000
Gregg CO 2 10000
John CO 3 11500
Von (empty) 4 NULL

query I
select distinct state from employee
----
CA
CO
(empty)

query II
select distinct a, b from t2
----
10 2
20 2
30 3
40 4