relationship comparisons to None are also leaking NEVER_SET, but also are potentially not forwards-compatible

Issue #3371 resolved
Mike Bayer repo owner created an issue
from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()


class A(Base):
    __tablename__ = 'a'
    id = Column(Integer, primary_key=True)

    status = Column(Integer)


class B(Base):
    __tablename__ = 'b'
    id = Column(Integer, primary_key=True)
    a_id = Column(ForeignKey('a.id'))

    status = Column(Integer)

    a = relationship("A")

    special_a = relationship(
        "A",
        primaryjoin="and_(A.id == B.a_id, A.status == B.status)"
    )

e = create_engine("sqlite://", echo=True)
Base.metadata.create_all(e)

s = Session(e)
print s.query(B).filter(B.special_a == A()).all()

in SA 1.0 we get the NEVER_SET symbols:

#!


SELECT b.id AS b_id, b.a_id AS b_a_id, b.status AS b_status 
FROM b 
WHERE ? = b.a_id AND ? = b.status
2015-04-20 15:04:06,533 INFO sqlalchemy.engine.base.Engine (symbol('NEVER_SET'), symbol('NEVER_SET'))

however, in 0.9 we still get a query that isn't forwards compatible, if we learn to fix those = comparisons to be "IS" for a NULL value:

#!


SELECT b.id AS b_id, b.a_id AS b_a_id, b.status AS b_status 
FROM b 
WHERE ? = b.a_id AND ? = b.status
2015-04-20 15:04:48,556 INFO sqlalchemy.engine.base.Engine (None, None)

above, if we ever fixed "? = b.status" to be "b.status IS NULL", the results would change.

therefore we should emit a warning, at least when the comparison is against a column that is not primary_key=True (for PK=true, which is the common case, PK cols are never NULL so the "False" comparison is OK).

Comments (1)

  1. Mike Bayer reporter
    • Fixed more regressions caused by NEVER_SET; comparisons to transient objects with attributes unset would leak NEVER_SET, and negated_contains_or_equals would do so for any transient object as the comparison used only the committed value. Repaired the NEVER_SET cases, fixes #3371, and also made negated_contains_or_equals() use state_attr_by_column() just like a non-negated comparison, fixes #3374

    → <<cset a3af638e1a95>>

  2. Log in to comment