mirror of
https://github.com/python/cpython.git
synced 2025-12-04 00:30:19 +00:00
bpo-44822: Don't truncate strs with embedded NULL chars returned by sqlite3 UDF callbacks (GH-27588)
This commit is contained in:
parent
3e4cb7f40f
commit
8f010dc920
3 changed files with 41 additions and 3 deletions
|
|
@ -53,6 +53,8 @@ def with_tracebacks(strings):
|
||||||
|
|
||||||
def func_returntext():
|
def func_returntext():
|
||||||
return "foo"
|
return "foo"
|
||||||
|
def func_returntextwithnull():
|
||||||
|
return "1\x002"
|
||||||
def func_returnunicode():
|
def func_returnunicode():
|
||||||
return "bar"
|
return "bar"
|
||||||
def func_returnint():
|
def func_returnint():
|
||||||
|
|
@ -163,11 +165,21 @@ class AggrSum:
|
||||||
def finalize(self):
|
def finalize(self):
|
||||||
return self.val
|
return self.val
|
||||||
|
|
||||||
|
class AggrText:
|
||||||
|
def __init__(self):
|
||||||
|
self.txt = ""
|
||||||
|
def step(self, txt):
|
||||||
|
self.txt = self.txt + txt
|
||||||
|
def finalize(self):
|
||||||
|
return self.txt
|
||||||
|
|
||||||
|
|
||||||
class FunctionTests(unittest.TestCase):
|
class FunctionTests(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.con = sqlite.connect(":memory:")
|
self.con = sqlite.connect(":memory:")
|
||||||
|
|
||||||
self.con.create_function("returntext", 0, func_returntext)
|
self.con.create_function("returntext", 0, func_returntext)
|
||||||
|
self.con.create_function("returntextwithnull", 0, func_returntextwithnull)
|
||||||
self.con.create_function("returnunicode", 0, func_returnunicode)
|
self.con.create_function("returnunicode", 0, func_returnunicode)
|
||||||
self.con.create_function("returnint", 0, func_returnint)
|
self.con.create_function("returnint", 0, func_returnint)
|
||||||
self.con.create_function("returnfloat", 0, func_returnfloat)
|
self.con.create_function("returnfloat", 0, func_returnfloat)
|
||||||
|
|
@ -211,6 +223,12 @@ class FunctionTests(unittest.TestCase):
|
||||||
self.assertEqual(type(val), str)
|
self.assertEqual(type(val), str)
|
||||||
self.assertEqual(val, "foo")
|
self.assertEqual(val, "foo")
|
||||||
|
|
||||||
|
def test_func_return_text_with_null_char(self):
|
||||||
|
cur = self.con.cursor()
|
||||||
|
res = cur.execute("select returntextwithnull()").fetchone()[0]
|
||||||
|
self.assertEqual(type(res), str)
|
||||||
|
self.assertEqual(res, "1\x002")
|
||||||
|
|
||||||
def test_func_return_unicode(self):
|
def test_func_return_unicode(self):
|
||||||
cur = self.con.cursor()
|
cur = self.con.cursor()
|
||||||
cur.execute("select returnunicode()")
|
cur.execute("select returnunicode()")
|
||||||
|
|
@ -390,6 +408,7 @@ class AggregateTests(unittest.TestCase):
|
||||||
self.con.create_aggregate("checkType", 2, AggrCheckType)
|
self.con.create_aggregate("checkType", 2, AggrCheckType)
|
||||||
self.con.create_aggregate("checkTypes", -1, AggrCheckTypes)
|
self.con.create_aggregate("checkTypes", -1, AggrCheckTypes)
|
||||||
self.con.create_aggregate("mysum", 1, AggrSum)
|
self.con.create_aggregate("mysum", 1, AggrSum)
|
||||||
|
self.con.create_aggregate("aggtxt", 1, AggrText)
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
#self.cur.close()
|
#self.cur.close()
|
||||||
|
|
@ -486,6 +505,15 @@ class AggregateTests(unittest.TestCase):
|
||||||
val = cur.fetchone()[0]
|
val = cur.fetchone()[0]
|
||||||
self.assertIsNone(val)
|
self.assertIsNone(val)
|
||||||
|
|
||||||
|
def test_aggr_text(self):
|
||||||
|
cur = self.con.cursor()
|
||||||
|
for txt in ["foo", "1\x002"]:
|
||||||
|
with self.subTest(txt=txt):
|
||||||
|
cur.execute("select aggtxt(?) from test", (txt,))
|
||||||
|
val = cur.fetchone()[0]
|
||||||
|
self.assertEqual(val, txt)
|
||||||
|
|
||||||
|
|
||||||
class AuthorizerTests(unittest.TestCase):
|
class AuthorizerTests(unittest.TestCase):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def authorizer_cb(action, arg1, arg2, dbname, source):
|
def authorizer_cb(action, arg1, arg2, dbname, source):
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
:mod:`sqlite3` user-defined functions and aggregators returning
|
||||||
|
:class:`strings <str>` with embedded NUL characters are no longer
|
||||||
|
truncated. Patch by Erlend E. Aasland.
|
||||||
|
|
@ -519,10 +519,17 @@ _pysqlite_set_result(sqlite3_context* context, PyObject* py_val)
|
||||||
} else if (PyFloat_Check(py_val)) {
|
} else if (PyFloat_Check(py_val)) {
|
||||||
sqlite3_result_double(context, PyFloat_AsDouble(py_val));
|
sqlite3_result_double(context, PyFloat_AsDouble(py_val));
|
||||||
} else if (PyUnicode_Check(py_val)) {
|
} else if (PyUnicode_Check(py_val)) {
|
||||||
const char *str = PyUnicode_AsUTF8(py_val);
|
Py_ssize_t sz;
|
||||||
if (str == NULL)
|
const char *str = PyUnicode_AsUTF8AndSize(py_val, &sz);
|
||||||
|
if (str == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
sqlite3_result_text(context, str, -1, SQLITE_TRANSIENT);
|
}
|
||||||
|
if (sz > INT_MAX) {
|
||||||
|
PyErr_SetString(PyExc_OverflowError,
|
||||||
|
"string is longer than INT_MAX bytes");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
sqlite3_result_text(context, str, (int)sz, SQLITE_TRANSIENT);
|
||||||
} else if (PyObject_CheckBuffer(py_val)) {
|
} else if (PyObject_CheckBuffer(py_val)) {
|
||||||
Py_buffer view;
|
Py_buffer view;
|
||||||
if (PyObject_GetBuffer(py_val, &view, PyBUF_SIMPLE) != 0) {
|
if (PyObject_GetBuffer(py_val, &view, PyBUF_SIMPLE) != 0) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue