this is fixed for 0.9.9 which you can get from git right now.

> On Nov 11, 2014, at 10:53 AM, Michael Bayer <mike...@zzzcomputing.com> wrote:
> 
> https://bitbucket.org/zzzeek/sqlalchemy/issue/3248/populate_result_map-gets-set-for-select
>  
> <https://bitbucket.org/zzzeek/sqlalchemy/issue/3248/populate_result_map-gets-set-for-select>
>  , will be most likely fixed today.
> 
> 
> 
> 
>> On Nov 11, 2014, at 10:18 AM, Bruno <br...@distributedmatter.net 
>> <mailto:br...@distributedmatter.net>> wrote:
>> 
>> Hello,
>> 
>> I've been trying to insert a row based on a correlated subquery that returns 
>> a UUID. The insert query itself returns a long, which somehow SQLAlchemy 
>> tries to process as a UUID/GUID.
>> 
>> I'm using SQLAlchemy 0.9.8, Psycopg2 2.5.4 and PostgreSQL 9.1.
>> 
>> 
>> Here is an example that demonstrates the problem:
>> 
>> #!/usr/bin/env python
>> # -*- coding: utf-8 -*-
>> import logging
>> import uuid
>> 
>> from sqlalchemy import create_engine, MetaData, Table, Column, ForeignKey, 
>> BigInteger, Text, select
>> from sqlalchemy.types import TypeDecorator, CHAR
>> from sqlalchemy.dialects.postgresql import UUID
>> 
>> # This GUID class comes from the SQLAlchemy documentation.
>> # 
>> http://docs.sqlalchemy.org/en/latest/core/types.html#backend-agnostic-guid-type
>>  
>> <http://docs.sqlalchemy.org/en/latest/core/types.html#backend-agnostic-guid-type>
>> class GUID(TypeDecorator):
>>     """Platform-independent GUID type.
>> 
>>     Uses Postgresql's UUID type, otherwise uses
>>     CHAR(32), storing as stringified hex values.
>> 
>>     """
>>     impl = CHAR
>> 
>>     def load_dialect_impl(self, dialect):
>>         if dialect.name == 'postgresql':
>>             return dialect.type_descriptor(UUID())
>>         else:
>>             return dialect.type_descriptor(CHAR(32))
>> 
>>     def process_bind_param(self, value, dialect):
>>         if value is None:
>>             return value
>>         elif dialect.name == 'postgresql':
>>             return str(value)
>>         else:
>>             if not isinstance(value, uuid.UUID):
>>                 return "%.32x" % uuid.UUID(value)
>>             else:
>>                 # hexstring
>>                 return "%.32x" % value
>> 
>>     def process_result_value(self, value, dialect):
>>         if value is None:
>>             return value
>>         else:
>>             return uuid.UUID(value)
>> 
>> logging.basicConfig()
>> logging.getLogger('sqlalchemy.engine').setLevel(logging.INFO)
>> 
>> metadata = MetaData()
>> 
>> table_a = Table('table_a',metadata,
>>     Column('id', GUID(), primary_key=True),
>> )
>>     
>> table_b = Table('table_b', metadata, 
>>     Column('id', BigInteger, primary_key=True),
>>     Column('ref_a', ForeignKey('table_a.id', onupdate='CASCADE', 
>> ondelete='SET NULL')),
>>     Column('value', Text)
>> )
>> 
>> engine = create_engine('postgresql:///test' <postgresql:///test'>)
>> metadata.create_all(engine)
>> 
>> test_uuid = str(uuid.uuid4())
>> 
>> conn = engine.connect()
>> 
>> # INSERT INTO table_a (id) VALUES (%(id)s)
>> conn.execute(table_a.insert().values(id=test_uuid))
>> 
>> # INSERT INTO table_b (ref_a, value) VALUES (%(ref_a)s, %(value)s) RETURNING 
>> table_b.id
>> conn.execute(table_b.insert().values(ref_a=test_uuid, value='X'))
>> 
>> # INSERT INTO table_b (ref_a, value) 
>> #     VALUES ((SELECT table_a.id FROM table_a WHERE table_a.id = %(id_1)s 
>> LIMIT %(param_1)s), %(value)s)
>> find_a_stmt = select([table_a.c.id]).where(table_a.c.id == 
>> test_uuid).limit(1)
>> conn.execute(table_b.insert(inline=True).values(ref_a=find_a_stmt, 
>> value='Y'))
>> 
>> # INSERT INTO table_b (ref_a, value) 
>> #     VALUES ((SELECT table_a.id FROM table_a WHERE table_a.id = %(id_1)s 
>> LIMIT %(param_1)s), %(value)s)
>> # RETURNING table_b.id
>> find_a_stmt = select([table_a.c.id]).where(table_a.c.id == 
>> test_uuid).limit(1)
>> conn.execute(table_b.insert().values(ref_a=find_a_stmt, value='Z'))
>> 
>> conn.close()
>> 
>> 
>> 
>> 
>> 
>> The last insert causes this error:
>> 
>> Traceback (most recent call last):
>>   File "dbtest.py", line 82, in <module>
>>     conn.execute(table_b.insert().values(ref_a=find_a_stmt, value='Z'))
>>   File 
>> "/tmp/dbtest/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py", 
>> line 729, in execute
>>     return meth(self, multiparams, params)
>>   File 
>> "/tmp/dbtest/local/lib/python2.7/site-packages/sqlalchemy/sql/elements.py", 
>> line 322, in _execute_on_connection
>>     return connection._execute_clauseelement(self, multiparams, params)
>>   File 
>> "/tmp/dbtest/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py", 
>> line 826, in _execute_clauseelement
>>     compiled_sql, distilled_params
>>   File 
>> "/tmp/dbtest/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py", 
>> line 978, in _execute_context
>>     context._fetch_implicit_returning(result)
>>   File 
>> "/tmp/dbtest/local/lib/python2.7/site-packages/sqlalchemy/engine/default.py",
>>  line 815, in _fetch_implicit_returning
>>     ipk.append(row[c])
>>   File 
>> "/tmp/dbtest/local/lib/python2.7/site-packages/sqlalchemy/sql/type_api.py", 
>> line 915, in process
>>     return process_value(value, dialect)
>>   File "dbtest.py", line 44, in process_result_value
>>     return uuid.UUID(value)
>>   File "/usr/lib/python2.7/uuid.py", line 131, in __init__
>>     hex = hex.replace('urn:', '').replace('uuid:', '')
>> AttributeError: 'long' object has no attribute 'replace'
>> 
>> 
>> 
>> 
>> 
>> It appears that it is trying to process the result of "RETURNING table_b.id" 
>> as a GUID, as if it was expecting the type of the result of the subquery 
>> statement.
>> The workaround I've found relies on using insert(inline=True), which is fine 
>> when the returned value is not needed, but the default is inline=False.
>> 
>> I'm just wondering whether I'm not using the type decorator correctly and 
>> this behaviour is expected, or whether this is a due to a bug.
>> 
>> (This problem doesn't seem to happen if table_a.id is of type Text instead 
>> of GUID.)
>> 
>> 
>> Best wishes,
>> 
>> Bruno.
>> 
>> -- 
>> 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 
>> <http://groups.google.com/group/sqlalchemy>.
>> For more options, visit https://groups.google.com/d/optout 
>> <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 
> <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 
> <http://groups.google.com/group/sqlalchemy>.
> For more options, visit https://groups.google.com/d/optout 
> <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.

Reply via email to