Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 023fe33

Browse files
committed
sqlite3: Handle strings with embedded zeros correctly
Closes #13676.
1 parent fc3ba6b commit 023fe33

5 files changed

Lines changed: 54 additions & 9 deletions

File tree

Lib/sqlite3/test/dbapi.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,13 @@ def CheckExecuteArgFloat(self):
225225
def CheckExecuteArgString(self):
226226
self.cu.execute("insert into test(name) values (?)", ("Hugo",))
227227

228+
def CheckExecuteArgStringWithZeroByte(self):
229+
self.cu.execute("insert into test(name) values (?)", ("Hu\x00go",))
230+
231+
self.cu.execute("select name from test where id=?", (self.cu.lastrowid,))
232+
row = self.cu.fetchone()
233+
self.assertEqual(row[0], "Hu\x00go")
234+
228235
def CheckExecuteWrongNoOfArgs1(self):
229236
# too many parameters
230237
try:

Lib/sqlite3/test/factory.py

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,13 +189,48 @@ def CheckOptimizedUnicode(self):
189189
def tearDown(self):
190190
self.con.close()
191191

192+
class TextFactoryTestsWithEmbeddedZeroBytes(unittest.TestCase):
193+
def setUp(self):
194+
self.con = sqlite.connect(":memory:")
195+
self.con.execute("create table test (value text)")
196+
self.con.execute("insert into test (value) values (?)", ("a\x00b",))
197+
198+
def CheckString(self):
199+
# text_factory defaults to str
200+
row = self.con.execute("select value from test").fetchone()
201+
self.assertIs(type(row[0]), str)
202+
self.assertEqual(row[0], "a\x00b")
203+
204+
def CheckBytes(self):
205+
self.con.text_factory = bytes
206+
row = self.con.execute("select value from test").fetchone()
207+
self.assertIs(type(row[0]), bytes)
208+
self.assertEqual(row[0], b"a\x00b")
209+
210+
def CheckBytearray(self):
211+
self.con.text_factory = bytearray
212+
row = self.con.execute("select value from test").fetchone()
213+
self.assertIs(type(row[0]), bytearray)
214+
self.assertEqual(row[0], b"a\x00b")
215+
216+
def CheckCustom(self):
217+
# A custom factory should receive a bytes argument
218+
self.con.text_factory = lambda x: x
219+
row = self.con.execute("select value from test").fetchone()
220+
self.assertIs(type(row[0]), bytes)
221+
self.assertEqual(row[0], b"a\x00b")
222+
223+
def tearDown(self):
224+
self.con.close()
225+
192226
def suite():
193227
connection_suite = unittest.makeSuite(ConnectionFactoryTests, "Check")
194228
cursor_suite = unittest.makeSuite(CursorFactoryTests, "Check")
195229
row_suite_compat = unittest.makeSuite(RowFactoryTestsBackwardsCompat, "Check")
196230
row_suite = unittest.makeSuite(RowFactoryTests, "Check")
197231
text_suite = unittest.makeSuite(TextFactoryTests, "Check")
198-
return unittest.TestSuite((connection_suite, cursor_suite, row_suite_compat, row_suite, text_suite))
232+
text_zero_bytes_suite = unittest.makeSuite(TextFactoryTestsWithEmbeddedZeroBytes, "Check")
233+
return unittest.TestSuite((connection_suite, cursor_suite, row_suite_compat, row_suite, text_suite, text_zero_bytes_suite))
199234

200235
def test():
201236
runner = unittest.TextTestRunner()

Misc/NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ Core and Builtins
113113
Library
114114
-------
115115

116+
- Issue #13676: Handle strings with embedded zeros correctly in sqlite3.
117+
116118
- Issue #13506: Add '' to path for IDLE Shell when started and restarted with Restart Shell.
117119
Original patches by Marco Scataglini and Roger Serwy.
118120

Modules/_sqlite/cursor.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -268,9 +268,9 @@ PyObject* _pysqlite_build_column_name(const char* colname)
268268
}
269269
}
270270

271-
PyObject* pysqlite_unicode_from_string(const char* val_str, int optimize)
271+
PyObject* pysqlite_unicode_from_string(const char* val_str, Py_ssize_t size, int optimize)
272272
{
273-
return PyUnicode_FromString(val_str);
273+
return PyUnicode_FromStringAndSize(val_str, size);
274274
}
275275

276276
/*
@@ -355,10 +355,11 @@ PyObject* _pysqlite_fetch_one_row(pysqlite_Cursor* self)
355355
converted = PyFloat_FromDouble(sqlite3_column_double(self->statement->st, i));
356356
} else if (coltype == SQLITE_TEXT) {
357357
val_str = (const char*)sqlite3_column_text(self->statement->st, i);
358+
nbytes = sqlite3_column_bytes(self->statement->st, i);
358359
if ((self->connection->text_factory == (PyObject*)&PyUnicode_Type)
359360
|| (self->connection->text_factory == pysqlite_OptimizedUnicode)) {
360361

361-
converted = pysqlite_unicode_from_string(val_str,
362+
converted = pysqlite_unicode_from_string(val_str, nbytes,
362363
self->connection->text_factory == pysqlite_OptimizedUnicode ? 1 : 0);
363364

364365
if (!converted) {
@@ -383,11 +384,11 @@ PyObject* _pysqlite_fetch_one_row(pysqlite_Cursor* self)
383384
}
384385
}
385386
} else if (self->connection->text_factory == (PyObject*)&PyBytes_Type) {
386-
converted = PyBytes_FromString(val_str);
387+
converted = PyBytes_FromStringAndSize(val_str, nbytes);
387388
} else if (self->connection->text_factory == (PyObject*)&PyByteArray_Type) {
388-
converted = PyByteArray_FromStringAndSize(val_str, strlen(val_str));
389+
converted = PyByteArray_FromStringAndSize(val_str, nbytes);
389390
} else {
390-
converted = PyObject_CallFunction(self->connection->text_factory, "y", val_str);
391+
converted = PyObject_CallFunction(self->connection->text_factory, "y#", val_str, nbytes);
391392
}
392393
} else {
393394
/* coltype == SQLITE_BLOB */

Modules/_sqlite/statement.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,9 +129,9 @@ int pysqlite_statement_bind_parameter(pysqlite_Statement* self, int pos, PyObjec
129129
rc = sqlite3_bind_double(self->st, pos, PyFloat_AsDouble(parameter));
130130
break;
131131
case TYPE_UNICODE:
132-
string = _PyUnicode_AsString(parameter);
132+
string = _PyUnicode_AsStringAndSize(parameter, &buflen);
133133
if (string != NULL)
134-
rc = sqlite3_bind_text(self->st, pos, string, -1, SQLITE_TRANSIENT);
134+
rc = sqlite3_bind_text(self->st, pos, string, buflen, SQLITE_TRANSIENT);
135135
else
136136
rc = -1;
137137
break;

0 commit comments

Comments
 (0)