replace_selectable broke, causing missing from-clause on compile

Issue #2518 resolved
Former user created an issue

Usage of replace_selectable in our codebase was working fine as of 0.7.5, and is broken in 0.7.6 up to the tip of rel_0_7.

Below is a boiled-down test case.

Per hg bisect this test starts failing as of 1378bf0d25319f3725cfe8ff947a5f0aeae4cc81; the failure is that the statement compiles without a from-clause.

from sqlalchemy import *
from test.lib import *

class BisectTest(fixtures.TestBase, AssertsCompiledSQL):
    __dialect__ = 'default'

    def test_append_column_after_replace_selectable(self):
        basesel = select([literal_column('1').label('a')](literal_column('1').label('a')))
        tojoin = select([           literal_column('1').label('a'),
            literal_column('2').label('b')
            ](
))
        basefrom = basesel.alias('basefrom')
        joinfrom = tojoin.alias('joinfrom')
        sel = select([basefrom.c.a](basefrom.c.a))
        replaced = sel.replace_selectable(
            basefrom,
            basefrom.join(joinfrom, basefrom.c.a == joinfrom.c.a)
        )
        self.assert_compile(
            replaced,
            "SELECT basefrom.a FROM (SELECT 1 AS a) AS basefrom "
            "JOIN (SELECT 1 AS a, 2 AS b) AS joinfrom "
            "ON basefrom.a = joinfrom.a"
        )
        replaced.append_column(joinfrom.c.b)
        self.assert_compile(
            replaced,
            "SELECT basefrom.a, joinfrom.b FROM (SELECT 1 AS a) AS basefrom "
            "JOIN (SELECT 1 AS a, 2 AS b) AS joinfrom "
            "ON basefrom.a = joinfrom.a"
        )

It's the first assert that fails; the statement compiles to just 'SELECT basefrom.a' (no from-clause).

I left in the append_column and second assert to illustrate the point of this usage.

Comments (4)

  1. Mike Bayer repo owner

    just a note here. replace_selectable() is a weird method, in this specific case, a join of A and B always trumps A and B individually, so the test works if you just use select_from():

    replaced = sel.select_from(basefrom.join(joinfrom, basefrom.c.a == joinfrom.c.a))
    

    just putting that out there. ill see if i can get my head around the replace mechanics here.

  2. Log in to comment