Skip to content

Commit 4e5fe9a

Browse files
committed
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
1 parent cd8ce3a commit 4e5fe9a

File tree

9 files changed

+717
-695
lines changed

9 files changed

+717
-695
lines changed

src/backend/catalog/partition.c

Lines changed: 80 additions & 375 deletions
Large diffs are not rendered by default.

src/backend/commands/copy.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "commands/copy.h"
2828
#include "commands/defrem.h"
2929
#include "commands/trigger.h"
30+
#include "executor/execPartition.h"
3031
#include "executor/executor.h"
3132
#include "libpq/libpq.h"
3233
#include "libpq/pqformat.h"

src/backend/executor/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ include $(top_builddir)/src/Makefile.global
1414

1515
OBJS = execAmi.o execCurrent.o execExpr.o execExprInterp.o \
1616
execGrouping.o execIndexing.o execJunk.o \
17-
execMain.o execParallel.o execProcnode.o \
17+
execMain.o execParallel.o execPartition.o execProcnode.o \
1818
execReplication.o execScan.o execSRF.o execTuples.o \
1919
execUtils.o functions.o instrument.o nodeAppend.o nodeAgg.o \
2020
nodeBitmapAnd.o nodeBitmapOr.o \

src/backend/executor/execMain.c

Lines changed: 3 additions & 263 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@
4343
#include "access/xact.h"
4444
#include "catalog/namespace.h"
4545
#include "catalog/partition.h"
46-
#include "catalog/pg_inherits_fn.h"
4746
#include "catalog/pg_publication.h"
4847
#include "commands/matview.h"
4948
#include "commands/trigger.h"
@@ -98,14 +97,8 @@ static char *ExecBuildSlotValueDescription(Oid reloid,
9897
TupleDesc tupdesc,
9998
Bitmapset *modifiedCols,
10099
int maxfieldlen);
101-
static char *ExecBuildSlotPartitionKeyDescription(Relation rel,
102-
Datum *values,
103-
bool *isnull,
104-
int maxfieldlen);
105100
static void EvalPlanQualStart(EPQState *epqstate, EState *parentestate,
106101
Plan *planTree);
107-
static void ExecPartitionCheck(ResultRelInfo *resultRelInfo,
108-
TupleTableSlot *slot, EState *estate);
109102

