simpify values when it's subquery

This commit is contained in:
meteorgan 2025-05-23 17:45:56 +08:00
parent 34e05ef974
commit 01c8a4ca63
2 changed files with 92 additions and 52 deletions

View file

@ -11,25 +11,60 @@ pub fn emit_values(
plan: &SelectPlan, plan: &SelectPlan,
resolver: &Resolver, resolver: &Resolver,
) -> Result<usize> { ) -> Result<usize> {
let values = &plan.values; if plan.values.len() == 1 {
if values.len() == 1 { let start_reg = emit_values_when_single_row(program, plan, resolver)?;
let first_row = &values[0];
let row_len = first_row.len();
let start_reg = program.alloc_registers(row_len);
for (i, v) in first_row.iter().enumerate() {
translate_expr_no_constant_opt(
program,
None,
&v,
start_reg + i,
resolver,
NoConstantOptReason::RegisterReuse,
)?;
}
emit_result_row(program, plan, start_reg, row_len)?;
return Ok(start_reg); return Ok(start_reg);
} }
let reg_result_cols_start = match plan.query_type {
SelectQueryType::TopLevel => emit_toplevel_values(program, plan, resolver)?,
SelectQueryType::Subquery { yield_reg, .. } => {
emit_values_in_subquery(program, plan, resolver, yield_reg)?
}
};
Ok(reg_result_cols_start)
}
fn emit_values_when_single_row(
program: &mut ProgramBuilder,
plan: &SelectPlan,
resolver: &Resolver,
) -> Result<usize> {
let first_row = &plan.values[0];
let row_len = first_row.len();
let start_reg = program.alloc_registers(row_len);
for (i, v) in first_row.iter().enumerate() {
translate_expr_no_constant_opt(
program,
None,
&v,
start_reg + i,
resolver,
NoConstantOptReason::RegisterReuse,
)?;
}
match plan.query_type {
SelectQueryType::TopLevel => {
program.emit_insn(Insn::ResultRow {
start_reg,
count: row_len,
});
}
SelectQueryType::Subquery { yield_reg, .. } => {
program.emit_insn(Insn::Yield {
yield_reg,
end_offset: BranchOffset::Offset(0),
});
}
}
Ok(start_reg)
}
fn emit_toplevel_values(
program: &mut ProgramBuilder,
plan: &SelectPlan,
resolver: &Resolver,
) -> Result<usize> {
let yield_reg = program.alloc_register(); let yield_reg = program.alloc_register();
let definition_label = program.allocate_label(); let definition_label = program.allocate_label();
let start_offset_label = program.allocate_label(); let start_offset_label = program.allocate_label();
@ -38,26 +73,10 @@ pub fn emit_values(
jump_on_definition: definition_label, jump_on_definition: definition_label,
start_offset: start_offset_label, start_offset: start_offset_label,
}); });
program.preassign_label_to_next_insn(start_offset_label); program.preassign_label_to_next_insn(start_offset_label);
let row_len = values[0].len();
let start_reg = program.alloc_registers(row_len); let start_reg = emit_values_in_subquery(program, plan, resolver, yield_reg)?;
for value in values {
for (i, v) in value.iter().enumerate() {
translate_expr_no_constant_opt(
program,
None,
&v,
start_reg + i,
resolver,
NoConstantOptReason::RegisterReuse,
)?;
}
program.emit_insn(Insn::Yield {
yield_reg,
end_offset: BranchOffset::Offset(0),
});
}
program.emit_insn(Insn::EndCoroutine { yield_reg }); program.emit_insn(Insn::EndCoroutine { yield_reg });
program.preassign_label_to_next_insn(definition_label); program.preassign_label_to_next_insn(definition_label);
@ -73,6 +92,7 @@ pub fn emit_values(
yield_reg, yield_reg,
end_offset: end_label, end_offset: end_label,
}); });
let row_len = plan.values[0].len();
let copy_start_reg = program.alloc_registers(row_len); let copy_start_reg = program.alloc_registers(row_len);
for i in 0..row_len { for i in 0..row_len {
program.emit_insn(Insn::Copy { program.emit_insn(Insn::Copy {
@ -81,7 +101,11 @@ pub fn emit_values(
amount: 0, amount: 0,
}); });
} }
emit_result_row(program, plan, copy_start_reg, row_len)?;
program.emit_insn(Insn::ResultRow {
start_reg: copy_start_reg,
count: row_len,
});
program.emit_insn(Insn::Goto { program.emit_insn(Insn::Goto {
target_pc: goto_label, target_pc: goto_label,
}); });
@ -90,23 +114,30 @@ pub fn emit_values(
Ok(copy_start_reg) Ok(copy_start_reg)
} }
fn emit_result_row( fn emit_values_in_subquery(
program: &mut ProgramBuilder, program: &mut ProgramBuilder,
plan: &SelectPlan, plan: &SelectPlan,
start_reg: usize, resolver: &Resolver,
count: usize, yield_reg: usize,
) -> Result<()> { ) -> Result<usize> {
match plan.query_type { let row_len = plan.values[0].len();
SelectQueryType::TopLevel => { let start_reg = program.alloc_registers(row_len);
program.emit_insn(Insn::ResultRow { start_reg, count }); for value in &plan.values {
Ok(()) for (i, v) in value.iter().enumerate() {
} translate_expr_no_constant_opt(
SelectQueryType::Subquery { yield_reg, .. } => { program,
program.emit_insn(Insn::Yield { None,
yield_reg, &v,
end_offset: BranchOffset::Offset(0), start_reg + i,
}); resolver,
Ok(()) NoConstantOptReason::RegisterReuse,
)?;
} }
program.emit_insn(Insn::Yield {
yield_reg,
end_offset: BranchOffset::Offset(0),
});
} }
Ok(start_reg)
} }

View file

@ -12,8 +12,17 @@ do_execsql_test values-2 {
} {1|2 } {1|2
3|4}; 3|4};
do_execsql_test values-3 {
values(1+1, 2*3);
} {2|6};
do_execsql_test values-in-from { do_execsql_test values-in-from {
select * from (values(3, 4, 5), (5, 6, 7), (8, 9, 10)); select * from (values(3, 4, 5), (5, 6, 7), (8, 9, 10));
} {3|4|5 } {3|4|5
5|6|7 5|6|7
8|9|10}; 8|9|10};
do_execsql_test values-in-join {
select * from (values(1, 2)) join (values(3, 4), (5, 6));
} {1|2|3|4
1|2|5|6};