From 2f7816cdbd94dec0c4be95579b3aafd0262be450 Mon Sep 17 00:00:00 2001 From: Tender Wang Date: Sat, 24 Oct 2026 15:52:09 +0800 Subject: [PATCH] Preserve row lock semantics during self-join elimination Self-join elimination checks whether row marks on the relations being merged have the same RowMarkType. However, it does not compare their lock strengths or wait policies. Consequently, when two aliases have row marks with the same RowMarkType but different wait policies, such as NOWAIT and SKIP LOCKED, remove_self_join_rel() discards one PlanRowMark and retains only the other policy. This can change an error into successful execution with the locked row skipped, or vice versa. Require the row mark type, lock strength, and wait policy to match before eliminating the self-join. --- src/backend/optimizer/plan/analyzejoins.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/backend/optimizer/plan/analyzejoins.c b/src/backend/optimizer/plan/analyzejoins.c index 7aad91fd34e..6d55e243352 100644 --- a/src/backend/optimizer/plan/analyzejoins.c +++ b/src/backend/optimizer/plan/analyzejoins.c @@ -1827,10 +1827,10 @@ remove_self_joins_one_group(PlannerInfo *root, Relids relids) continue; /* - * Check Row Marks equivalence. We can't remove the join if the - * relations have row marks of different strength (e.g., one is - * locked FOR UPDATE, and another just has ROW_MARK_REFERENCE for - * EvalPlanQual rechecking). + * Check row mark equivalence. If both relations have row marks, + * their mark type, locking strength, and wait policy must match. + * Otherwise, discarding the removed relation's row mark could change + * tuple-locking or EvalPlanQual behavior. */ foreach(lc, root->rowMarks) { @@ -1850,7 +1850,10 @@ remove_self_joins_one_group(PlannerInfo *root, Relids relids) if (kmark && rmark) break; } - if (kmark && rmark && kmark->markType != rmark->markType) + if (kmark && rmark && + (kmark->markType != rmark->markType || + kmark->strength != rmark->strength || + kmark->waitPolicy != rmark->waitPolicy)) continue; /* -- 2.43.0