Merge 'Fix INSERT to empty tables panic' from Kim Seon Woo

`page` from `let page = page.borrow()` lives while `write_complete` is running.

Ensure that `page` is dropped

https://github.com/penberg/limbo/issues/257

Closes #293
This commit is contained in:
Pekka Enberg
2024-08-19 07:35:23 +03:00
4 changed files with 58 additions and 11 deletions

View File

@@ -495,16 +495,21 @@ fn finish_read_page(
pub fn begin_write_btree_page(pager: &Pager, page: &Rc<RefCell<Page>>) -> Result<()> {
let page_source = &pager.page_io;
let page_finish = page.clone();
let page = page.borrow();
let contents = page.contents.read().unwrap();
let contents = contents.as_ref().unwrap();
let buffer = contents.buffer.clone();
let page_id = page.borrow().id;
let buffer = {
let page = page.borrow();
let contents = page.contents.read().unwrap();
let contents = contents.as_ref().unwrap();
contents.buffer.clone()
};
let write_complete = {
let buf_copy = buffer.clone();
Box::new(move |bytes_written: i32| {
let buf_copy = buf_copy.clone();
let buf_len = buf_copy.borrow().len();
page_finish.borrow_mut().clear_dirty();
if bytes_written < buf_len as i32 {
log::error!("wrote({bytes_written}) less than expected({buf_len})");
@@ -512,7 +517,7 @@ pub fn begin_write_btree_page(pager: &Pager, page: &Rc<RefCell<Page>>) -> Result
})
};
let c = Rc::new(Completion::Write(WriteCompletion::new(write_complete)));
page_source.write_page(page.id, buffer.clone(), c)?;
page_source.write_page(page_id, buffer.clone(), c)?;
Ok(())
}

View File

@@ -6,10 +6,12 @@ source $testdir/cmdlineshell.test
source $testdir/agg-functions.test
source $testdir/coalesce.test
source $testdir/join.test
source $testdir/pragma.test
source $testdir/select.test
source $testdir/where.test
source $testdir/like.test
source $testdir/scalar-functions.test
source $testdir/orderby.test
source $testdir/insert.test
source $testdir/join.test
source $testdir/json.test
source $testdir/like.test
source $testdir/orderby.test
source $testdir/pragma.test
source $testdir/scalar-functions.test
source $testdir/select.test
source $testdir/where.test

4
testing/insert.test Executable file
View File

@@ -0,0 +1,4 @@
#!/usr/bin/env tclsh
set testdir [file dirname $argv0]
source $testdir/tester.tcl

View File

@@ -16,9 +16,45 @@ proc run_test {sqlite_exec sql expected_output} {
}
}
proc run_test_check_err_msg {sqlite_exec sql expected_err_msg} {
set actual_output [catch {set actual_output [evaluate_sql $sqlite_exec $sql]} err_msg]
if {[string first $expected_err_msg $err_msg] == -1} {
puts "Test FAILED: '$sql'"
puts "returned '$err_msg'"
puts "expected '$expected_err_msg'"
exit 1
}
}
proc run_test_with_cleanup {sqlite_exec sql expected_output cleanup_sql} {
set actual_output [evaluate_sql $sqlite_exec $sql]
if {$actual_output ne $expected_output} {
puts "Test FAILED: '$sql'"
puts "returned '$actual_output'"
puts "expected '$expected_output'"
evaluate_sql $sqlite_exec $cleanup_sql
exit 1
}
evaluate_sql $sqlite_exec $cleanup_sql
}
proc do_execsql_test {test_name sql_statements expected_outputs} {
puts "Running test: $test_name"
set combined_sql [string trim $sql_statements]
set combined_expected_output [join $expected_outputs "\n"]
run_test $::sqlite_exec $combined_sql $combined_expected_output
}
proc do_execsql_check_err_msg {test_name sql_statements expected_err_msg} {
puts "Running test: $test_name"
set combined_sql [string trim $sql_statements]
run_test_check_err_msg $::sqlite_exec $combined_sql $expected_err_msg
}
proc do_execsql_with_cleanup_test {test_name sql_statements expected_outputs cleanup_statements} {
puts "Running test: $test_name"
set combined_sql [string trim $sql_statements]
set combined_expected_output [join $expected_outputs "\n"]
set combined_cleanup [string trim $cleanup_statements]
run_test_with_cleanup $::sqlite_exec $combined_sql $combined_expected_output $combined_cleanup
}