summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS1
-rw-r--r--psycopg/adapter_list.c16
-rwxr-xr-xtests/test_types_basic.py34
3 files changed, 50 insertions, 1 deletions
diff --git a/NEWS b/NEWS
index de5ead3..4aebbff 100644
--- a/NEWS
+++ b/NEWS
@@ -15,6 +15,7 @@ New features:
What's new in psycopg 2.6.1
^^^^^^^^^^^^^^^^^^^^^^^^^^^
+- Lists consisting of only `None` are escaped correctly (:ticket:`#285`).
- Fixed deadlock in multithread programs using OpenSSL (:ticket:`#290`).
- Correctly unlock the connection after error in flush (:ticket:`#294`).
- Fixed ``MinTimeLoggingCursor.callproc()`` (:ticket:`#309`).
diff --git a/psycopg/adapter_list.c b/psycopg/adapter_list.c
index e68b197..dec17b4 100644
--- a/psycopg/adapter_list.c
+++ b/psycopg/adapter_list.c
@@ -39,6 +39,14 @@ list_quote(listObject *self)
/* adapt the list by calling adapt() recursively and then wrapping
everything into "ARRAY[]" */
PyObject *tmp = NULL, *str = NULL, *joined = NULL, *res = NULL;
+
+ /* list consisting of only NULL don't work with the ARRAY[] construct
+ * so we use the {NULL,...} syntax. Note however that list of lists where
+ * some element is a list of only null still fails: for that we should use
+ * the '{...}' syntax uniformly but we cannot do it in the current
+ * infrastructure. TODO in psycopg3 */
+ int all_nulls = 1;
+
Py_ssize_t i, len;
len = PyList_GET_SIZE(self->wrapped);
@@ -60,6 +68,7 @@ list_quote(listObject *self)
quoted = microprotocol_getquoted(wrapped,
(connectionObject*)self->connection);
if (quoted == NULL) goto error;
+ all_nulls = 0;
}
/* here we don't loose a refcnt: SET_ITEM does not change the
@@ -74,7 +83,12 @@ list_quote(listObject *self)
joined = PyObject_CallMethod(str, "join", "(O)", tmp);
if (joined == NULL) goto error;
- res = Bytes_FromFormat("ARRAY[%s]", Bytes_AsString(joined));
+ /* PG doesn't like ARRAY[NULL..] */
+ if (!all_nulls) {
+ res = Bytes_FromFormat("ARRAY[%s]", Bytes_AsString(joined));
+ } else {
+ res = Bytes_FromFormat("'{%s}'", Bytes_AsString(joined));
+ }
error:
Py_XDECREF(tmp);
diff --git a/tests/test_types_basic.py b/tests/test_types_basic.py
index 6c4cc97..199dc1b 100755
--- a/tests/test_types_basic.py
+++ b/tests/test_types_basic.py
@@ -192,6 +192,40 @@ class TypesBasicTests(ConnectingTestCase):
self.assertRaises(psycopg2.DataError,
psycopg2.extensions.STRINGARRAY, b(s), curs)
+ def testArrayOfNulls(self):
+ curs = self.conn.cursor()
+ curs.execute("""
+ create table na (
+ texta text[],
+ inta int[],
+ boola boolean[],
+
+ textaa text[][],
+ intaa int[][],
+ boolaa boolean[][]
+ )""")
+
+ curs.execute("insert into na (texta) values (%s)", ([None],))
+ curs.execute("insert into na (texta) values (%s)", (['a', None],))
+ curs.execute("insert into na (texta) values (%s)", ([None, None],))
+ curs.execute("insert into na (inta) values (%s)", ([None],))
+ curs.execute("insert into na (inta) values (%s)", ([42, None],))
+ curs.execute("insert into na (inta) values (%s)", ([None, None],))
+ curs.execute("insert into na (boola) values (%s)", ([None],))
+ curs.execute("insert into na (boola) values (%s)", ([True, None],))
+ curs.execute("insert into na (boola) values (%s)", ([None, None],))
+
+ # TODO: array of array of nulls are not supported yet
+ # curs.execute("insert into na (textaa) values (%s)", ([[None]],))
+ curs.execute("insert into na (textaa) values (%s)", ([['a', None]],))
+ # curs.execute("insert into na (textaa) values (%s)", ([[None, None]],))
+ # curs.execute("insert into na (intaa) values (%s)", ([[None]],))
+ curs.execute("insert into na (intaa) values (%s)", ([[42, None]],))
+ # curs.execute("insert into na (intaa) values (%s)", ([[None, None]],))
+ # curs.execute("insert into na (boolaa) values (%s)", ([[None]],))
+ curs.execute("insert into na (boolaa) values (%s)", ([[True, None]],))
+ # curs.execute("insert into na (boolaa) values (%s)", ([[None, None]],))
+
@testutils.skip_from_python(3)
def testTypeRoundtripBuffer(self):
o1 = buffer("".join(map(chr, range(256))))