Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions Lib/test/test_sqlite3/test_regression.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,6 @@ def __del__(self):
con.isolation_level = value
self.assertEqual(con.isolation_level, "DEFERRED")

# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_cursor_constructor_call_check(self):
"""
Verifies that cursor methods check whether base class __init__ was
Expand Down
67 changes: 57 additions & 10 deletions stdlib/src/sqlite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1459,6 +1459,8 @@ mod _sqlite {
#[pytraverse(skip)]
rowcount: i64,
statement: Option<PyRef<Statement>>,
#[pytraverse(skip)]
closed: bool,
}

#[derive(FromArgs)]
Expand All @@ -1484,20 +1486,54 @@ mod _sqlite {
lastrowid: -1,
rowcount: -1,
statement: None,
closed: false,
})),
}
}

fn new_uninitialized(connection: PyRef<Connection>, _vm: &VirtualMachine) -> Self {
Self {
connection,
arraysize: Radium::new(1),
row_factory: PyAtomicRef::from(None),
inner: PyMutex::from(None),
}
}

#[pymethod]
fn __init__(&self, _connection: PyRef<Connection>, _vm: &VirtualMachine) -> PyResult<()> {
let mut guard = self.inner.lock();
if guard.is_some() {
// Already initialized (e.g., from a call to super().__init__)
return Ok(());
}
*guard = Some(CursorInner {
description: None,
row_cast_map: vec![],
lastrowid: -1,
rowcount: -1,
statement: None,
closed: false,
});
Ok(())
}

fn inner(&self, vm: &VirtualMachine) -> PyResult<PyMappedMutexGuard<'_, CursorInner>> {
let guard = self.inner.lock();
if guard.is_some() {
Ok(PyMutexGuard::map(guard, |x| unsafe {
x.as_mut().unwrap_unchecked()
}))
let inner_guard =
PyMutexGuard::map(guard, |x| unsafe { x.as_mut().unwrap_unchecked() });
if inner_guard.closed {
return Err(new_programming_error(
vm,
"Cannot operate on a closed cursor.".to_owned(),
));
}
Ok(inner_guard)
} else {
Err(new_programming_error(
vm,
"Cannot operate on a closed cursor.".to_owned(),
"Base Cursor.__init__ not called.".to_owned(),
))
}
}
Expand Down Expand Up @@ -1717,12 +1753,23 @@ mod _sqlite {
}

#[pymethod]
fn close(&self) {
if let Some(inner) = self.inner.lock().take()
&& let Some(stmt) = inner.statement
{
stmt.lock().reset();
fn close(&self, vm: &VirtualMachine) -> PyResult<()> {
// Check if __init__ was called
let mut guard = self.inner.lock();
if guard.is_none() {
return Err(new_programming_error(
vm,
"Base Cursor.__init__ not called.".to_owned(),
));
}

if let Some(inner) = guard.as_mut() {
if let Some(stmt) = &inner.statement {
stmt.lock().reset();
}
inner.closed = true;
}
Ok(())
}

#[pymethod]
Expand Down Expand Up @@ -1809,7 +1856,7 @@ mod _sqlite {
type Args = (PyRef<Connection>,);

fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult {
Self::new(args.0, None, vm)
Self::new_uninitialized(args.0, vm)
.into_ref_with_type(vm, cls)
.map(Into::into)
}
Expand Down
Loading