Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .unreleased/pr_10279
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Implements: #10279 Support ON CONFLICT DO SELECT with hypertables
86 changes: 50 additions & 36 deletions src/chunk_insert_state.c
Original file line number Diff line number Diff line change
Expand Up @@ -230,14 +230,17 @@ setup_on_conflict_state(ResultRelInfo *ht_rri, ModifyTableState *mtstate, ChunkI
Relation hyper_rel = ht_rri->ri_RelationDesc;
ModifyTable *mt = castNode(ModifyTable, mtstate->ps.plan);

/* DO UPDATE has a SET clause; DO SELECT only fetches the conflicting row. */
bool do_update = mt->onConflictAction == ONCONFLICT_UPDATE;

OnConflictActionState *onconfl = makeNode(OnConflictActionState);
memcpy(onconfl, ht_rri->ri_onConflict, sizeof(OnConflictActionState));
chunk_rri->ri_onConflict = onconfl;

chunk_rri->ri_RootToChildMap = map;
chunk_rri->ri_RootToChildMapValid = true;

Assert(mt->onConflictSet);
Assert(!do_update || mt->onConflictSet);
Assert(ht_rri->ri_onConflict != NULL);

/*
Expand Down Expand Up @@ -271,18 +274,6 @@ setup_on_conflict_state(ResultRelInfo *ht_rri, ModifyTableState *mtstate, ChunkI
}
else
{
List *onconflset;
List *onconflcols;

/*
* Translate expressions in onConflictSet to account for
* different attribute numbers. For that, map partition
* varattnos twice: first to catch the EXCLUDED
* pseudo-relation (INNER_VAR), and second to handle the main
* target relation (firstVarno).
*/
onconflset = copyObject(mt->onConflictSet);

Assert(map->outdesc == RelationGetDescr(chunk_rel));

if (!chunk_map)
Expand All @@ -291,33 +282,52 @@ setup_on_conflict_state(ResultRelInfo *ht_rri, ModifyTableState *mtstate, ChunkI
convert_tuples_by_name(RelationGetDescr(chunk_rel), RelationGetDescr(hyper_rel));
}

onconflset = translate_clause(onconflset, chunk_map, ht_rri->ri_RangeTableIndex, chunk_rel);

chunk_rri->ri_ChildToRootMap = chunk_map;
chunk_rri->ri_ChildToRootMapValid = true;

/* Finally, adjust the target colnos to match the chunk. */
if (chunk_map)
if (do_update)
{
onconflcols = adjust_chunk_colnos(mt->onConflictCols, chunk_rri);
List *onconflset;
List *onconflcols;

/*
* Translate expressions in onConflictSet to account for
* different attribute numbers. For that, map partition
* varattnos twice: first to catch the EXCLUDED
* pseudo-relation (INNER_VAR), and second to handle the main
* target relation (firstVarno).
*/
onconflset = copyObject(mt->onConflictSet);
onconflset =
translate_clause(onconflset, chunk_map, ht_rri->ri_RangeTableIndex, chunk_rel);

/*
* Finally, adjust the target colnos to match the chunk. When the
* descriptors match (e.g. a direct chunk insert) there is no
* child-to-root map and the parent colnos apply unchanged.
*/
if (chunk_map)
{
onconflcols = adjust_chunk_colnos(mt->onConflictCols, chunk_rri);
}
else
{
onconflcols = mt->onConflictCols;
}

/* create the tuple slot for the UPDATE SET projection */
onconfl->oc_ProjSlot = table_slot_create(chunk_rel, NULL);
state->conflproj_slot = onconfl->oc_ProjSlot;

/* build UPDATE SET projection state */
onconfl->oc_ProjInfo = ExecBuildUpdateProjection(onconflset,
true,
onconflcols,
RelationGetDescr(chunk_rel),
mtstate->ps.ps_ExprContext,
onconfl->oc_ProjSlot,
&mtstate->ps);
}
else
{
onconflcols = mt->onConflictCols;
}

/* create the tuple slot for the UPDATE SET projection */
onconfl->oc_ProjSlot = table_slot_create(chunk_rel, NULL);
state->conflproj_slot = onconfl->oc_ProjSlot;

/* build UPDATE SET projection state */
onconfl->oc_ProjInfo = ExecBuildUpdateProjection(onconflset,
true,
onconflcols,
RelationGetDescr(chunk_rel),
mtstate->ps.ps_ExprContext,
onconfl->oc_ProjSlot,
&mtstate->ps);

Node *onconflict_where = mt->onConflictWhere;

Expand Down Expand Up @@ -406,7 +416,11 @@ adjust_projections(ResultRelInfo *ht_rri, ModifyTableState *mtstate, ChunkInsert
{
set_arbiter_indexes(cis, ht_rri->ri_onConflictArbiterIndexes);

if (onConflictAction == ONCONFLICT_UPDATE)
if (onConflictAction == ONCONFLICT_UPDATE
#if PG19_GE
|| onConflictAction == ONCONFLICT_SELECT
#endif
)
{
setup_on_conflict_state(ht_rri, mtstate, cis, chunk_map);
}
Expand Down
Loading
Loading