Skip to content

Commit 532b413

Browse files
authored
Merge pull request #179 from benclmnt/orderby
Partial order by support
2 parents 3e5dfe2 + 066445e commit 532b413

17 files changed

+610
-222
lines changed

COMPAT.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ This document describes the SQLite compatibility status of Limbo:
4444
| SELECT ... WHERE | Partial | |
4545
| SELECT ... WHERE ... LIKE | Yes | |
4646
| SELECT ... LIMIT | Yes | |
47-
| SELECT ... ORDER BY | No | |
47+
| SELECT ... ORDER BY | Partial | |
4848
| SELECT ... GROUP BY | No | |
4949
| SELECT ... JOIN | Partial | |
5050
| SELECT ... CROSS JOIN | Partial | |

Cargo.lock

Lines changed: 0 additions & 49 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ fallible-iterator = "0.3.0"
3434
libc = "0.2.155"
3535
log = "0.4.20"
3636
nix = { version = "0.29.0", features = ["fs"] }
37-
ordered-multimap = "0.7.1"
3837
sieve-cache = "0.1.4"
3938
sqlite3-parser = "0.11.0"
4039
thiserror = "1.0.61"

core/btree.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,8 @@ impl Cursor for BTreeCursor {
152152
Ok(())
153153
}
154154

