mirror of
https://github.com/postgres/postgres.git
synced 2025-07-02 09:02:37 +03:00
Fix interaction of triggers, partitioning, and EXPLAIN ANALYZE.
Add a new EState member es_leaf_result_relations, so that the trigger code knows about ResultRelInfos created by tuple routing. Also make sure ExplainPrintTriggers knows about partition-related ResultRelInfos. Etsuro Fujita, reviewed by Amit Langote Discussion: http://postgr.es/m/57163e18-8e56-da83-337a-22f2c0008051@lab.ntt.co.jp
This commit is contained in:
@ -1415,59 +1415,6 @@ BeginCopy(ParseState *pstate,
|
||||
(errcode(ERRCODE_UNDEFINED_COLUMN),
|
||||
errmsg("table \"%s\" does not have OIDs",
|
||||
RelationGetRelationName(cstate->rel))));
|
||||
|
||||
/*
|
||||
* If there are any triggers with transition tables on the named
|
||||
* relation, we need to be prepared to capture transition tuples.
|
||||
*/
|
||||
cstate->transition_capture = MakeTransitionCaptureState(rel->trigdesc);
|
||||
|
||||
/* Initialize state for CopyFrom tuple routing. */
|
||||
if (is_from && rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
|
||||
{
|
||||
PartitionDispatch *partition_dispatch_info;
|
||||
ResultRelInfo *partitions;
|
||||
TupleConversionMap **partition_tupconv_maps;
|
||||
TupleTableSlot *partition_tuple_slot;
|
||||
int num_parted,
|
||||
num_partitions;
|
||||
|
||||
ExecSetupPartitionTupleRouting(rel,
|
||||
1,
|
||||
&partition_dispatch_info,
|
||||
&partitions,
|
||||
&partition_tupconv_maps,
|
||||
&partition_tuple_slot,
|
||||
&num_parted, &num_partitions);
|
||||
cstate->partition_dispatch_info = partition_dispatch_info;
|
||||
cstate->num_dispatch = num_parted;
|
||||
cstate->partitions = partitions;
|
||||
cstate->num_partitions = num_partitions;
|
||||
cstate->partition_tupconv_maps = partition_tupconv_maps;
|
||||
cstate->partition_tuple_slot = partition_tuple_slot;
|
||||
|
||||
/*
|
||||
* If we are capturing transition tuples, they may need to be
|
||||
* converted from partition format back to partitioned table
|
||||
* format (this is only ever necessary if a BEFORE trigger
|
||||
* modifies the tuple).
|
||||
*/
|
||||
if (cstate->transition_capture != NULL)
|
||||
{
|
||||
int i;
|
||||
|
||||
cstate->transition_tupconv_maps = (TupleConversionMap **)
|
||||
palloc0(sizeof(TupleConversionMap *) *
|
||||
cstate->num_partitions);
|
||||
for (i = 0; i < cstate->num_partitions; ++i)
|
||||
{
|
||||
cstate->transition_tupconv_maps[i] =
|
||||
convert_tuples_by_name(RelationGetDescr(cstate->partitions[i].ri_RelationDesc),
|
||||
RelationGetDescr(rel),
|
||||
gettext_noop("could not convert row type"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2482,6 +2429,63 @@ CopyFrom(CopyState cstate)
|
||||
/* Triggers might need a slot as well */
|
||||
estate->es_trig_tuple_slot = ExecInitExtraTupleSlot(estate);
|
||||
|
||||
/*
|
||||
* If there are any triggers with transition tables on the named relation,
|
||||
* we need to be prepared to capture transition tuples.
|
||||
*/
|
||||
cstate->transition_capture =
|
||||
MakeTransitionCaptureState(cstate->rel->trigdesc);
|
||||
|
||||
/*
|
||||
* If the named relation is a partitioned table, initialize state for
|
||||
* CopyFrom tuple routing.
|
||||
*/
|
||||
if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
|
||||
{
|
||||
PartitionDispatch *partition_dispatch_info;
|
||||
ResultRelInfo *partitions;
|
||||
TupleConversionMap **partition_tupconv_maps;
|
||||
TupleTableSlot *partition_tuple_slot;
|
||||
int num_parted,
|
||||
num_partitions;
|
||||
|
||||
ExecSetupPartitionTupleRouting(cstate->rel,
|
||||
1,
|
||||
estate,
|
||||
&partition_dispatch_info,
|
||||
&partitions,
|
||||
&partition_tupconv_maps,
|
||||
&partition_tuple_slot,
|
||||
&num_parted, &num_partitions);
|
||||
cstate->partition_dispatch_info = partition_dispatch_info;
|
||||
cstate->num_dispatch = num_parted;
|
||||
cstate->partitions = partitions;
|
||||
cstate->num_partitions = num_partitions;
|
||||
cstate->partition_tupconv_maps = partition_tupconv_maps;
|
||||
cstate->partition_tuple_slot = partition_tuple_slot;
|
||||
|
||||
/*
|
||||
* If we are capturing transition tuples, they may need to be
|
||||
* converted from partition format back to partitioned table format
|
||||
* (this is only ever necessary if a BEFORE trigger modifies the
|
||||
* tuple).
|
||||
*/
|
||||
if (cstate->transition_capture != NULL)
|
||||
{
|
||||
int i;
|
||||
|
||||
cstate->transition_tupconv_maps = (TupleConversionMap **)
|
||||
palloc0(sizeof(TupleConversionMap *) * cstate->num_partitions);
|
||||
for (i = 0; i < cstate->num_partitions; ++i)
|
||||
{
|
||||
cstate->transition_tupconv_maps[i] =
|
||||
convert_tuples_by_name(RelationGetDescr(cstate->partitions[i].ri_RelationDesc),
|
||||
RelationGetDescr(cstate->rel),
|
||||
gettext_noop("could not convert row type"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* It's more efficient to prepare a bunch of tuples for insertion, and
|
||||
* insert them in one heap_multi_insert() call, than call heap_insert()
|
||||
|
Reference in New Issue
Block a user