mirror of
https://github.com/aljazceru/turso.git
synced 2026-01-21 09:04:19 +01:00
Merge 'Support indent for Goto opcode when executing explain' from meteorgan
it works as expected ``` limbo> explain insert into tb1 select * from tb2 union select * from tb3; addr opcode p1 p2 p3 p4 p5 comment ---- ----------------- ---- ---- ---- ------------- -- ------- 0 Init 0 29 0 0 Start at 29 1 InitCoroutine 1 21 2 0 2 OpenEphemeral 0 0 0 0 cursor=0 is_table=false 3 OpenRead 1 3 0 0 table=tb2, root=3 4 Rewind 1 9 0 0 Rewind table tb2 5 Column 1 0 2 0 r[2]=tb2.age 6 MakeRecord 2 1 3 0 r[3]=mkrec(r[2..2]); for union_dedupe 7 IdxInsert 0 3 0 0 key=r[3] 8 Next 1 5 0 0 9 OpenRead 2 4 0 0 table=tb3, root=4 10 Rewind 2 15 0 0 Rewind table tb3 11 Column 2 0 2 0 r[2]=tb3.age 12 MakeRecord 2 1 4 0 r[4]=mkrec(r[2..2]); for union_dedupe 13 IdxInsert 0 4 0 0 key=r[4] 14 Next 2 11 0 0 15 Rewind 0 18 0 0 Rewind union_dedupe 16 Column 0 0 2 0 r[2]=union_dedupe.age 17 Yield 1 0 0 0 18 Next 0 16 0 0 19 Close 0 0 0 0 20 EndCoroutine 1 0 0 0 21 OpenWrite 3 2 0 0 root=2; tb1 22 Yield 1 28 0 0 23 Copy 2 7 0 0 r[7]=r[2] 24 NewRowid 3 6 0 0 r[6]=rowid 25 MakeRecord 7 1 8 0 r[8]=mkrec(r[7..7]) 26 Insert 3 8 6 tb1 0 intkey=r[6] data=r[8] 27 Goto 0 22 0 0 28 Halt 0 0 0 0 29 Transaction 0 1 0 0 write=true 30 Goto 0 1 0 0 ``` Reviewed-by: Jussi Saurio <jussi.saurio@gmail.com> Closes #1775
This commit is contained in:
@@ -471,11 +471,10 @@ impl Program {
|
||||
let mut buff = String::with_capacity(1024);
|
||||
buff.push_str("addr opcode p1 p2 p3 p4 p5 comment\n");
|
||||
buff.push_str("---- ----------------- ---- ---- ---- ------------- -- -------\n");
|
||||
let mut indent_count: usize = 0;
|
||||
let indent = " ";
|
||||
let mut prev_insn: Option<&Insn> = None;
|
||||
let indent_counts = get_indent_counts(&self.insns);
|
||||
for (addr, (insn, _)) in self.insns.iter().enumerate() {
|
||||
indent_count = get_indent_count(indent_count, insn, prev_insn);
|
||||
let indent_count = indent_counts[addr];
|
||||
print_insn(
|
||||
self,
|
||||
addr as InsnReference,
|
||||
@@ -484,7 +483,6 @@ impl Program {
|
||||
&mut buff,
|
||||
);
|
||||
buff.push('\n');
|
||||
prev_insn = Some(insn);
|
||||
}
|
||||
buff
|
||||
}
|
||||
@@ -565,27 +563,63 @@ fn print_insn(program: &Program, addr: InsnReference, insn: &Insn, indent: Strin
|
||||
w.push_str(&s);
|
||||
}
|
||||
|
||||
fn get_indent_count(indent_count: usize, curr_insn: &Insn, prev_insn: Option<&Insn>) -> usize {
|
||||
let indent_count = if let Some(insn) = prev_insn {
|
||||
// The indenting rules are(from SQLite):
|
||||
//
|
||||
// * For each "Next", "Prev", "VNext" or "VPrev" instruction, increase the ident number for
|
||||
// all opcodes that occur between the p2 jump destination and the opcode itself.
|
||||
//
|
||||
// * Do the previous for "Return" instructions for when P2 is positive.
|
||||
//
|
||||
// * For each "Goto", if the jump destination is earlier in the program and ends on one of:
|
||||
// Yield SeekGt SeekLt RowSetRead Rewind
|
||||
// or if the P1 parameter is one instead of zero, then increase the indent number for all
|
||||
// opcodes between the earlier instruction and "Goto"
|
||||
fn get_indent_counts(insns: &Vec<(Insn, InsnFunction)>) -> Vec<usize> {
|
||||
let mut indents = vec![0; insns.len()];
|
||||
|
||||
for (i, (insn, _)) in insns.iter().enumerate() {
|
||||
let mut start = 0;
|
||||
let mut end = 0;
|
||||
match insn {
|
||||
Insn::Rewind { .. }
|
||||
| Insn::Last { .. }
|
||||
| Insn::SorterSort { .. }
|
||||
| Insn::SeekGE { .. }
|
||||
| Insn::SeekGT { .. }
|
||||
| Insn::SeekLE { .. }
|
||||
| Insn::SeekLT { .. } => indent_count + 1,
|
||||
Insn::Next { pc_if_next, .. } | Insn::VNext { pc_if_next, .. } => {
|
||||
let dest = pc_if_next.to_debug_int() as usize;
|
||||
if dest < i {
|
||||
start = dest;
|
||||
end = i;
|
||||
}
|
||||
}
|
||||
Insn::Prev { pc_if_prev, .. } => {
|
||||
let dest = pc_if_prev.to_debug_int() as usize;
|
||||
if dest < i {
|
||||
start = dest;
|
||||
end = i;
|
||||
}
|
||||
}
|
||||
|
||||
_ => indent_count,
|
||||
Insn::Goto { target_pc } => {
|
||||
let dest = target_pc.to_debug_int() as usize;
|
||||
if dest < i
|
||||
&& matches!(
|
||||
insns.get(dest).map(|(insn, _)| insn),
|
||||
Some(Insn::Yield { .. })
|
||||
| Some(Insn::SeekGT { .. })
|
||||
| Some(Insn::SeekLT { .. })
|
||||
| Some(Insn::Rewind { .. })
|
||||
)
|
||||
{
|
||||
start = dest;
|
||||
end = i;
|
||||
}
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
for i in start..end {
|
||||
indents[i] += 1;
|
||||
}
|
||||
} else {
|
||||
indent_count
|
||||
};
|
||||
|
||||
match curr_insn {
|
||||
Insn::Next { .. } | Insn::SorterNext { .. } | Insn::Prev { .. } => indent_count - 1,
|
||||
_ => indent_count,
|
||||
}
|
||||
|
||||
indents
|
||||
}
|
||||
|
||||
pub trait FromValueRow<'a> {
|
||||
|
||||
Reference in New Issue
Block a user