<p dir="auto"><strong>Migrated issue, originally created by Michael Bayer (<a href="https://github.com/zzzeek">@zzzeek</a>)</strong></p>
<p dir="auto">The <code class="notranslate">orm/inheritance/abc_inheritance</code> test relies upon <code class="notranslate">fold_equivalents</code> to spell out a UNION which builds a polymorphic discriminator column on the fly.  This whole use case (i.e., joined table inheritance with no discriminator column) is more easily managed by using regular joined table inheritance, joining to all tables (i.e. with_polymorphic), and using a callable <code class="notranslate">polymorphic_on</code> function which checks for the presence of each joined table in order to determine the type.   This is an easy enhancement and makes us compatible with Hibernate's joined table inheritance behavior.   the whole <code class="notranslate">fold_equivalents</code> feature <del>which nobody is using anyway can then be removed</del> won't be needed in this case (a nicer fold_equivalents proposed in <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="384619824" data-permission-text="Title is private" data-url="https://github.com/sqlalchemy/sqlalchemy/issues/1729" data-hovercard-type="issue" data-hovercard-url="/sqlalchemy/sqlalchemy/issues/1729/hovercard" href="https://github.com/sqlalchemy/sqlalchemy/issues/1729">#1729</a>).</p>
<h3 dir="auto">Describe the bug</h3>
<p dir="auto">It's not possible to create <code class="notranslate">type-decorator</code> for <code class="notranslate">postgresql</code> <code class="notranslate">Range</code> classes.</p>
<h3 dir="auto">To Reproduce</h3>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="from dataclasses import dataclass
from typing import Any

from sqlalchemy import create_engine, TypeDecorator, literal, select
from sqlalchemy.dialects.postgresql import INT4RANGE, Range

engine = create_engine('...')


@dataclass(frozen=True)
class MyRange:
    start: int
    end: int


class MyINT4RANGE(TypeDecorator):
    cache_ok = True
    impl = INT4RANGE

    def process_bind_param(self, value: Any, dialect: Any) -&gt; Any:
        match value:
            case MyRange(start, end):
                return Range(start, end, bounds='[]')
            case _:
                return value


with engine.begin() as conn:
    res = conn.scalar(select(literal(MyRange(1, 10), MyINT4RANGE)))

    print(res)"><pre class="notranslate"><span class="pl-k">from</span> <span class="pl-s1">dataclasses</span> <span class="pl-k">import</span> <span class="pl-s1">dataclass</span>
<span class="pl-k">from</span> <span class="pl-s1">typing</span> <span class="pl-k">import</span> <span class="pl-v">Any</span>

<span class="pl-k">from</span> <span class="pl-s1">sqlalchemy</span> <span class="pl-k">import</span> <span class="pl-s1">create_engine</span>, <span class="pl-v">TypeDecorator</span>, <span class="pl-s1">literal</span>, <span class="pl-s1">select</span>
<span class="pl-k">from</span> <span class="pl-s1">sqlalchemy</span>.<span class="pl-s1">dialects</span>.<span class="pl-s1">postgresql</span> <span class="pl-k">import</span> <span class="pl-v">INT4RANGE</span>, <span class="pl-v">Range</span>

<span class="pl-s1">engine</span> <span class="pl-c1">=</span> <span class="pl-en">create_engine</span>(<span class="pl-s">'...'</span>)


<span class="pl-en">@<span class="pl-en">dataclass</span>(<span class="pl-s1">frozen</span><span class="pl-c1">=</span><span class="pl-c1">True</span>)</span>
<span class="pl-k">class</span> <span class="pl-v">MyRange</span>:
    <span class="pl-s1">start</span>: <span class="pl-s1">int</span>
    <span class="pl-s1">end</span>: <span class="pl-s1">int</span>


<span class="pl-k">class</span> <span class="pl-v">MyINT4RANGE</span>(<span class="pl-v">TypeDecorator</span>):
    <span class="pl-s1">cache_ok</span> <span class="pl-c1">=</span> <span class="pl-c1">True</span>
    <span class="pl-s1">impl</span> <span class="pl-c1">=</span> <span class="pl-v">INT4RANGE</span>

    <span class="pl-k">def</span> <span class="pl-en">process_bind_param</span>(<span class="pl-s1">self</span>, <span class="pl-s1">value</span>: <span class="pl-v">Any</span>, <span class="pl-s1">dialect</span>: <span class="pl-v">Any</span>) <span class="pl-c1">-&gt;</span> <span class="pl-v">Any</span>:
        <span class="pl-k">match</span> <span class="pl-s1">value</span>:
            <span class="pl-k">case</span> <span class="pl-v">MyRange</span>(<span class="pl-s1">start</span>, <span class="pl-s1">end</span>):
                <span class="pl-k">return</span> <span class="pl-v">Range</span>(<span class="pl-s1">start</span>, <span class="pl-s1">end</span>, <span class="pl-s1">bounds</span><span class="pl-c1">=</span><span class="pl-s">'[]'</span>)
            <span class="pl-k">case</span> <span class="pl-s1">_</span>:
                <span class="pl-k">return</span> <span class="pl-s1">value</span>


<span class="pl-k">with</span> <span class="pl-s1">engine</span>.<span class="pl-en">begin</span>() <span class="pl-k">as</span> <span class="pl-s1">conn</span>:
    <span class="pl-s1">res</span> <span class="pl-c1">=</span> <span class="pl-s1">conn</span>.<span class="pl-en">scalar</span>(<span class="pl-en">select</span>(<span class="pl-en">literal</span>(<span class="pl-v">MyRange</span>(<span class="pl-c1">1</span>, <span class="pl-c1">10</span>), <span class="pl-v">MyINT4RANGE</span>)))

    <span class="pl-en">print</span>(<span class="pl-s1">res</span>)</pre></div>
<h3 dir="auto">Error</h3>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="# Copy complete stack trace and error message here, including SQL log output if applicable.
Traceback (most recent call last):
  File &quot;/Users/yuriikarabas/PycharmProjects/sandbox/foo.py&quot;, line 29, in &lt;module&gt;
    res = conn.scalar(select(literal(MyRange(1, 10), MyINT4RANGE)))
  File &quot;/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/engine/base.py&quot;, line 1299, in scalar
    return meth(
  File &quot;/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/sql/elements.py&quot;, line 507, in _execute_on_scalar
    return self._execute_on_connection(
  File &quot;/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/sql/elements.py&quot;, line 489, in _execute_on_connection
    return connection._execute_clauseelement(
  File &quot;/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/engine/base.py&quot;, line 1630, in _execute_clauseelement
    compiled_sql, extracted_params, cache_hit = elem._compile_w_cache(
  File &quot;/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/sql/elements.py&quot;, line 654, in _compile_w_cache
    compiled_sql = self._compiler(
  File &quot;/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/sql/elements.py&quot;, line 289, in _compiler
    return dialect.statement_compiler(dialect, self, **kw)
  File &quot;/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/sql/compiler.py&quot;, line 1137, in __init__
    Compiled.__init__(self, dialect, statement, **kwargs)
  File &quot;/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/sql/compiler.py&quot;, line 664, in __init__
    self.string = self.process(self.statement, **compile_kwargs)
  File &quot;/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/sql/compiler.py&quot;, line 701, in process
    return obj._compiler_dispatch(self, **kwargs)
  File &quot;/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/sql/visitors.py&quot;, line 143, in _compiler_dispatch
    return meth(self, **kw)  # type: ignore  # noqa: E501
  File &quot;/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/sql/compiler.py&quot;, line 4265, in visit_select
    for c in [
  File &quot;/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/sql/compiler.py&quot;, line 4266, in &lt;listcomp&gt;
    self._label_select_column(
  File &quot;/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/sql/compiler.py&quot;, line 4091, in _label_select_column
    return result_expr._compiler_dispatch(self, **column_clause_args)
  File &quot;/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/sql/visitors.py&quot;, line 143, in _compiler_dispatch
    return meth(self, **kw)  # type: ignore  # noqa: E501
  File &quot;/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/sql/compiler.py&quot;, line 2134, in visit_label
    label.element._compiler_dispatch(
  File &quot;/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/sql/visitors.py&quot;, line 143, in _compiler_dispatch
    return meth(self, **kw)  # type: ignore  # noqa: E501
  File &quot;/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/sql/compiler.py&quot;, line 3317, in visit_bindparam
    ret = self.bindparam_string(
  File &quot;/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/sql/compiler.py&quot;, line 3481, in bindparam_string
    type_impl = bindparam_type._unwrapped_dialect_impl(self.dialect)
  File &quot;/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/sql/type_api.py&quot;, line 1853, in _unwrapped_dialect_impl
    return typ.load_dialect_impl(dialect).dialect_impl(dialect)
  File &quot;/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/sql/type_api.py&quot;, line 875, in dialect_impl
    return self._dialect_info(dialect)[&quot;impl&quot;]
  File &quot;/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/sql/type_api.py&quot;, line 974, in _dialect_info
    impl = self.adapt(type(self))
  File &quot;/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/dialects/postgresql/ranges.py&quot;, line 702, in adapt
    return type(  # type: ignore
TypeError: duplicate base class INT4RANGERangeImpl"><pre class="notranslate"><code class="notranslate"># Copy complete stack trace and error message here, including SQL log output if applicable.
Traceback (most recent call last):
  File "/Users/yuriikarabas/PycharmProjects/sandbox/foo.py", line 29, in &lt;module&gt;
    res = conn.scalar(select(literal(MyRange(1, 10), MyINT4RANGE)))
  File "/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/engine/base.py", line 1299, in scalar
    return meth(
  File "/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/sql/elements.py", line 507, in _execute_on_scalar
    return self._execute_on_connection(
  File "/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/sql/elements.py", line 489, in _execute_on_connection
    return connection._execute_clauseelement(
  File "/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/engine/base.py", line 1630, in _execute_clauseelement
    compiled_sql, extracted_params, cache_hit = elem._compile_w_cache(
  File "/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/sql/elements.py", line 654, in _compile_w_cache
    compiled_sql = self._compiler(
  File "/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/sql/elements.py", line 289, in _compiler
    return dialect.statement_compiler(dialect, self, **kw)
  File "/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/sql/compiler.py", line 1137, in __init__
    Compiled.__init__(self, dialect, statement, **kwargs)
  File "/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/sql/compiler.py", line 664, in __init__
    self.string = self.process(self.statement, **compile_kwargs)
  File "/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/sql/compiler.py", line 701, in process
    return obj._compiler_dispatch(self, **kwargs)
  File "/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/sql/visitors.py", line 143, in _compiler_dispatch
    return meth(self, **kw)  # type: ignore  # noqa: E501
  File "/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/sql/compiler.py", line 4265, in visit_select
    for c in [
  File "/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/sql/compiler.py", line 4266, in &lt;listcomp&gt;
    self._label_select_column(
  File "/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/sql/compiler.py", line 4091, in _label_select_column
    return result_expr._compiler_dispatch(self, **column_clause_args)
  File "/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/sql/visitors.py", line 143, in _compiler_dispatch
    return meth(self, **kw)  # type: ignore  # noqa: E501
  File "/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/sql/compiler.py", line 2134, in visit_label
    label.element._compiler_dispatch(
  File "/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/sql/visitors.py", line 143, in _compiler_dispatch
    return meth(self, **kw)  # type: ignore  # noqa: E501
  File "/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/sql/compiler.py", line 3317, in visit_bindparam
    ret = self.bindparam_string(
  File "/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/sql/compiler.py", line 3481, in bindparam_string
    type_impl = bindparam_type._unwrapped_dialect_impl(self.dialect)
  File "/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/sql/type_api.py", line 1853, in _unwrapped_dialect_impl
    return typ.load_dialect_impl(dialect).dialect_impl(dialect)
  File "/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/sql/type_api.py", line 875, in dialect_impl
    return self._dialect_info(dialect)["impl"]
  File "/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/sql/type_api.py", line 974, in _dialect_info
    impl = self.adapt(type(self))
  File "/Users/yuriikarabas/PycharmProjects/sandbox/venv310/lib/python3.10/site-packages/sqlalchemy/dialects/postgresql/ranges.py", line 702, in adapt
    return type(  # type: ignore
TypeError: duplicate base class INT4RANGERangeImpl
</code></pre></div>
<h3 dir="auto">Versions</h3>
<ul dir="auto">
<li>OS: macOS</li>
<li>Python: 3.10</li>
<li>SQLAlchemy: 2.0.0b4</li>
<li>Database: postgresql</li>
<li>DBAPI (eg: psycopg, cx_oracle, mysqlclient): psycopg</li>
</ul>
<h3 dir="auto">Additional context</h3>
<p dir="auto">Please, delete <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="1506617176" data-permission-text="Title is private" data-url="https://github.com/sqlalchemy/sqlalchemy/issues/9019" data-hovercard-type="issue" data-hovercard-url="/sqlalchemy/sqlalchemy/issues/9019/hovercard" href="https://github.com/sqlalchemy/sqlalchemy/issues/9019">#9019</a> as it's a duplicate of this issue.</p>