summaryrefslogtreecommitdiff
path: root/src/backend/commands/copy.c
diff options
context:
space:
mode:
authorRobert Haas <rhaas@postgresql.org>2017-08-18 13:01:05 -0400
committerRobert Haas <rhaas@postgresql.org>2017-08-18 13:01:05 -0400
commitc4b841ba6aa9252ab9dacd59d317aba8cfa9b31a (patch)
treef04bad7b7d401e1639c2fad616242dced8609c52 /src/backend/commands/copy.c
parenta20aac890a89e6f88e841dedbbfa8d9d5f7309fc (diff)
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
Diffstat (limited to 'src/backend/commands/copy.c')
-rw-r--r--src/backend/commands/copy.c110
1 files changed, 57 insertions, 53 deletions
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index a258965c200..375a25fbcf8 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -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
{
@@ -2483,6 +2430,63 @@ CopyFrom(CopyState cstate)
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()
* separately for every tuple. However, we can't do that if there are