Skip to content

Commit de2163c

Browse files
committed
refactor: bind ORM queries through binder plans
1 parent 02c7378 commit de2163c

22 files changed

Lines changed: 2486 additions & 1310 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ rocksdb = ["dep:rocksdb"]
3434
unsafe_txdb_checkpoint = ["rocksdb", "dep:librocksdb-sys"]
3535
lmdb = ["dep:lmdb", "dep:lmdb-sys"]
3636
pprof = ["pprof/criterion", "pprof/flamegraph"]
37-
python = ["dep:pyo3"]
37+
python = ["parser", "dep:pyo3"]
3838
shell = ["parser", "dep:comfy-table", "dep:rustyline"]
3939

4040
[[bench]]

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ test:
1818

1919
## Run Python binding API tests implemented with pyo3.
2020
test-python:
21-
PYO3_PYTHON=$(PYO3_PYTHON) $(CARGO) test --features python test_python_
21+
PYO3_PYTHON=$(PYO3_PYTHON) $(CARGO) test --features python,decimal test_python_
2222

2323
## Perform a `cargo check` across the workspace.
2424
cargo-check:

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ For the full ORM guide, see [`src/orm/README.md`](src/orm/README.md).
5555
```rust
5656
use kite_sql::db::DataBaseBuilder;
5757
use kite_sql::errors::DatabaseError;
58-
use kite_sql::orm::{BoundExpressionOps, OrmQueryResultExt};
58+
use kite_sql::orm::OrmQueryResultExt;
5959
use kite_sql::Model;
6060

6161
#[derive(Default, Debug, PartialEq, Model)]
@@ -114,8 +114,9 @@ fn main() -> Result<(), DatabaseError> {
114114
ctx.from::<User>()?
115115
.filter(|e| e.column(User::age())?.gte(18))?
116116
.project_scalars((User::id(), User::name()))?
117-
.asc_by(User::name())?
118-
.limit(10)
117+
.order_by(User::name())?
118+
.limit(10)?
119+
.finish()
119120
})?
120121
.project_tuple::<(i32, String)>();
121122

examples/hello_world.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
mod app {
1717
use kite_sql::db::{DataBaseBuilder, Database};
1818
use kite_sql::errors::DatabaseError;
19-
use kite_sql::orm::BoundExpressionOps;
2019
use kite_sql::storage::Storage;
2120
use kite_sql::Model;
2221
use std::env;

kite_sql_serde_macros/src/projection.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,9 @@ pub(crate) fn handle(ast: DeriveInput) -> Result<TokenStream, Error> {
9999
T: ::kite_sql::storage::Transaction,
100100
A: AsRef<[(&'static str, ::kite_sql::types::value::DataValue)]>,
101101
{
102-
Ok(::std::vec![#(#projection_exprs),*])
102+
Ok(::std::vec![
103+
#(::kite_sql::orm::IntoOrmScalarExpression::into_orm_scalar(#projection_exprs)),*
104+
])
103105
}
104106
}
105107

src/binder/expr.rs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -214,10 +214,14 @@ impl<'a, T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<'a, '_, T
214214
let (sub_query, column, correlated) =
215215
self.bind_subquery_plan_with_output(None, arena, build)?;
216216
let sub_query = ScalarSubqueryOperator::build(sub_query);
217-
let (expr, sub_query) = if !self.context.is_step(&QueryBindStep::Where) {
218-
self.bind_temp_table(column, sub_query, arena)?
219-
} else {
220-
(column, sub_query)
217+
let (expr, sub_query) = match self.context.step_now() {
218+
QueryBindStep::Where => (column, sub_query),
219+
QueryBindStep::Project => self.bind_temp_table(column, sub_query, arena)?,
220+
_ => {
221+
return Err(DatabaseError::UnsupportedStmt(
222+
"scalar subqueries can only appear in `WHERE` or SELECT list".to_string(),
223+
))
224+
}
221225
};
222226
self.context.sub_query(SubQueryType::SubQuery {
223227
plan: sub_query,
@@ -238,6 +242,12 @@ impl<'a, T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<'a, '_, T
238242
&mut PlanArena<'arena>,
239243
) -> Result<LogicalPlan, DatabaseError>,
240244
{
245+
if !self.context.is_step(&QueryBindStep::Where) {
246+
return Err(DatabaseError::UnsupportedStmt(
247+
"EXISTS subqueries can only appear in `WHERE`".to_string(),
248+
));
249+
}
250+
241251
let (sub_query, correlated) = self.bind_subquery_plan(arena, build)?;
242252
let (_, marker_ref) = self.bind_temp_table_alias(
243253
ScalarExpression::Constant(DataValue::Boolean(true)),

src/binder/mod.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,18 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
macro_rules! with_query_bind_step {
16+
($binder:expr, $step:expr, $body:block) => {{
17+
let current_step = $binder.context.step_now();
18+
$binder.context.step($step);
19+
let result = (|| -> Result<_, DatabaseError> { Ok($body) })();
20+
$binder.context.step(current_step);
21+
result
22+
}};
23+
}
24+
25+
pub(crate) use with_query_bind_step;
26+
1527
pub mod aggregate;
1628
mod alter_table;
1729
mod analyze;

src/binder/parser.rs

Lines changed: 40 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use super::select::{
1717
BindPlanHaving, BindPlanProjected, BindPlanSelectList, BindPlanStart, JoinConstraintInput,
1818
TableAliasInput,
1919
};
20-
use super::{is_valid_identifier, Binder, QueryBindStep, SetOperatorKind};
20+
use super::{is_valid_identifier, with_query_bind_step, Binder, QueryBindStep, SetOperatorKind};
2121
#[cfg(feature = "copy")]
2222
use crate::binder::copy::{ExtSource, FileFormat};
2323
use crate::catalog::{ColumnCatalog, ColumnDesc, ColumnRef, TableName};
@@ -1376,12 +1376,11 @@ where
13761376
self,
13771377
projection: Vec<SelectItem>,
13781378
) -> Result<BindPlanSelectList<'s, 'a, 'b, 'arena, T, A>, DatabaseError> {
1379-
let select_bind_step = self.binder.context.step_now();
1380-
self.binder.context.step(QueryBindStep::Project);
1381-
let select_list = self.binder.normalize_select_item(projection, self.arena)?;
1382-
self.binder.context.step(select_bind_step);
1379+
let select_list = with_query_bind_step!(self.binder, QueryBindStep::Project, {
1380+
self.binder.normalize_select_item(projection, self.arena)?
1381+
});
13831382

1384-
Ok(self.select_list(select_list))
1383+
Ok(self.select_list(select_list?))
13851384
}
13861385
}
13871386

@@ -1395,8 +1394,9 @@ where
13951394
selection: Option<Expr>,
13961395
) -> Result<BindPlanFiltered<'s, 'a, 'b, 'arena, T, A>, DatabaseError> {
13971396
let predicate = if let Some(predicate) = selection {
1398-
self.binder.context.step(QueryBindStep::Where);
1399-
Some(self.binder.bind_expr(predicate, self.arena)?)
1397+
Some(with_query_bind_step!(self.binder, QueryBindStep::Where, {
1398+
self.binder.bind_expr(predicate, self.arena)?
1399+
})?)
14001400
} else {
14011401
None
14021402
};
@@ -1416,34 +1416,42 @@ where
14161416
having: Option<Expr>,
14171417
orderby: Option<Vec<OrderByExpr>>,
14181418
) -> Result<BindPlanAggregated<'s, 'a, 'b, 'arena, T, A>, DatabaseError> {
1419-
let group_by = match group_by {
1420-
GroupByExpr::Expressions(group_by_exprs, modifiers) => {
1421-
if !modifiers.is_empty() {
1419+
let group_by = with_query_bind_step!(self.binder, QueryBindStep::Agg, {
1420+
match group_by {
1421+
GroupByExpr::Expressions(group_by_exprs, modifiers) => {
1422+
if !modifiers.is_empty() {
1423+
return Err(DatabaseError::UnsupportedStmt(
1424+
"GROUP BY modifiers are not supported".to_string(),
1425+
));
1426+
}
1427+
group_by_exprs
1428+
.into_iter()
1429+
.map(|expr| self.binder.bind_expr(expr, self.arena))
1430+
.collect::<Result<Vec<_>, DatabaseError>>()?
1431+
}
1432+
GroupByExpr::All(_) => {
14221433
return Err(DatabaseError::UnsupportedStmt(
1423-
"GROUP BY modifiers are not supported".to_string(),
1424-
));
1434+
"GROUP BY ALL is not supported".to_string(),
1435+
))
14251436
}
1426-
group_by_exprs
1427-
.into_iter()
1428-
.map(|expr| self.binder.bind_expr(expr, self.arena))
1429-
.collect::<Result<Vec<_>, DatabaseError>>()?
14301437
}
1431-
GroupByExpr::All(_) => {
1432-
return Err(DatabaseError::UnsupportedStmt(
1433-
"GROUP BY ALL is not supported".to_string(),
1434-
))
1435-
}
1436-
};
1438+
})?;
14371439
let having = having
1438-
.map(|having| self.binder.bind_expr(having, self.arena))
1440+
.map(|having| {
1441+
with_query_bind_step!(self.binder, QueryBindStep::Having, {
1442+
self.binder.bind_expr(having, self.arena)?
1443+
})
1444+
})
14391445
.transpose()?;
14401446
self.aggregate(group_by, having, orderby, |binder, arena, orderby| {
14411447
let OrderByExpr { expr, options, .. } = orderby;
1442-
Ok(SortField::new(
1443-
binder.bind_expr(expr, arena)?,
1444-
options.asc.is_none_or(|asc| asc),
1445-
options.nulls_first.unwrap_or(false),
1446-
))
1448+
with_query_bind_step!(binder, QueryBindStep::Sort, {
1449+
SortField::new(
1450+
binder.bind_expr(expr, arena)?,
1451+
options.asc.is_none_or(|asc| asc),
1452+
options.nulls_first.unwrap_or(false),
1453+
)
1454+
})
14471455
})
14481456
}
14491457
}
@@ -2570,9 +2578,9 @@ impl<'a, 'parent, T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<
25702578
predicate: Expr,
25712579
arena: &mut PlanArena,
25722580
) -> Result<LogicalPlan, DatabaseError> {
2573-
self.context.step(QueryBindStep::Where);
2574-
2575-
let predicate = self.bind_expr(predicate, arena)?;
2581+
let predicate = with_query_bind_step!(self, QueryBindStep::Where, {
2582+
self.bind_expr(predicate, arena)?
2583+
})?;
25762584

25772585
self.bind_where_expr(children, predicate, arena)
25782586
}

src/binder/select.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,27 @@ where
363363
})
364364
}
365365

366+
pub(crate) fn aggregate_without_group(self) -> Result<Self, DatabaseError> {
367+
let sorted = self
368+
.filter_expr(None)?
369+
.aggregate(
370+
Vec::new(),
371+
None,
372+
None::<Vec<SortField>>,
373+
|_binder, _arena, order| Ok(order),
374+
)?
375+
.having()?
376+
.distinct(false)?
377+
.order_by()?;
378+
Ok(BindPlanSelectList {
379+
binder: sorted.binder,
380+
arena: sorted.arena,
381+
plan: sorted.plan,
382+
select_list: sorted.select_list,
383+
_marker: std::marker::PhantomData,
384+
})
385+
}
386+
366387
pub(crate) fn having_expr(mut self, expr: ScalarExpression) -> Result<Self, DatabaseError> {
367388
self.plan = self.binder.bind_having(self.plan, expr, self.arena)?;
368389
Ok(self)
@@ -401,6 +422,9 @@ where
401422
}
402423

403424
pub fn finish(self) -> Result<LogicalPlan, DatabaseError> {
425+
if self.select_list.iter().any(ScalarExpression::has_agg_call) {
426+
return self.aggregate_without_group()?.finish();
427+
}
404428
self.binder
405429
.bind_project(self.plan, self.select_list, self.arena)
406430
}

src/expression/mod.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use crate::expression::function::scala::ScalarFunction;
1919
use crate::expression::function::table::TableFunction;
2020
use crate::expression::visitor::{walk_expr, Visitor};
2121
use crate::expression::visitor_mut::VisitorMut;
22+
use crate::planner::operator::sort::SortField;
2223
use crate::planner::{MetaArena, PlanArena};
2324
use crate::types::evaluator::{
2425
binary_create, cast_create, unary_create, BinaryEvaluatorRef, CastEvaluatorRef,
@@ -379,6 +380,22 @@ impl Visitor<'_> for HasCountStar {
379380
}
380381

381382
impl ScalarExpression {
383+
pub fn asc(self) -> SortField {
384+
SortField::from(self).asc()
385+
}
386+
387+
pub fn desc(self) -> SortField {
388+
SortField::from(self).desc()
389+
}
390+
391+
pub fn nulls_first(self) -> SortField {
392+
SortField::from(self).nulls_first()
393+
}
394+
395+
pub fn nulls_last(self) -> SortField {
396+
SortField::from(self).nulls_last()
397+
}
398+
382399
pub fn column_expr(column: ColumnRef, position: usize) -> ScalarExpression {
383400
ScalarExpression::ColumnRef { column, position }
384401
}

0 commit comments

Comments
 (0)