Columns incorrectly renamed when using label_length

Issue #2610 resolved
Former user created an issue

The code below will fail when a column name in ModelA is longer than "label_length". This happens in all versions after 0.7.5.

The sql generated is:

SELECT tbl_b.id AS _1, tbl_b.a_id AS _2, _1.id AS _3, _1._5 AS _4 
FROM tbl_b LEFT OUTER JOIN tbl_a AS _1 ON _1.id = tbl_b.a_id

"_1._5 AS _4" should be "_.1.abcde AS _4"

import sqlalchemy as sql
from sqlalchemy import orm, Column as C
from sqlalchemy.ext.declarative import declarative_base

BaseModel = declarative_base()


class ModelA(BaseModel):

    __tablename__ = 'tbl_a'

    id = C(sql.Integer, primary_key=True)

    abcde = C(sql.String)


class ModelB(BaseModel):

    __tablename__ = 'tbl_b'

    id = C(sql.Integer, primary_key=True)
    a_id = C(sql.Integer, sql.ForeignKey(ModelA.id))

    modela = orm.relationship(ModelA)


engine = sql.create_engine('sqlite://', label_length=4)
BaseModel.metadata.bind = engine
BaseModel.metadata.create_all()
Session = orm.sessionmaker(bind=engine)
ses = Session()

m_a = ModelA()
m_b = ModelB(modela=m_a)

ses.add(m_b)

ses.commit()

ses.query(ModelB).options(orm.joinedload(ModelB.modela)).all()

Comments (5)

  1. Mike Bayer repo owner

    here's a test

    from sqlalchemy.engine import default
    from sqlalchemy.sql import table, column, select
    
    dialect = default.DefaultDialect(label_length=4)
    t1 = table('a', column('abcde'))
    a1 = t1.alias(name='asdf')
    
    print select([a1](a1)).compile(dialect=dialect)
    

    and here's a patch that doesn't work elsewhere but illustrates where the tinkering will be needed

    diff -r 7bd1dbc4cf009c92f943a9f5313f99e8db604c41 lib/sqlalchemy/schema.py
    --- a/lib/sqlalchemy/schema.py  Mon Nov 19 10:23:11 2012 -0500
    +++ b/lib/sqlalchemy/schema.py  Mon Nov 19 21:16:06 2012 -0500
    @@ -1118,7 +1118,7 @@
                         "been assigned.")
             try:
                 c = self._constructor(
    -                expression._as_truncated(name or self.name),
    +                expression._as_truncated(name) if name else self.name,
                     self.type,
                     key=key if key else name if name else self.key,
                     primary_key=self.primary_key,
    diff -r 7bd1dbc4cf009c92f943a9f5313f99e8db604c41 lib/sqlalchemy/sql/expression.py
    --- a/lib/sqlalchemy/sql/expression.py  Mon Nov 19 10:23:11 2012 -0500
    +++ b/lib/sqlalchemy/sql/expression.py  Mon Nov 19 21:16:06 2012 -0500
    @@ -4415,7 +4415,7 @@
             # otherwise its considered to be a label
             is_literal = self.is_literal and (name is None or name == self.name)
             c = self._constructor(
    -                    _as_truncated(name if name else self.name),
    +                    _as_truncated(name) if name else self.name,
                         selectable=selectable,
                         type_=self.type,
                         is_literal=is_literal
    
  2. Mike Bayer repo owner

    also, the reason this case isn't covered is that the original assumption of label_length (and possibly requirement, I need to re-acquaint myself with the code here) was that it's only used to satisfy the max identifier length of the target database, from which it follows that no column name would ever be outside of that range.

  3. Mike Bayer repo owner

    the attached patch fixes this and passes all tests. some cleanup will be needed and tests for the new functionality, and we may want to modernize test_labels also.

    This is best left in the 0.8 series for now. If there are major issues with that let me know.

  4. Log in to comment