summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--psycopg/connection_int.c51
-rw-r--r--psycopg/connection_type.c22
-rwxr-xr-xtests/test_connection.py14
3 files changed, 58 insertions, 29 deletions
diff --git a/psycopg/connection_int.c b/psycopg/connection_int.c
index fa714f6..6006b15 100644
--- a/psycopg/connection_int.c
+++ b/psycopg/connection_int.c
@@ -236,6 +236,39 @@ conn_get_standard_conforming_strings(PGconn *pgconn)
return equote;
}
+
+/* Remove irrelevant chars from encoding name and turn it uppercase.
+ *
+ * Return a buffer allocated on Python heap,
+ * NULL and set an exception on error.
+ */
+static char *
+clean_encoding_name(const char *enc)
+{
+ const char *i = enc;
+ char *rv, *j;
+
+ /* convert to upper case and remove '-' and '_' from string */
+ if (!(j = rv = PyMem_Malloc(strlen(enc) + 1))) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ while (*i) {
+ if (!isalnum(*i)) {
+ ++i;
+ }
+ else {
+ *j++ = toupper(*i++);
+ }
+ }
+ *j = '\0';
+
+ Dprintf("clean_encoding_name: %s -> %s", enc, rv);
+
+ return rv;
+}
+
/* Convert a PostgreSQL encoding to a Python codec.
*
* Return a new copy of the codec name allocated on the Python heap,
@@ -246,11 +279,16 @@ conn_encoding_to_codec(const char *enc)
{
char *tmp;
Py_ssize_t size;
+ char *norm_enc = NULL;
PyObject *pyenc = NULL;
char *rv = NULL;
+ if (!(norm_enc = clean_encoding_name(enc))) {
+ goto exit;
+ }
+
/* Find the Py codec name from the PG encoding */
- if (!(pyenc = PyDict_GetItemString(psycoEncodings, enc))) {
+ if (!(pyenc = PyDict_GetItemString(psycoEncodings, norm_enc))) {
PyErr_Format(OperationalError,
"no Python codec for client encoding '%s'", enc);
goto exit;
@@ -270,6 +308,7 @@ conn_encoding_to_codec(const char *enc)
rv = psycopg_strdup(tmp, size);
exit:
+ PyMem_Free(norm_enc);
Py_XDECREF(pyenc);
return rv;
}
@@ -285,7 +324,7 @@ exit:
static int
conn_read_encoding(connectionObject *self, PGconn *pgconn)
{
- char *enc = NULL, *codec = NULL, *j;
+ char *enc = NULL, *codec = NULL;
const char *tmp;
int rv = -1;
@@ -297,16 +336,10 @@ conn_read_encoding(connectionObject *self, PGconn *pgconn)
goto exit;
}
- if (!(enc = PyMem_Malloc(strlen(tmp)+1))) {
- PyErr_NoMemory();
+ if (!(enc = psycopg_strdup(tmp, 0))) {
goto exit;
}
- /* turn encoding in uppercase */
- j = enc;
- while (*tmp) { *j++ = toupper(*tmp++); }
- *j = '\0';
-
/* Look for this encoding in Python codecs. */
if (!(codec = conn_encoding_to_codec(enc))) {
goto exit;
diff --git a/psycopg/connection_type.c b/psycopg/connection_type.c
index b0c9ddc..7ca395d 100644
--- a/psycopg/connection_type.c
+++ b/psycopg/connection_type.c
@@ -423,36 +423,18 @@ static PyObject *
psyco_conn_set_client_encoding(connectionObject *self, PyObject *args)
{
const char *enc;
- char *buffer, *dest;
PyObject *rv = NULL;
- Py_ssize_t len;
EXC_IF_CONN_CLOSED(self);
EXC_IF_CONN_ASYNC(self, set_client_encoding);
EXC_IF_TPC_PREPARED(self, set_client_encoding);
- if (!PyArg_ParseTuple(args, "s#", &enc, &len)) return NULL;
+ if (!PyArg_ParseTuple(args, "s", &enc)) return NULL;
- /* convert to upper case and remove '-' and '_' from string */
- if (!(dest = buffer = PyMem_Malloc(len+1))) {
- return PyErr_NoMemory();
- }
-
- while (*enc) {
- if (*enc == '_' || *enc == '-') {
- ++enc;
- }
- else {
- *dest++ = toupper(*enc++);
- }
- }
- *dest = '\0';
-
- if (conn_set_client_encoding(self, buffer) == 0) {
+ if (conn_set_client_encoding(self, enc) == 0) {
Py_INCREF(Py_None);
rv = Py_None;
}
- PyMem_Free(buffer);
return rv;
}
diff --git a/tests/test_connection.py b/tests/test_connection.py
index e237524..d9da471 100755
--- a/tests/test_connection.py
+++ b/tests/test_connection.py
@@ -22,6 +22,7 @@
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
# License for more details.
+import os
import time
import threading
from testutils import unittest, decorate_all_tests, skip_before_postgres
@@ -141,6 +142,19 @@ class ConnectionTests(unittest.TestCase):
cur.execute("select 'foo'::text;")
self.assertEqual(cur.fetchone()[0], u'foo')
+ def test_connect_nonnormal_envvar(self):
+ # We must perform encoding normalization at connection time
+ self.conn.close()
+ oldenc = os.environ.get('PGCLIENTENCODING')
+ os.environ['PGCLIENTENCODING'] = 'utf-8' # malformed spelling
+ try:
+ self.conn = psycopg2.connect(dsn)
+ finally:
+ if oldenc is not None:
+ os.environ['PGCLIENTENCODING'] = oldenc
+ else:
+ del os.environ['PGCLIENTENCODING']
+
def test_weakref(self):
from weakref import ref
conn = psycopg2.connect(dsn)