110103
/*
111104
* Note that GetUpdatedColumns() also exists in commands/trigger.c. There does
@@ -1854,8 +1847,10 @@ ExecRelCheck(ResultRelInfo *resultRelInfo,
18541847

18551848
/*
18561849
* ExecPartitionCheck --- check that tuple meets the partition constraint.
1850+
*
1851+
* Exported in executor.h for outside use.
18571852
*/
1858-
static void
1853+
void
18591854
ExecPartitionCheck(ResultRelInfo *resultRelInfo, TupleTableSlot *slot,
18601855
EState *estate)
18611856
{
@@ -3245,258 +3240,3 @@ EvalPlanQualEnd(EPQState *epqstate)
32453240
epqstate->planstate = NULL;
32463241
epqstate->origslot = NULL;
32473242
}
3248-
3249-
/*
3250-
* ExecSetupPartitionTupleRouting - set up information needed during
3251-
* tuple routing for partitioned tables
3252-
*
3253-
* Output arguments:
3254-
* 'pd' receives an array of PartitionDispatch objects with one entry for
3255-
* every partitioned table in the partition tree
3256-
* 'partitions' receives an array of ResultRelInfo* objects with one entry for
3257-
* every leaf partition in the partition tree
3258-
* 'tup_conv_maps' receives an array of TupleConversionMap objects with one
3259-
* entry for every leaf partition (required to convert input tuple based
3260-
* on the root table's rowtype to a leaf partition's rowtype after tuple
3261-
* routing is done)
3262-
* 'partition_tuple_slot' receives a standalone TupleTableSlot to be used
3263-
* to manipulate any given leaf partition's rowtype after that partition
3264-
* is chosen by tuple-routing.
3265-
* 'num_parted' receives the number of partitioned tables in the partition
3266-
* tree (= the number of entries in the 'pd' output array)
3267-
* 'num_partitions' receives the number of leaf partitions in the partition
3268-
* tree (= the number of entries in the 'partitions' and 'tup_conv_maps'
3269-
* output arrays
3270-
*
3271-
* Note that all the relations in the partition tree are locked using the
3272-
* RowExclusiveLock mode upon return from this function.
3273-
*/
3274-
void
3275-
ExecSetupPartitionTupleRouting(Relation rel,
3276-
Index resultRTindex,
3277-
EState *estate,
3278-
PartitionDispatch **pd,
3279-
ResultRelInfo ***partitions,
3280-
TupleConversionMap ***tup_conv_maps,
3281-
TupleTableSlot **partition_tuple_slot,
3282-
int *num_parted, int *num_partitions)
3283-
{
3284-
TupleDesc tupDesc = RelationGetDescr(rel);
3285-
List *leaf_parts;
3286-
ListCell *cell;
3287-
int i;
3288-
ResultRelInfo *leaf_part_rri;
3289-
3290-
/*
3291-
* Get the information about the partition tree after locking all the
3292-
* partitions.
3293-
*/
3294-
(void) find_all_inheritors(RelationGetRelid(rel), RowExclusiveLock, NULL);
3295-
*pd = RelationGetPartitionDispatchInfo(rel, num_parted, &leaf_parts);
3296-
*num_partitions = list_length(leaf_parts);
3297-
*partitions = (ResultRelInfo **) palloc(*num_partitions *
3298-
sizeof(ResultRelInfo *));
3299-
*tup_conv_maps = (TupleConversionMap **) palloc0(*num_partitions *
3300-
sizeof(TupleConversionMap *));
3301-
3302-
/*
3303-
* Initialize an empty slot that will be used to manipulate tuples of any
3304-
* given partition's rowtype. It is attached to the caller-specified node
3305-
* (such as ModifyTableState) and released when the node finishes
3306-
* processing.
3307-
*/
3308-
*partition_tuple_slot = MakeTupleTableSlot();
3309-
3310-
leaf_part_rri = (ResultRelInfo *) palloc0(*num_partitions *
3311-
sizeof(ResultRelInfo));
3312-
i = 0;
3313-
foreach(cell, leaf_parts)
3314-
{
3315-
Relation partrel;
3316-
TupleDesc part_tupdesc;
3317-
3318-
/*
3319-
* We locked all the partitions above including the leaf partitions.
3320-
* Note that each of the relations in *partitions are eventually
3321-
* closed by the caller.
3322-
*/
3323-
partrel = heap_open(lfirst_oid(cell), NoLock);
3324-
part_tupdesc = RelationGetDescr(partrel);
3325-
3326-
/*
3327-
* Save a tuple conversion map to convert a tuple routed to this
3328-
* partition from the parent's type to the partition's.
3329-
*/
3330-
(*tup_conv_maps)[i] = convert_tuples_by_name(tupDesc, part_tupdesc,
3331-
gettext_noop("could not convert row type"));
3332-
3333-
InitResultRelInfo(leaf_part_rri,
3334-
partrel,
3335-
resultRTindex,
3336-
rel,
3337-
estate->es_instrument);
3338-
3339-
/*
3340-
* Verify result relation is a valid target for INSERT.
3341-
*/
3342-
CheckValidResultRel(leaf_part_rri, CMD_INSERT);
3343-
3344-
/*
3345-
* Open partition indices (remember we do not support ON CONFLICT in
3346-
* case of partitioned tables, so we do not need support information
3347-
* for speculative insertion)
3348-
*/
3349-
if (leaf_part_rri->ri_RelationDesc->rd_rel->relhasindex &&
3350-
leaf_part_rri->ri_IndexRelationDescs == NULL)
3351-
ExecOpenIndices(leaf_part_rri, false);
3352-
3353-
estate->es_leaf_result_relations =
3354-
lappend(estate->es_leaf_result_relations, leaf_part_rri);
3355-
3356-
(*partitions)[i] = leaf_part_rri++;
3357-
i++;
3358-
}
3359-
}
3360-
3361-
/*
3362-
* ExecFindPartition -- Find a leaf partition in the partition tree rooted
3363-
* at parent, for the heap tuple contained in *slot
3364-
*
3365-
* estate must be non-NULL; we'll need it to compute any expressions in the
3366-
* partition key(s)
3367-
*
3368-
* If no leaf partition is found, this routine errors out with the appropriate
3369-
* error message, else it returns the leaf partition sequence number returned
3370-
* by get_partition_for_tuple() unchanged.
3371-
*/
3372-
int
3373-
ExecFindPartition(ResultRelInfo *resultRelInfo, PartitionDispatch *pd,
3374-
TupleTableSlot *slot, EState *estate)
3375-
{
3376-
int result;
3377-
PartitionDispatchData *failed_at;
3378-
TupleTableSlot *failed_slot;
3379-
3380-
/*
3381-
* First check the root table's partition constraint, if any. No point in
3382-
* routing the tuple if it doesn't belong in the root table itself.
3383-
*/
3384-
if (resultRelInfo->ri_PartitionCheck)
3385-
ExecPartitionCheck(resultRelInfo, slot, estate);
3386-
3387-
result = get_partition_for_tuple(pd, slot, estate,
3388-
&failed_at, &failed_slot);
3389-
if (result < 0)
3390-
{
3391-
Relation failed_rel;
3392-
Datum key_values[PARTITION_MAX_KEYS];
3393-
bool key_isnull[PARTITION_MAX_KEYS];
3394-
char *val_desc;
3395-
ExprContext *ecxt = GetPerTupleExprContext(estate);
3396-
3397-
failed_rel = failed_at->reldesc;
3398-
ecxt->ecxt_scantuple = failed_slot;
3399-
FormPartitionKeyDatum(failed_at, failed_slot, estate,
3400-
key_values, key_isnull);
3401-
val_desc = ExecBuildSlotPartitionKeyDescription(failed_rel,
3402-
key_values,
3403-
key_isnull,
3404-
64);
3405-
Assert(OidIsValid(RelationGetRelid(failed_rel)));
3406-
ereport(ERROR,
3407-
(errcode(ERRCODE_CHECK_VIOLATION),
3408-
errmsg("no partition of relation \"%s\" found for row",
3409-
RelationGetRelationName(failed_rel)),
3410-
val_desc ? errdetail("Partition key of the failing row contains %s.", val_desc) : 0));
3411-
}
3412-
3413-
return result;
3414-
}
3415-
3416-
/*
3417-
* BuildSlotPartitionKeyDescription
3418-
*
3419-
* This works very much like BuildIndexValueDescription() and is currently
3420-
* used for building error messages when ExecFindPartition() fails to find
3421-
* partition for a row.
3422-
*/
3423-
static char *
3424-
ExecBuildSlotPartitionKeyDescription(Relation rel,
3425-
Datum *values,
3426-
bool *isnull,
3427-
int maxfieldlen)
3428-
{
3429-
StringInfoData buf;
3430-
PartitionKey key = RelationGetPartitionKey(rel);
3431-
int partnatts = get_partition_natts(key);
3432-
int i;
3433-
Oid relid = RelationGetRelid(rel);
3434-
AclResult aclresult;
3435-
3436-
if (check_enable_rls(relid, InvalidOid, true) == RLS_ENABLED)
3437-
return NULL;
3438-
3439-
/* If the user has table-level access, just go build the description. */
3440-
aclresult = pg_class_aclcheck(relid, GetUserId(), ACL_SELECT);
3441-
if (aclresult != ACLCHECK_OK)
3442-
{
3443-
/*
3444-
* Step through the columns of the partition key and make sure the
3445-
* user has SELECT rights on all of them.
3446-
*/
3447-
for (i = 0; i < partnatts; i++)
3448-
{
3449-
AttrNumber attnum = get_partition_col_attnum(key, i);
3450-
3451-
/*
3452-
* If this partition key column is an expression, we return no
3453-
* detail rather than try to figure out what column(s) the
3454-
* expression includes and if the user has SELECT rights on them.
3455-
*/
3456-
if (attnum == InvalidAttrNumber ||
3457-
pg_attribute_aclcheck(relid, attnum, GetUserId(),
3458-
ACL_SELECT) != ACLCHECK_OK)
3459-
return NULL;
3460-
}
3461-
}
3462-
3463-
initStringInfo(&buf);
3464-
appendStringInfo(&buf, "(%s) = (",
3465-
pg_get_partkeydef_columns(relid, true));
3466-
3467-
for (i = 0; i < partnatts; i++)
3468-
{
3469-
char *val;
3470-
int vallen;
3471-
3472-
if (isnull[i])
3473-
val = "null";
3474-
else
3475-
{
3476-
Oid foutoid;
3477-
bool typisvarlena;
3478-
3479-
getTypeOutputInfo(get_partition_col_typid(key, i),
3480-
&foutoid, &typisvarlena);
3481-
val = OidOutputFunctionCall(foutoid, values[i]);
3482-
}
3483-
3484-
if (i > 0)
3485-
appendStringInfoString(&buf, ", ");
3486-
3487-
/* truncate if needed */
3488-
vallen = strlen(val);
3489-
if (vallen <= maxfieldlen)
3490-
appendStringInfoString(&buf, val);
3491-
else
3492-
{
3493-
vallen = pg_mbcliplen(val, vallen, maxfieldlen);
3494-
appendBinaryStringInfo(&buf, val, vallen);
3495-
appendStringInfoString(&buf, "...");
3496-
}
3497-
}
3498-
3499-
appendStringInfoChar(&buf, ')');
3500-
3501-
return buf.data;
3502-
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy