mirror of
https://github.com/psycopg/psycopg2.git
synced 2025-02-17 01:20:32 +03:00
Avoid encoding strdup in qstring adapter
Dropped encoding parameter in the constructor: it is used nowhere and not documented. Use directly the connection encoding if available, else the previous latin1 fallback.
This commit is contained in:
parent
7a5a226b49
commit
736a78f3f6
|
@ -32,26 +32,32 @@
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
static const char *default_encoding = "latin1";
|
||||||
|
|
||||||
/* qstring_quote - do the quote process on plain and unicode strings */
|
/* qstring_quote - do the quote process on plain and unicode strings */
|
||||||
|
|
||||||
BORROWED static PyObject *
|
static PyObject *
|
||||||
qstring_quote(qstringObject *self)
|
qstring_quote(qstringObject *self)
|
||||||
{
|
{
|
||||||
PyObject *str;
|
PyObject *str = NULL;
|
||||||
char *s, *buffer;
|
char *s, *buffer = NULL;
|
||||||
Py_ssize_t len, qlen;
|
Py_ssize_t len, qlen;
|
||||||
|
const char *encoding = default_encoding;
|
||||||
|
PyObject *rv = NULL;
|
||||||
|
|
||||||
/* if the wrapped object is an unicode object we can encode it to match
|
/* if the wrapped object is an unicode object we can encode it to match
|
||||||
self->encoding but if the encoding is not specified we don't know what
|
conn->encoding but if the encoding is not specified we don't know what
|
||||||
to do and we raise an exception */
|
to do and we raise an exception */
|
||||||
|
if (self->conn) {
|
||||||
|
encoding = self->conn->codec;
|
||||||
|
}
|
||||||
|
|
||||||
Dprintf("qstring_quote: encoding to %s", self->encoding);
|
Dprintf("qstring_quote: encoding to %s", encoding);
|
||||||
|
|
||||||
if (PyUnicode_Check(self->wrapped) && self->encoding) {
|
if (PyUnicode_Check(self->wrapped) && encoding) {
|
||||||
str = PyUnicode_AsEncodedString(self->wrapped, self->encoding, NULL);
|
str = PyUnicode_AsEncodedString(self->wrapped, encoding, NULL);
|
||||||
Dprintf("qstring_quote: got encoded object at %p", str);
|
Dprintf("qstring_quote: got encoded object at %p", str);
|
||||||
if (str == NULL) return NULL;
|
if (str == NULL) goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if PY_MAJOR_VERSION < 3
|
#if PY_MAJOR_VERSION < 3
|
||||||
|
@ -68,29 +74,28 @@ qstring_quote(qstringObject *self)
|
||||||
else {
|
else {
|
||||||
PyErr_SetString(PyExc_TypeError,
|
PyErr_SetString(PyExc_TypeError,
|
||||||
"can't quote non-string object (or missing encoding)");
|
"can't quote non-string object (or missing encoding)");
|
||||||
return NULL;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* encode the string into buffer */
|
/* encode the string into buffer */
|
||||||
Bytes_AsStringAndSize(str, &s, &len);
|
Bytes_AsStringAndSize(str, &s, &len);
|
||||||
if (!(buffer = psycopg_escape_string(self->conn, s, len, NULL, &qlen))) {
|
if (!(buffer = psycopg_escape_string((PyObject *)self->conn, s, len, NULL, &qlen))) {
|
||||||
Py_DECREF(str);
|
goto exit;
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qlen > (size_t) PY_SSIZE_T_MAX) {
|
if (qlen > (size_t) PY_SSIZE_T_MAX) {
|
||||||
PyErr_SetString(PyExc_IndexError,
|
PyErr_SetString(PyExc_IndexError,
|
||||||
"PG buffer too large to fit in Python buffer.");
|
"PG buffer too large to fit in Python buffer.");
|
||||||
PyMem_Free(buffer);
|
goto exit;
|
||||||
Py_DECREF(str);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self->buffer = Bytes_FromStringAndSize(buffer, qlen);
|
rv = Bytes_FromStringAndSize(buffer, qlen);
|
||||||
PyMem_Free(buffer);
|
|
||||||
Py_DECREF(str);
|
|
||||||
|
|
||||||
return self->buffer;
|
exit:
|
||||||
|
PyMem_Free(buffer);
|
||||||
|
Py_XDECREF(str);
|
||||||
|
|
||||||
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* qstring_str, qstring_getquoted - return result of quoting */
|
/* qstring_str, qstring_getquoted - return result of quoting */
|
||||||
|
@ -99,7 +104,7 @@ static PyObject *
|
||||||
qstring_getquoted(qstringObject *self, PyObject *args)
|
qstring_getquoted(qstringObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
if (self->buffer == NULL) {
|
if (self->buffer == NULL) {
|
||||||
qstring_quote(self);
|
self->buffer = qstring_quote(self);
|
||||||
}
|
}
|
||||||
Py_XINCREF(self->buffer);
|
Py_XINCREF(self->buffer);
|
||||||
return self->buffer;
|
return self->buffer;
|
||||||
|
@ -114,19 +119,11 @@ qstring_str(qstringObject *self)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
qstring_prepare(qstringObject *self, PyObject *args)
|
qstring_prepare(qstringObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
PyObject *conn;
|
connectionObject *conn;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "O!", &connectionType, &conn))
|
if (!PyArg_ParseTuple(args, "O!", &connectionType, &conn))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* we bother copying the encoding only if the wrapped string is unicode,
|
|
||||||
we don't need the encoding if that's not the case */
|
|
||||||
if (PyUnicode_Check(self->wrapped)) {
|
|
||||||
if (self->encoding) free(self->encoding);
|
|
||||||
self->encoding = strdup(((connectionObject *)conn)->codec);
|
|
||||||
Dprintf("qstring_prepare: set encoding to %s", self->encoding);
|
|
||||||
}
|
|
||||||
|
|
||||||
Py_CLEAR(self->conn);
|
Py_CLEAR(self->conn);
|
||||||
Py_INCREF(conn);
|
Py_INCREF(conn);
|
||||||
self->conn = conn;
|
self->conn = conn;
|
||||||
|
@ -151,6 +148,18 @@ qstring_conform(qstringObject *self, PyObject *args)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
qstring_get_encoding(qstringObject *self)
|
||||||
|
{
|
||||||
|
const char *encoding = default_encoding;
|
||||||
|
|
||||||
|
if (self->conn) {
|
||||||
|
encoding = self->conn->codec;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Text_FromUTF8(encoding);
|
||||||
|
}
|
||||||
|
|
||||||
/** the QuotedString object **/
|
/** the QuotedString object **/
|
||||||
|
|
||||||
/* object member list */
|
/* object member list */
|
||||||
|
@ -158,7 +167,6 @@ qstring_conform(qstringObject *self, PyObject *args)
|
||||||
static struct PyMemberDef qstringObject_members[] = {
|
static struct PyMemberDef qstringObject_members[] = {
|
||||||
{"adapted", T_OBJECT, offsetof(qstringObject, wrapped), READONLY},
|
{"adapted", T_OBJECT, offsetof(qstringObject, wrapped), READONLY},
|
||||||
{"buffer", T_OBJECT, offsetof(qstringObject, buffer), READONLY},
|
{"buffer", T_OBJECT, offsetof(qstringObject, buffer), READONLY},
|
||||||
{"encoding", T_STRING, offsetof(qstringObject, encoding), READONLY},
|
|
||||||
{NULL}
|
{NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -173,22 +181,24 @@ static PyMethodDef qstringObject_methods[] = {
|
||||||
{NULL} /* Sentinel */
|
{NULL} /* Sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static PyGetSetDef qstringObject_getsets[] = {
|
||||||
|
{ "encoding",
|
||||||
|
(getter)qstring_get_encoding,
|
||||||
|
(setter)NULL,
|
||||||
|
"current encoding of the adapter" },
|
||||||
|
{NULL}
|
||||||
|
};
|
||||||
|
|
||||||
/* initialization and finalization methods */
|
/* initialization and finalization methods */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
qstring_setup(qstringObject *self, PyObject *str, const char *enc)
|
qstring_setup(qstringObject *self, PyObject *str)
|
||||||
{
|
{
|
||||||
Dprintf("qstring_setup: init qstring object at %p, refcnt = "
|
Dprintf("qstring_setup: init qstring object at %p, refcnt = "
|
||||||
FORMAT_CODE_PY_SSIZE_T,
|
FORMAT_CODE_PY_SSIZE_T,
|
||||||
self, Py_REFCNT(self)
|
self, Py_REFCNT(self)
|
||||||
);
|
);
|
||||||
|
|
||||||
self->buffer = NULL;
|
|
||||||
self->conn = NULL;
|
|
||||||
|
|
||||||
/* FIXME: remove this orrible strdup */
|
|
||||||
if (enc) self->encoding = strdup(enc);
|
|
||||||
|
|
||||||
Py_INCREF(str);
|
Py_INCREF(str);
|
||||||
self->wrapped = str;
|
self->wrapped = str;
|
||||||
|
|
||||||
|
@ -219,8 +229,6 @@ qstring_dealloc(PyObject* obj)
|
||||||
Py_CLEAR(self->buffer);
|
Py_CLEAR(self->buffer);
|
||||||
Py_CLEAR(self->conn);
|
Py_CLEAR(self->conn);
|
||||||
|
|
||||||
if (self->encoding) free(self->encoding);
|
|
||||||
|
|
||||||
Dprintf("qstring_dealloc: deleted qstring object at %p, refcnt = "
|
Dprintf("qstring_dealloc: deleted qstring object at %p, refcnt = "
|
||||||
FORMAT_CODE_PY_SSIZE_T,
|
FORMAT_CODE_PY_SSIZE_T,
|
||||||
obj, Py_REFCNT(obj)
|
obj, Py_REFCNT(obj)
|
||||||
|
@ -233,12 +241,11 @@ static int
|
||||||
qstring_init(PyObject *obj, PyObject *args, PyObject *kwds)
|
qstring_init(PyObject *obj, PyObject *args, PyObject *kwds)
|
||||||
{
|
{
|
||||||
PyObject *str;
|
PyObject *str;
|
||||||
const char *enc = "latin-1"; /* default encoding as in Python */
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "O|s", &str, &enc))
|
if (!PyArg_ParseTuple(args, "O", &str))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return qstring_setup((qstringObject *)obj, str, enc);
|
return qstring_setup((qstringObject *)obj, str);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
@ -257,7 +264,7 @@ qstring_repr(qstringObject *self)
|
||||||
/* object type */
|
/* object type */
|
||||||
|
|
||||||
#define qstringType_doc \
|
#define qstringType_doc \
|
||||||
"QuotedString(str, enc) -> new quoted object with 'enc' encoding"
|
"QuotedString(str) -> new quoted object"
|
||||||
|
|
||||||
PyTypeObject qstringType = {
|
PyTypeObject qstringType = {
|
||||||
PyVarObject_HEAD_INIT(NULL, 0)
|
PyVarObject_HEAD_INIT(NULL, 0)
|
||||||
|
@ -288,7 +295,7 @@ PyTypeObject qstringType = {
|
||||||
0, /*tp_iternext*/
|
0, /*tp_iternext*/
|
||||||
qstringObject_methods, /*tp_methods*/
|
qstringObject_methods, /*tp_methods*/
|
||||||
qstringObject_members, /*tp_members*/
|
qstringObject_members, /*tp_members*/
|
||||||
0, /*tp_getset*/
|
qstringObject_getsets, /*tp_getset*/
|
||||||
0, /*tp_base*/
|
0, /*tp_base*/
|
||||||
0, /*tp_dict*/
|
0, /*tp_dict*/
|
||||||
0, /*tp_descr_get*/
|
0, /*tp_descr_get*/
|
||||||
|
@ -306,10 +313,9 @@ PyObject *
|
||||||
psyco_QuotedString(PyObject *module, PyObject *args)
|
psyco_QuotedString(PyObject *module, PyObject *args)
|
||||||
{
|
{
|
||||||
PyObject *str;
|
PyObject *str;
|
||||||
const char *enc = "latin-1"; /* default encoding as in Python */
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "O|s", &str, &enc))
|
if (!PyArg_ParseTuple(args, "O", &str))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return PyObject_CallFunction((PyObject *)&qstringType, "Os", str, enc);
|
return PyObject_CallFunctionObjArgs((PyObject *)&qstringType, str, NULL);
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,13 +37,8 @@ typedef struct {
|
||||||
|
|
||||||
PyObject *wrapped;
|
PyObject *wrapped;
|
||||||
PyObject *buffer;
|
PyObject *buffer;
|
||||||
/* NOTE: this used to be a PostgreSQL encoding: changed in 2.3.2 to be a
|
|
||||||
* Python codec name. I don't expect there has been any user for this
|
|
||||||
* object other than adapting str/unicode, so I don't expect client code
|
|
||||||
* broken for this reason. */
|
|
||||||
char *encoding;
|
|
||||||
|
|
||||||
PyObject *conn;
|
connectionObject *conn;
|
||||||
} qstringObject;
|
} qstringObject;
|
||||||
|
|
||||||
/* functions exported to psycopgmodule.c */
|
/* functions exported to psycopgmodule.c */
|
||||||
|
|
|
@ -162,6 +162,22 @@ class QuotingTestCase(unittest.TestCase):
|
||||||
self.assert_(not self.conn.notices)
|
self.assert_(not self.conn.notices)
|
||||||
|
|
||||||
|
|
||||||
|
class TestQuotedString(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.conn = psycopg2.connect(dsn)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
self.conn.close()
|
||||||
|
|
||||||
|
def test_encoding(self):
|
||||||
|
q = psycopg2.extensions.QuotedString('hi')
|
||||||
|
self.assertEqual(q.encoding, 'latin1')
|
||||||
|
|
||||||
|
self.conn.set_client_encoding('utf_8')
|
||||||
|
q.prepare(self.conn)
|
||||||
|
self.assertEqual(q.encoding, 'utf_8')
|
||||||
|
|
||||||
|
|
||||||
def test_suite():
|
def test_suite():
|
||||||
return unittest.TestLoader().loadTestsFromName(__name__)
|
return unittest.TestLoader().loadTestsFromName(__name__)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user