--- /dev/null
+.. change::
+ :tags: bug, postgresql
+ :tickets: 12761
+
+ A :class:`.CompileError` is raised if attempting to create a PostgreSQL
+ :class:`_postgresql.ENUM` or :class:`_postgresql.DOMAIN` datatype using a
+ name that matches a known pg_catalog datatype name, and a default schema is
+ not specified. These types must be explicit within a schema in order to
+ be differentiated from the built-in pg_catalog type. The "public" or
+ otherwise default schema is not chosen by default here since the type can
+ only be reflected back using the explicit schema name as well (it is
+ otherwise not visible due to the pg_catalog name). Pull request courtesy
+ Kapil Dagur.
+
+
name = self.quote(type_.name)
effective_schema = self.schema_for_object(type_)
+ # a built-in type with the same name will obscure this type, so raise
+ # for that case. this applies really to any visible type with the same
+ # name in any other visible schema that would not be appropriate for
+ # us to check against, so this is not a robust check, but
+ # at least do something for an obvious built-in name conflict
+ if (
+ effective_schema is None
+ and type_.name in self.dialect.ischema_names
+ ):
+ raise exc.CompileError(
+ f"{type_!r} has name "
+ f"'{type_.name}' that matches an existing type, and "
+ "requires an explicit schema name in order to be rendered "
+ "in DDL."
+ )
+
if (
not self.omit_schema
and use_schema
e["name"] for e in inspect(connection).get_enums()
]
+ @testing.variation("type_type", ["enum", "domain"])
+ @testing.variation("use_schema", ["none", "default", "explicit"])
+ def test_builtin_name_conflict(
+ self,
+ connection,
+ metadata,
+ type_type: testing.Variation,
+ use_schema: testing.Variation,
+ ):
+ """test #12761"""
+
+ if use_schema.none:
+ kw = {}
+ elif use_schema.default:
+ kw = {"schema": testing.db.dialect.default_schema_name}
+ elif use_schema.explicit:
+ kw = {"schema": testing.config.test_schema}
+ else:
+ use_schema.fail()
+
+ if type_type.enum:
+ type_ = ENUM("a", "b", "c", name="text", **kw)
+ elif type_type.domain:
+ type_ = DOMAIN(name="text", data_type=Integer, **kw)
+ else:
+ type_type.fail()
+
+ Table("t", metadata, Column("c", type_))
+
+ if use_schema.none:
+ with expect_raises_message(
+ exc.CompileError,
+ r"(ENUM.*|DOMAIN.*) has name 'text' that "
+ r"matches an existing type,",
+ ):
+ metadata.create_all(connection)
+ return
+
+ metadata.create_all(connection)
+
+ type_names = (
+ {elem["name"] for elem in inspect(connection).get_enums(**kw)}
+ if type_type.enum
+ else {
+ elem["name"] for elem in inspect(connection).get_domains(**kw)
+ }
+ )
+
+ assert "text" in type_names
+
+ cols = inspect(connection).get_columns("t")
+
+ if type_type.enum:
+ assert isinstance(cols[0]["type"], ENUM)
+ elif type_type.domain:
+ assert isinstance(cols[0]["type"], DOMAIN)
+ else:
+ type_type.fail()
+
class DomainTest(
AssertsCompiledSQL, fixtures.TestBase, AssertsExecutionResults