Thanks a lot Mike.
Although I did see the "Specify 'fetch' or False for the
synchronize_session parameter" in the error I associated that with a
connection-time parameter and I thought 'no.. that has nothing to do with
my problem'.
My bad.
Thanks a lot.

On Mon, Apr 13, 2015 at 3:31 PM, Mike Bayer <mike...@zzzcomputing.com>
wrote:

>
>
> On 4/13/15 2:25 PM, Gabriel Becedillas wrote:
>
> Dear Michael,
> Thanks a lot for your reply.
> In trying to narrow the problem as much as possible, I missed something
> important in my example. I'm actually doing an UPDATE, not a SELECT. When I
> wrote 'I tried casting my decimals using sqlalcheme.cast(...,
> sqlalchemy.Numeric(precision=16, scale=8)) but that didn't work because the
> filter expression failed' I meant that it didn't work in an update
> scenario. In a select scenario it works ok. This is what I should have
> wrote in my bug_test.py:
>
>   amount = decimal.Decimal('0.00000001')
>  query = session.query(Balance)
>  query = query.filter(
>      Balance.available_balance + sqlalchemy.cast(amount,
> sqlalchemy.Numeric(precision=16, scale=8)) <= Balance.full_balance
>  )
>
>   values = {}
>  values[Balance.available_balance] = Balance.available_balance + amount
>  row_count = query.update(values)
>  print row_count, "rows updated"
>
>
>  and the error I get is 'sqlalchemy.exc.InvalidRequestError: Could not
> evaluate current criteria in Python. Specify 'fetch' or False for the
> synchronize_session parameter.'. This is not even getting to MySQL.
>
> for query.update() you usually want to send synchronize_session=False.
>
> also the cast() needs to be Decimal(), not Numeric().  Will not work with
> Numeric().
>
>
>
>
>   Thanks a lot
>
> On Monday, April 13, 2015 at 2:46:14 PM UTC-3, Michael Bayer wrote:
>>
>>
>>
>> On 4/13/15 11:50 AM, Gabriel Becedillas wrote:
>>
>> Dear all,
>> I have a table that has 2 numeric columns, and I'm writing a query that
>> performs some arithmetic on the filter clause between those columns and a
>> Decimal. The problem that I'm facing is that I don't get any results at
>> all. After a while I realized that the SQL statement getting generated is
>> dumping Decimals as strings, and when strings are involved in a numeric
>> expression they get converted to floats. So, my query is not returning
>> anything at all due to float representation limitations.
>>
>>  I tried casting my decimals using sqlalcheme.cast(...,
>> sqlalchemy.Numeric(precision=16, scale=8)) but that didn't work because
>> the filter expression failed. Can anyone help me in getting a cast over a
>> query parameter to work in a filter expression ?
>>
>>
>> this is driver stuff.  If you change the query to see what you're getting:
>>
>> query = session.query(Balance.available_balance + amount,
>> Balance.full_balance)
>>
>> you can see there's some floating point noise in there, not to mention
>> we're even getting the value back as a floating point:
>>
>> Col (u'anon_1', u'balance_full_balance')
>> 2015-04-13 13:10:39,798 DEBUG sqlalchemy.engine.base.Engine Row
>> (3.0000000000000004e-08, Decimal('3E-8'))
>>
>> I'm getting the same result with MySQL-Python, PyMySQL, and
>> Mysql-connector.   The issue is definitely in the drivers however, the code
>> below produces no result for all three drivers:
>>
>>     conn = engine.raw_connection()
>>     cursor = conn.cursor()
>>     cursor.execute(
>>         "SELECT balance.available_balance + %s AS anon_1, "
>>         "balance.full_balance AS balance_full_balance FROM balance "
>>         "WHERE balance.available_balance + %s <= balance.full_balance",
>>         (amount, amount))
>>
>>     print cursor.fetchall()
>>
>> If I embed the number 0000000.1 as is into the query without using a
>> parameter, then it works, as it does on the command line.
>>
>> Looking into PyMySQL since that's the driver I'm most familiar with, if
>> we send a Decimal it is doing this:
>>
>> SELECT balance.available_balance + 1E-8 AS anon_1, balance.full_balance
>> AS balance_full_balance FROM balance WHERE balance.available_balance + 1E-8
>> <= balance.full_balance
>>
>> What is interesting is that these values as passed in an INSERT *are*
>> working correctly.    Which means really, this is a MySQL bug; I can prove
>> it at the command line.
>>
>> First, we illustrate that scientific notation *is* accepted directly by
>> MySQL:
>>
>> mysql> insert into balance (full_balance, available_balance) values
>> (3E-8, 2E-8);
>> Query OK, 1 row affected (0.00 sec)
>>
>>
>> values go in just fine (note I increased the scale in the table here,
>> hence the two trailing 0's):
>>
>> mysql> select * from balance;
>> +----+--------------+-------------------+
>> | id | full_balance | available_balance |
>> +----+--------------+-------------------+
>> |  2 | 0.0000000300 |      0.0000000200 |
>> +----+--------------+-------------------+
>> 1 row in set (0.00 sec)
>>
>> but in the WHERE clause, *it fails*:
>>
>> mysql> select * from balance where available_balance + 1E-8 <=
>> full_balance;
>> Empty set (0.00 sec)
>>
>> writing out the whole value, *it succeeds*:
>>
>> mysql> select * from balance where available_balance + 0.00000001 <=
>> full_balance;
>> +----+--------------+-------------------+
>> | id | full_balance | available_balance |
>> +----+--------------+-------------------+
>> |  2 | 0.0000000300 |      0.0000000200 |
>> +----+--------------+-------------------+
>> 1 row in set (0.00 sec)
>>
>> we can see that *MySQL itself is doing floating point*, so that's really
>> the bug here:
>>
>> mysql> select available_balance + 1E-8 from balance;
>> +----------------------------+
>> | available_balance + 1E-8   |
>> +----------------------------+
>> | 0.000000030000000000000004 |
>> +----------------------------+
>> 1 row in set (0.00 sec)
>>
>> We can in fact make it work with a CAST.  However!  crazytown time.  Even
>> though NUMERIC and DECIMAL are equivalent in MySQL, cast will *not* accept
>> NUMERIC (note SQLAlchemy only warns on these and only as of 1.0 I think):
>>
>> mysql> select available_balance + CAST(1E-8 AS NUMERIC) from balance;
>> ERROR 1064 (42000): You have an error in your SQL syntax; check the
>> manual that corresponds to your MySQL server version for the right syntax
>> to use near 'NUMERIC) from balance' at line 1
>>
>> But it *will* accept DECIMAL:
>>
>> mysql> select available_balance + CAST(1E-8 AS DECIMAL) from balance;
>> +-------------------------------------------+
>> | available_balance + CAST(1E-8 AS DECIMAL) |
>> +-------------------------------------------+
>> |                              0.0000000200 |
>> +-------------------------------------------+
>> 1 row in set (0.00 sec)
>>
>> So there's our answer:
>>
>>     from sqlalchemy import cast, DECIMAL
>>
>>     amount = decimal.Decimal('0.00000001')
>>     query = session.query(Balance.available_balance + cast(amount,
>> DECIMAL()), Balance.full_balance)
>>     query = query.filter(
>>         Balance.available_balance + cast(amount, DECIMAL()) <=
>> Balance.full_balance
>>     )
>>
>>
>> SELECT balance.available_balance + CAST(%s AS DECIMAL) AS anon_1,
>> balance.full_balance AS balance_full_balance
>> FROM balance
>> WHERE balance.available_balance + CAST(%s AS DECIMAL) <=
>> balance.full_balance
>> 2015-04-13 13:43:16,630 INFO sqlalchemy.engine.base.Engine
>> (Decimal('1E-8'), Decimal('1E-8'))
>> 2015-04-13 13:43:16,631 DEBUG sqlalchemy.engine.base.Engine Col
>> (u'anon_1', u'balance_full_balance')
>> 2015-04-13 13:43:16,631 DEBUG sqlalchemy.engine.base.Engine Row
>> (Decimal('2E-8'), Decimal('3E-8'))
>> 1 should be > 0
>>
>> The drivers would really be nice if they expanded out these values from
>> scientific notation.    However, MySQL's bizarrely inconsistent behavior
>> here is probably why the need for this hasn't been observed.    So stick
>> with cast(value, DECIMAL()) for now when using the value in the WHERE
>> clause.
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>  I'm attaching a sample to reproduce the issue.
>> Thanks a lot.
>>  --
>> 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+...@googlegroups.com.
>> To post to this group, send email to sqlal...@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.
>
>
>  --
> 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/lRWebyWl_A4/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.

Reply via email to