]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
sqlite3: Handle strings with embedded zeros correctly
authorPetri Lehtinen <petri@digip.org>
Wed, 1 Feb 2012 20:18:19 +0000 (22:18 +0200)
committerPetri Lehtinen <petri@digip.org>
Wed, 1 Feb 2012 20:18:35 +0000 (22:18 +0200)
Closes #13676.

Lib/sqlite3/test/dbapi.py
Lib/sqlite3/test/factory.py
Misc/NEWS
Modules/_sqlite/cursor.c
Modules/_sqlite/statement.c

index 518b8ae41098f750a7af9b274148b6ee1712a179..202bd38876084bb6d8f4e280a1874b85e2ea0ce8 100644 (file)
@@ -225,6 +225,13 @@ class CursorTests(unittest.TestCase):
     def CheckExecuteArgString(self):
         self.cu.execute("insert into test(name) values (?)", ("Hugo",))
 
+    def CheckExecuteArgStringWithZeroByte(self):
+        self.cu.execute("insert into test(name) values (?)", ("Hu\x00go",))
+
+        self.cu.execute("select name from test where id=?", (self.cu.lastrowid,))
+        row = self.cu.fetchone()
+        self.assertEqual(row[0], "Hu\x00go")
+
     def CheckExecuteWrongNoOfArgs1(self):
         # too many parameters
         try:
index 1adab2fef3678cc386b89928fd88237382ec95d4..7f6f3473f3e7300dd231e5f2ca0606dcbd1fb2f5 100644 (file)
@@ -189,13 +189,48 @@ class TextFactoryTests(unittest.TestCase):
     def tearDown(self):
         self.con.close()
 
+class TextFactoryTestsWithEmbeddedZeroBytes(unittest.TestCase):
+    def setUp(self):
+        self.con = sqlite.connect(":memory:")
+        self.con.execute("create table test (value text)")
+        self.con.execute("insert into test (value) values (?)", ("a\x00b",))
+
+    def CheckString(self):
+        # text_factory defaults to str
+        row = self.con.execute("select value from test").fetchone()
+        self.assertIs(type(row[0]), str)
+        self.assertEqual(row[0], "a\x00b")
+
+    def CheckBytes(self):
+        self.con.text_factory = bytes
+        row = self.con.execute("select value from test").fetchone()
+        self.assertIs(type(row[0]), bytes)
+        self.assertEqual(row[0], b"a\x00b")
+
+    def CheckBytearray(self):
+        self.con.text_factory = bytearray
+        row = self.con.execute("select value from test").fetchone()
+        self.assertIs(type(row[0]), bytearray)
+        self.assertEqual(row[0], b"a\x00b")
+
+    def CheckCustom(self):
+        # A custom factory should receive a bytes argument
+        self.con.text_factory = lambda x: x
+        row = self.con.execute("select value from test").fetchone()
+        self.assertIs(type(row[0]), bytes)
+        self.assertEqual(row[0], b"a\x00b")
+
+    def tearDown(self):
+        self.con.close()
+
 def suite():
     connection_suite = unittest.makeSuite(ConnectionFactoryTests, "Check")
     cursor_suite = unittest.makeSuite(CursorFactoryTests, "Check")
     row_suite_compat = unittest.makeSuite(RowFactoryTestsBackwardsCompat, "Check")
     row_suite = unittest.makeSuite(RowFactoryTests, "Check")
     text_suite = unittest.makeSuite(TextFactoryTests, "Check")
-    return unittest.TestSuite((connection_suite, cursor_suite, row_suite_compat, row_suite, text_suite))
+    text_zero_bytes_suite = unittest.makeSuite(TextFactoryTestsWithEmbeddedZeroBytes, "Check")
+    return unittest.TestSuite((connection_suite, cursor_suite, row_suite_compat, row_suite, text_suite, text_zero_bytes_suite))
 
 def test():
     runner = unittest.TextTestRunner()
index 2f552c37486c89b039078089c17eb8a73381a450..aa05096592f8c8b81a22663a65153025ab466001 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -113,6 +113,8 @@ Core and Builtins
 Library
 -------
 
+- Issue #13676: Handle strings with embedded zeros correctly in sqlite3.
+
 - Issue #13506: Add '' to path for IDLE Shell when started and restarted with Restart Shell.
   Original patches by Marco Scataglini and Roger Serwy.
 
index b9a4358b1a9d18237900dff5cb38d2419416afaa..763322ff1b64231ba4338cd747a6ce7ec7ce25db 100644 (file)
@@ -268,9 +268,9 @@ PyObject* _pysqlite_build_column_name(const char* colname)
     }
 }
 
-PyObject* pysqlite_unicode_from_string(const char* val_str, int optimize)
+PyObject* pysqlite_unicode_from_string(const char* val_str, Py_ssize_t size, int optimize)
 {
-    return PyUnicode_FromString(val_str);
+    return PyUnicode_FromStringAndSize(val_str, size);
 }
 
 /*
@@ -355,10 +355,11 @@ PyObject* _pysqlite_fetch_one_row(pysqlite_Cursor* self)
                 converted = PyFloat_FromDouble(sqlite3_column_double(self->statement->st, i));
             } else if (coltype == SQLITE_TEXT) {
                 val_str = (const char*)sqlite3_column_text(self->statement->st, i);
+                nbytes = sqlite3_column_bytes(self->statement->st, i);
                 if ((self->connection->text_factory == (PyObject*)&PyUnicode_Type)
                     || (self->connection->text_factory == pysqlite_OptimizedUnicode)) {
 
-                    converted = pysqlite_unicode_from_string(val_str,
+                    converted = pysqlite_unicode_from_string(val_str, nbytes,
                         self->connection->text_factory == pysqlite_OptimizedUnicode ? 1 : 0);
 
                     if (!converted) {
@@ -383,11 +384,11 @@ PyObject* _pysqlite_fetch_one_row(pysqlite_Cursor* self)
                         }
                     }
                 } else if (self->connection->text_factory == (PyObject*)&PyBytes_Type) {
-                    converted = PyBytes_FromString(val_str);
+                    converted = PyBytes_FromStringAndSize(val_str, nbytes);
                 } else if (self->connection->text_factory == (PyObject*)&PyByteArray_Type) {
-                    converted = PyByteArray_FromStringAndSize(val_str, strlen(val_str));
+                    converted = PyByteArray_FromStringAndSize(val_str, nbytes);
                 } else {
-                    converted = PyObject_CallFunction(self->connection->text_factory, "y", val_str);
+                    converted = PyObject_CallFunction(self->connection->text_factory, "y#", val_str, nbytes);
                 }
             } else {
                 /* coltype == SQLITE_BLOB */
index f89fc9abf197eb6363199d44a44bd00b1d16c000..80bcc385b5928a076e1462b139045d7d6a157755 100644 (file)
@@ -129,9 +129,9 @@ int pysqlite_statement_bind_parameter(pysqlite_Statement* self, int pos, PyObjec
             rc = sqlite3_bind_double(self->st, pos, PyFloat_AsDouble(parameter));
             break;
         case TYPE_UNICODE:
-            string = _PyUnicode_AsString(parameter);
+            string = _PyUnicode_AsStringAndSize(parameter, &buflen);
             if (string != NULL)
-                rc = sqlite3_bind_text(self->st, pos, string, -1, SQLITE_TRANSIENT);
+                rc = sqlite3_bind_text(self->st, pos, string, buflen, SQLITE_TRANSIENT);
             else
                 rc = -1;
             break;