Skip to content

Commit 498db83

Browse files
committed
Extract table names when comparing to nrte error
Fixed issue where the process of joining two tables could fail if one of the tables had an unrelated, unresolvable foreign key constraint which would raise :class:`_exc.NoReferenceError` within the join process, which nonetheless could be bypassed to allow the join to complete. The logic which tested the exception for signficance within the process would make assumptions about the construct which would fail. Fixes: sqlalchemy#5952 Change-Id: I492dacd082ddcf8abb1310ed447a6ed734595bb7
1 parent f41b9cb commit 498db83

File tree

3 files changed

+67
-2
lines changed

3 files changed

+67
-2
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
.. change::
2+
:tags: bug, orm
3+
:tickets: 5952
4+
5+
Fixed issue where the process of joining two tables could fail if one of
6+
the tables had an unrelated, unresolvable foreign key constraint which
7+
would raise :class:`_exc.NoReferenceError` within the join process, which
8+
nonetheless could be bypassed to allow the join to complete. The logic
9+
which tested the exception for signficance within the process would make
10+
assumptions about the construct which would fail.
11+

lib/sqlalchemy/sql/selectable.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1229,9 +1229,12 @@ def _can_join(cls, left, right, consider_as_foreign_keys=None):
12291229
return bool(constraints)
12301230

12311231
@classmethod
1232+
@util.preload_module("sqlalchemy.sql.util")
12321233
def _joincond_scan_left_right(
12331234
cls, a, a_subset, b, consider_as_foreign_keys
12341235
):
1236+
sql_util = util.preloaded.sql_util
1237+
12351238
a = coercions.expect(roles.FromClauseRole, a)
12361239
b = coercions.expect(roles.FromClauseRole, b)
12371240

@@ -1251,7 +1254,8 @@ def _joincond_scan_left_right(
12511254
try:
12521255
col = fk.get_referent(left)
12531256
except exc.NoReferenceError as nrte:
1254-
if nrte.table_name == left.name:
1257+
table_names = {t.name for t in sql_util.find_tables(left)}
1258+
if nrte.table_name in table_names:
12551259
raise
12561260
else:
12571261
continue
@@ -1270,7 +1274,8 @@ def _joincond_scan_left_right(
12701274
try:
12711275
col = fk.get_referent(b)
12721276
except exc.NoReferenceError as nrte:
1273-
if nrte.table_name == b.name:
1277+
table_names = {t.name for t in sql_util.find_tables(b)}
1278+
if nrte.table_name in table_names:
12741279
raise
12751280
else:
12761281
continue

test/sql/test_selectable.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1834,6 +1834,55 @@ def test_join_cond_no_such_unrelated_column(self):
18341834
assert sql_util.join_condition(t1, t2).compare(t1.c.x == t2.c.id)
18351835
assert sql_util.join_condition(t2, t1).compare(t1.c.x == t2.c.id)
18361836

1837+
def test_join_cond_no_such_unrelated_table_dont_compare_names(self):
1838+
m = MetaData()
1839+
t1 = Table(
1840+
"t1",
1841+
m,
1842+
Column("y", Integer, ForeignKey("t22.id")),
1843+
Column("x", Integer, ForeignKey("t2.id")),
1844+
Column("q", Integer, ForeignKey("t22.id")),
1845+
)
1846+
t2 = Table(
1847+
"t2",
1848+
m,
1849+
Column("id", Integer),
1850+
Column("t3id", ForeignKey("t3.id")),
1851+
Column("z", ForeignKey("t33.id")),
1852+
)
1853+
t3 = Table(
1854+
"t3", m, Column("id", Integer), Column("q", ForeignKey("t4.id"))
1855+
)
1856+
1857+
j1 = t1.join(t2)
1858+
1859+
assert sql_util.join_condition(j1, t3).compare(t2.c.t3id == t3.c.id)
1860+
1861+
def test_join_cond_no_such_unrelated_column_dont_compare_names(self):
1862+
m = MetaData()
1863+
t1 = Table(
1864+
"t1",
1865+
m,
1866+
Column("x", Integer, ForeignKey("t2.id")),
1867+
)
1868+
t2 = Table(
1869+
"t2",
1870+
m,
1871+
Column("id", Integer),
1872+
Column("t3id", ForeignKey("t3.id")),
1873+
Column("q", ForeignKey("t5.q")),
1874+
)
1875+
t3 = Table(
1876+
"t3", m, Column("id", Integer), Column("t4id", ForeignKey("t4.id"))
1877+
)
1878+
t4 = Table("t4", m, Column("id", Integer))
1879+
Table("t5", m, Column("id", Integer))
1880+
j1 = t1.join(t2)
1881+
1882+
j2 = t3.join(t4)
1883+
1884+
assert sql_util.join_condition(j1, j2).compare(t2.c.t3id == t3.c.id)
1885+
18371886
def test_join_cond_no_such_related_table(self):
18381887
m1 = MetaData()
18391888
m2 = MetaData()

0 commit comments

Comments
 (0)