Closed
Description
Migrated issue, originally created by lincolnq (@lincolnq)
On sqlalchemy 1.0.15, the below test code outputs
(test -> %(test_1)s) IS NOT NULL
On sqlalchemy 1.1.0b3, it outputs
test -> %(test_1)s IS NOT NULL
Note the omitted parentheses.
The latter code is correct in Postgres 9.5 and above where the IS NOT NULL operator has lower precedence than ->, but below 9.5, the IS NOT NULL operator's precedence is higher than the -> operator. Thus, SQL fails to compile the expression because -> can't take a boolean on the rhs.
Here is the test case:
from sqlalchemy import Column
from sqlalchemy.dialects import postgresql
col = Column(postgresql.HSTORE, name='test', primary_key=True)
print(str((col['key'] != None).compile(dialect=postgresql.dialect())))
Metadata
Metadata
Assignees
Labels
Type
Projects
Relationships
Development
No branches or pull requests
Activity
sqlalchemy-bot commentedon Sep 27, 2016
Changes by lincolnq (@lincolnq):
sqlalchemy-bot commentedon Sep 27, 2016
Changes by lincolnq (@lincolnq):
sqlalchemy-bot commentedon Sep 27, 2016
lincolnq (@lincolnq) wrote:
I noticed that commit a80bb4e changed the precedence of -> from 5 to 15, which seems like it would explain the problem.
sqlalchemy-bot commentedon Sep 27, 2016
Michael Bayer (@zzzeek) wrote:
If I change it to 5 I get this:
fails with:
which is a disaster.
I don't have a solution at the moment and I have a great fear that the precedence rules here are not backend-agnostic, meaning the whole refactor would have to be done again.
sqlalchemy-bot commentedon Sep 27, 2016
Changes by Michael Bayer (@zzzeek):
sqlalchemy-bot commentedon Sep 27, 2016
Changes by Michael Bayer (@zzzeek):
sqlalchemy-bot commentedon Sep 27, 2016
Michael Bayer (@zzzeek) wrote:
uh but if I change precedence to '5' your test fails anyway. so...that's not the problem.
sqlalchemy-bot commentedon Sep 27, 2016
Michael Bayer (@zzzeek) wrote:
oh, because HSTORE is separate.
sqlalchemy-bot commentedon Sep 27, 2016
Michael Bayer (@zzzeek) wrote:
proposed fix at https://gerrit.sqlalchemy.org/197
sqlalchemy-bot commentedon Sep 29, 2016
lincolnq (@lincolnq) wrote:
I think your fix is probably the right direction -- Sqlalchemy should output extra parentheses for safety and this seems like the right way to do it (though I don't know the code at all so I can't comment on most of it).
This bug's existence implies a whole class of similar operator-precedence bugs on old Postgres (many having nothing to do with HSTORE/JSON) -- it looks like you only implemented the change for HSTORE and JSON, right? It seems like it would be worth making sure all operators which changed precedence between these two versions have the eager_grouping enabled.
https://www.postgresql.org/docs/9.4/static/sql-syntax-lexical.html#SQL-PRECEDENCE-TABLE
https://www.postgresql.org/docs/9.5/static/sql-syntax-lexical.html#SQL-PRECEDENCE-TABLE
sqlalchemy-bot commentedon Sep 29, 2016
Michael Bayer (@zzzeek) wrote:
it looks like they moved the precedence of "IS / IS NOT" to be lower. The use case of "a b <IS/ISNOT> (NULL/true/false)" is not that common outside of the json/hstore index operations, and in any case the issue here is a regression from 1.0.x specific to index operations. The solution I took here was just to hardwire extra parenthesization into these operators, the reason we are conservative about parenthesis otherwise is that you if you aren't you end up with things like "((a + b) / c) + ((((e + f) + g) + h ) + i)" which is difficult to work with and is often rejected by the database itself if the expression is in a less common place (not Postgresql, more like SQL Server, Oracle, SQLite etc. have had issues with unnecessary parenthesis causing syntax errors).
we've not had any issues reported from the change in precedence of IS/ISNOT from 9.4 to 9.5 across existing SQLAlchemy releases, those can be dealt with as they are reported.
sqlalchemy-bot commentedon Oct 3, 2016
Michael Bayer (@zzzeek) wrote:
Add "eager_parenthesis" late-compilation rule, use w/ PG JSON/HSTORE
Added compiler-level flags used by Postgresql to place additional
parenthesis than would normally be generated by precedence rules
around operations involving JSON, HSTORE indexing operators as well as
within their operands since it has been observed that Postgresql's
precedence rules for at least the HSTORE indexing operator is not
consistent between 9.4 and 9.5.
Fixes: #3806
Change-Id: I5899677b330595264543b055abd54f3c76bfabf2
→ 333414f
sqlalchemy-bot commentedon Oct 3, 2016
Changes by Michael Bayer (@zzzeek):
2 remaining items