From 34dbe6afa27db5288629e1ec6fe5fbcd675a3b2f Mon Sep 17 00:00:00 2001 From: zhouyizhen Date: Wed, 5 Jun 2024 15:28:53 -0400 Subject: [PATCH] Fix postgres detect serial in autogenerate (#1479) Fixes: https://github.com/sqlalchemy/alembic/issues/1479 ### Description In https://github.com/sqlalchemy/alembic/issues/73, it tries to detact postgresql serial in autogenerate, so it won't take `nextval('seq'::regclass)` as server default for that column. But it takes not effect for tables not in search path. This PR fixed it. ### Checklist This pull request is: - [ ] A documentation / typographical error fix - Good to go, no issue or tests are needed - [x] A short code fix - please include the issue number, and create an issue if none exists, which must include a complete example of the issue. one line code fixes without an issue and demonstration will not be accepted. - Please include: `Fixes: #` in the commit message - please include tests. one line code fixes without tests will not be accepted. - [ ] A new feature implementation - please include the issue number, and create an issue if none exists, which must include a complete example of how the feature would look. - Please include: `Fixes: #` in the commit message - please include tests. **Have a nice day!** Closes: #1486 Pull-request: https://github.com/sqlalchemy/alembic/pull/1486 Pull-request-sha: 24df8f906d281df92c531df5a9e1f64d8cdb8527 Change-Id: I50276875bfb1d4f920f0fcd20136337ae09b5384 --- alembic/ddl/postgresql.py | 3 ++- docs/build/unreleased/1479.rst | 6 +++++ tests/test_postgresql.py | 44 +++++++++++++++++++++------------- 3 files changed, 36 insertions(+), 17 deletions(-) create mode 100644 docs/build/unreleased/1479.rst diff --git a/alembic/ddl/postgresql.py b/alembic/ddl/postgresql.py index 6507fcbd..de64a4e0 100644 --- a/alembic/ddl/postgresql.py +++ b/alembic/ddl/postgresql.py @@ -218,7 +218,8 @@ def autogen_column_reflect(self, inspector, table, column_info): "join pg_class t on t.oid=d.refobjid " "join pg_attribute a on a.attrelid=t.oid and " "a.attnum=d.refobjsubid " - "where c.relkind='S' and c.relname=:seqname" + "where c.relkind='S' and " + "c.oid=cast(:seqname as regclass)" ), seqname=seq_match.group(1), ).first() diff --git a/docs/build/unreleased/1479.rst b/docs/build/unreleased/1479.rst new file mode 100644 index 00000000..5a653201 --- /dev/null +++ b/docs/build/unreleased/1479.rst @@ -0,0 +1,6 @@ +.. change:: + :tags: bug, autogenerate, postgresql + :tickets: 1479 + + Fixed the detection of serial column in autogenerate with tables + not under default schema on PostgreSQL diff --git a/tests/test_postgresql.py b/tests/test_postgresql.py index 5741b080..e42ea9d3 100644 --- a/tests/test_postgresql.py +++ b/tests/test_postgresql.py @@ -859,8 +859,8 @@ def teardown_class(cls): clear_staging_env() @provide_metadata - def _expect_default(self, c_expected, col, seq=None): - Table("t", self.metadata, col) + def _expect_default(self, c_expected, col, schema=None, seq=None): + Table("t", self.metadata, col, schema=schema) self.autogen_context.metadata = self.metadata @@ -871,7 +871,7 @@ def _expect_default(self, c_expected, col, seq=None): insp = inspect(config.db) uo = ops.UpgradeOps(ops=[]) - _compare_tables({(None, "t")}, set(), insp, uo, self.autogen_context) + _compare_tables({(schema, "t")}, set(), insp, uo, self.autogen_context) diffs = uo.as_diffs() tab = diffs[0][1] @@ -884,12 +884,12 @@ def _expect_default(self, c_expected, col, seq=None): insp = inspect(config.db) uo = ops.UpgradeOps(ops=[]) - m2 = MetaData() + m2 = MetaData(schema=schema) Table("t", m2, Column("x", BigInteger())) self.autogen_context.metadata = m2 _compare_tables( - {(None, "t")}, - {(None, "t")}, + {(schema, "t")}, + {(schema, "t")}, insp, uo, self.autogen_context, @@ -903,35 +903,47 @@ def _expect_default(self, c_expected, col, seq=None): c_expected, ) - def test_serial(self): - self._expect_default(None, Column("x", Integer, primary_key=True)) + @testing.combinations((None,), ("test_schema",)) + def test_serial(self, schema): + self._expect_default( + None, Column("x", Integer, primary_key=True), schema + ) - def test_separate_seq(self): - seq = Sequence("x_id_seq") + @testing.combinations((None,), ("test_schema",)) + def test_separate_seq(self, schema): + seq = Sequence("x_id_seq", schema=schema) + seq_name = seq.name if schema is None else f"{schema}.{seq.name}" self._expect_default( - "nextval('x_id_seq'::regclass)", + f"nextval('{seq_name}'::regclass)", Column( "x", Integer, server_default=seq.next_value(), primary_key=True ), + schema, seq, ) - def test_numeric(self): - seq = Sequence("x_id_seq") + @testing.combinations((None,), ("test_schema",)) + def test_numeric(self, schema): + seq = Sequence("x_id_seq", schema=schema) + seq_name = seq.name if schema is None else f"{schema}.{seq.name}" self._expect_default( - "nextval('x_id_seq'::regclass)", + f"nextval('{seq_name}'::regclass)", Column( "x", Numeric(8, 2), server_default=seq.next_value(), primary_key=True, ), + schema, seq, ) - def test_no_default(self): + @testing.combinations((None,), ("test_schema",)) + def test_no_default(self, schema): self._expect_default( - None, Column("x", Integer, autoincrement=False, primary_key=True) + None, + Column("x", Integer, autoincrement=False, primary_key=True), + schema, )