Skip to content

ON CONFLICT ... DO UPDATE ... WHERE (conditional upsert) is rejected as unsupported #3235

Description

@pdlug

Version: dolthub/doltgresql:1.3.0 (clean Docker container, empty database, 2026-08-31). Verified against postgres:15 with identical SQL — it works there.

ON CONFLICT ... DO UPDATE SET ... works, but adding the optional WHERE condition to the DO UPDATE action is rejected:

ERROR:  the ON CONFLICT clause provided is not yet supported

Repro

CREATE TABLE t (id int PRIMARY KEY, v int);
INSERT INTO t VALUES (1, 1);

-- OK
INSERT INTO t VALUES (1, 2) ON CONFLICT (id) DO UPDATE SET v = 2;

-- ERROR: the ON CONFLICT clause provided is not yet supported
INSERT INTO t VALUES (1, 3) ON CONFLICT (id) DO UPDATE SET v = 3 WHERE t.v <= 3;

Any WHERE is rejected, including a constant one (... DO UPDATE SET v = 8 WHERE true), so this is the clause form rather than anything about the predicate. Unqualified (WHERE v <= 3) and table-qualified (WHERE t.v <= 3) both fail.

Related but distinct: ON CONFLICT ON CONSTRAINT <name> DO UPDATE reports at or near "<name>": syntax error: unimplemented: this syntax. And the excluded alias is still #1258 — worth noting the three together make the conditional-upsert idiom unavailable in every form, since excluded is the usual way to write the predicate.

Why it matters

ON CONFLICT (k) DO UPDATE SET v = $1 WHERE t.v <= $1 is the standard monotonic upsert — the one-statement way to advance a version/watermark row without a read-modify-write race. It is how TypeGraph records its installed base-schema version, so this statement is on the very first bootstrap path: a store cannot initialize against Doltgres 1.3.0 at all.

GREATEST(t.v, $1) in the SET is a workaround for the numeric case specifically, but it does not generalize (it cannot leave the row untouched, so any sibling column in the SET is still overwritten by a losing writer).


Part of the same clean-room deviation battery as #3011, #3012, #3013 and #3099 (fresh official Docker container + empty database per probe, postgres:15 control running identical probes). Happy to re-test against a nightly.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions