@@ -230,14 +230,17 @@ setup_on_conflict_state(ResultRelInfo *ht_rri, ModifyTableState *mtstate, ChunkI
230230 Relation hyper_rel = ht_rri -> ri_RelationDesc ;
231231 ModifyTable * mt = castNode (ModifyTable , mtstate -> ps .plan );
232232
233+ /* DO UPDATE has a SET clause; DO SELECT only fetches the conflicting row. */
234+ bool do_update = mt -> onConflictAction == ONCONFLICT_UPDATE ;
235+
233236 OnConflictActionState * onconfl = makeNode (OnConflictActionState );
234237 memcpy (onconfl , ht_rri -> ri_onConflict , sizeof (OnConflictActionState ));
235238 chunk_rri -> ri_onConflict = onconfl ;
236239
237240 chunk_rri -> ri_RootToChildMap = map ;
238241 chunk_rri -> ri_RootToChildMapValid = true;
239242
240- Assert (mt -> onConflictSet );
243+ Assert (! do_update || mt -> onConflictSet );
241244 Assert (ht_rri -> ri_onConflict != NULL );
242245
243246 /*
@@ -271,18 +274,6 @@ setup_on_conflict_state(ResultRelInfo *ht_rri, ModifyTableState *mtstate, ChunkI
271274 }
272275 else
273276 {
274- List * onconflset ;
275- List * onconflcols ;
276-
277- /*
278- * Translate expressions in onConflictSet to account for
279- * different attribute numbers. For that, map partition
280- * varattnos twice: first to catch the EXCLUDED
281- * pseudo-relation (INNER_VAR), and second to handle the main
282- * target relation (firstVarno).
283- */
284- onconflset = copyObject (mt -> onConflictSet );
285-
286277 Assert (map -> outdesc == RelationGetDescr (chunk_rel ));
287278
288279 if (!chunk_map )
@@ -291,33 +282,52 @@ setup_on_conflict_state(ResultRelInfo *ht_rri, ModifyTableState *mtstate, ChunkI
291282 convert_tuples_by_name (RelationGetDescr (chunk_rel ), RelationGetDescr (hyper_rel ));
292283 }
293284
294- onconflset = translate_clause (onconflset , chunk_map , ht_rri -> ri_RangeTableIndex , chunk_rel );
295-
296285 chunk_rri -> ri_ChildToRootMap = chunk_map ;
297286 chunk_rri -> ri_ChildToRootMapValid = true;
298287
299- /* Finally, adjust the target colnos to match the chunk. */
300- if (chunk_map )
288+ if (do_update )
301289 {
302- onconflcols = adjust_chunk_colnos (mt -> onConflictCols , chunk_rri );
290+ List * onconflset ;
291+ List * onconflcols ;
292+
293+ /*
294+ * Translate expressions in onConflictSet to account for
295+ * different attribute numbers. For that, map partition
296+ * varattnos twice: first to catch the EXCLUDED
297+ * pseudo-relation (INNER_VAR), and second to handle the main
298+ * target relation (firstVarno).
299+ */
300+ onconflset = copyObject (mt -> onConflictSet );
301+ onconflset =
302+ translate_clause (onconflset , chunk_map , ht_rri -> ri_RangeTableIndex , chunk_rel );
303+
304+ /*
305+ * Finally, adjust the target colnos to match the chunk. When the
306+ * descriptors match (e.g. a direct chunk insert) there is no
307+ * child-to-root map and the parent colnos apply unchanged.
308+ */
309+ if (chunk_map )
310+ {
311+ onconflcols = adjust_chunk_colnos (mt -> onConflictCols , chunk_rri );
312+ }
313+ else
314+ {
315+ onconflcols = mt -> onConflictCols ;
316+ }
317+
318+ /* create the tuple slot for the UPDATE SET projection */
319+ onconfl -> oc_ProjSlot = table_slot_create (chunk_rel , NULL );
320+ state -> conflproj_slot = onconfl -> oc_ProjSlot ;
321+
322+ /* build UPDATE SET projection state */
323+ onconfl -> oc_ProjInfo = ExecBuildUpdateProjection (onconflset ,
324+ true,
325+ onconflcols ,
326+ RelationGetDescr (chunk_rel ),
327+ mtstate -> ps .ps_ExprContext ,
328+ onconfl -> oc_ProjSlot ,
329+ & mtstate -> ps );
303330 }
304- else
305- {
306- onconflcols = mt -> onConflictCols ;
307- }
308-
309- /* create the tuple slot for the UPDATE SET projection */
310- onconfl -> oc_ProjSlot = table_slot_create (chunk_rel , NULL );
311- state -> conflproj_slot = onconfl -> oc_ProjSlot ;
312-
313- /* build UPDATE SET projection state */
314- onconfl -> oc_ProjInfo = ExecBuildUpdateProjection (onconflset ,
315- true,
316- onconflcols ,
317- RelationGetDescr (chunk_rel ),
318- mtstate -> ps .ps_ExprContext ,
319- onconfl -> oc_ProjSlot ,
320- & mtstate -> ps );
321331
322332 Node * onconflict_where = mt -> onConflictWhere ;
323333
@@ -406,7 +416,11 @@ adjust_projections(ResultRelInfo *ht_rri, ModifyTableState *mtstate, ChunkInsert
406416 {
407417 set_arbiter_indexes (cis , ht_rri -> ri_onConflictArbiterIndexes );
408418
409- if (onConflictAction == ONCONFLICT_UPDATE )
419+ if (onConflictAction == ONCONFLICT_UPDATE
420+ #if PG19_GE
421+ || onConflictAction == ONCONFLICT_SELECT
422+ #endif
423+ )
410424 {
411425 setup_on_conflict_state (ht_rri , mtstate , cis , chunk_map );
412426 }
0 commit comments