Skip to content

bpo-43369: sqlite3_column_text() and sqlite3_column_blob() failures now raise MemoryError #24723

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Mar 4, 2021
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
23 changes: 22 additions & 1 deletion Lib/sqlite3/test/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,20 @@ def __conform__(self, protocol):
def setUp(self):
self.con = sqlite.connect(":memory:", detect_types=sqlite.PARSE_DECLTYPES)
self.cur = self.con.cursor()
self.cur.execute("create table test(i int, s str, f float, b bool, u unicode, foo foo, bin blob, n1 number, n2 number(5), bad bad)")
self.cur.execute("""
create table test(
i int,
s str,
f float,
b bool,
u unicode,
foo foo,
bin blob,
n1 number,
n2 number(5),
bad bad,
cbin cblob)
""")

# override float, make them always return the same number
sqlite.converters["FLOAT"] = lambda x: 47.2
Expand All @@ -121,6 +134,7 @@ def setUp(self):
sqlite.converters["BAD"] = DeclTypesTests.BadConform
sqlite.converters["WRONG"] = lambda x: "WRONG"
sqlite.converters["NUMBER"] = float
sqlite.converters["CBLOB"] = lambda x: b"blobish"

def tearDown(self):
del sqlite.converters["FLOAT"]
Expand All @@ -129,6 +143,7 @@ def tearDown(self):
del sqlite.converters["BAD"]
del sqlite.converters["WRONG"]
del sqlite.converters["NUMBER"]
del sqlite.converters["CBLOB"]
self.cur.close()
self.con.close()

Expand Down Expand Up @@ -237,6 +252,12 @@ def test_number2(self):
# if the converter is not used, it's an int instead of a float
self.assertEqual(type(value), float)

def test_convert_zero_sized_blob(self):
self.con.execute("insert into test(cbin) values (?)", (b"",))
cur = self.con.execute("select cbin from test")
self.assertEqual(cur.fetchone()[0], b"blobish")


class ColNamesTests(unittest.TestCase):
def setUp(self):
self.con = sqlite.connect(":memory:", detect_types=sqlite.PARSE_COLNAMES)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Improve :mod:`sqlite3` error handling: If ``sqlite3_column_text()`` and
``sqlite3_column_blob()`` set ``SQLITE_NOMEM``, :exc:`MemoryError` is now
raised. Patch by Erlend E. Aasland.
33 changes: 23 additions & 10 deletions Modules/_sqlite/cursor.c
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ _pysqlite_fetch_one_row(pysqlite_Cursor* self)
if (!row)
return NULL;

sqlite3 *db = self->connection->db;
for (i = 0; i < numcols; i++) {
if (self->connection->detect_types
&& self->row_cast_map != NULL
Expand All @@ -280,17 +281,19 @@ _pysqlite_fetch_one_row(pysqlite_Cursor* self)
* See https://sqlite.org/c3ref/column_blob.html for details.
*/
if (converter != Py_None) {
const char *blob = (const char*)sqlite3_column_blob(self->statement->st, i);
const void *blob = sqlite3_column_blob(self->statement->st, i);
if (blob == NULL && sqlite3_errcode(db) == SQLITE_NOMEM) {
PyErr_NoMemory();
goto error;
}

nbytes = sqlite3_column_bytes(self->statement->st, i);
if (!blob) {
converted = Py_NewRef(Py_None);
} else {
item = PyBytes_FromStringAndSize(blob, nbytes);
if (!item)
goto error;
converted = PyObject_CallOneArg(converter, item);
Py_DECREF(item);
item = PyBytes_FromStringAndSize(blob, nbytes);
if (item == NULL) {
goto error;
}
converted = PyObject_CallOneArg(converter, item);
Py_DECREF(item);
} else {
Py_BEGIN_ALLOW_THREADS
coltype = sqlite3_column_type(self->statement->st, i);
Expand All @@ -303,6 +306,11 @@ _pysqlite_fetch_one_row(pysqlite_Cursor* self)
converted = PyFloat_FromDouble(sqlite3_column_double(self->statement->st, i));
} else if (coltype == SQLITE_TEXT) {
const char *text = (const char*)sqlite3_column_text(self->statement->st, i);
if (text == NULL && sqlite3_errcode(db) == SQLITE_NOMEM) {
PyErr_NoMemory();
goto error;
}

nbytes = sqlite3_column_bytes(self->statement->st, i);
if (self->connection->text_factory == (PyObject*)&PyUnicode_Type) {
converted = PyUnicode_FromStringAndSize(text, nbytes);
Expand Down Expand Up @@ -332,7 +340,12 @@ _pysqlite_fetch_one_row(pysqlite_Cursor* self)
}
} else {
/* coltype == SQLITE_BLOB */
const char *blob = sqlite3_column_blob(self->statement->st, i);
const void *blob = sqlite3_column_blob(self->statement->st, i);
if (blob == NULL && sqlite3_errcode(db) == SQLITE_NOMEM) {
PyErr_NoMemory();
goto error;
}

nbytes = sqlite3_column_bytes(self->statement->st, i);
converted = PyBytes_FromStringAndSize(blob, nbytes);
}
Expand Down