Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't insert integer array in PostgreSQL #37

Open
timothyqiu opened this issue Jun 30, 2020 · 3 comments
Open

Can't insert integer array in PostgreSQL #37

timothyqiu opened this issue Jun 30, 2020 · 3 comments

Comments

@timothyqiu
Copy link
Contributor

PostgreSQL (psycopg2 driver) uses list to pass integer array type (integer[]), but pugsql expands list params not only for the IN clause, but also in other places:

@compiles(BindParameter)
def _visit_bindparam(element, compiler, **kw):
cc = getattr(_locals, 'compile_context', None)
if cc:
if _is_expanding_param(element, cc):
element.expanding = True
return compiler.visit_bindparam(element)
def _is_expanding_param(element, cc):
if element.key not in cc['params']:
return False
return isinstance(cc['params'][element.key], (tuple, list))

For example:

CREATE TABLE foo (
    id SERIAL PRIMARY KEY,
    bar INTEGER[] NOT NULL
);

and the SQL:

-- :name create :scalar
INSERT INTO foo (bar) VALUES (:bar)
  • queries.create(bar=[1, 2]) yields: sqlalchemy.exc.ProgrammingError: (psycopg2.errors.DatatypeMismatch) column "bar" is of type integer[] but expression is of type record
  • queries.create(bar=[1, ]) yields: sqlalchemy.exc.ProgrammingError: (psycopg2.errors.DatatypeMismatch) column "bar" is of type integer[] but expression is of type integer

It works fine if I comment out line 29-31 in the source code above.

@mcfunley
Copy link
Owner

mcfunley commented Jul 2, 2020

Ah interesting, so if i understand correctly our _visit_bindparam is getting in the way of this just working with the underlying sqlalchemy, because we're just naively testing if the value is iterable?

Good catch, I probably won't have time to dig for a while but it seems like you're pretty deep into investigating. Any ideas on how to fix?

@timothyqiu
Copy link
Contributor Author

A proper fix might be expanding the parameter only for IN clauses, but it seems hard to implement.

My current workaround is changing the column type from integer[] to jsonb, so that I can call the function with psycopg2.extras.Json([1, 2, 3]) to save the integer array. Maybe PugSQL can also introduce a wrapper like this, e.g. ArrayLiteral, so that queries.create(bar=ArrayLiteral([1, 2])) passes the list as is.

@mcfunley
Copy link
Owner

mcfunley commented Jul 9, 2020

Yeah that's a potentially good approach. I've gone down the path of parsing the sql a few times and thought better of it every time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants