Hi,

On 2026-08-19 12:33:01 +0100, Zsolt Parragi wrote:
> While testing the new INSERT...ON CONFLICT DO SELECT feature I found a
> possible serialization violation: the row returned back by DO SELECT
> is not covered by any SIREAD lock, so a concurrent transaction can
> modify it.

Good catch.


> @@ -3337,6 +3338,27 @@ ExecOnConflictSelect(ModifyTableContext *context,
>                       return false;
>       }
>  
> +     /*
> +      * At SERIALIZABLE, record an SIREAD lock on the tuple.  Returning the
> +      * existing row (or filtering it out with the WHERE clause) is a read 
> for
> +      * SSI purposes, but neither the arbiter index probe (dirty snapshot) 
> nor
> +      * the fetch above (SnapshotAny) takes predicate locks, and the SELECT
> +      * path writes nothing that would trigger conflict-in detection.
> +      */
> +     if (IsolationIsSerializable())
> +     {
> +             Datum           xminDatum;
> +             TransactionId xmin;
> +             bool            isnull;
> +
> +             xminDatum = slot_getsysattr(existing, 
> MinTransactionIdAttributeNumber, &isnull);
> +             Assert(!isnull);
> +             xmin = DatumGetTransactionId(xminDatum);
> +
> +             PredicateLockTID(relation, conflictTid, 
> context->estate->es_snapshot,
> +                                              xmin);
> +     }
> +

I don't think this is quite right though. The details of how heapam uses SI
locks is heapam specific and should live in the heapam code.  I also think you
actually need to acquire the predicate lock before ExecOnConflictLockRow()?

Greetings,

Andres Freund


Reply via email to