MagicStack / asyncpg

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

When using Redshift - PostgresSyntaxError: syntax error at or near "ORDER" - in query with no "ORDER" #1009

Open yehorb opened 1 year ago

yehorb commented 1 year ago

Running this snippet:

options = ConnectionOptions()

sslctx = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
sslctx.check_hostname = False
sslctx.verify_mode = ssl.CERT_NONE

connection = await asyncpg.connect(options.dsn, ssl=sslctx)

try:
    query = "select 'all' = any($1::text[])"
    await connection.fetch(query, ["all"])

finally:
    await connection.close()

I get this exception:

asyncpg.exceptions.PostgresSyntaxError: syntax error at or near "ORDER"

I am wondering, where the "syntax error at or near "ORDER" comes from, as there is no "ORDER" in the original query.

If asyncpg does not rewrite queries in any way, and the query passed to fetch is forwarded to the database without modification (https://github.com/MagicStack/asyncpg/issues/434#issuecomment-910474719, https://github.com/MagicStack/asyncpg/discussions/859#discussioncomment-1742492) - where does the "ORDER" come from?

Can this issue be worked around, or I should abandon asyncpg as a Redshift client? I do understand that Redshift is not officially supported, but this client is very good otherwise.

I was not able to reproduce the error with the postgres:9.0 instance (the oldest I was able to find quickly). The same (except ssl=False) snippet works without errors.

elprans commented 1 year ago

The error comes from the type introspection query. It might be possible to adapt asyncpg to Redshift, PRs welcome.

stefanondisponibile commented 8 months ago

Hey @elprans I'm experiencing the same error when trying to simply select a SUPER field from Redshift. Did you already have an idea of what are the main points to make asyncpg Redshift-compatible?

stefanondisponibile commented 8 months ago

For anyone else stumbling into this: the solution for me was to register a custom encoder/decoder for the super type via asyncpg's Connection.set_type_codec.

KevinLeung-LTP commented 5 months ago

Hi @elprans , I meet the same problem when trying a simple select query without ORDER from redshift. Are there any solution for this problem?

remigabillet commented 4 months ago

For anyone else stumbling into this: the solution for me was to register a custom encoder/decoder for the super type via asyncpg's Connection.set_type_codec.

@stefanondisponibile Thanks for the help. I can't get past this error though. Can you share the code you used?

stefanondisponibile commented 4 months ago

hey @remigabillet, I think that could depend specifically on the error you're getting, but you can find an example here. So for example:

# ...
await connection.set_type_codec(
  typename="super",
  schema="pg_catalog",
  encoder=your_encoder, decoder=your_decoder
)

# your_encoder and your_decoder can be as simple as json.dumps/json.loads to more complex implementations depending also on how you're storing your data.
remigabillet commented 4 months ago

@stefanondisponibile this works! thank you!. I wasn't sure which schema to set. In case it's useful, here's the code I'm using:

import json

await conn.set_type_codec(
  "super",
  schema="pg_catalog",
  encoder=json.dumps,
  decoder=json.loads
  )
stefanondisponibile commented 4 months ago

Glad it helped!

remigabillet commented 4 months ago

@stefanondisponibile I'm running into the same error again when querying Redshift, when trying to bind a list: PostgresSyntaxError: syntax error at or near "ORDER"

await conn.fetch(
  "SELECT id, name FROM t WHERE id = ANY($1::BIGINT[])",
  [976646132813407501, 976646132813407502]
)

I debugged the code found OID 1016 is the one with a missing code. It maps to the type _int8. Unfortunately, when trying to set a codec, I get a new error:

InterfaceError: cannot use custom codec on type pg_catalog._int8: it is neither a scalar type nor a composite type

asyncpg returns this error if typelem is not 0, which is the case:

Screenshot 2024-05-03 at 09 47 44

I'm not sure hot how to proceed. Let me know if you have any ideas.

stefanondisponibile commented 4 months ago

@remigabillet I'm not sure that's directly related to this issue. Are you experiencing it also with other queries?

Is the query you want to execute even working if you run it directly from the Redshift editor or psql? Array support in Redshift is quite different from Postgres (it's very poor actually, they have some ARRAY functions but they don't support the equivalent of the Postgres array data type), I would write that query with something like:

SELECT id, name FROM t WHERE id IN (976646132813407501, 976646132813407502)

So maybe in your case I wouldn't even use args ($1). Is asyncpg your only option here? I think in this issue we're trying to find some way to make asyncpg work as much as possible with Redshift given the overlap, but I wouldn't expect asyncpg to support Redshift at all, they're different kind of animals.