From: Ellis Valentiner Date: Mon, 8 Jan 2024 16:16:21 +0000 (-0500) Subject: Support reflecting no inherit check constraint in pg. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=890b84e1693ce702ef0e20046cadc6e741274013;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git Support reflecting no inherit check constraint in pg. Added support for reflection of PostgreSQL CHECK constraints marked with "NO INHERIT", setting the key ``no_inherit=True`` in the reflected data. Pull request courtesy Ellis Valentiner. Fixes: #10777 Closes: #10778 Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/10778 Pull-request-sha: 058082ff6297f9ccdc4977e65ef024e9a093426e Change-Id: Ia33e29c0c57cf0076e8819311f4628d712fdc332 --- diff --git a/doc/build/changelog/unreleased_20/10777.rst b/doc/build/changelog/unreleased_20/10777.rst new file mode 100644 index 0000000000..cee5092e8d --- /dev/null +++ b/doc/build/changelog/unreleased_20/10777.rst @@ -0,0 +1,7 @@ +.. change:: + :tags: usecase, postgresql, reflection + :tickets: 10777 + + Added support for reflection of PostgreSQL CHECK constraints marked with + "NO INHERIT", setting the key ``no_inherit=True`` in the reflected data. + Pull request courtesy Ellis Valentiner. diff --git a/lib/sqlalchemy/dialects/postgresql/base.py b/lib/sqlalchemy/dialects/postgresql/base.py index a7cd0ca829..c39e8be75c 100644 --- a/lib/sqlalchemy/dialects/postgresql/base.py +++ b/lib/sqlalchemy/dialects/postgresql/base.py @@ -4696,9 +4696,13 @@ class PGDialect(default.DefaultDialect): # "CHECK (((a > 1) AND (a < 5))) NOT VALID" # "CHECK (some_boolean_function(a))" # "CHECK (((a\n < 1)\n OR\n (a\n >= 5))\n)" + # "CHECK (a NOT NULL) NO INHERIT" + # "CHECK (a NOT NULL) NO INHERIT NOT VALID" m = re.match( - r"^CHECK *\((.+)\)( NOT VALID)?$", src, flags=re.DOTALL + r"^CHECK *\((.+)\)( NO INHERIT)?( NOT VALID)?$", + src, + flags=re.DOTALL, ) if not m: util.warn("Could not parse CHECK constraint text: %r" % src) @@ -4712,8 +4716,14 @@ class PGDialect(default.DefaultDialect): "sqltext": sqltext, "comment": comment, } - if m and m.group(2): - entry["dialect_options"] = {"not_valid": True} + if m: + do = {} + if " NOT VALID" in m.groups(): + do["not_valid"] = True + if " NO INHERIT" in m.groups(): + do["no_inherit"] = True + if do: + entry["dialect_options"] = do check_constraints[(schema, table_name)].append(entry) return check_constraints.items() diff --git a/test/dialect/postgresql/test_reflection.py b/test/dialect/postgresql/test_reflection.py index ab4fa2c038..dd6c8aa88e 100644 --- a/test/dialect/postgresql/test_reflection.py +++ b/test/dialect/postgresql/test_reflection.py @@ -2197,6 +2197,42 @@ class ReflectionTest( ], ) + def test_reflect_with_no_inherit_check_constraint(self): + rows = [ + ("foo", "some name", "CHECK ((a IS NOT NULL)) NO INHERIT", None), + ( + "foo", + "some name", + "CHECK ((a IS NOT NULL)) NO INHERIT NOT VALID", + None, + ), + ] + conn = mock.Mock( + execute=lambda *arg, **kw: mock.MagicMock( + fetchall=lambda: rows, __iter__=lambda self: iter(rows) + ) + ) + check_constraints = testing.db.dialect.get_check_constraints( + conn, "foo" + ) + eq_( + check_constraints, + [ + { + "name": "some name", + "sqltext": "a IS NOT NULL", + "dialect_options": {"no_inherit": True}, + "comment": None, + }, + { + "name": "some name", + "sqltext": "a IS NOT NULL", + "dialect_options": {"not_valid": True, "no_inherit": True}, + "comment": None, + }, + ], + ) + def _apply_stm(self, connection, use_map): if use_map: return connection.execution_options(