fix+refactor: incorrect label placement

also added a `cursor_loop` helper on `ProgramBuilder` to avoid making
this mistake in the future. this is zero-cost, and will be optimized to
the same thing (hopefully).
This commit is contained in:
Levy A. 2025-05-21 16:15:55 -03:00
parent 6d0a3c95c6
commit 6945c0c09e
3 changed files with 73 additions and 54 deletions

View file

@ -188,9 +188,6 @@ pub fn translate_inner(
syms,
program,
|program| {
let loop_start = program.allocate_label();
let loop_end = program.allocate_label();
let column_count = btree.columns.len();
let root_page = btree.root_page;
let table_name = btree.name.clone();
@ -205,62 +202,50 @@ pub fn translate_inner(
name: table_name.clone(),
});
program.emit_insn(Insn::Rewind {
cursor_id,
pc_if_empty: loop_end,
});
program.cursor_loop(cursor_id, |program| {
let rowid = program.alloc_register();
let rowid = program.alloc_register();
program.emit_insn(Insn::RowId {
cursor_id,
dest: rowid,
});
program.preassign_label_to_next_insn(loop_start);
let first_column = program.alloc_registers(column_count);
let mut iter = first_column;
for i in 0..(column_count + 1) {
if i == dropped_col {
continue;
}
program.emit_insn(Insn::Column {
program.emit_insn(Insn::RowId {
cursor_id,
column: i,
dest: iter,
dest: rowid,
});
iter += 1;
}
let first_column = program.alloc_registers(column_count);
let record = program.alloc_register();
let mut iter = first_column;
program.emit_insn(Insn::MakeRecord {
start_reg: first_column,
count: column_count,
dest_reg: record,
index_name: None,
for i in 0..(column_count + 1) {
if i == dropped_col {
continue;
}
program.emit_insn(Insn::Column {
cursor_id,
column: i,
dest: iter,
});
iter += 1;
}
let record = program.alloc_register();
program.emit_insn(Insn::MakeRecord {
start_reg: first_column,
count: column_count,
dest_reg: record,
index_name: None,
});
program.emit_insn(Insn::Insert {
cursor: cursor_id,
key_reg: rowid,
record_reg: record,
flag: 0,
table_name: table_name.clone(),
});
});
program.emit_insn(Insn::Insert {
cursor: cursor_id,
key_reg: rowid,
record_reg: record,
flag: 0,
table_name: table_name.clone(),
});
program.emit_insn(Insn::Next {
cursor_id,
pc_if_next: loop_start,
});
program.preassign_label_to_next_insn(loop_end);
program.emit_insn(Insn::ParseSchema {
db: usize::MAX, // TODO: This value is unused, change when we do something with it
where_clause: None,
@ -291,6 +276,7 @@ pub fn translate_inner(
schema,
&mut update,
syms,
program,
|program| {
program.emit_insn(Insn::ParseSchema {
db: usize::MAX, // TODO: This value is unused, change when we do something with it
@ -330,6 +316,7 @@ pub fn translate_inner(
schema,
&mut update,
syms,
program,
|program| {
program.emit_insn(Insn::ParseSchema {
db: usize::MAX, // TODO: This value is unused, change when we do something with it

View file

@ -771,6 +771,26 @@ impl ProgramBuilder {
self.table_references.contains_table(table)
}
#[inline]
pub fn cursor_loop(&mut self, cursor_id: CursorID, f: impl Fn(&mut ProgramBuilder)) {
let loop_start = self.allocate_label();
let loop_end = self.allocate_label();
self.emit_insn(Insn::Rewind {
cursor_id,
pc_if_empty: loop_end,
});
self.preassign_label_to_next_insn(loop_start);
f(self);
self.emit_insn(Insn::Next {
cursor_id,
pc_if_next: loop_start,
});
self.preassign_label_to_next_insn(loop_end);
}
pub fn build(
mut self,
database_header: Arc<SpinLock<DatabaseHeader>>,

View file

@ -32,24 +32,36 @@ do_execsql_test_on_specific_db {:memory:} alter-table-add-column {
do_execsql_test_on_specific_db {:memory:} alter-table-add-column-typed {
CREATE TABLE t(a);
ALTER TABLE t ADD b TEXT;
ALTER TABLE t ADD c INTEGER DEFAULT(0);
ALTER TABLE t ADD c INTEGER DEFAULT 0;
SELECT sql FROM sqlite_schema;
INSERT INTO t VALUES (1, 'a');
SELECT * FROM t;
} {
"CREATE TABLE t(a, b TEXT, c INTEGER DEFAULT(0))"
"1|a|0"
}
do_execsql_test_on_specific_db {:memory:} alter-table-drop-column {
CREATE TABLE t(a, b);
INSERT INTO t VALUES (1, 2);
INSERT INTO t VALUES (1, 1), (2, 2), (3, 3);
SELECT * FROM t;
ALTER TABLE t DROP b;
SELECT sql FROM sqlite_schema;
SELECT * FROM t;
} {
"1|2"
"1|1"
"2|2"
"3|3"
"CREATE TABLE t(a)"
"1"
"2"
"3"
}
do_execsql_test_in_memory_any_error fail-alter-table-drop-unique-column {