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. 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 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.