Skip to content

new selectinload does not tolerate failing primary join conditions #4777

Closed
@ljos

Description

@ljos

If a foreign key column contains an empty string and there are no corresponding empty string key in the other tables primary key column, sqlalchemy fails with the confusing error KeyError: ('missing_key',):

Traceback (most recent call last):
  File "test.py", line 49, in <module>
    list(session.query(Bar))
  File "/usr/lib/python3.7/site-packages/sqlalchemy/orm/loading.py", line 105, in instances
    util.raise_from_cause(err)
  File "/usr/lib/python3.7/site-packages/sqlalchemy/util/compat.py", line 398, in raise_from_cause
    reraise(type(exception), exception, tb=exc_tb, cause=cause)
  File "/usr/lib/python3.7/site-packages/sqlalchemy/util/compat.py", line 153, in reraise
    raise value
  File "/usr/lib/python3.7/site-packages/sqlalchemy/orm/loading.py", line 93, in instances
    post_load.invoke(context, path)
  File "/usr/lib/python3.7/site-packages/sqlalchemy/orm/loading.py", line 877, in invoke
    loader(context, path, states, self.load_keys, *arg, **kw)
  File "<string>", line 1, in <lambda>
  File "/usr/lib/python3.7/site-packages/sqlalchemy/orm/strategies.py", line 2361, in _load_for_path
    self._load_via_child(our_states, query_info, q, context)
  File "/usr/lib/python3.7/site-packages/sqlalchemy/orm/strategies.py", line 2384, in _load_via_child
    related_obj = data[key]
KeyError: ('missing_key',)

The following python code demonstrates the error:

from sqlalchemy import Column, String, create_engine, ForeignKey
from sqlalchemy.orm import sessionmaker, relationship
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()


class Foo(Base):
    __tablename__ = "Foo"
    foo_id = Column(String(), primary_key=True)


class Bar(Base):
    __tablename__ = "Bar"

    bar_id = Column(String, primary_key=True)
    foo_id = Column(ForeignKey(Foo.foo_id))
    foo = relationship(Foo, lazy="selectin", uselist=False)


engine = create_engine("sqlite://")
Session = sessionmaker(bind=engine)

if __name__ == "__main__":
    engine.execute('CREATE TABLE Bar (bar_id VARCHAR, foo_id VARCHAR, PRIMARY KEY (bar_id));')
    engine.execute('CREATE TABLE Foo (foo_id VARCHAR, PRIMARY KEY (foo_id));')
    engine.execute('INSERT INTO Foo (foo_id) VALUES ("one"), ("two");')
    engine.execute('INSERT INTO Bar (bar_id, foo_id) VALUES ("1", "one"), ("2", "missing_key");')

    session = Session()
    list(session.query(Bar))

Activity

changed the title [-]Empty string in ForeignKey causes `KeyError('',)` if missing in table[/-] [+]Missing ForeignKey causes `KeyError('missing_key',)` if missing in table[/+] on Jul 23, 2019
added
loader optionsORM options like joinedload(), load_only(), these are complicated and have a lot of issues
regressionsomething worked and was broken by a change
on Jul 23, 2019
changed the title [-]Missing ForeignKey causes `KeyError('missing_key',)` if missing in table[/-] [+]new selectinload does not tolerate failing primary join conditions[/+] on Jul 23, 2019
added this to the 1.3.xx milestone on Jul 23, 2019
zzzeek

zzzeek commented on Jul 23, 2019

@zzzeek
Member

this is a regression new in 1.3.6 caused by #4775. please downgrade to 1.3.5 if this issue is problematic for now.

zzzeek

zzzeek commented on Jul 23, 2019

@zzzeek
Member

oh you can also force the old logic like this:

class Bar(Base):
    __tablename__ = "Bar"

    bar_id = Column(String, primary_key=True)
    foo_id = Column(ForeignKey(Foo.foo_id))
    foo = relationship(Foo, lazy="selectin", uselist=False, omit_join=False)

ljos

ljos commented on Jul 23, 2019

@ljos
Author

I also found that chaging the line at "/sqlalchemy/orm/strategies.py", line 2384, in _load_via_child to:

    related_obj = data.get(key, None)

fixed the problem as well. I just couldn't figure out how to write a test for it.

sqla-tester

sqla-tester commented on Jul 23, 2019

@sqla-tester
Collaborator

Mike Bayer has proposed a fix for this issue in the master branch:

Don't assume m2o key is present in the dictionary https://gerrit.sqlalchemy.org/1373

sqla-tester

sqla-tester commented on Jul 23, 2019

@sqla-tester
Collaborator

Mike Bayer has proposed a fix for this issue in the rel_1_3 branch:

Don't assume m2o key is present in the dictionary https://gerrit.sqlalchemy.org/1374

added a commit that references this issue on Jul 23, 2019
c4e7fed
modified the milestones: 1.3.xx, 1.3.x on Dec 18, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    loader optionsORM options like joinedload(), load_only(), these are complicated and have a lot of issuesormregressionsomething worked and was broken by a change

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @zzzeek@ljos@sqla-tester

        Issue actions

          new selectinload does not tolerate failing primary join conditions · Issue #4777 · sqlalchemy/sqlalchemy