encapsulate_partinfo_preparatory.patch
application/octet-stream
Filename: encapsulate_partinfo_preparatory.patch
Type: application/octet-stream
Part: 0
Patch
Format: unified
| File | + | − |
|---|---|---|
| src/backend/commands/copy.c | 25 | 39 |
| src/backend/executor/execPartition.c | 18 | 30 |
| src/backend/executor/nodeModifyTable.c | 43 | 49 |
| src/include/executor/execPartition.h | 35 | 5 |
| src/include/nodes/execnodes.h | 1 | 8 |
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 13eb9e3..61ead28 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -165,12 +165,9 @@ typedef struct CopyStateData
bool volatile_defexprs; /* is any of defexprs volatile? */
List *range_table;
- PartitionDispatch *partition_dispatch_info;
- int num_dispatch; /* Number of entries in the above array */
- int num_partitions; /* Number of members in the following arrays */
- ResultRelInfo **partitions; /* Per partition result relation pointers */
- TupleConversionMap **partition_tupconv_maps;
- TupleTableSlot *partition_tuple_slot;
+ PartitionTupleRouting *partition_tuple_routing;
+ /* Tuple-routing support info */
+
TransitionCaptureState *transition_capture;
TupleConversionMap **transition_tupconv_maps;
@@ -2471,27 +2468,14 @@ CopyFrom(CopyState cstate)
*/
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;
+ PartitionTupleRouting *ptr;
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;
+ &cstate->partition_tuple_routing);
+
+ ptr = cstate->partition_tuple_routing;
/*
* If we are capturing transition tuples, they may need to be
@@ -2504,11 +2488,11 @@ CopyFrom(CopyState cstate)
int i;
cstate->transition_tupconv_maps = (TupleConversionMap **)
- palloc0(sizeof(TupleConversionMap *) * cstate->num_partitions);
- for (i = 0; i < cstate->num_partitions; ++i)
+ palloc0(sizeof(TupleConversionMap *) * ptr->num_partitions);
+ for (i = 0; i < ptr->num_partitions; ++i)
{
cstate->transition_tupconv_maps[i] =
- convert_tuples_by_name(RelationGetDescr(cstate->partitions[i]->ri_RelationDesc),
+ convert_tuples_by_name(RelationGetDescr(ptr->partitions[i]->ri_RelationDesc),
RelationGetDescr(cstate->rel),
gettext_noop("could not convert row type"));
}
@@ -2528,7 +2512,7 @@ CopyFrom(CopyState cstate)
if ((resultRelInfo->ri_TrigDesc != NULL &&
(resultRelInfo->ri_TrigDesc->trig_insert_before_row ||
resultRelInfo->ri_TrigDesc->trig_insert_instead_row)) ||
- cstate->partition_dispatch_info != NULL ||
+ cstate->partition_tuple_routing != NULL ||
cstate->volatile_defexprs)
{
useHeapMultiInsert = false;
@@ -2603,10 +2587,11 @@ CopyFrom(CopyState cstate)
ExecStoreTuple(tuple, slot, InvalidBuffer, false);
/* Determine the partition to heap_insert the tuple into */
- if (cstate->partition_dispatch_info)
+ if (cstate->partition_tuple_routing)
{
int leaf_part_index;
TupleConversionMap *map;
+ PartitionTupleRouting *ptr = cstate->partition_tuple_routing;
/*
* Away we go ... If we end up not finding a partition after all,
@@ -2617,11 +2602,11 @@ CopyFrom(CopyState cstate)
* partition, respectively.
*/
leaf_part_index = ExecFindPartition(resultRelInfo,
- cstate->partition_dispatch_info,
+ ptr->partition_dispatch_info,
slot,
estate);
Assert(leaf_part_index >= 0 &&
- leaf_part_index < cstate->num_partitions);
+ leaf_part_index < ptr->num_partitions);
/*
* If this tuple is mapped to a partition that is not same as the
@@ -2639,7 +2624,7 @@ CopyFrom(CopyState cstate)
* to the selected partition.
*/
saved_resultRelInfo = resultRelInfo;
- resultRelInfo = cstate->partitions[leaf_part_index];
+ resultRelInfo = ptr->partitions[leaf_part_index];
/* We do not yet have a way to insert into a foreign partition */
if (resultRelInfo->ri_FdwRoutine)
@@ -2686,7 +2671,7 @@ CopyFrom(CopyState cstate)
* We might need to convert from the parent rowtype to the
* partition rowtype.
*/
- map = cstate->partition_tupconv_maps[leaf_part_index];
+ map = ptr->partition_tupconv_maps[leaf_part_index];
if (map)
{
Relation partrel = resultRelInfo->ri_RelationDesc;
@@ -2698,7 +2683,7 @@ CopyFrom(CopyState cstate)
* point on. Use a dedicated slot from this point on until
* we're finished dealing with the partition.
*/
- slot = cstate->partition_tuple_slot;
+ slot = ptr->partition_tuple_slot;
Assert(slot != NULL);
ExecSetSlotDescriptor(slot, RelationGetDescr(partrel));
ExecStoreTuple(tuple, slot, InvalidBuffer, true);
@@ -2850,8 +2835,9 @@ CopyFrom(CopyState cstate)
ExecCloseIndices(resultRelInfo);
/* Close all the partitioned tables, leaf partitions, and their indices */
- if (cstate->partition_dispatch_info)
+ if (cstate->partition_tuple_routing)
{
+ PartitionTupleRouting *ptr = cstate->partition_tuple_routing;
int i;
/*
@@ -2860,23 +2846,23 @@ CopyFrom(CopyState cstate)
* the main target table of COPY that will be closed eventually by
* DoCopy(). Also, tupslot is NULL for the root partitioned table.
*/
- for (i = 1; i < cstate->num_dispatch; i++)
+ for (i = 1; i < ptr->num_dispatch; i++)
{
- PartitionDispatch pd = cstate->partition_dispatch_info[i];
+ PartitionDispatch pd = ptr->partition_dispatch_info[i];
heap_close(pd->reldesc, NoLock);
ExecDropSingleTupleTableSlot(pd->tupslot);
}
- for (i = 0; i < cstate->num_partitions; i++)
+ for (i = 0; i < ptr->num_partitions; i++)
{
- ResultRelInfo *resultRelInfo = cstate->partitions[i];
+ ResultRelInfo *resultRelInfo = ptr->partitions[i];
ExecCloseIndices(resultRelInfo);
heap_close(resultRelInfo->ri_RelationDesc, NoLock);
}
/* Release the standalone partition tuple descriptor */
- ExecDropSingleTupleTableSlot(cstate->partition_tuple_slot);
+ ExecDropSingleTupleTableSlot(ptr->partition_tuple_slot);
}
/* Close any trigger target relations */
diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c
index 59a0ca4..4b9f451 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -42,22 +42,9 @@ static char *ExecBuildSlotPartitionKeyDescription(Relation rel,
* tuple routing for partitioned tables
*
* Output arguments:
- * 'pd' receives an array of PartitionDispatch objects with one entry for
- * every partitioned table in the partition tree
- * 'partitions' receives an array of ResultRelInfo* objects with one entry for
- * every leaf partition in the partition tree
- * 'tup_conv_maps' receives an array of TupleConversionMap objects with one
- * entry for every leaf partition (required to convert input tuple based
- * on the root table's rowtype to a leaf partition's rowtype after tuple
- * routing is done)
- * 'partition_tuple_slot' receives a standalone TupleTableSlot to be used
- * to manipulate any given leaf partition's rowtype after that partition
- * is chosen by tuple-routing.
- * 'num_parted' receives the number of partitioned tables in the partition
- * tree (= the number of entries in the 'pd' output array)
- * 'num_partitions' receives the number of leaf partitions in the partition
- * tree (= the number of entries in the 'partitions' and 'tup_conv_maps'
- * output arrays
+ *
+ * 'partition_tuple_routing' encapsulates all the partition related information
+ * required to do tuple routing.
*
* Note that all the relations in the partition tree are locked using the
* RowExclusiveLock mode upon return from this function.
@@ -66,29 +53,30 @@ void
ExecSetupPartitionTupleRouting(Relation rel,
Index resultRTindex,
EState *estate,
- PartitionDispatch **pd,
- ResultRelInfo ***partitions,
- TupleConversionMap ***tup_conv_maps,
- TupleTableSlot **partition_tuple_slot,
- int *num_parted, int *num_partitions)
+ PartitionTupleRouting **partition_tuple_routing)
{
TupleDesc tupDesc = RelationGetDescr(rel);
List *leaf_parts;
ListCell *cell;
int i;
ResultRelInfo *leaf_part_rri;
+ PartitionTupleRouting *ptr;
/*
* Get the information about the partition tree after locking all the
* partitions.
*/
(void) find_all_inheritors(RelationGetRelid(rel), RowExclusiveLock, NULL);
- *pd = RelationGetPartitionDispatchInfo(rel, num_parted, &leaf_parts);
- *num_partitions = list_length(leaf_parts);
- *partitions = (ResultRelInfo **) palloc(*num_partitions *
+ ptr = *partition_tuple_routing =
+ (PartitionTupleRouting *) palloc0(sizeof(PartitionTupleRouting));
+ ptr->partition_dispatch_info =
+ RelationGetPartitionDispatchInfo(rel, &ptr->num_dispatch, &leaf_parts);
+ ptr->num_partitions = list_length(leaf_parts);
+ ptr->partitions = (ResultRelInfo **) palloc(ptr->num_partitions *
sizeof(ResultRelInfo *));
- *tup_conv_maps = (TupleConversionMap **) palloc0(*num_partitions *
- sizeof(TupleConversionMap *));
+ ptr->partition_tupconv_maps =
+ (TupleConversionMap **) palloc0(ptr->num_partitions *
+ sizeof(TupleConversionMap *));
/*
* Initialize an empty slot that will be used to manipulate tuples of any
@@ -96,9 +84,9 @@ ExecSetupPartitionTupleRouting(Relation rel,
* (such as ModifyTableState) and released when the node finishes
* processing.
*/
- *partition_tuple_slot = MakeTupleTableSlot();
+ ptr->partition_tuple_slot = MakeTupleTableSlot();
- leaf_part_rri = (ResultRelInfo *) palloc0(*num_partitions *
+ leaf_part_rri = (ResultRelInfo *) palloc0(ptr->num_partitions *
sizeof(ResultRelInfo));
i = 0;
foreach(cell, leaf_parts)
@@ -118,7 +106,7 @@ ExecSetupPartitionTupleRouting(Relation rel,
* Save a tuple conversion map to convert a tuple routed to this
* partition from the parent's type to the partition's.
*/
- (*tup_conv_maps)[i] = convert_tuples_by_name(tupDesc, part_tupdesc,
+ ptr->partition_tupconv_maps[i] = convert_tuples_by_name(tupDesc, part_tupdesc,
gettext_noop("could not convert row type"));
InitResultRelInfo(leaf_part_rri,
@@ -144,7 +132,7 @@ ExecSetupPartitionTupleRouting(Relation rel,
estate->es_leaf_result_relations =
lappend(estate->es_leaf_result_relations, leaf_part_rri);
- (*partitions)[i] = leaf_part_rri++;
+ ptr->partitions[i] = leaf_part_rri++;
i++;
}
}
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 1e3ece9..16789fa 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -279,32 +279,33 @@ ExecInsert(ModifyTableState *mtstate,
resultRelInfo = estate->es_result_relation_info;
/* Determine the partition to heap_insert the tuple into */
- if (mtstate->mt_partition_dispatch_info)
+ if (mtstate->mt_partition_tuple_routing)
{
int leaf_part_index;
+ PartitionTupleRouting *ptr = mtstate->mt_partition_tuple_routing;
TupleConversionMap *map;
/*
* Away we go ... If we end up not finding a partition after all,
* ExecFindPartition() does not return and errors out instead.
* Otherwise, the returned value is to be used as an index into arrays
- * mt_partitions[] and mt_partition_tupconv_maps[] that will get us
+ * ptr->partitions[] and ptr->partition_tupconv_maps[] that will get us
* the ResultRelInfo and TupleConversionMap for the partition,
* respectively.
*/
leaf_part_index = ExecFindPartition(resultRelInfo,
- mtstate->mt_partition_dispatch_info,
+ ptr->partition_dispatch_info,
slot,
estate);
Assert(leaf_part_index >= 0 &&
- leaf_part_index < mtstate->mt_num_partitions);
+ leaf_part_index < ptr->num_partitions);
/*
* Save the old ResultRelInfo and switch to the one corresponding to
* the selected partition.
*/
saved_resultRelInfo = resultRelInfo;
- resultRelInfo = mtstate->mt_partitions[leaf_part_index];
+ resultRelInfo = ptr->partitions[leaf_part_index];
/* We do not yet have a way to insert into a foreign partition */
if (resultRelInfo->ri_FdwRoutine)
@@ -352,7 +353,7 @@ ExecInsert(ModifyTableState *mtstate,
* We might need to convert from the parent rowtype to the partition
* rowtype.
*/
- map = mtstate->mt_partition_tupconv_maps[leaf_part_index];
+ map = ptr->partition_tupconv_maps[leaf_part_index];
if (map)
{
Relation partrel = resultRelInfo->ri_RelationDesc;
@@ -364,7 +365,7 @@ ExecInsert(ModifyTableState *mtstate,
* on, until we're finished dealing with the partition. Use the
* dedicated slot for that.
*/
- slot = mtstate->mt_partition_tuple_slot;
+ slot = ptr->partition_tuple_slot;
Assert(slot != NULL);
ExecSetSlotDescriptor(slot, RelationGetDescr(partrel));
ExecStoreTuple(tuple, slot, InvalidBuffer, true);
@@ -1500,9 +1501,10 @@ ExecSetupTransitionCaptureState(ModifyTableState *mtstate, EState *estate)
mtstate->mt_oc_transition_capture != NULL)
{
int numResultRelInfos;
+ PartitionTupleRouting *ptr = mtstate->mt_partition_tuple_routing;
- numResultRelInfos = (mtstate->mt_partition_tuple_slot != NULL ?
- mtstate->mt_num_partitions :
+ numResultRelInfos = (ptr != NULL ?
+ ptr->num_partitions :
mtstate->mt_nplans);
/*
@@ -1515,13 +1517,13 @@ ExecSetupTransitionCaptureState(ModifyTableState *mtstate, EState *estate)
palloc0(sizeof(TupleConversionMap *) * numResultRelInfos);
/* Choose the right set of partitions */
- if (mtstate->mt_partition_dispatch_info != NULL)
+ if (ptr != NULL)
{
/*
* For tuple routing among partitions, we need TupleDescs based on
* the partition routing table.
*/
- ResultRelInfo **resultRelInfos = mtstate->mt_partitions;
+ ResultRelInfo **resultRelInfos = ptr->partitions;
for (i = 0; i < numResultRelInfos; ++i)
{
@@ -1833,6 +1835,8 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
ListCell *l;
int i;
Relation rel;
+ PartitionTupleRouting *ptr = NULL;
+ int num_partitions = 0;
/* check for unsupported flags */
Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
@@ -1946,27 +1950,13 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
if (operation == CMD_INSERT &&
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,
node->nominalRelation,
estate,
- &partition_dispatch_info,
- &partitions,
- &partition_tupconv_maps,
- &partition_tuple_slot,
- &num_parted, &num_partitions);
- mtstate->mt_partition_dispatch_info = partition_dispatch_info;
- mtstate->mt_num_dispatch = num_parted;
- mtstate->mt_partitions = partitions;
- mtstate->mt_num_partitions = num_partitions;
- mtstate->mt_partition_tupconv_maps = partition_tupconv_maps;
- mtstate->mt_partition_tuple_slot = partition_tuple_slot;
+ &mtstate->mt_partition_tuple_routing);
+
+ ptr = mtstate->mt_partition_tuple_routing;
+ num_partitions = ptr->num_partitions;
}
/*
@@ -2009,7 +1999,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
* will suffice. This only occurs for the INSERT case; UPDATE/DELETE
* cases are handled above.
*/
- if (node->withCheckOptionLists != NIL && mtstate->mt_num_partitions > 0)
+ if (node->withCheckOptionLists != NIL && num_partitions > 0)
{
List *wcoList;
PlanState *plan;
@@ -2026,14 +2016,14 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
mtstate->mt_nplans == 1);
wcoList = linitial(node->withCheckOptionLists);
plan = mtstate->mt_plans[0];
- for (i = 0; i < mtstate->mt_num_partitions; i++)
+ for (i = 0; i < num_partitions; i++)
{
Relation partrel;
List *mapped_wcoList;
List *wcoExprs = NIL;
ListCell *ll;
- resultRelInfo = mtstate->mt_partitions[i];
+ resultRelInfo = ptr->partitions[i];
partrel = resultRelInfo->ri_RelationDesc;
/* varno = node->nominalRelation */
@@ -2102,12 +2092,12 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
* are handled above.
*/
returningList = linitial(node->returningLists);
- for (i = 0; i < mtstate->mt_num_partitions; i++)
+ for (i = 0; i < num_partitions; i++)
{
Relation partrel;
List *rlist;
- resultRelInfo = mtstate->mt_partitions[i];
+ resultRelInfo = ptr->partitions[i];
partrel = resultRelInfo->ri_RelationDesc;
/* varno = node->nominalRelation */
@@ -2376,29 +2366,33 @@ ExecEndModifyTable(ModifyTableState *node)
/*
* Close all the partitioned tables, leaf partitions, and their indices
*
- * Remember node->mt_partition_dispatch_info[0] corresponds to the root
+ * Remember ptr->partition_dispatch_info[0] corresponds to the root
* partitioned table, which we must not try to close, because it is the
* main target table of the query that will be closed by ExecEndPlan().
* Also, tupslot is NULL for the root partitioned table.
*/
- for (i = 1; i < node->mt_num_dispatch; i++)
+ if (node->mt_partition_tuple_routing)
{
- PartitionDispatch pd = node->mt_partition_dispatch_info[i];
+ PartitionTupleRouting *ptr = node->mt_partition_tuple_routing;
- heap_close(pd->reldesc, NoLock);
- ExecDropSingleTupleTableSlot(pd->tupslot);
- }
- for (i = 0; i < node->mt_num_partitions; i++)
- {
- ResultRelInfo *resultRelInfo = node->mt_partitions[i];
+ for (i = 1; i < ptr->num_dispatch; i++)
+ {
+ PartitionDispatch pd = ptr->partition_dispatch_info[i];
- ExecCloseIndices(resultRelInfo);
- heap_close(resultRelInfo->ri_RelationDesc, NoLock);
- }
+ heap_close(pd->reldesc, NoLock);
+ ExecDropSingleTupleTableSlot(pd->tupslot);
+ }
+ for (i = 0; i < ptr->num_partitions; i++)
+ {
+ ResultRelInfo *resultRelInfo = ptr->partitions[i];
+ ExecCloseIndices(resultRelInfo);
+ heap_close(resultRelInfo->ri_RelationDesc, NoLock);
+ }
- /* Release the standalone partition tuple descriptor, if any */
- if (node->mt_partition_tuple_slot)
- ExecDropSingleTupleTableSlot(node->mt_partition_tuple_slot);
+ /* Release the standalone partition tuple descriptor, if any */
+ if (ptr->partition_tuple_slot)
+ ExecDropSingleTupleTableSlot(ptr->partition_tuple_slot);
+ }
/*
* Free the exprcontext
diff --git a/src/include/executor/execPartition.h b/src/include/executor/execPartition.h
index 43ca990..8a7cedf 100644
--- a/src/include/executor/execPartition.h
+++ b/src/include/executor/execPartition.h
@@ -49,14 +49,44 @@ typedef struct PartitionDispatchData
typedef struct PartitionDispatchData *PartitionDispatch;
+/*-----------------------
+ * PartitionTupleRouting - Encapsulates all information required to execute
+ * tuple-routing between partitions.
+ *
+ * partition_dispatch_info Array of PartitionDispatch objects with one
+ * entry for every partitioned table in the
+ * partition tree.
+ * num_dispatch number of partitioned tables in the partition
+ * tree (= length of partition_dispatch_info[])
+ * partitions Array of ResultRelInfo* objects with one entry
+ * for every leaf partition in the partition tree.
+ * num_partitions Number of leaf partitions in the partition tree
+ * (= 'partitions' array length)
+ * partition_tupconv_maps Array of TupleConversionMap objects with one
+ * entry for every leaf partition (required to
+ * convert input tuple based on the root table's
+ * rowtype to a leaf partition's rowtype after
+ * tuple routing is done)
+ * partition_tuple_slot TupleTableSlot to be used to manipulate any
+ * given leaf partition's rowtype after that
+ * partition is chosen for insertion by
+ * tuple-routing.
+ *-----------------------
+ */
+typedef struct PartitionTupleRouting
+{
+ PartitionDispatch *partition_dispatch_info;
+ int num_dispatch;
+ ResultRelInfo **partitions;
+ int num_partitions;
+ TupleConversionMap **partition_tupconv_maps;
+ TupleTableSlot *partition_tuple_slot;
+} PartitionTupleRouting;
+
extern void ExecSetupPartitionTupleRouting(Relation rel,
Index resultRTindex,
EState *estate,
- PartitionDispatch **pd,
- ResultRelInfo ***partitions,
- TupleConversionMap ***tup_conv_maps,
- TupleTableSlot **partition_tuple_slot,
- int *num_parted, int *num_partitions);
+ PartitionTupleRouting **partition_tuple_routing);
extern int ExecFindPartition(ResultRelInfo *resultRelInfo,
PartitionDispatch *pd,
TupleTableSlot *slot,
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index e05bc04..6b481b4 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -976,15 +976,8 @@ typedef struct ModifyTableState
TupleTableSlot *mt_existing; /* slot to store existing target tuple in */
List *mt_excludedtlist; /* the excluded pseudo relation's tlist */
TupleTableSlot *mt_conflproj; /* CONFLICT ... SET ... projection target */
- struct PartitionDispatchData **mt_partition_dispatch_info;
+ struct PartitionTupleRouting *mt_partition_tuple_routing;
/* Tuple-routing support info */
- int mt_num_dispatch; /* Number of entries in the above array */
- int mt_num_partitions; /* Number of members in the following
- * arrays */
- ResultRelInfo **mt_partitions; /* Per partition result relation pointers */
- TupleConversionMap **mt_partition_tupconv_maps;
- /* Per partition tuple conversion map */
- TupleTableSlot *mt_partition_tuple_slot;
struct TransitionCaptureState *mt_transition_capture;
/* controls transition table population for specified operation */
struct TransitionCaptureState *mt_oc_transition_capture;