Correctly implement isolation_level setter to handle deletion (#5983)

This commit is contained in:
Jiseok CHOI
2025-07-18 23:08:51 +09:00
committed by GitHub
parent 799f38baea
commit f8d03fd680
2 changed files with 27 additions and 16 deletions

View File

@@ -409,8 +409,6 @@ class RegressionTests(unittest.TestCase):
del ref
support.gc_collect()
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_del_isolation_level_segfault(self):
with self.assertRaises(AttributeError):
del self.con.isolation_level

View File

@@ -61,7 +61,10 @@ mod _sqlite {
PyInt, PyIntRef, PySlice, PyStr, PyStrRef, PyTuple, PyTupleRef, PyType, PyTypeRef,
},
convert::IntoObject,
function::{ArgCallable, ArgIterable, FsPath, FuncArgs, OptionalArg, PyComparisonValue},
function::{
ArgCallable, ArgIterable, FsPath, FuncArgs, OptionalArg, PyComparisonValue,
PySetterValue,
},
object::{Traverse, TraverseFn},
protocol::{PyBuffer, PyIterReturn, PyMappingMethods, PySequence, PySequenceMethods},
sliceable::{SaturatedSliceIter, SliceableSequenceOp},
@@ -1357,22 +1360,32 @@ mod _sqlite {
self.isolation_level.deref().map(|x| x.to_owned())
}
#[pygetset(setter)]
fn set_isolation_level(&self, val: Option<PyStrRef>, vm: &VirtualMachine) -> PyResult<()> {
if let Some(val) = &val {
begin_statement_ptr_from_isolation_level(val, vm)?;
}
fn set_isolation_level(
&self,
value: PySetterValue<Option<PyStrRef>>,
vm: &VirtualMachine,
) -> PyResult<()> {
match value {
PySetterValue::Assign(value) => {
if let Some(val_str) = &value {
begin_statement_ptr_from_isolation_level(val_str, vm)?;
}
// If setting isolation_level to None (auto-commit mode), commit any pending transaction
if val.is_none() {
let db = self.db_lock(vm)?;
if !db.is_autocommit() {
// Keep the lock and call implicit_commit directly to avoid race conditions
db.implicit_commit(vm)?;
// If setting isolation_level to None (auto-commit mode), commit any pending transaction
if value.is_none() {
let db = self.db_lock(vm)?;
if !db.is_autocommit() {
// Keep the lock and call implicit_commit directly to avoid race conditions
db.implicit_commit(vm)?;
}
}
let _ = unsafe { self.isolation_level.swap(value) };
Ok(())
}
PySetterValue::Delete => Err(vm.new_attribute_error(
"'isolation_level' attribute cannot be deleted".to_owned(),
)),
}
let _ = unsafe { self.isolation_level.swap(val) };
Ok(())
}
#[pygetset]