155-
fn rowid(&self) -> Result<Ref<Option<u64>>> {
156-
Ok(self.rowid.borrow())
155+
fn rowid(&self) -> Result<Option<u64>> {
156+
Ok(*self.rowid.borrow())
157157
}
158158

159159
fn record(&self) -> Result<Ref<Option<OwnedRecord>>> {

core/expr.rs

Lines changed: 54 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use sqlite3_parser::ast::{self, Expr, UnaryOperator};
33

44
use crate::{
55
function::{Func, SingleRowFunc},
6-
schema::{Column, Schema, Table},
6+
schema::{Schema, Table, Type},
77
select::{ColumnInfo, Select, SrcTable},
88
util::normalize_ident,
99
vdbe::{BranchOffset, Insn, ProgramBuilder},
@@ -78,6 +78,7 @@ pub fn build_select<'a>(schema: &Schema, select: &'a ast::Select) -> Result<Sele
7878
column_info,
7979
src_tables: joins,
8080
limit: &select.limit,
81+
order_by: &select.order_by,
8182
exist_aggregation,
8283
where_clause,
8384
loops: Vec::new(),
@@ -98,6 +99,7 @@ pub fn build_select<'a>(schema: &Schema, select: &'a ast::Select) -> Result<Sele
9899
column_info,
99100
src_tables: Vec::new(),
100101
limit: &select.limit,
102+
order_by: &select.order_by,
101103
where_clause,
102104
exist_aggregation,
103105
loops: Vec::new(),
@@ -112,14 +114,15 @@ pub fn translate_expr(
112114
select: &Select,
113115
expr: &ast::Expr,
114116
target_register: usize,
117+
cursor_hint: Option<usize>,
115118
) -> Result<usize> {
116119
match expr {
117120
ast::Expr::Between { .. } => todo!(),
118121
ast::Expr::Binary(e1, op, e2) => {
119122
let e1_reg = program.alloc_register();
120123
let e2_reg = program.alloc_register();
121-
let _ = translate_expr(program, select, e1, e1_reg)?;
122-
let _ = translate_expr(program, select, e2, e2_reg)?;
124+
let _ = translate_expr(program, select, e1, e1_reg, cursor_hint)?;
125+
let _ = translate_expr(program, select, e2, e2_reg, cursor_hint)?;
123126

124127
match op {
125128
ast::Operator::NotEquals => {
@@ -250,7 +253,13 @@ pub fn translate_expr(
250253
// whenever a not null check succeeds, we jump to the end of the series
251254
let label_coalesce_end = program.allocate_label();
252255
for (index, arg) in args.iter().enumerate() {
253-
let reg = translate_expr(program, select, arg, target_register)?;
256+
let reg = translate_expr(
257+
program,
258+
select,
259+
arg,
260+
target_register,
261+
cursor_hint,
262+
)?;
254263
if index < args.len() - 1 {
255264
program.emit_insn_with_label_dependency(
256265
Insn::NotNull {
@@ -282,7 +291,7 @@ pub fn translate_expr(
282291
};
283292
for arg in args {
284293
let reg = program.alloc_register();
285-
let _ = translate_expr(program, select, &arg, reg)?;
294+
let _ = translate_expr(program, select, &arg, reg, cursor_hint)?;
286295
match arg {
287296
ast::Expr::Literal(_) => program.mark_last_insn_constant(),
288297
_ => {}
@@ -315,7 +324,7 @@ pub fn translate_expr(
315324
};
316325

317326
let regs = program.alloc_register();
318-
translate_expr(program, select, &args[0], regs)?;
327+
translate_expr(program, select, &args[0], regs, cursor_hint)?;
319328
program.emit_insn(Insn::Function {
320329
start_reg: regs,
321330
dest: target_register,
@@ -356,7 +365,7 @@ pub fn translate_expr(
356365

357366
for arg in args.iter() {
358367
let reg = program.alloc_register();
359-
translate_expr(program, select, arg, reg)?;
368+
translate_expr(program, select, arg, reg, cursor_hint)?;
360369
if let ast::Expr::Literal(_) = arg {
361370
program.mark_last_insn_constant();
362371
}
@@ -378,8 +387,9 @@ pub fn translate_expr(
378387
ast::Expr::FunctionCallStar { .. } => todo!(),
379388
ast::Expr::Id(ident) => {
380389
// let (idx, col) = table.unwrap().get_column(&ident.0).unwrap();
381-
let (idx, col, cursor_id) = resolve_ident_table(program, &ident.0, select)?;
382-
if col.primary_key {
390+
let (idx, col_type, cursor_id, is_primary_key) =
391+
resolve_ident_table(program, &ident.0, select, cursor_hint)?;
392+
if is_primary_key {
383393
program.emit_insn(Insn::RowId {
384394
cursor_id,
385395
dest: target_register,
@@ -391,7 +401,7 @@ pub fn translate_expr(
391401
cursor_id,
392402
});
393403
}
394-
maybe_apply_affinity(col, target_register, program);
404+
maybe_apply_affinity(col_type, target_register, program);
395405
Ok(target_register)
396406
}
397407
ast::Expr::InList { .. } => todo!(),
@@ -439,8 +449,9 @@ pub fn translate_expr(
439449
ast::Expr::NotNull(_) => todo!(),
440450
ast::Expr::Parenthesized(_) => todo!(),
441451
ast::Expr::Qualified(tbl, ident) => {
442-
let (idx, col, cursor_id) = resolve_ident_qualified(program, &tbl.0, &ident.0, select)?;
443-
if col.primary_key {
452+
let (idx, col_type, cursor_id, is_primary_key) =
453+
resolve_ident_qualified(program, &tbl.0, &ident.0, select, cursor_hint)?;
454+
if is_primary_key {
444455
program.emit_insn(Insn::RowId {
445456
cursor_id,
446457
dest: target_register,
@@ -452,7 +463,7 @@ pub fn translate_expr(
452463
cursor_id,
453464
});
454465
}
455-
maybe_apply_affinity(col, target_register, program);
466+
maybe_apply_affinity(col_type, target_register, program);
456467
Ok(target_register)
457468
}
458469
ast::Expr::Raise(_, _) => todo!(),
@@ -563,7 +574,8 @@ pub fn resolve_ident_qualified<'a>(
563574
table_name: &String,
564575
ident: &String,
565576
select: &'a Select,
566-
) -> Result<(usize, &'a Column, usize)> {
577+
cursor_hint: Option<usize>,
578+
) -> Result<(usize, Type, usize, bool)> {
567579
for join in &select.src_tables {
568580
match join.table {
569581
Table::BTree(ref table) => {
@@ -579,8 +591,8 @@ pub fn resolve_ident_qualified<'a>(
579591
.find(|(_, col)| col.name == *ident);
580592
if res.is_some() {
581593
let (idx, col) = res.unwrap();
582-
let cursor_id = program.resolve_cursor_id(&table_identifier);
583-
return Ok((idx, col, cursor_id));
594+
let cursor_id = program.resolve_cursor_id(&table_identifier, cursor_hint);
595+
return Ok((idx, col.ty, cursor_id, col.primary_key));
584596
}
585597
}
586598
}
@@ -598,7 +610,8 @@ pub fn resolve_ident_table<'a>(
598610
program: &ProgramBuilder,
599611
ident: &String,
600612
select: &'a Select,
601-
) -> Result<(usize, &'a Column, usize)> {
613+
cursor_hint: Option<usize>,
614+
) -> Result<(usize, Type, usize, bool)> {
602615
let mut found = Vec::new();
603616
for join in &select.src_tables {
604617
match join.table {
@@ -611,11 +624,29 @@ pub fn resolve_ident_table<'a>(
611624
.columns
612625
.iter()
613626
.enumerate()
614-
.find(|(_, col)| col.name == *ident);
627+
.find(|(_, col)| col.name == *ident)
628+
.map(|(idx, col)| (idx, col.ty, col.primary_key));
629+
let mut idx;
630+
let mut col_type;
631+
let mut is_primary_key;
615632
if res.is_some() {
616-
let (idx, col) = res.unwrap();
617-
let cursor_id = program.resolve_cursor_id(&table_identifier);
618-
found.push((idx, col, cursor_id));
633+
(idx, col_type, is_primary_key) = res.unwrap();
634+
// overwrite if cursor hint is provided
635+
if let Some(cursor_hint) = cursor_hint {
636+
let cols = &program.cursor_ref[cursor_hint].1;
637+
if let Some(res) = cols.as_ref().and_then(|res| {
638+
res.columns()
639+
.iter()
640+
.enumerate()
641+
.find(|x| x.1.name == *ident)
642+
}) {
643+
idx = res.0;
644+
col_type = res.1.ty;
645+
is_primary_key = res.1.primary_key;
646+
}
647+
}
648+
let cursor_id = program.resolve_cursor_id(&table_identifier, cursor_hint);
649+
found.push((idx, col_type, cursor_id, is_primary_key));
619650
}
620651
}
621652
Table::Pseudo(_) => todo!(),
@@ -631,8 +662,8 @@ pub fn resolve_ident_table<'a>(
631662
anyhow::bail!("Parse error: ambiguous column name {}", ident.as_str());
632663
}
633664

634-
pub fn maybe_apply_affinity(col: &Column, target_register: usize, program: &mut ProgramBuilder) {
635-
if col.ty == crate::schema::Type::Real {
665+
pub fn maybe_apply_affinity(col_type: Type, target_register: usize, program: &mut ProgramBuilder) {
666+
if col_type == crate::schema::Type::Real {
636667
program.emit_insn(Insn::RealAffinity {
637668
register: target_register,
638669
})

core/function.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ impl ToString for SingleRowFunc {
5656
}
5757
}
5858

59+
#[derive(Debug)]
5960
pub enum Func {
6061
Agg(AggFunc),
6162
SingleRow(SingleRowFunc),

core/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ mod expr;
44
mod function;
55
mod io;
66
mod pager;
7+
mod pseudo;
78
mod schema;
89
mod select;
910
mod sorter;

core/pseudo.rs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
use anyhow::Result;
2+
use std::cell::{Ref, RefCell};
3+
4+
use crate::types::{Cursor, CursorResult, OwnedRecord, OwnedValue};
5+
6+
pub struct PseudoCursor {
7+
current: RefCell<Option<OwnedRecord>>,
8+
}
9+
10+
impl PseudoCursor {
11+
pub fn new() -> Self {
12+
Self {
13+
current: RefCell::new(None),
14+
}
15+
}
16+
}
17+
18+
impl Cursor for PseudoCursor {
19+
fn is_empty(&self) -> bool {
20+
self.current.borrow().is_none()
21+
}
22+
23+
fn rewind(&mut self) -> Result<CursorResult<()>> {
24+
*self.current.borrow_mut() = None;
25+
Ok(CursorResult::Ok(()))
26+
}
27+
28+
fn next(&mut self) -> Result<CursorResult<()>> {
29+
*self.current.borrow_mut() = None;
30+
Ok(CursorResult::Ok(()))
31+
}
32+
33+
fn wait_for_completion(&mut self) -> Result<()> {
34+
Ok(())
35+
}
36+
37+
fn rowid(&self) -> Result<Option<u64>> {
38+
let x = self
39+
.current
40+
.borrow()
41+
.as_ref()
42+
.map(|record| match record.values[0] {
43+
OwnedValue::Integer(rowid) => rowid as u64,
44+
_ => panic!("Expected integer value"),
45+
});
46+
Ok(x)
47+
}
48+
49+
fn record(&self) -> Result<Ref<Option<OwnedRecord>>> {
50+
Ok(self.current.borrow())
51+
}
52+
53+
fn insert(&mut self, record: &OwnedRecord) -> Result<()> {
54+
*self.current.borrow_mut() = Some(record.clone());
55+
Ok(())
56+
}
57+
58+
fn get_null_flag(&self) -> bool {
59+
false
60+
}
61+
62+
fn set_null_flag(&mut self, _null_flag: bool) {
63+
// Do nothing
64+
}
65+
}

0 commit comments

Comments
 (0)