Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for offset in select queries #779

Merged
merged 6 commits into from
Jan 30, 2025
Merged
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Emit Integer, OffsetLimit instructions, and emit IfPos instruction to
skip rows

Emit Integer, OffsetLimit instructions for offset, and define function to emit IfPosinstruction to skip rows

Emit IfPos instructions to handle offset for simple select

Emit IfPos to handle offset for select with order by

Moved repeated emit_offset function call into emit_select_result
ben594 committed Jan 26, 2025
commit 983fe4c151c3974ea1b97044da61708b91a6d92b
2 changes: 1 addition & 1 deletion core/translate/aggregation.rs
Original file line number Diff line number Diff line change
@@ -41,7 +41,7 @@ pub fn emit_ungrouped_aggregation<'a>(

// This always emits a ResultRow because currently it can only be used for a single row result
// Limit is None because we early exit on limit 0 and the max rows here is 1
emit_select_result(program, t_ctx, plan, None)?;
emit_select_result(program, t_ctx, plan, None, None)?;

Ok(())
}
8 changes: 7 additions & 1 deletion core/translate/group_by.rs
Original file line number Diff line number Diff line change
@@ -394,7 +394,13 @@ pub fn emit_group_by<'a>(

match &plan.order_by {
None => {
emit_select_result(program, t_ctx, plan, Some(label_group_by_end))?;
emit_select_result(
program,
t_ctx,
plan,
Some(label_group_by_end),
Some(group_by_end_without_emitting_row_label),
)?;
}
Some(_) => {
order_by_sorter_insert(program, t_ctx, plan)?;
12 changes: 11 additions & 1 deletion core/translate/main_loop.rs
Original file line number Diff line number Diff line change
@@ -705,7 +705,17 @@ fn emit_loop_source(
plan.aggregates.is_empty(),
"We should not get here with aggregates"
);
emit_select_result(program, t_ctx, plan, t_ctx.label_main_loop_end)?;
let loop_labels = *t_ctx
.labels_main_loop
.get(&plan.source.id())
.expect("source has no loop labels");
emit_select_result(
program,
t_ctx,
plan,
t_ctx.label_main_loop_end,
Some(loop_labels.next),
)?;

Ok(())
}
6 changes: 5 additions & 1 deletion core/translate/order_by.rs
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@ use super::{
emitter::TranslateCtx,
expr::translate_expr,
plan::{Direction, ResultSetColumn, SelectPlan},
result_row::emit_result_row_and_limit,
result_row::{emit_offset, emit_result_row_and_limit},
};

// Metadata for handling ORDER BY operations
@@ -63,6 +63,7 @@ pub fn emit_order_by(
let order_by = plan.order_by.as_ref().unwrap();
let result_columns = &plan.result_columns;
let sort_loop_start_label = program.allocate_label();
let sort_loop_next_label = program.allocate_label();
let sort_loop_end_label = program.allocate_label();
let mut pseudo_columns = vec![];
for (i, _) in order_by.iter().enumerate() {
@@ -117,6 +118,8 @@ pub fn emit_order_by(
});

program.resolve_label(sort_loop_start_label, program.offset());
emit_offset(program, t_ctx, plan, sort_loop_next_label)?;

program.emit_insn(Insn::SorterData {
cursor_id: sort_cursor,
dest_reg: reg_sorter_data,
@@ -138,6 +141,7 @@ pub fn emit_order_by(

emit_result_row_and_limit(program, t_ctx, plan, start_reg, Some(sort_loop_end_label))?;

program.resolve_label(sort_loop_next_label, program.offset());
program.emit_insn(Insn::SorterNext {
cursor_id: sort_cursor,
pc_if_next: sort_loop_start_label,
41 changes: 41 additions & 0 deletions core/translate/result_row.rs
Original file line number Diff line number Diff line change
@@ -18,7 +18,12 @@ pub fn emit_select_result(
t_ctx: &mut TranslateCtx,
plan: &SelectPlan,
label_on_limit_reached: Option<BranchOffset>,
offset_jump_to: Option<BranchOffset>,
) -> Result<()> {
if let (Some(jump_to), Some(_)) = (offset_jump_to, label_on_limit_reached) {
emit_offset(program, t_ctx, plan, jump_to)?;
}

let start_reg = t_ctx.reg_result_cols_start.unwrap();
for (i, rc) in plan.result_columns.iter().enumerate() {
let reg = start_reg + i;
@@ -71,10 +76,46 @@ pub fn emit_result_row_and_limit(
dest: t_ctx.reg_limit.unwrap(),
});
program.mark_last_insn_constant();

if let Some(offset) = plan.offset {
program.emit_insn(Insn::Integer {
value: offset as i64,
dest: t_ctx.reg_offset.unwrap(),
});
program.mark_last_insn_constant();

program.emit_insn(Insn::OffsetLimit {
limit_reg: t_ctx.reg_limit.unwrap(),
combined_reg: t_ctx.reg_limit_offset_sum.unwrap(),
offset_reg: t_ctx.reg_offset.unwrap(),
});
program.mark_last_insn_constant();
}

program.emit_insn(Insn::DecrJumpZero {
reg: t_ctx.reg_limit.unwrap(),
target_pc: label_on_limit_reached.unwrap(),
});
}
Ok(())
}

pub fn emit_offset(
program: &mut ProgramBuilder,
t_ctx: &mut TranslateCtx,
plan: &SelectPlan,
jump_to: BranchOffset,
) -> Result<()> {
match plan.offset {
Some(offset) if offset > 0 => {
program.add_comment(program.offset(), "OFFSET");
program.emit_insn(Insn::IfPos {
reg: t_ctx.reg_offset.unwrap(),
target_pc: jump_to,
decrement_by: 1,
});
}
_ => {}
}
Ok(())
}