On Feb 5, 2012, at 7:50 PM, Anthony Foglia wrote:
> How do I set up an engine so that Oracle Number fields are not
> converted to Decimal?
>
> I'm dealing with a bunch of code with hand-rolled SQL query strings,
> and as the first step was going to use connections from SqlAlchemy's
> connection pool, as I change the queries one-by-one. The only problem
> is that our main queries get 500 Number columns and SqlAlchemy is
> converting them to Decimals, slowing the queries down by a factor of
> 10.
>
> Here's an example
>
>>>> engine = sqlalchemy.create_engine("oracle+cx_oracle://"+connString)
>>>> conn = engine.pool.connect()
>>>> cursor = conn.cursor()
>>>> cursor.execute("""SELECT * FROM MY_TABLE""")
>>>> r = cursor.fetchone()
>>>> r[-1]
> Decimal('0.878935370620606')
>
> The conversion is done via the outputtypehandler of the connection
> object. I can circumvent it by either setting
>
>>>> cursor.connection.outputtypehandler = None
>
> or
>
>>>> cursor.outputtypehandler = lambda *args : None
>
> but is there a better, more standard way to convert the Numbers to
> floats and not Decimals for arbitrary queries?
>
> (Setting engine.dialect.supports_native_decimal to False doesn't work.
> I believe the dialect is creating the output type handler before any
> connection is opened.)
The output handler is there because otherwise cx_oracle immediately converts to
Python float, which is then a lossy format. So we need to turn that off on
cx_oracle's side immediately. There's a lot of discussion of this at
http://docs.sqlalchemy.org/en/latest/dialects/oracle.html#precision-numerics .
My first suggestion would be to just use cdecimal. That way performance would
not be an issue - I patch it in at program start time using the example at
http://docs.sqlalchemy.org/en/latest/core/types.html#sqlalchemy.types.Numeric .
I've been using this approach in production financial applications for
several years without issue.
If you use the Float() type, the Decimal will be coerced into a regular
float(), but you're looking for performance here so that's not the solution.
There's not a public API right now to turn off this handling - it would imply
the _OracleNumeric type and other parts of the cx_oracle dialect would need to
be further complicated to support two modes of operation, and it was enormously
difficult to get precision numeric round trips as it is. A monkeypatch that
would force it off would be:
engine = create_engine(...)
engine.dialect._to_decimal = float
another way you could do it would be to use a connection pool event. Using
the connect event:
from sqlalchemy import event
@event.listens_for(engine, "connect")
def connect(connection, rec):
connection.outputtypehandler = None
Note that disabling the outputtypehandler will also mess up unicode handling,
unless you replace it with another output handler that returns a "unicode"
cursor.var().
--
You received this message because you are subscribed to the Google Groups
"sqlalchemy" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/sqlalchemy?hl=en.