[Sqlalchemy-tickets] Issue #3813: 'on conflict ... do update ...' where clause and implicit returni
Brought to you by:
zzzeek
From: Pawel <iss...@bi...> - 2016-10-04 14:53:48
|
New issue 3813: 'on conflict ... do update ...' where clause and implicit returning https://bitbucket.org/zzzeek/sqlalchemy/issues/3813/on-conflict-do-update-where-clause-and Pawel: When using Postgres 9.5 INSERT ... ON CONFLICT ... DO UPDATE ... I get an error: ``` #!python File ".../sqlalchemy/orm/scoping.py", line 157, in do return getattr(self.registry(), name)(*args, **kwargs) File ".../sqlalchemy/orm/session.py", line 1044, in execute bind, close_with_result=True).execute(clause, params or {}) File ".../sqlalchemy/engine/base.py", line 947, in execute return meth(self, multiparams, params) File ".../sqlalchemy/sql/elements.py", line 262, in _execute_on_connection return connection._execute_clauseelement(self, multiparams, params) File ".../sqlalchemy/engine/base.py", line 1055, in _execute_clauseelement compiled_sql, distilled_params File ".../sqlalchemy/engine/base.py", line 1204, in _execute_context result = context._setup_crud_result_proxy() File ".../sqlalchemy/engine/default.py", line 862, in _setup_crud_result_proxy self._setup_ins_pk_from_implicit_returning(row) File ".../sqlalchemy/engine/default.py", line 927, in _setup_ins_pk_from_implicit_returning for col in table.primary_key TypeError: 'NoneType' object has no attribute '__getitem__' ``` I have hard time recreating issue with test (sorry I'm a bit new to the project), but i think I know what conditions cause this error. 1. INSERT must give a CONFLICT 2. ON UPDATE must have a WHERE with condition that does not allow for update 3. There should be only one data set for the INSERT VALUES (so that the implicit returning is `True` so sth like this should give an error: ``` #!python conn.execute(users.insert(), dict(id=1, name='name1')) i = insert(users) i = i.on_conflict_do_update( index_elements=[users.c.id], set_=dict(name=i.excluded.name), where=(i.excluded.name == 'other_name'')) ) conn.execute(u, [dict(id=1, name='name2')]) ``` This test passes but `_implicit_returning` here is `False`. In my code I use session and `implicit_returning` is `True` (is it because of session?) Then in file: `sqlalchemy/engine/default.py:862` function: `_setup_crud_result_proxy` we go inside both `if`'s and `row = result.fetchone()` sets row to `None` because of the `where` clause I think (nothing will be inserted or updated). Then the call `self._setup_ins_pk_from_implicit_returning(row)` with `row == None` give an error. ``` #!python if self.isinsert: if self._is_implicit_returning: # when implicit_returning is True! # row == None row = result.fetchone() self.returned_defaults = row # if row == None we get an error in this method! self._setup_ins_pk_from_implicit_returning(row) result._soft_close(_autoclose_connection=False) result._metadata = None elif not self._is_explicit_returning: result._soft_close(_autoclose_connection=False) result._metadata = None ``` |