Subject: Adaptation in psycopg3

From: Daniele Varrazzo <[email-masked]>
Date: Tue, 24 Nov 2020 16:52:58 +0000

Hello,

I wrote a description of the psycopg3 adaptation system and the main
differences compared to psycopg2: available at
https://www.psycopg.org/articles/2020/11/24/psycopg3-adaptation/

Initial API docs are available at
https://www.psycopg.org/psycopg3/docs/adaptation.html

Feedback is welcome. Cheers!

-- Daniele

---

From: listas <[email-masked]>
Date: Wed, 25 Nov 2020 13:29:46 +0100

> Feedback is welcome. Cheers!

Hi Daniele, thanks for your effort.

After reading the docs i have a question about the parameters in the 
'in' clause.

In psycopg2 i do:

  params = (1,2,3,4)
  cursor.execute("select * from mytable where field1 in %s", (params,))

or

  params = ('black','red','green')
  cursor.execute("select * from mytable where field2 in %s", (params,))

What will it be like in psycopg3, will it be the same?, will I have to 
create a special adapter?

Thanks
--
Oswaldo Hernández

---

From: Adrian Klaver <[email-masked]>
Date: Wed, 25 Nov 2020 06:35:21 -0800

> create a special adapter?

 From the link:

"cannot use the IN (...) construct:

# Must use "AND nation = any (%s)"
cur.execute("... AND nation in %s", [("IT", "FR", "DE")])

"

-- 
Adrian Klaver
[email-masked]

---

From: Daniele Varrazzo <[email-masked]>
Date: Wed, 25 Nov 2020 14:45:30 +0000

> create a special adapter?

Hollo Oswaldo,

"IN" cannot be used, because it's a SQL construct, so "(1, 2, 3)" is
not something that postgres will understand as a parameter.

You can use "= any (%s)" and pass a list. This is something you can do
in psycopg2 too, and it's actually a better choice, because it works
with empty lists too, unless `IN ()`, which is a syntax error for
Postgres.

What you can do is:

    params = ['black','red','green']
    cursor.execute("select * from mytable where field2 = any(%s)", (params,))

interesting fact: "= any" is what postgres really uses internally,
even if you use the "IN ()" syntax:

    piro=# explain select * from mytable where myint in (1,2,3);
                          QUERY PLAN
    ---------------------------------------------------------
    Seq Scan on mytable  (cost=0.00..45.06 rows=38 width=4)
      Filter: (myint = ANY ('{1,2,3}'::integer[]))
    (2 rows)

 -- Daniele

---

From: listas <[email-masked]>
Date: Wed, 25 Nov 2020 19:00:21 +0100

>      piro=# explain select * from mytable where myint in (1,2,3);

Thank for your replies, I will use "=any(params list)" in psycopg3

The second question is: if psycopg3 is going to do the automatic cast of 
the types, will it be able to distinguish between a json and a list of 
values?.
Example:

data = ["a", "b", "c"]
idList = [4,7,2]

cursor.execute("update mytable set jsfield=%s where id = any(%s)", 
(data, idList))

What will be the correct syntax in this case?

Thanks,
--
Oswaldo Hernández

---

From: Daniele Varrazzo <[email-masked]>
Date: Wed, 25 Nov 2020 19:02:42 +0000

> Thank for your replies, I will use "=any(params list)" in psycopg3

No problem. But if it was not clear, this is something that works
already in psycopg2 too: it could be useful if you want to port code
later.

> What will be the correct syntax in this case?

You would do like in psycopg2. There isn't a single json type in
python (it could be a list, dict, number, None...) so there is a
"Json" wrapper to tell psycopg to pass e.g. a json number rather than
a number-number:
https://www.psycopg.org/docs/extras.html?highlight=json#json-adaptation

What you would do, both in psycopg2 and 3, would be something like:

    (Json(data), idList))

Code like this should work in both versions.

Cheers

-- Daniele

---

From: listas <[email-masked]>
Date: Wed, 25 Nov 2020 21:05:50 +0100

...
> Code like this should work in both versions.

perfect :) thank you very much

-- 
Oswaldo Hernández