MagicStack / asyncpg

A fast PostgreSQL Database Client Library for Python/asyncio.
Apache License 2.0
6.88k stars 399 forks source link

Containment query on range types fails with DataError #1095

Closed stj closed 10 months ago

stj commented 10 months ago

Bug description

Trying to run a containment query against a range type. https://www.postgresql.org/docs/13/rangetypes.html

Simplified version of the SQL

SELECT tstzrange('[2023-10-01 00:00Z, 2024-01-01 00:00Z)') @> now()

Using asyncpg with a python datetime

>>> import asyncpg
>>> from datetime import datetime, timezone
>>> timestamp = datetime.now(tz=timezone.utc)
>>> con = await asyncpg.connect()
>>> await con.execute("SELECT tstzrange('[2023-10-01 00:00Z, 2024-01-01 00:00Z)') @> $1", timestamp)
...
File "asyncpg/protocol/protocol.pyx", line 183, in bind_execute
  File "asyncpg/protocol/prepared_stmt.pyx", line 197, in asyncpg.protocol.protocol.PreparedStatementState._encode_bind_msg
asyncpg.exceptions.DataError: invalid input for query argument $1: datetime.datetime(2023, 10, 27, 20, 24, ... (list, tuple or Range object expected (got type <class 'datetime.datetime'>))

Same behaviour is observed with other range types

SELECT int4range(10, 20) @> 3;

File "asyncpg/protocol/protocol.pyx", line 183, in bind_execute File "asyncpg/protocol/prepared_stmt.pyx", line 197, in asyncpg.protocol.protocol.PreparedStatementState._encode_bind_msg asyncpg.exceptions.DataError: invalid input for query argument $1: 3 (list, tuple or Range object expected (got type <class 'int'>))

Expected behaviour

Allow the argument of a containment query to be of the range type (int, datetime, date).

elprans commented 10 months ago

PostgreSQL cannot infer the correct type of the argument from a query like this, you should cast it explicitly like this:

SELECT tstzrange('[2023-10-01 00:00Z, 2024-01-01 00:00Z)') @> $1::timestamptz
stj commented 10 months ago

Amazing! Thanks for the quick response.