Skip to content

PG on conflict does not honor index names; implementation is wrong #9023

Closed
@zzzeek

Description

@zzzeek
Member

Discussed in #9022

not sure how 1. we aren't testing this and 2. nobody's ever reported this but you can't put an index name in ON CONFLICT ON CONSTRAINT.

from sqlalchemy import Column
from sqlalchemy import create_engine
from sqlalchemy import Index
from sqlalchemy import Integer
from sqlalchemy import String
from sqlalchemy import UniqueConstraint
from sqlalchemy.dialects.postgresql import insert
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import Session

Base = declarative_base()


class MyTable(Base):
    __tablename__ = "my_table"

    id = Column(Integer, primary_key=True)
    name = Column(String)
    col1 = Column(String, nullable=True)
    col2 = Column(String, nullable=True)

    # fails:
    if True:
        ix_col1_col2 = Index(
            "ix_col1_col2",
            name,
            unique=True,
        )

    # works
    if False:
        ix_col1_col2 = UniqueConstraint(
            name,
            name="ix_col1_col2"
        )


e = create_engine("postgresql://scott:tiger@localhost/test", echo=True)
Base.metadata.drop_all(e)
Base.metadata.create_all(e)

data = [
    {"name": "foo", "col1": "qux", "col2": None},
    {"name": "bar", "col1": None, "col2": "quux"},
]
column_names = data[0].keys()

stmt = insert(MyTable).values(data)
upsert = stmt.on_conflict_do_update(
    constraint=MyTable.ix_col1_col2,
    set_={
        key: val for key, val in stmt.excluded.items() if key in column_names
    },
)

with Session(e) as sess:
    sess.execute(upsert)
sqlalchemy.exc.ProgrammingError: (psycopg2.errors.UndefinedObject) constraint "ix_col1_col2" for table "my_table" does not exist

not matching index by name would fix:

@@ -188,7 +189,7 @@ class OnConflictClause(ClauseElement):
         if constraint is not None:
             if not isinstance(constraint, util.string_types) and isinstance(
                 constraint,
-                (schema.Index, schema.Constraint, ext.ExcludeConstraint),
+                (schema.Constraint, ext.ExcludeConstraint),
             ):
                 constraint = getattr(constraint, "name") or constraint
 

Activity

added
bugSomething isn't working
near-term releaseaddition to the milestone which indicates this should be in a near-term release
on Dec 22, 2022
added this to the 1.4.x milestone on Dec 22, 2022
sqla-tester

sqla-tester commented on Dec 22, 2022

@sqla-tester
Collaborator

Mike Bayer has proposed a fix for this issue in the main branch:

expand out Index if passed to "constraint" https://gerrit.sqlalchemy.org/c/sqlalchemy/sqlalchemy/+/4322

sqla-tester

sqla-tester commented on Dec 22, 2022

@sqla-tester
Collaborator

Mike Bayer has proposed a fix for this issue in the rel_1_4 branch:

expand out Index if passed to "constraint" https://gerrit.sqlalchemy.org/c/sqlalchemy/sqlalchemy/+/4323

added a commit that references this issue on Dec 23, 2022
667e2e6
added a commit that references this issue on Jun 9, 2025
5cc18bb
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingnear-term releaseaddition to the milestone which indicates this should be in a near-term releasepostgresqlupserts

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @zzzeek@sqla-tester

        Issue actions

          PG on conflict does not honor index names; implementation is wrong · Issue #9023 · sqlalchemy/sqlalchemy