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

View file

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