From 983fe4c151c3974ea1b97044da61708b91a6d92b Mon Sep 17 00:00:00 2001 From: ben594 Date: Sun, 26 Jan 2025 01:15:37 -0500 Subject: [PATCH] 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 --- core/translate/aggregation.rs | 2 +- core/translate/group_by.rs | 8 ++++++- core/translate/main_loop.rs | 12 +++++++++- core/translate/order_by.rs | 6 ++++- core/translate/result_row.rs | 41 +++++++++++++++++++++++++++++++++++ 5 files changed, 65 insertions(+), 4 deletions(-) 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(()) +}