diff --git a/core/translate/aggregation.rs b/core/translate/aggregation.rs index d23caf3ec..7eec4531f 100644 --- a/core/translate/aggregation.rs +++ b/core/translate/aggregation.rs @@ -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(()) } diff --git a/core/translate/group_by.rs b/core/translate/group_by.rs index dfb92f20a..1e52a98b5 100644 --- a/core/translate/group_by.rs +++ b/core/translate/group_by.rs @@ -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)?; diff --git a/core/translate/main_loop.rs b/core/translate/main_loop.rs index 9ce449b9e..4396842e5 100644 --- a/core/translate/main_loop.rs +++ b/core/translate/main_loop.rs @@ -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(()) } diff --git a/core/translate/order_by.rs b/core/translate/order_by.rs index 1d02639d2..db6ada538 100644 --- a/core/translate/order_by.rs +++ b/core/translate/order_by.rs @@ -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, diff --git a/core/translate/result_row.rs b/core/translate/result_row.rs index 5c76f3008..0b4b343d3 100644 --- a/core/translate/result_row.rs +++ b/core/translate/result_row.rs @@ -18,7 +18,12 @@ pub fn emit_select_result( t_ctx: &mut TranslateCtx, plan: &SelectPlan, label_on_limit_reached: Option, + offset_jump_to: Option, ) -> 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,6 +76,22 @@ 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(), @@ -78,3 +99,23 @@ pub fn emit_result_row_and_limit( } 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(()) +}