Oracle mapper against select with inheritance and having properties for relations fails in conjunction with normal mapper query

Issue #308 resolved
florian created an issue

Page inherits from content. lang_data has a foreign key to language and content. Making a normal mapper for content/page and making a mapper for a custom select works. Querying the custom select mapper works, but only if the normal mapper hasn't been queried first.

The test programm:

from sqlalchemy import (
    Table, Column,
    BoundMetaData,
    Integer,
    Sequence, ForeignKey,
    create_session,
    mapper, relation,
    )

metadata = BoundMetaData('oracle://test:test@myoracle')

language = Table(
    'language',
    metadata,
    Column('id', Integer, Sequence('language_seq'), primary_key=True),
    )

content = Table(
    'content',
    metadata,
    Column('id', Integer, Sequence('content_seq'), primary_key=True),
    )

lang_data = Table(
    'lang_data',
    metadata,
    Column('id', Integer, Sequence('lang_data_seq'), primary_key=True),
    Column('content_id', Integer, ForeignKey('content.id')),
    Column('language_id', Integer, ForeignKey('language.id')),
    )

page = Table(
    'page',
    metadata,
    Column('id', Integer, ForeignKey('content.id'), primary_key=True),
    )

class ContentType(object): pass
class Content(object): pass
class Page(Content): pass
class Language(object): pass
class LangData(object): pass

languages = mapper(Language, language)
lang_datas = mapper(LangData, lang_data)
lang_datas.add_property('language', relation(languages, lazy=False))
contents = mapper(Content, content)
contents.add_property('lang_data', relation(lang_datas, lazy=False))
pages = mapper(Page, page, inherits=contents)

try:
    metadata.create_all()
    r = content.insert().execute()
    page.insert().execute(id=r.last_inserted_ids()[0](0))

    session = create_session()
    obj = session.query(pages).select() #remove to make error go away 
    m = mapper(Page, content.select().alias('foobar'), non_primary=True)
    session.query(m).select()[0](0).lang_data
finally:
    metadata.drop_all()

The error message:

Traceback (most recent call last):
  File "test_inheritance.py", line 59, in ?
    session.query(m).select()[0](0).lang_data
  File "build/bdist.linux-i686/egg/sqlalchemy/attributes.py", line 32, in __get__
  File "build/bdist.linux-i686/egg/sqlalchemy/attributes.py", line 137, in get
  File "build/bdist.linux-i686/egg/sqlalchemy/orm/properties.py", line 408, in lazyload
  File "build/bdist.linux-i686/egg/sqlalchemy/orm/query.py", line 232, in select_whereclause
  File "build/bdist.linux-i686/egg/sqlalchemy/orm/query.py", line 302, in _select_statement
  File "build/bdist.linux-i686/egg/sqlalchemy/orm/query.py", line 264, in instances
  File "build/bdist.linux-i686/egg/sqlalchemy/orm/session.py", line 114, in execute
  File "build/bdist.linux-i686/egg/sqlalchemy/engine/base.py", line 244, in execute
  File "build/bdist.linux-i686/egg/sqlalchemy/engine/base.py", line 268, in execute_clauseelement
  File "build/bdist.linux-i686/egg/sqlalchemy/engine/base.py", line 284, in execute_compiled
  File "build/bdist.linux-i686/egg/sqlalchemy/engine/base.py", line 280, in proxy
  File "build/bdist.linux-i686/egg/sqlalchemy/engine/base.py", line 319, in _execute_raw
  File "build/bdist.linux-i686/egg/sqlalchemy/engine/base.py", line 338, in _execute
sqlalchemy.exceptions.SQLError: (DatabaseError) ORA-00904: "LANG_DATA_59FB"."LANGUAGE_ID": invalid identifier
 'SELECT lang_data.content_id AS lang_data_content_id, lang_data.id AS lang_data_id, language_8eca.id AS language_8eca_id, lang_data.language_id AS lang_data_language_id \nFROM lang_data lang_data_59fb, lang_data LEFT OUTER JOIN language language_8eca ON language_8eca.id = lang_data_59fb.language_id \nWHERE :lazy_9f71 = lang_data.content_id ORDER BY lang_data.rowid, language_8eca.rowid' {'lazy_9f71': 1}

The wrong sql reformatted:

SELECT 
    lang_data.content_id AS lang_data_content_id, 
    lang_data.id AS lang_data_id, 
    language_8eca.id AS language_8eca_id, 
    lang_data.language_id AS lang_data_language_id
FROM 
    lang_data lang_data_59fb, 
    lang_data LEFT OUTER JOIN language language_8eca ON language_8eca.id = lang_data_59fb.language_id
WHERE 
    :lazy_9f71 = lang_data.content_id ORDER BY lang_data.rowid, language_8eca.rowid

{'lazy_9f71': 1}

Comments (2)

  1. Mike Bayer repo owner

    this is a very complicated bug, which comes down to a failure of the eager loaders on "lang_data" to properly degrade to a lazy loader when the parent object has been loaded by a mapper that does not include columns required by the eager loaders.

    i believe the change made in changeset:1876 addreses it, by moving away the "eager chain" of relations/mappers used to create the join query from the normal chain of mappers that is needed for lazy loading...test case then passes.

    also need to add unit tests to the "eager degrade" set of tests, so keeping it open.

    finding this bug also revealed #309.

  2. Mike Bayer repo owner

    changeset:1877 adds a unit test for deep eager loaders degrading properly to a lazy loader. while its "failure" condition without the fixes from changeset:1876 is not quite as complicated as the test case on this ticket, it still relies on the concept of the eager chain not polluting the default chain of mappers/properties.

  3. Log in to comment