From 588092f21da461da5e825acc01bcac10e61bea30 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 20 Aug 2026 14:28:03 +0300 Subject: [PATCH 1/3] gh-156101: Fix sqlite3 Cursor.arraysize on a failed assignment PyLong_AsUInt32() stores 0 in the target on error, so the attribute was clobbered when the assigned value was too large. --- Lib/test/test_sqlite3/test_dbapi.py | 2 ++ .../Library/2026-08-20-12-10-00.gh-issue-156101.Qb2xNv.rst | 3 +++ Modules/_sqlite/cursor.c | 7 ++++++- 3 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-08-20-12-10-00.gh-issue-156101.Qb2xNv.rst diff --git a/Lib/test/test_sqlite3/test_dbapi.py b/Lib/test/test_sqlite3/test_dbapi.py index c21448a92361d7..ebb146280ecfc8 100644 --- a/Lib/test/test_sqlite3/test_dbapi.py +++ b/Lib/test/test_sqlite3/test_dbapi.py @@ -1078,6 +1078,8 @@ def test_invalid_array_size(self): self.assertRaises(TypeError, setter, 1.0) self.assertRaises(ValueError, setter, -3) self.assertRaises(OverflowError, setter, UINT32_MAX + 1) + # a failed assignment does not change the value + self.assertEqual(self.cu.arraysize, 1) def test_fetchmany(self): # no active SQL statement diff --git a/Misc/NEWS.d/next/Library/2026-08-20-12-10-00.gh-issue-156101.Qb2xNv.rst b/Misc/NEWS.d/next/Library/2026-08-20-12-10-00.gh-issue-156101.Qb2xNv.rst new file mode 100644 index 00000000000000..817f4a7207d7fa --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-08-20-12-10-00.gh-issue-156101.Qb2xNv.rst @@ -0,0 +1,3 @@ +Fix :attr:`sqlite3.Cursor.arraysize` being set to 0 if the assigned value is +too large. +The attribute is now left unchanged if the assignment fails. diff --git a/Modules/_sqlite/cursor.c b/Modules/_sqlite/cursor.c index 5a61e43617984d..3778ccd32fe4c4 100644 --- a/Modules/_sqlite/cursor.c +++ b/Modules/_sqlite/cursor.c @@ -1378,7 +1378,12 @@ static int _sqlite3_Cursor_arraysize_set_impl(pysqlite_Cursor *self, PyObject *value) /*[clinic end generated code: output=af59a6b09f8cce6e input=ace48cb114e26060]*/ { - return PyLong_AsUInt32(value, &self->arraysize); + uint32_t arraysize; + if (PyLong_AsUInt32(value, &arraysize) < 0) { + return -1; + } + self->arraysize = arraysize; + return 0; } static PyMethodDef cursor_methods[] = { From 9ffd62d017841f00edac78b2c991214f2a39e37c Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 20 Aug 2026 14:51:11 +0300 Subject: [PATCH 2/3] Check that a failed assignment does not change the value --- Lib/test/test_sqlite3/test_dbapi.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_sqlite3/test_dbapi.py b/Lib/test/test_sqlite3/test_dbapi.py index ebb146280ecfc8..9cf1ee3d39a064 100644 --- a/Lib/test/test_sqlite3/test_dbapi.py +++ b/Lib/test/test_sqlite3/test_dbapi.py @@ -1075,11 +1075,13 @@ def test_invalid_array_size(self): UINT32_MAX = (1 << 32) - 1 setter = functools.partial(setattr, self.cu, 'arraysize') + self.cu.arraysize = 2 self.assertRaises(TypeError, setter, 1.0) self.assertRaises(ValueError, setter, -3) self.assertRaises(OverflowError, setter, UINT32_MAX + 1) + self.assertRaises(ValueError, setter, -(UINT32_MAX + 1)) # a failed assignment does not change the value - self.assertEqual(self.cu.arraysize, 1) + self.assertEqual(self.cu.arraysize, 2) def test_fetchmany(self): # no active SQL statement From ebd1811d232e480b4bdd1dedfd295f3e185a6dc6 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 20 Aug 2026 15:06:46 +0300 Subject: [PATCH 3/3] Test values which do not fit in any C integer type --- Lib/test/test_sqlite3/test_dbapi.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_sqlite3/test_dbapi.py b/Lib/test/test_sqlite3/test_dbapi.py index 9cf1ee3d39a064..375f12e8d4791d 100644 --- a/Lib/test/test_sqlite3/test_dbapi.py +++ b/Lib/test/test_sqlite3/test_dbapi.py @@ -1079,7 +1079,8 @@ def test_invalid_array_size(self): self.assertRaises(TypeError, setter, 1.0) self.assertRaises(ValueError, setter, -3) self.assertRaises(OverflowError, setter, UINT32_MAX + 1) - self.assertRaises(ValueError, setter, -(UINT32_MAX + 1)) + self.assertRaises(OverflowError, setter, 2**1000) + self.assertRaises(ValueError, setter, -2**1000) # a failed assignment does not change the value self.assertEqual(self.cu.arraysize, 2)