On 04/22/2016 10:40 AM, Piotr Dobrogost wrote:
It seems BufferedColumnResultProxy class (used only in Oracle dialect)
has a bug.

_init_metadata() method defined at
https://github.com/zzzeek/sqlalchemy/blob/rel_1_0_12/lib/sqlalchemy/engine/result.py#L1238
is being called even for already cached data (that's probably bug) and
because this method clears a list of processors (metadata._processors =
[None for _ in range(len(metadata.keys))]) the list of original
processors (metadata._orig_processors) gets cleared the second time
_init_metadata() method is called. The end result is that column's value
is not being processed to proper Python type from the db original type
and one gets errors like:

File
"/home/piotr/.virtualenvs/kotti/lib/python2.7/site-packages/sqlalchemy/ext/mutable.py",
line 403, in coerce
raise ValueError(msg % (key, type(value)))
ValueError: Attribute '_acl' does not accept objects of type <type
'cx_Oracle.LOB'>

Whole traceback is available at http://pastebin.com/Ssui33XC

Guarding method's body after line L1240 with "if not hasattr(metadata,
'_orig_processors'):" solves the problem but it's neither pretty nor
it's the right solution. The right solution is probably to not call
_init_metadata() method on cached data at all.

I'd appreciate if someone with good understanding of SA internals could
take a look and confirm (better yet fix) this bug.

I cannot confirm it, would need a test case. Here's one that is extremely simple but exercises the features you describe. I have no doubt that what you're seeing is a bug however so I'd need to know what to add to this test to illustrate the issue:

from sqlalchemy import create_engine
from sqlalchemy import select, literal, type_coerce
from sqlalchemy import LargeBinary, TypeDecorator

e = create_engine("oracle://scott:tiger@xe", echo='debug')

class MyType(TypeDecorator):
    impl = LargeBinary()

    def process_result_value(self, value, dialect):
        return value + "HELLO"

result = e.execute(select([type_coerce(literal('well '), MyType)]))

from sqlalchemy.engine.result import BufferedColumnResultProxy
assert isinstance(result, BufferedColumnResultProxy)

value = result.scalar()
print value
assert value == 'well HELLO'


output:

2016-04-22 11:12:46,581 INFO sqlalchemy.engine.base.Engine SELECT USER FROM DUAL
2016-04-22 11:12:46,581 INFO sqlalchemy.engine.base.Engine {}
2016-04-22 11:12:46,581 DEBUG sqlalchemy.engine.base.Engine Col ('USER',)
2016-04-22 11:12:46,582 DEBUG sqlalchemy.engine.base.Engine Row ('SCOTT',)
2016-04-22 11:12:46,582 INFO sqlalchemy.engine.base.Engine SELECT CAST('test plain returns' AS VARCHAR(60 CHAR)) AS anon_1 FROM DUAL
2016-04-22 11:12:46,582 INFO sqlalchemy.engine.base.Engine {}
2016-04-22 11:12:46,583 INFO sqlalchemy.engine.base.Engine SELECT CAST('test unicode returns' AS NVARCHAR2(60)) AS anon_1 FROM DUAL
2016-04-22 11:12:46,583 INFO sqlalchemy.engine.base.Engine {}
2016-04-22 11:12:46,584 INFO sqlalchemy.engine.base.Engine SELECT :param_1 AS anon_1 FROM DUAL 2016-04-22 11:12:46,584 INFO sqlalchemy.engine.base.Engine {'param_1': 'well '}
2016-04-22 11:12:46,587 DEBUG sqlalchemy.engine.base.Engine Col ('ANON_1',)
2016-04-22 11:12:46,587 DEBUG sqlalchemy.engine.base.Engine Row (<cx_Oracle.LOB object at 0x7f37f3029050>,)
well HELLO




I have to admit it
took a top notch developer a couple of hours of debugging to go through
much of SA code and establish the root cause of this problem.

There is no need for you or your developers to attempt to debug deep issues like these; I can identify them within minutes given a demonstration of the behavior and I am glad to do this work once an incorrect behavior is demonstrated.

The work that you need to do when you encounter stack traces like this is to isolate the behavior into a simple test case, such as the one I have above. Using the "divide and conquer" approach, where you begin with your whole application, then slowly remove pieces of it that continue to exhibit the bad behavior until you have something entirely minimal. The guidelines that I often refer to at http://stackoverflow.com/help/mcve have an excellent description of this.


I'm going to raise issue on tracker as soon as someone confirms this bug.

Best regards,
Piotr Dobrogost

--
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 https://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 https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

Reply via email to