Hi Mike, Your fix worked - the example I gave and our other tests pass now.
Many thanks, Tom On Mon, 19 Oct 2015 at 17:19 Mike Bayer <mike...@zzzcomputing.com> wrote: > > > On 10/19/15 11:57 AM, Mike Bayer wrote: > > > > > > On 10/19/15 11:44 AM, Steven Winfield wrote: > >> The problem seems to be that the result set from an executemany() call > >> in psycopg2 is discarded - here is a good stackoverflow article on this > >> subject: > >> > http://stackoverflow.com/questions/21624844/getting-ids-of-multiple-rows-inserted-in-psycopg2 > >> > >> In _emit_update_statements in orm/persistence.py, and here > >> < > http://docs.sqlalchemy.org/en/rel_1_0/changelog/migration_10.html?highlight=version_id_col#update-statements-are-now-batched-with-executemany-in-a-flush > > > >> in the v1.0 migration docs, one of the conditions for using executemany > is: > >> "The mapping does not use a |version_id_col| > >> < > http://docs.sqlalchemy.org/en/rel_1_0/orm/mapping_api.html#sqlalchemy.orm.mapper.params.version_id_col > >, > >> or the backend dialect supports a “sane” rowcount for an executemany() > >> operation;" > >> > >> ...but I'm not sure that is enough - psycopg2 does support sane > >> rowcounts, and its dialect's supports_sane_rowcount and > >> supports_sane_multi_rowcount are both rightly True (I work with Tom, and > >> we're using psycopg2 v2.6 by the way - I know those values are > >> predicated on the psycopg2 version). > >> > >> I'm working on a patch that adds another member to the default dialect > >> called "supports_executemany_results" that defaults to True > > > > I wouldn't do that, no DBAPI has results for executemany. The flag is > > not needed. > > > > This is very likely yet another 1.0 regression caused by > > > http://docs.sqlalchemy.org/en/rel_1_0/changelog/migration_10.html#update-statements-are-now-batched-with-executemany-in-a-flush > > and not checking closely enough for the right conditions. I'll add a > > new ticket soon. > > issue > > https://bitbucket.org/zzzeek/sqlalchemy/issues/3556/update-executemany-enhancement-breaks > which is now resolved. I will try to release 1.0.9 this week; please > confirm the fix in the latest rel_1_0 branch fixes this issue for you as > well, thanks! > > > > > > > > > > > > > > > but is set > >> to False in PGDialect_psycopg2 in dialects/postgres/psycopg2.py. This > >> can then be used in the determination of allow_multirow (line 646 in > >> orm/persistence.py). This will preserve the current behaviour of other > >> dialects, but of course there could be others with the same problem. > >> > >> Steve > >> > >> On Monday, October 19, 2015 at 4:22:36 PM UTC+1, Tom Flannaghan wrote: > >> > >> Hi, > >> > >> We are currently trying to upgrade to sqlalchemy 1.0.8 and have hit > >> a problem with executemany() and row versioning. We are using > >> postgres and psycopg2 as a backend. We have tables that use server > >> side versioning (as discussed at > >> > http://docs.sqlalchemy.org/en/rel_0_9/orm/versioning.html#server-side-version-counters > >> < > http://docs.sqlalchemy.org/en/rel_0_9/orm/versioning.html#server-side-version-counters > >), > >> and when multiple rows are updated, the UPDATE statements are > >> batched together using executemany() in the new version of > >> sqlalchemy. Unfortunately, psycopg2 does not support iterating over > >> the results of an executemany() query (see > >> http://initd.org/psycopg/docs/cursor.html#cursor.executemany > >> <http://initd.org/psycopg/docs/cursor.html#cursor.executemany>) so > >> the new row versions returned by the update statement cannot be > read. > >> > >> Here is an example that illustrates the problem: > >> > >> from sqlalchemy import Column, FetchedValue, Integer, String > >> from sqlalchemy.ext.declarative import declarative_base > >> from sqlalchemy.orm import sessionmaker > >> > >> Base = declarative_base() > >> > >> class Port(Base): > >> ''' Table for storing ports. ''' > >> __tablename__ = "port" > >> > >> name = Column(String, primary_key=True) > >> port = Column(Integer) > >> > >> xmin = Column(Integer, server_default=FetchedValue(), > >> server_onupdate=FetchedValue(), system=True) > >> __mapper_args__ = {"version_id_col": xmin, > >> "version_id_generator": False} > >> > >> > >> engine = create_engine(...) > >> Session = sessionmaker(bind=engine) > >> > >> session = Session() > >> session.bind.echo = True > >> > >> p1 = Port(name='a', port=1) > >> p2 = Port(name='b', port=2) > >> session.add(p1) > >> session.add(p2) > >> session.flush() > >> > >> # this update fails > >> p1.port = 3 > >> p2.port = 4 > >> session.flush() > >> > >> session.rollback() > >> > >> The SQL generated for the update looks like this: > >> > >> 2015-10-19 14:46:30,289 INFO sqlalchemy.engine.base.Engine UPDATE > >> comm.port SET port=%(port)s WHERE comm.port.name > >> <http://comm.port.name> = %(comm_port_name)s AND comm.port.xmin = > >> %(comm_port_xmin)s RETURNING comm.port.xmin > >> 2015-10-19 14:46:30,289 INFO sqlalchemy.engine.base.Engine > >> ({'comm_port_xmin': '536394944', 'comm_port_name': 'a', 'port': 3}, > >> {'comm_port_xmin': '536394944', 'comm_port_name': 'b', 'port': 4}) > >> > >> This code raises the following exception: > >> > >> File user!flannt!untitled6.py, line 52, in : session.flush() > >> File > >> > > I:\sw\external\20151014-0\python27\lib\site-packages\sqlalchemy-1.0.8-py2.7-win32.egg\sqlalchemy\orm\session.py, > >> line 2004, in flush : self._flush(objects) > >> File > >> > > I:\sw\external\20151014-0\python27\lib\site-packages\sqlalchemy-1.0.8-py2.7-win32.egg\sqlalchemy\orm\session.py, > >> line 2122, in _flush : transaction.rollback(_capture_exception=True) > >> File > >> > > I:\sw\external\20151014-0\python27\lib\site-packages\sqlalchemy-1.0.8-py2.7-win32.egg\sqlalchemy\util\langhelpers.py, > >> line 60, in __exit__ : compat.reraise(exc_type, exc_value, exc_tb) > >> File > >> > > I:\sw\external\20151014-0\python27\lib\site-packages\sqlalchemy-1.0.8-py2.7-win32.egg\sqlalchemy\orm\session.py, > >> line 2086, in _flush : flush_context.execute() > >> File > >> > > I:\sw\external\20151014-0\python27\lib\site-packages\sqlalchemy-1.0.8-py2.7-win32.egg\sqlalchemy\orm\unitofwork.py, > >> line 373, in execute : rec.execute(self) > >> File > >> > > I:\sw\external\20151014-0\python27\lib\site-packages\sqlalchemy-1.0.8-py2.7-win32.egg\sqlalchemy\orm\unitofwork.py, > >> line 532, in execute : uow > >> File > >> > > I:\sw\external\20151014-0\python27\lib\site-packages\sqlalchemy-1.0.8-py2.7-win32.egg\sqlalchemy\orm\persistence.py, > >> line 170, in save_obj : mapper, table, update) > >> File > >> > > I:\sw\external\20151014-0\python27\lib\site-packages\sqlalchemy-1.0.8-py2.7-win32.egg\sqlalchemy\orm\persistence.py, > >> line 692, in _emit_update_statements : execute(statement, > multiparams) > >> File > >> > > I:\sw\external\20151014-0\python27\lib\site-packages\sqlalchemy-1.0.8-py2.7-win32.egg\sqlalchemy\engine\base.py, > >> line 914, in execute : return meth(self, multiparams, params) > >> File > >> > > I:\sw\external\20151014-0\python27\lib\site-packages\sqlalchemy-1.0.8-py2.7-win32.egg\sqlalchemy\sql\elements.py, > >> line 323, in _execute_on_connection : return > >> connection._execute_clauseelement(self, multiparams, params) > >> File > >> > > I:\sw\external\20151014-0\python27\lib\site-packages\sqlalchemy-1.0.8-py2.7-win32.egg\sqlalchemy\engine\base.py, > >> line 1010, in _execute_clauseelement : compiled_sql, > distilled_params > >> File > >> > > I:\sw\external\20151014-0\python27\lib\site-packages\sqlalchemy-1.0.8-py2.7-win32.egg\sqlalchemy\engine\base.py, > >> line 1159, in _execute_context : result = > >> context._setup_crud_result_proxy() > >> File > >> > > I:\sw\external\20151014-0\python27\lib\site-packages\sqlalchemy-1.0.8-py2.7-win32.egg\sqlalchemy\engine\default.py, > >> line 832, in _setup_crud_result_proxy : row = result.fetchone() > >> File > >> > > I:\sw\external\20151014-0\python27\lib\site-packages\sqlalchemy-1.0.8-py2.7-win32.egg\sqlalchemy\engine\result.py, > >> line 1026, in fetchone : self.cursor, self.context) > >> File > >> > > I:\sw\external\20151014-0\python27\lib\site-packages\sqlalchemy-1.0.8-py2.7-win32.egg\sqlalchemy\engine\base.py, > >> line 1341, in _handle_dbapi_exception : exc_info > >> File > >> > > I:\sw\external\20151014-0\python27\lib\site-packages\sqlalchemy-1.0.8-py2.7-win32.egg\sqlalchemy\util\compat.py, > >> line 199, in raise_from_cause : reraise(type(exception), exception, > >> tb=exc_tb) > >> File > >> > > I:\sw\external\20151014-0\python27\lib\site-packages\sqlalchemy-1.0.8-py2.7-win32.egg\sqlalchemy\engine\result.py, > >> line 1017, in fetchone : row = self._fetchone_impl() > >> File > >> > > I:\sw\external\20151014-0\python27\lib\site-packages\sqlalchemy-1.0.8-py2.7-win32.egg\sqlalchemy\engine\result.py, > >> line 898, in _fetchone_impl : return self.cursor.fetchone() > >> ProgrammingError: (psycopg2.ProgrammingError) no results to fetch > >> > >> -- > >> You received this message because you are subscribed to the Google > >> Groups "sqlalchemy" group. > >> To unsubscribe from this group and stop receiving emails from it, send > >> an email to sqlalchemy+unsubscr...@googlegroups.com > >> <mailto:sqlalchemy+unsubscr...@googlegroups.com>. > >> To post to this group, send email to sqlalchemy@googlegroups.com > >> <mailto:sqlalchemy@googlegroups.com>. > >> Visit this group at http://groups.google.com/group/sqlalchemy. > >> For more options, visit https://groups.google.com/d/optout. > > -- > You received this message because you are subscribed to a topic in the > Google Groups "sqlalchemy" group. > To unsubscribe from this topic, visit > https://groups.google.com/d/topic/sqlalchemy/_ui4mhIUmwM/unsubscribe. > To unsubscribe from this group and all its topics, send an email to > sqlalchemy+unsubscr...@googlegroups.com. > To post to this group, send email to sqlalchemy@googlegroups.com. > Visit this group at http://groups.google.com/group/sqlalchemy. > For more options, visit https://groups.google.com/d/optout. > -- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy+unsubscr...@googlegroups.com. To post to this group, send email to sqlalchemy@googlegroups.com. Visit this group at http://groups.google.com/group/sqlalchemy. For more options, visit https://groups.google.com/d/optout.