Skip to content

Commit

Permalink
test: add many e2e test
Browse files Browse the repository at this point in the history
- insert.slt
- join_left_inner.slt
- limit.slt
- where.slt

tips: fix `limit` operator
  • Loading branch information
KKould committed Oct 13, 2023
1 parent b6700ac commit 863b2ae
Show file tree
Hide file tree
Showing 8 changed files with 301 additions and 32 deletions.
26 changes: 9 additions & 17 deletions src/binder/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use crate::planner::operator::join::JoinCondition;
use crate::planner::operator::sort::{SortField, SortOperator};
use crate::planner::LogicalPlan;
use crate::storage::Transaction;
use crate::types::errors::TypeError;
use crate::types::LogicalType;
use itertools::Itertools;
use sqlparser::ast;
Expand Down Expand Up @@ -178,7 +179,6 @@ impl<'a, T: Transaction> Binder<'a, T> {
if tables.len() > 1 {
todo!("Implement virtual tables for multiple table aliases");
}
// FIXME
self.context
.add_table_alias(alias.to_string(), tables.remove(0))?;

Expand Down Expand Up @@ -366,19 +366,15 @@ impl<'a, T: Transaction> Binder<'a, T> {
limit_expr: &Option<Expr>,
offset_expr: &Option<Offset>,
) -> Result<LogicalPlan, BindError> {
let mut limit = 0;
let mut offset = 0;
let mut limit = None;
let mut offset = None;
if let Some(expr) = limit_expr {
let expr = self.bind_expr(expr)?;
match expr {
ScalarExpression::Constant(dv) => match dv.as_ref() {
DataValue::Int32(Some(v)) if *v > 0 => limit = *v as usize,
DataValue::Int64(Some(v)) if *v > 0 => limit = *v as usize,
_ => {
return Err(BindError::InvalidColumn(
"invalid limit expression.".to_owned(),
))
}
DataValue::Int32(Some(v)) if *v >= 0 => limit = Some(*v as usize),
DataValue::Int64(Some(v)) if *v >= 0 => limit = Some(*v as usize),
_ => return Err(BindError::from(TypeError::InvalidType)),
},
_ => {
return Err(BindError::InvalidColumn(
Expand All @@ -392,13 +388,9 @@ impl<'a, T: Transaction> Binder<'a, T> {
let expr = self.bind_expr(&expr.value)?;
match expr {
ScalarExpression::Constant(dv) => match dv.as_ref() {
DataValue::Int32(Some(v)) if *v > 0 => offset = *v as usize,
DataValue::Int64(Some(v)) if *v > 0 => offset = *v as usize,
_ => {
return Err(BindError::InvalidColumn(
"invalid limit expression.".to_owned(),
))
}
DataValue::Int32(Some(v)) if *v > 0 => offset = Some(*v as usize),
DataValue::Int64(Some(v)) if *v > 0 => offset = Some(*v as usize),
_ => return Err(BindError::from(TypeError::InvalidType)),
},
_ => {
return Err(BindError::InvalidColumn(
Expand Down
4 changes: 2 additions & 2 deletions src/execution/executor/dql/limit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ pub struct Limit {
impl From<(LimitOperator, BoxedExecutor)> for Limit {
fn from((LimitOperator { offset, limit }, input): (LimitOperator, BoxedExecutor)) -> Self {
Limit {
offset: Some(offset),
limit: Some(limit),
offset,
limit,
input,
}
}
Expand Down
35 changes: 25 additions & 10 deletions src/optimizer/rule/pushdown_limit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,10 @@ impl Rule for EliminateLimits {
if let Operator::Limit(op) = graph.operator(node_id) {
let child_id = graph.children_at(node_id)[0];
if let Operator::Limit(child_op) = graph.operator(child_id) {
let new_limit_op = LimitOperator {
offset: op.offset + child_op.offset,
limit: cmp::min(op.limit, child_op.limit),
};
let offset = Self::binary_options(op.offset, child_op.offset, |a, b| a + b);
let limit = Self::binary_options(op.limit, child_op.limit, |a, b| cmp::min(a, b));

let new_limit_op = LimitOperator { offset, limit };

graph.remove_node(child_id, false);
graph.replace_node(
Expand All @@ -92,6 +92,21 @@ impl Rule for EliminateLimits {
}
}

impl EliminateLimits {
fn binary_options<F: Fn(usize, usize) -> usize>(
a: Option<usize>,
b: Option<usize>,
_fn: F,
) -> Option<usize> {
match (a, b) {
(Some(a), Some(b)) => Some(_fn(a, b)),
(Some(a), None) => Some(a),
(None, Some(b)) => Some(b),
(None, None) => None,
}
}
}

/// Add extra limits below JOIN:
/// 1. For LEFT OUTER and RIGHT OUTER JOIN, we push limits to the left and right sides,
/// respectively.
Expand Down Expand Up @@ -147,7 +162,7 @@ impl Rule for PushLimitIntoScan {
if let Operator::Scan(scan_op) = graph.operator(child_index) {
let mut new_scan_op = scan_op.clone();

new_scan_op.limit = (Some(limit_op.offset), Some(limit_op.limit));
new_scan_op.limit = (limit_op.offset, limit_op.limit);

graph.remove_node(node_id, false);
graph.replace_node(
Expand Down Expand Up @@ -208,8 +223,8 @@ mod tests {
);

let new_limit_op = LimitOperator {
offset: 2,
limit: 1,
offset: Some(2),
limit: Some(1),
};

optimizer
Expand All @@ -219,8 +234,8 @@ mod tests {
let best_plan = optimizer.find_best()?;

if let Operator::Limit(op) = &best_plan.operator {
assert_eq!(op.limit, 1);
assert_eq!(op.offset, 3);
assert_eq!(op.limit, Some(1));
assert_eq!(op.offset, Some(3));
} else {
unreachable!("Should be a project operator")
}
Expand Down Expand Up @@ -253,7 +268,7 @@ mod tests {
}

if let Operator::Limit(op) = &best_plan.childrens[0].childrens[0].childrens[0].operator {
assert_eq!(op.limit, 1);
assert_eq!(op.limit, Some(1));
} else {
unreachable!("Should be a limit operator")
}
Expand Down
6 changes: 3 additions & 3 deletions src/planner/operator/limit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ use super::Operator;

#[derive(Debug, PartialEq, Clone)]
pub struct LimitOperator {
pub offset: usize,
pub limit: usize,
pub offset: Option<usize>,
pub limit: Option<usize>,
}

impl LimitOperator {
pub fn new(offset: usize, limit: usize, children: LogicalPlan) -> LogicalPlan {
pub fn new(offset: Option<usize>, limit: Option<usize>, children: LogicalPlan) -> LogicalPlan {
LogicalPlan {
operator: Operator::Limit(LimitOperator { offset, limit }),
childrens: vec![children],
Expand Down
33 changes: 33 additions & 0 deletions tests/slt/insert.slt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
statement ok
create table t(id int primary key, v1 int null, v2 int null, v3 int null)

statement ok
insert into t values (0,1,10,100)

statement ok
insert into t values (1,1,10,100), (2,2,20,200), (3,3,30,300), (4,4,40,400)

statement ok
insert into t(id, v1, v2, v3) values (5, 1,10,100)

statement ok
insert into t(id, v1, v2) values (6,1,10)

statement ok
insert into t(id, v2, v1) values (7,1,10)

statement ok
insert into t values (8,NULL,NULL,NULL)

query III rowsort
select * from t
----
0 1 10 100
1 1 10 100
2 2 20 200
3 3 30 300
4 4 40 400
5 1 10 100
6 1 10 null
7 10 1 null
8 null null null
93 changes: 93 additions & 0 deletions tests/slt/join_left_inner.slt
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
statement ok
create table x(id int primary key, a int, b int);

statement ok
create table y(id int primary key, c int, d int);

statement ok
insert into x values (0, 1, 2), (1, 1, 3);

query IIII
select a, b, c, d from x join y on a = c;
----

statement ok
insert into y values (0, 1, 5), (1, 1, 6), (2, 2, 7);

query IIII
select a, b, c, d from x join y on a = c;
----
1 2 1 5
1 3 1 5
1 2 1 6
1 3 1 6

statement ok
drop table x;

statement ok
drop table y;

statement ok
create table a(id int primary key, v1 int, v2 int);

statement ok
create table b(id int primary key, v3 int, v4 int);

statement ok
insert into a values (0, 1, 1), (1, 2, 2), (2, 3, 3);

query IIII rowsort
select v1, v2, v3, v4 from a left join b on v1 = v3;
----
1 1 null null
2 2 null null
3 3 null null

statement ok
insert into b values (0, 1, 100), (1, 3, 300), (2, 4, 400);

query IIII rowsort
select v1, v2, v3, v4 from a left join b on v1 = v3;
----
1 1 1 100
2 2 null null
3 3 3 300

statement ok
drop table a;

statement ok
drop table b;

statement ok
create table a(id int primary key, v1 int, v2 int);

statement ok
create table b(id int primary key, v3 int, v4 int, v5 int);

statement ok
insert into a values (0, 1, 1), (1, 2, 2), (2, 3, 3);

statement ok
insert into b values (0, 1, 1, 1), (1, 2, 2, 2), (2, 3, 3, 4), (3, 1, 1, 5);

query IIIII
select v1, v2, v3, v4, v5 from a join b on v1 = v3 and v2 = v4;
----
1 1 1 1 1
2 2 2 2 2
3 3 3 3 4
1 1 1 1 5

query IIIII
select v1, v2, v3, v4, v5 from a join b on v1 = v3 and v2 = v4 and v1 < v5;
----
3 3 3 3 4
1 1 1 1 5

statement ok
drop table a;

statement ok
drop table b;
50 changes: 50 additions & 0 deletions tests/slt/limit.slt
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
statement ok
create table t(id int primary key, v1 int not null, v2 int not null)

statement ok
insert into t values (0, 1, 1), (1, 4, 2), (2, 3, 3), (3, 10, 12), (4, 2, 5)

query I
select v1 from t limit 3
----
1
4
3

query I
select v1 from t offset 2
----
3
10
2

query I
select v1 from t limit 2 offset 2
----
3
10

query I
select v1 from t limit 6
----
1
4
3
10
2

query I
select v1 from t limit 0
----

query I
select v1 from t offset 5
----

# test case for https://github.com/risinglightdb/risinglight/issues/264
statement ok
insert into t values (5, 1, 1)

query I
select v1 from t limit 0
----
Loading

0 comments on commit 863b2ae

Please sign in to comment.