aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/execMain.c
diff options
context:
space:
mode:
authorRobert Haas <rhaas@postgresql.org>2017-11-15 10:23:28 -0500
committerRobert Haas <rhaas@postgresql.org>2017-11-15 10:26:25 -0500
commit4e5fe9ad19e14af360de7970caa8b150436c9dec (patch)
tree95526a43235178d03305a6e1dd632d16b66f6870 /src/backend/executor/execMain.c
parentcd8ce3a22c0b48d32ffe6543837ba3bb647ac2b2 (diff)
downloadpostgresql-4e5fe9ad19e14af360de7970caa8b150436c9dec.tar.gz
postgresql-4e5fe9ad19e14af360de7970caa8b150436c9dec.zip
Centralize executor-related partitioning code.
Some code is moved from partition.c, which has grown very quickly lately; splitting the executor parts out might help to keep it from getting totally out of control. Other code is moved from execMain.c. All is moved to a new file execPartition.c. get_partition_for_tuple now has a new interface that more clearly separates executor concerns from generic concerns. Amit Langote. A slight comment tweak by me. Discussion: http://postgr.es/m/1f0985f8-3b61-8bc4-4350-baa6d804cb6d@lab.ntt.co.jp
Diffstat (limited to 'src/backend/executor/execMain.c')
-rw-r--r--src/backend/executor/execMain.c266
1 files changed, 3 insertions, 263 deletions
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 47f21316429..dbaa47f2d30 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -43,7 +43,6 @@
#include "access/xact.h"
#include "catalog/namespace.h"
#include "catalog/partition.h"
-#include "catalog/pg_inherits_fn.h"
#include "catalog/pg_publication.h"
#include "commands/matview.h"
#include "commands/trigger.h"
@@ -98,14 +97,8 @@ static char *ExecBuildSlotValueDescription(Oid reloid,
TupleDesc tupdesc,
Bitmapset *modifiedCols,
int maxfieldlen);
-static char *ExecBuildSlotPartitionKeyDescription(Relation rel,
- Datum *values,
- bool *isnull,
- int maxfieldlen);
static void EvalPlanQualStart(EPQState *epqstate, EState *parentestate,
Plan *planTree);
-static void ExecPartitionCheck(ResultRelInfo *resultRelInfo,
- TupleTableSlot *slot, EState *estate);
/*
* Note that GetUpdatedColumns() also exists in commands/trigger.c. There does
@@ -1854,8 +1847,10 @@ ExecRelCheck(ResultRelInfo *resultRelInfo,
/*
* ExecPartitionCheck --- check that tuple meets the partition constraint.
+ *
+ * Exported in executor.h for outside use.
*/
-static void
+void
ExecPartitionCheck(ResultRelInfo *resultRelInfo, TupleTableSlot *slot,
EState *estate)
{
@@ -3245,258 +3240,3 @@ EvalPlanQualEnd(EPQState *epqstate)
epqstate->planstate = NULL;
epqstate->origslot = NULL;
}
-
-/*
- * ExecSetupPartitionTupleRouting - set up information needed during
- * 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
- *
- * Note that all the relations in the partition tree are locked using the
- * RowExclusiveLock mode upon return from this function.
- */
-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)
-{
- TupleDesc tupDesc = RelationGetDescr(rel);
- List *leaf_parts;
- ListCell *cell;
- int i;
- ResultRelInfo *leaf_part_rri;
-
- /*
- * 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 *
- sizeof(ResultRelInfo *));
- *tup_conv_maps = (TupleConversionMap **) palloc0(*num_partitions *
- sizeof(TupleConversionMap *));
-
- /*
- * Initialize an empty slot that will be used to manipulate tuples of any
- * given partition's rowtype. It is attached to the caller-specified node
- * (such as ModifyTableState) and released when the node finishes
- * processing.
- */
- *partition_tuple_slot = MakeTupleTableSlot();
-
- leaf_part_rri = (ResultRelInfo *) palloc0(*num_partitions *
- sizeof(ResultRelInfo));
- i = 0;
- foreach(cell, leaf_parts)
- {
- Relation partrel;
- TupleDesc part_tupdesc;
-
- /*
- * We locked all the partitions above including the leaf partitions.
- * Note that each of the relations in *partitions are eventually
- * closed by the caller.
- */
- partrel = heap_open(lfirst_oid(cell), NoLock);
- part_tupdesc = RelationGetDescr(partrel);
-
- /*
- * 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,
- gettext_noop("could not convert row type"));
-
- InitResultRelInfo(leaf_part_rri,
- partrel,
- resultRTindex,
- rel,
- estate->es_instrument);
-
- /*
- * Verify result relation is a valid target for INSERT.
- */
- CheckValidResultRel(leaf_part_rri, CMD_INSERT);
-
- /*
- * Open partition indices (remember we do not support ON CONFLICT in
- * case of partitioned tables, so we do not need support information
- * for speculative insertion)
- */
- if (leaf_part_rri->ri_RelationDesc->rd_rel->relhasindex &&
- leaf_part_rri->ri_IndexRelationDescs == NULL)
- ExecOpenIndices(leaf_part_rri, false);
-
- estate->es_leaf_result_relations =
- lappend(estate->es_leaf_result_relations, leaf_part_rri);
-
- (*partitions)[i] = leaf_part_rri++;
- i++;
- }
-}
-
-/*
- * ExecFindPartition -- Find a leaf partition in the partition tree rooted
- * at parent, for the heap tuple contained in *slot
- *
- * estate must be non-NULL; we'll need it to compute any expressions in the
- * partition key(s)
- *
- * If no leaf partition is found, this routine errors out with the appropriate
- * error message, else it returns the leaf partition sequence number returned
- * by get_partition_for_tuple() unchanged.
- */
-int
-ExecFindPartition(ResultRelInfo *resultRelInfo, PartitionDispatch *pd,
- TupleTableSlot *slot, EState *estate)
-{
- int result;
- PartitionDispatchData *failed_at;
- TupleTableSlot *failed_slot;
-
- /*
- * First check the root table's partition constraint, if any. No point in
- * routing the tuple if it doesn't belong in the root table itself.
- */
- if (resultRelInfo->ri_PartitionCheck)
- ExecPartitionCheck(resultRelInfo, slot, estate);
-
- result = get_partition_for_tuple(pd, slot, estate,
- &failed_at, &failed_slot);
- if (result < 0)
- {
- Relation failed_rel;
- Datum key_values[PARTITION_MAX_KEYS];
- bool key_isnull[PARTITION_MAX_KEYS];
- char *val_desc;
- ExprContext *ecxt = GetPerTupleExprContext(estate);
-
- failed_rel = failed_at->reldesc;
- ecxt->ecxt_scantuple = failed_slot;
- FormPartitionKeyDatum(failed_at, failed_slot, estate,
- key_values, key_isnull);
- val_desc = ExecBuildSlotPartitionKeyDescription(failed_rel,
- key_values,
- key_isnull,
- 64);
- Assert(OidIsValid(RelationGetRelid(failed_rel)));
- ereport(ERROR,
- (errcode(ERRCODE_CHECK_VIOLATION),
- errmsg("no partition of relation \"%s\" found for row",
- RelationGetRelationName(failed_rel)),
- val_desc ? errdetail("Partition key of the failing row contains %s.", val_desc) : 0));
- }
-
- return result;
-}
-
-/*
- * BuildSlotPartitionKeyDescription
- *
- * This works very much like BuildIndexValueDescription() and is currently
- * used for building error messages when ExecFindPartition() fails to find
- * partition for a row.
- */
-static char *
-ExecBuildSlotPartitionKeyDescription(Relation rel,
- Datum *values,
- bool *isnull,
- int maxfieldlen)
-{
- StringInfoData buf;
- PartitionKey key = RelationGetPartitionKey(rel);
- int partnatts = get_partition_natts(key);
- int i;
- Oid relid = RelationGetRelid(rel);
- AclResult aclresult;
-
- if (check_enable_rls(relid, InvalidOid, true) == RLS_ENABLED)
- return NULL;
-
- /* If the user has table-level access, just go build the description. */
- aclresult = pg_class_aclcheck(relid, GetUserId(), ACL_SELECT);
- if (aclresult != ACLCHECK_OK)
- {
- /*
- * Step through the columns of the partition key and make sure the
- * user has SELECT rights on all of them.
- */
- for (i = 0; i < partnatts; i++)
- {
- AttrNumber attnum = get_partition_col_attnum(key, i);
-
- /*
- * If this partition key column is an expression, we return no
- * detail rather than try to figure out what column(s) the
- * expression includes and if the user has SELECT rights on them.
- */
- if (attnum == InvalidAttrNumber ||
- pg_attribute_aclcheck(relid, attnum, GetUserId(),
- ACL_SELECT) != ACLCHECK_OK)
- return NULL;
- }
- }
-
- initStringInfo(&buf);
- appendStringInfo(&buf, "(%s) = (",
- pg_get_partkeydef_columns(relid, true));
-
- for (i = 0; i < partnatts; i++)
- {
- char *val;
- int vallen;
-
- if (isnull[i])
- val = "null";
- else
- {
- Oid foutoid;
- bool typisvarlena;
-
- getTypeOutputInfo(get_partition_col_typid(key, i),
- &foutoid, &typisvarlena);
- val = OidOutputFunctionCall(foutoid, values[i]);
- }
-
- if (i > 0)
- appendStringInfoString(&buf, ", ");
-
- /* truncate if needed */
- vallen = strlen(val);
- if (vallen <= maxfieldlen)
- appendStringInfoString(&buf, val);
- else
- {
- vallen = pg_mbcliplen(val, vallen, maxfieldlen);
- appendBinaryStringInfo(&buf, val, vallen);
- appendStringInfoString(&buf, "...");
- }
- }
-
- appendStringInfoChar(&buf, ')');
-
- return buf.data;
-}