Re: bug report: some issues about pg_15_stable(8fa4a1ac61189efffb8b851ee77e1bc87360c445)
От | Dean Rasheed |
---|---|
Тема | Re: bug report: some issues about pg_15_stable(8fa4a1ac61189efffb8b851ee77e1bc87360c445) |
Дата | |
Msg-id | CAEZATCVCFDWQXyfBgcO8HxoH22aV1kKbBnJhRY7+wWDLRCMV2w@mail.gmail.com обсуждение исходный текст |
Ответ на | 回复: bug report: some issues about pg_15_stable(8fa4a1ac61189efffb8b851ee77e1bc87360c445) ("zwj" <sxzwj@vip.qq.com>) |
Ответы |
Re: bug report: some issues about pg_15_stable(8fa4a1ac61189efffb8b851ee77e1bc87360c445)
|
Список | pgsql-hackers |
[cc'ing Alvaro] On Tue, 5 Mar 2024 at 10:04, zwj <sxzwj@vip.qq.com> wrote: > > If I only execute merge , I will get the following error: > merge into tgt a using src1 c on a.a = c.a when matched then update set b = c.b when not matched then insert (a,b)values(c.a,c.b); -- excute fail > ERROR: MERGE command cannot affect row a second time > HIINT: Ensure that not more than one source row matches any one target row. > > But when I execute the update and merge concurrently, I will get the following result set. > Yes, this should still produce that error, even after a concurrent update. In the first example without a concurrent update, when we reach the tgt.a = 3 row the second time, ExecUpdateAct() returns TM_SelfModified and we do this: case TM_SelfModified: /* * The SQL standard disallows this for MERGE. */ if (TransactionIdIsCurrentTransactionId(context->tmfd.xmax)) ereport(ERROR, (errcode(ERRCODE_CARDINALITY_VIOLATION), /* translator: %s is a SQL command name */ errmsg("%s command cannot affect row a second time", "MERGE"), errhint("Ensure that not more than one source row matches any one target row."))); /* This shouldn't happen */ elog(ERROR, "attempted to update or delete invisible tuple"); break; whereas in the second case, after a concurrent update, ExecUpdateAct() returns TM_Updated, we attempt to lock the tuple prior to running EPQ, and table_tuple_lock() returns TM_SelfModified, which does this: case TM_SelfModified: /* * This can be reached when following an update * chain from a tuple updated by another session, * reaching a tuple that was already updated in * this transaction. If previously modified by * this command, ignore the redundant update, * otherwise error out. * * See also response to TM_SelfModified in * ExecUpdate(). */ if (context->tmfd.cmax != estate->es_output_cid) ereport(ERROR, (errcode(ERRCODE_TRIGGERED_DATA_CHANGE_VIOLATION), errmsg("tuple to be updated or deleted was already modified by an operation triggered by the current command"), errhint("Consider using an AFTER trigger instead of a BEFORE trigger to propagate changes to other rows."))); return false; My initial reaction is that neither of those blocks of code is entirely correct, and that they should both be doing both of those checks. I.e., something like the attached (which probably needs some additional test cases). Regards, Dean
Вложения
В списке pgsql-hackers по дате отправления: