From: Daniele Varrazzo Date: Sun, 18 Sep 2022 21:45:48 +0000 (+0100) Subject: fix: fix queries with repeated named parameters in ClientCursor X-Git-Tag: 3.1.2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5636d2ab44b2499d89f9a5519e288ed4dc8d7416;p=thirdparty%2Fpsycopg.git fix: fix queries with repeated named parameters in ClientCursor Close #378. --- diff --git a/docs/news.rst b/docs/news.rst index 1ede13cd8..675b6d79d 100644 --- a/docs/news.rst +++ b/docs/news.rst @@ -18,6 +18,7 @@ Psycopg 3.1.2 (unreleased) - Fix segfault occurring when a loader fails initialization (:ticket:`#372`). - Fix invalid SAVEPOINT issued when entering `Connection.transaction()` within a pipeline using an implicit transaction (:ticket:`#374`). +- Fix queries with repeated named parameters in `ClientCursor` (:ticket:`#378`). Current release diff --git a/psycopg/psycopg/_queries.py b/psycopg/psycopg/_queries.py index 2b0838e34..f2b916d7a 100644 --- a/psycopg/psycopg/_queries.py +++ b/psycopg/psycopg/_queries.py @@ -225,6 +225,7 @@ def _query2pg_client( chunks.append(ph) else: chunks.append(seen[part.item][0]) + order.append(part.item) # last part chunks.append(parts[-1].pre) diff --git a/tests/test_client_cursor.py b/tests/test_client_cursor.py index b79c0360a..20900c4d9 100644 --- a/tests/test_client_cursor.py +++ b/tests/test_client_cursor.py @@ -578,6 +578,21 @@ def test_query_params_execute(conn): assert cur._query.params == (b"'wat'",) +@pytest.mark.parametrize( + "query, params, want", + [ + ("select %(x)s", {"x": 1}, (1,)), + ("select %(x)s, %(y)s", {"x": 1, "y": 2}, (1, 2)), + ("select %(x)s, %(x)s", {"x": 1}, (1, 1)), + ], +) +def test_query_params_named(conn, query, params, want): + cur = conn.cursor() + cur.execute(query, params) + rec = cur.fetchone() + assert rec == want + + def test_query_params_executemany(conn): cur = conn.cursor() @@ -795,13 +810,18 @@ def test_leak(conn_cls, dsn, faker, fetch, row_factory): assert n[0] == n[1] == n[2], f"objects leaked: {n[1] - n[0]}, {n[2] - n[1]}" -def test_mogrify(conn): +@pytest.mark.parametrize( + "query, params, want", + [ + ("select 'hello'", (), "select 'hello'"), + ("select %s, %s", ([1, dt.date(2020, 1, 1)],), "select 1, '2020-01-01'::date"), + ("select %(foo)s, %(foo)s", ({"foo": "x"},), "select 'x', 'x'"), + ], +) +def test_mogrify(conn, query, params, want): cur = conn.cursor() - q = cur.mogrify("select 'hello'") - assert q == "select 'hello'" - - q = cur.mogrify("select %s, %s", [1, dt.date(2020, 1, 1)]) - assert q == "select 1, '2020-01-01'::date" + got = cur.mogrify(query, *params) + assert got == want @pytest.mark.parametrize("encoding", ["utf8", crdb_encoding("latin9")]) diff --git a/tests/test_client_cursor_async.py b/tests/test_client_cursor_async.py index d3816754e..d3a074f22 100644 --- a/tests/test_client_cursor_async.py +++ b/tests/test_client_cursor_async.py @@ -573,6 +573,21 @@ async def test_query_params_execute(aconn): assert cur._query.params == (b"'wat'",) +@pytest.mark.parametrize( + "query, params, want", + [ + ("select %(x)s", {"x": 1}, (1,)), + ("select %(x)s, %(y)s", {"x": 1, "y": 2}, (1, 2)), + ("select %(x)s, %(x)s", {"x": 1}, (1, 1)), + ], +) +async def test_query_params_named(aconn, query, params, want): + cur = aconn.cursor() + await cur.execute(query, params) + rec = await cur.fetchone() + assert rec == want + + async def test_query_params_executemany(aconn): cur = aconn.cursor() @@ -667,13 +682,18 @@ async def test_leak(aconn_cls, dsn, faker, fetch, row_factory): assert n[0] == n[1] == n[2], f"objects leaked: {n[1] - n[0]}, {n[2] - n[1]}" -async def test_mogrify(aconn): +@pytest.mark.parametrize( + "query, params, want", + [ + ("select 'hello'", (), "select 'hello'"), + ("select %s, %s", ([1, dt.date(2020, 1, 1)],), "select 1, '2020-01-01'::date"), + ("select %(foo)s, %(foo)s", ({"foo": "x"},), "select 'x', 'x'"), + ], +) +async def test_mogrify(aconn, query, params, want): cur = aconn.cursor() - q = cur.mogrify("select 'hello'") - assert q == "select 'hello'" - - q = cur.mogrify("select %s, %s", [1, dt.date(2020, 1, 1)]) - assert q == "select 1, '2020-01-01'::date" + got = cur.mogrify(query, *params) + assert got == want @pytest.mark.parametrize("encoding", ["utf8", crdb_encoding("latin9")])