Hmm, there's something else going on here. After getting rid of the assertion failure, I see that the plan looks like
# explain MERGE INTO tt USING st ON tt.tid = st.sid WHEN NOT MATCHED THEN INSERT VALUES (st.sid); QUERY PLAN ------------------------------------------------------------- Merge on tt (cost=0.00..35.50 rows=0 width=0) -> Seq Scan on st (cost=0.00..35.50 rows=2550 width=10) (2 rows) which is fairly nonsensical and doesn't match v15's plan: Merge on tt (cost=0.15..544.88 rows=0 width=0) Merge on ttp tt_1 -> Nested Loop Left Join (cost=0.15..544.88 rows=32512 width=14) -> Seq Scan on st (cost=0.00..35.50 rows=2550 width=4) -> Index Scan using ttp_pkey on ttp tt_1 (cost=0.15..0.19 rows=1 widt h=14) Index Cond: (tid = st.sid) It looks like we're somehow triggering the elide-a-left-join code when we shouldn't? That explains why the target table's RelOptInfo has gone missing and broken make_modifytable's expectations. That code is still unnecessarily fragile so I intend to rearrange it, but there's more to do here. regards, tom lane