Re: ON CONFLICT DO SELECT (take 3)
jian he <jian.universality@gmail.com>
From: jian he <jian.universality@gmail.com>
To: Dean Rasheed <dean.a.rasheed@gmail.com>
Cc: "v@viktorh.net" <v@viktorh.net>, pgsql-hackers@postgresql.org
Date: 2025-11-20T15:26:51Z
Lists: pgsql-hackers
Commits
Same data as JSON:
GET /api/v1/messages/:b64id/commits
the thread's linked commits as JSON, with link sources.
API reference →
-
Add support for INSERT ... ON CONFLICT DO SELECT.
- 88327092ff06 19 (unreleased) landed
-
doc: Fix statement about ON CONFLICT and deferrable constraints.
- f188bc5145b5 15.16 landed
- 4c4fa53b9d2d 14.21 landed
- 8348004b54a7 16.12 landed
- 7a02ac28ab11 17.8 landed
- e9443a55265f 19 (unreleased) landed
- ae627d8a3cb0 18.2 landed
-
Fix ON CONFLICT ON CONSTRAINT during REINDEX CONCURRENTLY
- 2bc7e886fc1b 19 (unreleased) cited
>
>
> https://www.postgresql.org/docs/current/ddl-priv.html#DDL-PRIV-UPDATE
> says:
> ```
> SELECT ... FOR UPDATE and SELECT ... FOR SHARE also require this privilege on at
> least one column, in addition to the SELECT privilege.
> ```
> I attached extensive permission tests for ON CONFLICT DO SELECT
>
>
+ For <literal>ON CONFLICT DO SELECT</literal>, <literal>SELECT</literal>
+ privilege is required on any column whose values are read in the
+ <replaceable>condition</replaceable>.
If you do <literal>ON CONFLICT DO SELECT FOR UPDATE</literal>
then <literal>UPDATE</literal> permission is also required (at least
one column),
can we also mention this?
+ /* Parse analysis should already have disallowed this */
+ Assert(resultRelInfo->ri_projectReturning);
+
+ /* Process RETURNING like an UPDATE that didn't change anything */
+ *rslot = ExecProcessReturning(context, resultRelInfo, CMD_UPDATE,
+ existing, existing, context->planSlot);
The above two comments seem confusing. If you look at the code
ExecProcessReturning, I think you can set the cmdType as CMD_INSERT.
+ if (lockstrength != LCS_NONE)
+ {
+ LockTupleMode lockmode;
+
+ switch (lockstrength)
+ {
+ case LCS_FORKEYSHARE:
+ lockmode = LockTupleKeyShare;
+ break;
+ case LCS_FORSHARE:
+ lockmode = LockTupleShare;
+ break;
+ case LCS_FORNOKEYUPDATE:
+ lockmode = LockTupleNoKeyExclusive;
+ break;
+ case LCS_FORUPDATE:
+ lockmode = LockTupleExclusive;
+ break;
+ default:
+ elog(ERROR, "unexpected lock strength %d", lockstrength);
+ }
+
+ if (!ExecOnConflictLockRow(context, existing, conflictTid,
+ resultRelInfo->ri_RelationDesc, lockmode, false))
+ return false;
isolation tests do not test the case where ExecOnConflictLockRow returns false.
actually it's reachable.
-----------------------------setup---------------------
drop table if exists tsa1;
create table tsa1(a int, b int, constraint xxidx unique (a));
insert into tsa1 values (1,2);
session1, using GDB set a breakpoint at ExecOnConflictLockRow.
session1:
insert into tsa1 values(1,3) on conflict(a) do select
for update returning *;
session2:
update tsa1 set a = 111;
session1: session 1 already reached the GDB breakpoint
(ExecOnConflictLockRow), issue
``continue`` in GDB let session1 complete.
----------------------------------------------------------------------------
I'm wondering how we can add test coverage for this.
+ <row>
+ <entry><command>ON CONFLICT DO SELECT FOR UPDATE/SHARE</command></entry>
+ <entry>Check existing rows</entry>
+ <entry>—</entry>
+ <entry>Existing row</entry>
+ <entry>—</entry>
+ <entry>—</entry>
</row>
Here, it should be "
<entry>Check existing row</entry>
"?
If you search 'ON CONFLICT', it appears on many sgml files, currently we only
made change to:
doc/src/sgml/dml.sgml
doc/src/sgml/ref/create_policy.sgml
doc/src/sgml/ref/insert.sgml
seems other sgml files also need to be updated.
--
jian
https://www.enterprisedb.com/