Skip to content

Commit e128c69

Browse files
committed
Support ON CONFLICT DO SELECT on hypertables for PostgreSQL 19
PostgreSQL 19 added INSERT ... ON CONFLICT DO SELECT, which returns the conflicting row instead of updating it and can optionally lock it. Upstream changes: Add support for INSERT ... ON CONFLICT DO SELECT. postgres/postgres@88327092ff0
1 parent 62575c3 commit e128c69

5 files changed

Lines changed: 696 additions & 36 deletions

File tree

src/chunk_insert_state.c

Lines changed: 38 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -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,41 @@ 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
{
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+
/* Finally, adjust the target colnos to match the chunk. */
302305
onconflcols = adjust_chunk_colnos(mt->onConflictCols, chunk_rri);
303-
}
304-
else
305-
{
306-
onconflcols = mt->onConflictCols;
307-
}
308306

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);
307+
/* create the tuple slot for the UPDATE SET projection */
308+
onconfl->oc_ProjSlot = table_slot_create(chunk_rel, NULL);
309+
state->conflproj_slot = onconfl->oc_ProjSlot;
310+
311+
/* build UPDATE SET projection state */
312+
onconfl->oc_ProjInfo = ExecBuildUpdateProjection(onconflset,
313+
true,
314+
onconflcols,
315+
RelationGetDescr(chunk_rel),
316+
mtstate->ps.ps_ExprContext,
317+
onconfl->oc_ProjSlot,
318+
&mtstate->ps);
319+
}
321320

322321
Node *onconflict_where = mt->onConflictWhere;
323322

@@ -406,7 +405,11 @@ adjust_projections(ResultRelInfo *ht_rri, ModifyTableState *mtstate, ChunkInsert
406405
{
407406
set_arbiter_indexes(cis, ht_rri->ri_onConflictArbiterIndexes);
408407

409-
if (onConflictAction == ONCONFLICT_UPDATE)
408+
if (onConflictAction == ONCONFLICT_UPDATE
409+
#if PG19_GE
410+
|| onConflictAction == ONCONFLICT_SELECT
411+
#endif
412+
)
410413
{
411414
setup_on_conflict_state(ht_rri, mtstate, cis, chunk_map);
412415
}

0 commit comments

Comments
 (0)