From: Mike Bayer Date: Tue, 24 Apr 2012 20:08:35 +0000 (-0400) Subject: - [bug] All of UniqueConstraint, ForeignKeyConstraint, X-Git-Tag: rel_0_8_0b1~453 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=f69ccd193b5f1bfe4f2f50e93fe912ceac1af66e;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - [bug] All of UniqueConstraint, ForeignKeyConstraint, CheckConstraint, and PrimaryKeyConstraint will attach themselves to their parent table automatically when they refer to a Table-bound Column object directly (i.e. not just string column name), and refer to one and only one Table. Prior to 0.8 this behavior occurred for UniqueConstraint and PrimaryKeyConstraint, but not ForeignKeyConstraint or CheckConstraint. [ticket:2410] --- diff --git a/CHANGES b/CHANGES index 5e5790554f..8d3153bed1 100644 --- a/CHANGES +++ b/CHANGES @@ -173,6 +173,16 @@ CHANGES by setting "case_insensitive=False" on create_engine(). [ticket:2423] + - [bug] All of UniqueConstraint, ForeignKeyConstraint, + CheckConstraint, and PrimaryKeyConstraint will + attach themselves to their parent table automatically + when they refer to a Table-bound Column object directly + (i.e. not just string column name), and refer to + one and only one Table. Prior to 0.8 this behavior + occurred for UniqueConstraint and PrimaryKeyConstraint, + but not ForeignKeyConstraint or CheckConstraint. + [ticket:2410] + - [bug] column.label(None) now produces an anonymous label, instead of returning the column object itself, consistent with the behavior diff --git a/lib/sqlalchemy/schema.py b/lib/sqlalchemy/schema.py index 0a22d8855d..f710ae7367 100644 --- a/lib/sqlalchemy/schema.py +++ b/lib/sqlalchemy/schema.py @@ -1980,6 +1980,14 @@ class CheckConstraint(Constraint): self.sqltext = expression._literal_as_text(sqltext) if table is not None: self._set_parent_with_dispatch(table) + else: + cols = sqlutil.find_columns(self.sqltext) + tables = set([c.table for c in cols + if c.table is not None]) + if len(tables) == 1: + self._set_parent_with_dispatch( + tables.pop()) + def __visit_name__(self): if isinstance(self.parent, Table): @@ -2083,6 +2091,11 @@ class ForeignKeyConstraint(Constraint): if table is not None: self._set_parent_with_dispatch(table) + elif columns and \ + isinstance(columns[0], Column) and \ + columns[0].table is not None: + self._set_parent_with_dispatch(columns[0].table) + @property def columns(self): diff --git a/test/sql/test_constraints.py b/test/sql/test_constraints.py index 5ea5a7edaa..546a14ca2f 100644 --- a/test/sql/test_constraints.py +++ b/test/sql/test_constraints.py @@ -437,7 +437,8 @@ class ConstraintCompilationTest(fixtures.TestBase, AssertsCompiledSQL): ) constraint = CheckConstraint('a < b',name="my_test_constraint", - deferrable=True,initially='DEFERRED', table=t) + deferrable=True,initially='DEFERRED', + table=t) # before we create an AddConstraint, @@ -513,4 +514,44 @@ class ConstraintCompilationTest(fixtures.TestBase, AssertsCompiledSQL): "ALTER TABLE tbl ADD PRIMARY KEY (a)" ) + def test_auto_append_constraint(self): + m = MetaData() + + t = Table('tbl', m, + Column('a', Integer), + Column('b', Integer) + ) + + t2 = Table('t2', m, + Column('a', Integer), + Column('b', Integer) + ) + + for c in ( + UniqueConstraint(t.c.a), + CheckConstraint(t.c.a > 5), + ForeignKeyConstraint([t.c.a], [t2.c.a]), + PrimaryKeyConstraint(t.c.a) + ): + assert c in t.constraints + t.append_constraint(c) + assert c in t.constraints + c = Index('foo', t.c.a) + assert c in t.indexes + + def test_ambig_check_constraint_auto_append(self): + m = MetaData() + + t = Table('tbl', m, + Column('a', Integer), + Column('b', Integer) + ) + + t2 = Table('t2', m, + Column('a', Integer), + Column('b', Integer) + ) + c = CheckConstraint(t.c.a > t2.c.b) + assert c not in t.constraints + assert c not in t2.constraints \ No newline at end of file