PostgreSQL Source Code  git master
partbounds.h File Reference
#include "fmgr.h"
#include "parser/parse_node.h"
#include "partitioning/partdefs.h"
Include dependency graph for partbounds.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  PartitionBoundInfoData
 

Macros

#define partition_bound_accepts_nulls(bi)   ((bi)->null_index != -1)
 
#define partition_bound_has_default(bi)   ((bi)->default_index != -1)
 

Typedefs

typedef struct PartitionBoundInfoData PartitionBoundInfoData
 

Functions

int get_hash_partition_greatest_modulus (PartitionBoundInfo b)
 
uint64 compute_partition_hash_value (int partnatts, FmgrInfo *partsupfunc, Oid *partcollation, Datum *values, bool *isnull)
 
Listget_qual_from_partbound (Relation parent, PartitionBoundSpec *spec)
 
PartitionBoundInfo partition_bounds_create (PartitionBoundSpec **boundspecs, int nparts, PartitionKey key, int **mapping)
 
bool partition_bounds_equal (int partnatts, int16 *parttyplen, bool *parttypbyval, PartitionBoundInfo b1, PartitionBoundInfo b2)
 
PartitionBoundInfo partition_bounds_copy (PartitionBoundInfo src, PartitionKey key)
 
PartitionBoundInfo partition_bounds_merge (int partnatts, FmgrInfo *partsupfunc, Oid *partcollation, struct RelOptInfo *outer_rel, struct RelOptInfo *inner_rel, JoinType jointype, List **outer_parts, List **inner_parts)
 
bool partitions_are_ordered (PartitionBoundInfo boundinfo, Bitmapset *live_parts)
 
void check_new_partition_bound (char *relname, Relation parent, PartitionBoundSpec *spec, ParseState *pstate)
 
void check_default_partition_contents (Relation parent, Relation defaultRel, PartitionBoundSpec *new_spec)
 
int32 partition_rbound_datum_cmp (FmgrInfo *partsupfunc, Oid *partcollation, Datum *rb_datums, PartitionRangeDatumKind *rb_kind, Datum *tuple_datums, int n_tuple_datums)
 
int partition_list_bsearch (FmgrInfo *partsupfunc, Oid *partcollation, PartitionBoundInfo boundinfo, Datum value, bool *is_equal)
 
int partition_range_datum_bsearch (FmgrInfo *partsupfunc, Oid *partcollation, PartitionBoundInfo boundinfo, int nvalues, Datum *values, bool *is_equal)
 
int partition_hash_bsearch (PartitionBoundInfo boundinfo, int modulus, int remainder)
 

Macro Definition Documentation

◆ partition_bound_accepts_nulls

#define partition_bound_accepts_nulls (   bi)    ((bi)->null_index != -1)

◆ partition_bound_has_default

Typedef Documentation

◆ PartitionBoundInfoData

Function Documentation

◆ check_default_partition_contents()

void check_default_partition_contents ( Relation  parent,
Relation  defaultRel,
PartitionBoundSpec new_spec 
)

Definition at line 3264 of file partbounds.c.

References AccessExclusiveLock, CHECK_FOR_INTERRUPTS, CreateExecutorState(), DEBUG1, ExprContext::ecxt_scantuple, ereport, errcode(), errmsg(), errmsg_internal(), ERROR, errtable(), EState::es_tupleTable, ExecCheck(), ExecDropSingleTupleTableSlot(), ExecPrepareExpr(), find_all_inheritors(), ForwardScanDirection, FreeExecutorState(), get_proposed_default_constraint(), get_qual_for_list(), get_qual_for_range(), GetLatestSnapshot(), GetPerTupleExprContext, GetPerTupleMemoryContext, lfirst_oid, list_make1_oid, make_ands_explicit(), map_partition_varattnos(), MemoryContextSwitchTo(), NoLock, PartConstraintImpliedByRelConstraint(), PARTITION_STRATEGY_LIST, RelationData::rd_rel, RegisterSnapshot(), RelationGetRelationName, RelationGetRelid, ResetExprContext, PartitionBoundSpec::strategy, table_beginscan(), table_close(), table_endscan(), table_open(), table_scan_getnextslot(), table_slot_create(), UnregisterSnapshot(), and WARNING.

Referenced by DefineRelation().

3266 {
3267  List *new_part_constraints;
3268  List *def_part_constraints;
3269  List *all_parts;
3270  ListCell *lc;
3271 
3272  new_part_constraints = (new_spec->strategy == PARTITION_STRATEGY_LIST)
3273  ? get_qual_for_list(parent, new_spec)
3274  : get_qual_for_range(parent, new_spec, false);
3275  def_part_constraints =
3276  get_proposed_default_constraint(new_part_constraints);
3277 
3278  /*
3279  * Map the Vars in the constraint expression from parent's attnos to
3280  * default_rel's.
3281  */
3282  def_part_constraints =
3283  map_partition_varattnos(def_part_constraints, 1, default_rel,
3284  parent);
3285 
3286  /*
3287  * If the existing constraints on the default partition imply that it will
3288  * not contain any row that would belong to the new partition, we can
3289  * avoid scanning the default partition.
3290  */
3291  if (PartConstraintImpliedByRelConstraint(default_rel, def_part_constraints))
3292  {
3293  ereport(DEBUG1,
3294  (errmsg_internal("updated partition constraint for default partition \"%s\" is implied by existing constraints",
3295  RelationGetRelationName(default_rel))));
3296  return;
3297  }
3298 
3299  /*
3300  * Scan the default partition and its subpartitions, and check for rows
3301  * that do not satisfy the revised partition constraints.
3302  */
3303  if (default_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
3304  all_parts = find_all_inheritors(RelationGetRelid(default_rel),
3305  AccessExclusiveLock, NULL);
3306  else
3307  all_parts = list_make1_oid(RelationGetRelid(default_rel));
3308 
3309  foreach(lc, all_parts)
3310  {
3311  Oid part_relid = lfirst_oid(lc);
3312  Relation part_rel;
3313  Expr *partition_constraint;
3314  EState *estate;
3315  ExprState *partqualstate = NULL;
3316  Snapshot snapshot;
3317  ExprContext *econtext;
3318  TableScanDesc scan;
3319  MemoryContext oldCxt;
3320  TupleTableSlot *tupslot;
3321 
3322  /* Lock already taken above. */
3323  if (part_relid != RelationGetRelid(default_rel))
3324  {
3325  part_rel = table_open(part_relid, NoLock);
3326 
3327  /*
3328  * Map the Vars in the constraint expression from default_rel's
3329  * the sub-partition's.
3330  */
3331  partition_constraint = make_ands_explicit(def_part_constraints);
3332  partition_constraint = (Expr *)
3333  map_partition_varattnos((List *) partition_constraint, 1,
3334  part_rel, default_rel);
3335 
3336  /*
3337  * If the partition constraints on default partition child imply
3338  * that it will not contain any row that would belong to the new
3339  * partition, we can avoid scanning the child table.
3340  */
3342  def_part_constraints))
3343  {
3344  ereport(DEBUG1,
3345  (errmsg_internal("updated partition constraint for default partition \"%s\" is implied by existing constraints",
3346  RelationGetRelationName(part_rel))));
3347 
3348  table_close(part_rel, NoLock);
3349  continue;
3350  }
3351  }
3352  else
3353  {
3354  part_rel = default_rel;
3355  partition_constraint = make_ands_explicit(def_part_constraints);
3356  }
3357 
3358  /*
3359  * Only RELKIND_RELATION relations (i.e. leaf partitions) need to be
3360  * scanned.
3361  */
3362  if (part_rel->rd_rel->relkind != RELKIND_RELATION)
3363  {
3364  if (part_rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
3365  ereport(WARNING,
3366  (errcode(ERRCODE_CHECK_VIOLATION),
3367  errmsg("skipped scanning foreign table \"%s\" which is a partition of default partition \"%s\"",
3368  RelationGetRelationName(part_rel),
3369  RelationGetRelationName(default_rel))));
3370 
3371  if (RelationGetRelid(default_rel) != RelationGetRelid(part_rel))
3372  table_close(part_rel, NoLock);
3373 
3374  continue;
3375  }
3376 
3377  estate = CreateExecutorState();
3378 
3379  /* Build expression execution states for partition check quals */
3380  partqualstate = ExecPrepareExpr(partition_constraint, estate);
3381 
3382  econtext = GetPerTupleExprContext(estate);
3383  snapshot = RegisterSnapshot(GetLatestSnapshot());
3384  tupslot = table_slot_create(part_rel, &estate->es_tupleTable);
3385  scan = table_beginscan(part_rel, snapshot, 0, NULL);
3386 
3387  /*
3388  * Switch to per-tuple memory context and reset it for each tuple
3389  * produced, so we don't leak memory.
3390  */
3392 
3393  while (table_scan_getnextslot(scan, ForwardScanDirection, tupslot))
3394  {
3395  econtext->ecxt_scantuple = tupslot;
3396 
3397  if (!ExecCheck(partqualstate, econtext))
3398  ereport(ERROR,
3399  (errcode(ERRCODE_CHECK_VIOLATION),
3400  errmsg("updated partition constraint for default partition \"%s\" would be violated by some row",
3401  RelationGetRelationName(default_rel)),
3402  errtable(default_rel)));
3403 
3404  ResetExprContext(econtext);
3406  }
3407 
3408  MemoryContextSwitchTo(oldCxt);
3409  table_endscan(scan);
3410  UnregisterSnapshot(snapshot);
3412  FreeExecutorState(estate);
3413 
3414  if (RelationGetRelid(default_rel) != RelationGetRelid(part_rel))
3415  table_close(part_rel, NoLock); /* keep the lock until commit */
3416  }
3417 }
TupleTableSlot * table_slot_create(Relation relation, List **reglist)
Definition: tableam.c:91
#define DEBUG1
Definition: elog.h:25
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:810
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:698
static bool table_scan_getnextslot(TableScanDesc sscan, ScanDirection direction, TupleTableSlot *slot)
Definition: tableam.h:1032
unsigned int Oid
Definition: postgres_ext.h:31
ExprState * ExecPrepareExpr(Expr *node, EState *estate)
Definition: execExpr.c:746
void FreeExecutorState(EState *estate)
Definition: execUtils.c:186
#define GetPerTupleExprContext(estate)
Definition: executor.h:533
#define ERROR
Definition: elog.h:46
static TableScanDesc table_beginscan(Relation rel, Snapshot snapshot, int nkeys, struct ScanKeyData *key)
Definition: tableam.h:883
#define NoLock
Definition: lockdefs.h:34
List * get_proposed_default_constraint(List *new_part_constraints)
Definition: partition.c:368
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1254
#define RelationGetRelationName(relation)
Definition: rel.h:511
EState * CreateExecutorState(void)
Definition: execUtils.c:90
void UnregisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:852
#define WARNING
Definition: elog.h:40
List * es_tupleTable
Definition: execnodes.h:602
Expr * make_ands_explicit(List *andclauses)
Definition: makefuncs.c:708
#define list_make1_oid(x1)
Definition: pg_list.h:236
#define ereport(elevel,...)
Definition: elog.h:157
int errmsg_internal(const char *fmt,...)
Definition: elog.c:996
static List * get_qual_for_range(Relation parent, PartitionBoundSpec *spec, bool for_default)
Definition: partbounds.c:4288
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:226
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:827
Snapshot GetLatestSnapshot(void)
Definition: snapmgr.c:325
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:538
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:991
#define AccessExclusiveLock
Definition: lockdefs.h:45
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:256
int errmsg(const char *fmt,...)
Definition: elog.c:909
bool ExecCheck(ExprState *state, ExprContext *econtext)
Definition: execExpr.c:853
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:120
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
int errtable(Relation rel)
Definition: relcache.c:5636
List * map_partition_varattnos(List *expr, int fromrel_varno, Relation to_rel, Relation from_rel)
Definition: partition.c:221
#define RelationGetRelid(relation)
Definition: rel.h:477
static List * get_qual_for_list(Relation parent, PartitionBoundSpec *spec)
Definition: partbounds.c:4079
#define ResetExprContext(econtext)
Definition: executor.h:527
#define lfirst_oid(lc)
Definition: pg_list.h:171
bool PartConstraintImpliedByRelConstraint(Relation scanrel, List *partConstraint)
Definition: tablecmds.c:17005

◆ check_new_partition_bound()

void check_new_partition_bound ( char *  relname,
Relation  parent,
PartitionBoundSpec spec,
ParseState pstate 
)

Definition at line 2905 of file partbounds.c.

References Abs, Assert, PartitionDescData::boundinfo, Const::constisnull, Const::constvalue, DatumGetInt32, PartitionRangeBound::datums, PartitionBoundInfoData::datums, PartitionBoundInfoData::default_index, elog, equal(), ereport, errcode(), errdetail(), errmsg(), ERROR, get_range_partbound_string(), get_rel_name(), PartitionBoundInfoData::indexes, PartitionBoundSpec::is_default, sort-test::key, PartitionRangeBound::kind, PartitionBoundInfoData::kind, lfirst_node, linitial, list_nth(), PartitionBoundSpec::listdatums, Const::location, PartitionBoundSpec::location, PartitionRangeDatum::location, lower(), PartitionBoundSpec::lowerdatums, make_one_partition_rbound(), PartitionBoundSpec::modulus, PartitionBoundInfoData::ndatums, PartitionBoundInfoData::nindexes, PartitionDescData::nparts, PartitionBoundInfoData::null_index, PartitionDescData::oids, parser_errposition(), PartitionKeyData::partcollation, partition_bound_accepts_nulls, partition_bound_has_default, partition_hash_bsearch(), partition_list_bsearch(), partition_range_bsearch(), partition_rbound_cmp(), PARTITION_STRATEGY_HASH, PARTITION_STRATEGY_LIST, PARTITION_STRATEGY_RANGE, PartitionKeyData::partnatts, PartitionKeyData::partsupfunc, RelationGetPartitionDesc(), RelationGetPartitionKey(), PartitionHashBound::remainder, PartitionBoundSpec::remainder, PartitionKeyData::strategy, PartitionBoundInfoData::strategy, PartitionBoundSpec::strategy, upper(), PartitionBoundSpec::upperdatums, and val.

Referenced by ATExecAttachPartition(), and DefineRelation().

2907 {
2909  PartitionDesc partdesc = RelationGetPartitionDesc(parent, false);
2910  PartitionBoundInfo boundinfo = partdesc->boundinfo;
2911  int with = -1;
2912  bool overlap = false;
2913  int overlap_location = -1;
2914 
2915  if (spec->is_default)
2916  {
2917  /*
2918  * The default partition bound never conflicts with any other
2919  * partition's; if that's what we're attaching, the only possible
2920  * problem is that one already exists, so check for that and we're
2921  * done.
2922  */
2923  if (boundinfo == NULL || !partition_bound_has_default(boundinfo))
2924  return;
2925 
2926  /* Default partition already exists, error out. */
2927  ereport(ERROR,
2928  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2929  errmsg("partition \"%s\" conflicts with existing default partition \"%s\"",
2930  relname, get_rel_name(partdesc->oids[boundinfo->default_index])),
2931  parser_errposition(pstate, spec->location)));
2932  }
2933 
2934  switch (key->strategy)
2935  {
2937  {
2939  Assert(spec->remainder >= 0 && spec->remainder < spec->modulus);
2940 
2941  if (partdesc->nparts > 0)
2942  {
2943  int greatest_modulus;
2944  int remainder;
2945  int offset;
2946 
2947  /*
2948  * Check rule that every modulus must be a factor of the
2949  * next larger modulus. (For example, if you have a bunch
2950  * of partitions that all have modulus 5, you can add a
2951  * new partition with modulus 10 or a new partition with
2952  * modulus 15, but you cannot add both a partition with
2953  * modulus 10 and a partition with modulus 15, because 10
2954  * is not a factor of 15.) We need only check the next
2955  * smaller and next larger existing moduli, relying on
2956  * previous enforcement of this rule to be sure that the
2957  * rest are in line.
2958  */
2959 
2960  /*
2961  * Get the greatest (modulus, remainder) pair contained in
2962  * boundinfo->datums that is less than or equal to the
2963  * (spec->modulus, spec->remainder) pair.
2964  */
2965  offset = partition_hash_bsearch(boundinfo,
2966  spec->modulus,
2967  spec->remainder);
2968  if (offset < 0)
2969  {
2970  int next_modulus;
2971 
2972  /*
2973  * All existing moduli are greater or equal, so the
2974  * new one must be a factor of the smallest one, which
2975  * is first in the boundinfo.
2976  */
2977  next_modulus = DatumGetInt32(boundinfo->datums[0][0]);
2978  if (next_modulus % spec->modulus != 0)
2979  ereport(ERROR,
2980  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2981  errmsg("every hash partition modulus must be a factor of the next larger modulus"),
2982  errdetail("The new modulus %d is not a factor of %d, the modulus of existing partition \"%s\".",
2983  spec->modulus, next_modulus,
2984  get_rel_name(partdesc->oids[0]))));
2985  }
2986  else
2987  {
2988  int prev_modulus;
2989 
2990  /*
2991  * We found the largest (modulus, remainder) pair less
2992  * than or equal to the new one. That modulus must be
2993  * a divisor of, or equal to, the new modulus.
2994  */
2995  prev_modulus = DatumGetInt32(boundinfo->datums[offset][0]);
2996 
2997  if (spec->modulus % prev_modulus != 0)
2998  ereport(ERROR,
2999  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3000  errmsg("every hash partition modulus must be a factor of the next larger modulus"),
3001  errdetail("The new modulus %d is not divisible by %d, the modulus of existing partition \"%s\".",
3002  spec->modulus,
3003  prev_modulus,
3004  get_rel_name(partdesc->oids[offset]))));
3005 
3006  if (offset + 1 < boundinfo->ndatums)
3007  {
3008  int next_modulus;
3009 
3010  /*
3011  * Look at the next higher (modulus, remainder)
3012  * pair. That could have the same modulus and a
3013  * larger remainder than the new pair, in which
3014  * case we're good. If it has a larger modulus,
3015  * the new modulus must divide that one.
3016  */
3017  next_modulus = DatumGetInt32(boundinfo->datums[offset + 1][0]);
3018 
3019  if (next_modulus % spec->modulus != 0)
3020  ereport(ERROR,
3021  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3022  errmsg("every hash partition modulus must be a factor of the next larger modulus"),
3023  errdetail("The new modulus %d is not a factor of %d, the modulus of existing partition \"%s\".",
3024  spec->modulus, next_modulus,
3025  get_rel_name(partdesc->oids[offset + 1]))));
3026  }
3027  }
3028 
3029  greatest_modulus = boundinfo->nindexes;
3030  remainder = spec->remainder;
3031 
3032  /*
3033  * Normally, the lowest remainder that could conflict with
3034  * the new partition is equal to the remainder specified
3035  * for the new partition, but when the new partition has a
3036  * modulus higher than any used so far, we need to adjust.
3037  */
3038  if (remainder >= greatest_modulus)
3039  remainder = remainder % greatest_modulus;
3040 
3041  /* Check every potentially-conflicting remainder. */
3042  do
3043  {
3044  if (boundinfo->indexes[remainder] != -1)
3045  {
3046  overlap = true;
3047  overlap_location = spec->location;
3048  with = boundinfo->indexes[remainder];
3049  break;
3050  }
3051  remainder += spec->modulus;
3052  } while (remainder < greatest_modulus);
3053  }
3054 
3055  break;
3056  }
3057 
3059  {
3061 
3062  if (partdesc->nparts > 0)
3063  {
3064  ListCell *cell;
3065 
3066  Assert(boundinfo &&
3067  boundinfo->strategy == PARTITION_STRATEGY_LIST &&
3068  (boundinfo->ndatums > 0 ||
3069  partition_bound_accepts_nulls(boundinfo) ||
3070  partition_bound_has_default(boundinfo)));
3071 
3072  foreach(cell, spec->listdatums)
3073  {
3074  Const *val = lfirst_node(Const, cell);
3075 
3076  overlap_location = val->location;
3077  if (!val->constisnull)
3078  {
3079  int offset;
3080  bool equal;
3081 
3082  offset = partition_list_bsearch(&key->partsupfunc[0],
3083  key->partcollation,
3084  boundinfo,
3085  val->constvalue,
3086  &equal);
3087  if (offset >= 0 && equal)
3088  {
3089  overlap = true;
3090  with = boundinfo->indexes[offset];
3091  break;
3092  }
3093  }
3094  else if (partition_bound_accepts_nulls(boundinfo))
3095  {
3096  overlap = true;
3097  with = boundinfo->null_index;
3098  break;
3099  }
3100  }
3101  }
3102 
3103  break;
3104  }
3105 
3107  {
3109  *upper;
3110  int cmpval;
3111 
3113  lower = make_one_partition_rbound(key, -1, spec->lowerdatums, true);
3114  upper = make_one_partition_rbound(key, -1, spec->upperdatums, false);
3115 
3116  /*
3117  * First check if the resulting range would be empty with
3118  * specified lower and upper bounds. partition_rbound_cmp
3119  * cannot return zero here, since the lower-bound flags are
3120  * different.
3121  */
3122  cmpval = partition_rbound_cmp(key->partnatts,
3123  key->partsupfunc,
3124  key->partcollation,
3125  lower->datums, lower->kind,
3126  true, upper);
3127  Assert(cmpval != 0);
3128  if (cmpval > 0)
3129  {
3130  /* Point to problematic key in the lower datums list. */
3131  PartitionRangeDatum *datum = list_nth(spec->lowerdatums,
3132  cmpval - 1);
3133 
3134  ereport(ERROR,
3135  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3136  errmsg("empty range bound specified for partition \"%s\"",
3137  relname),
3138  errdetail("Specified lower bound %s is greater than or equal to upper bound %s.",
3141  parser_errposition(pstate, datum->location)));
3142  }
3143 
3144  if (partdesc->nparts > 0)
3145  {
3146  int offset;
3147 
3148  Assert(boundinfo &&
3149  boundinfo->strategy == PARTITION_STRATEGY_RANGE &&
3150  (boundinfo->ndatums > 0 ||
3151  partition_bound_has_default(boundinfo)));
3152 
3153  /*
3154  * Test whether the new lower bound (which is treated
3155  * inclusively as part of the new partition) lies inside
3156  * an existing partition, or in a gap.
3157  *
3158  * If it's inside an existing partition, the bound at
3159  * offset + 1 will be the upper bound of that partition,
3160  * and its index will be >= 0.
3161  *
3162  * If it's in a gap, the bound at offset + 1 will be the
3163  * lower bound of the next partition, and its index will
3164  * be -1. This is also true if there is no next partition,
3165  * since the index array is initialised with an extra -1
3166  * at the end.
3167  */
3168  offset = partition_range_bsearch(key->partnatts,
3169  key->partsupfunc,
3170  key->partcollation,
3171  boundinfo, lower,
3172  &cmpval);
3173 
3174  if (boundinfo->indexes[offset + 1] < 0)
3175  {
3176  /*
3177  * Check that the new partition will fit in the gap.
3178  * For it to fit, the new upper bound must be less
3179  * than or equal to the lower bound of the next
3180  * partition, if there is one.
3181  */
3182  if (offset + 1 < boundinfo->ndatums)
3183  {
3184  Datum *datums;
3186  bool is_lower;
3187 
3188  datums = boundinfo->datums[offset + 1];
3189  kind = boundinfo->kind[offset + 1];
3190  is_lower = (boundinfo->indexes[offset + 1] == -1);
3191 
3192  cmpval = partition_rbound_cmp(key->partnatts,
3193  key->partsupfunc,
3194  key->partcollation,
3195  datums, kind,
3196  is_lower, upper);
3197  if (cmpval < 0)
3198  {
3199  /*
3200  * Point to problematic key in the upper
3201  * datums list.
3202  */
3203  PartitionRangeDatum *datum =
3204  list_nth(spec->upperdatums, Abs(cmpval) - 1);
3205 
3206  /*
3207  * The new partition overlaps with the
3208  * existing partition between offset + 1 and
3209  * offset + 2.
3210  */
3211  overlap = true;
3212  overlap_location = datum->location;
3213  with = boundinfo->indexes[offset + 2];
3214  }
3215  }
3216  }
3217  else
3218  {
3219  /*
3220  * The new partition overlaps with the existing
3221  * partition between offset and offset + 1.
3222  */
3223  PartitionRangeDatum *datum;
3224 
3225  /*
3226  * Point to problematic key in the lower datums list;
3227  * if we have equality, point to the first one.
3228  */
3229  datum = cmpval == 0 ? linitial(spec->lowerdatums) :
3230  list_nth(spec->lowerdatums, Abs(cmpval) - 1);
3231  overlap = true;
3232  overlap_location = datum->location;
3233  with = boundinfo->indexes[offset + 1];
3234  }
3235  }
3236 
3237  break;
3238  }
3239 
3240  default:
3241  elog(ERROR, "unexpected partition strategy: %d",
3242  (int) key->strategy);
3243  }
3244 
3245  if (overlap)
3246  {
3247  Assert(with >= 0);
3248  ereport(ERROR,
3249  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3250  errmsg("partition \"%s\" would overlap partition \"%s\"",
3251  relname, get_rel_name(partdesc->oids[with])),
3252  parser_errposition(pstate, overlap_location)));
3253  }
3254 }
Datum constvalue
Definition: primnodes.h:219
PartitionRangeDatumKind ** kind
Definition: partbounds.h:82
PartitionRangeDatumKind * kind
Definition: partbounds.c:68
#define DatumGetInt32(X)
Definition: postgres.h:516
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:3149
Datum lower(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:46
FmgrInfo * partsupfunc
Definition: partcache.h:35
PartitionRangeDatumKind
Definition: parsenodes.h:862
int errcode(int sqlerrcode)
Definition: elog.c:698
Datum upper(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:77
PartitionKey RelationGetPartitionKey(Relation rel)
Definition: partcache.c:54
NameData relname
Definition: pg_class.h:38
PartitionBoundInfo boundinfo
Definition: partdesc.h:38
#define Abs(x)
Definition: c.h:992
static PartitionRangeBound * make_one_partition_rbound(PartitionKey key, int index, List *datums, bool lower)
Definition: partbounds.c:3441
#define linitial(l)
Definition: pg_list.h:174
#define ERROR
Definition: elog.h:46
static void * list_nth(const List *list, int n)
Definition: pg_list.h:278
#define lfirst_node(type, lc)
Definition: pg_list.h:172
PartitionDesc RelationGetPartitionDesc(Relation rel, bool omit_detached)
Definition: partdesc.c:72
int errdetail(const char *fmt,...)
Definition: elog.c:1042
#define partition_bound_has_default(bi)
Definition: partbounds.h:97
int partition_hash_bsearch(PartitionBoundInfo boundinfo, int modulus, int remainder)
Definition: partbounds.c:3751
char * get_range_partbound_string(List *bound_datums)
Definition: ruleutils.c:12020
Oid * partcollation
Definition: partcache.h:38
int location
Definition: primnodes.h:226
uintptr_t Datum
Definition: postgres.h:411
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:826
#define partition_bound_accepts_nulls(bi)
Definition: partbounds.h:96
int partition_list_bsearch(FmgrInfo *partsupfunc, Oid *partcollation, PartitionBoundInfo boundinfo, Datum value, bool *is_equal)
Definition: partbounds.c:3620
#define ereport(elevel,...)
Definition: elog.h:157
static int32 partition_rbound_cmp(int partnatts, FmgrInfo *partsupfunc, Oid *partcollation, Datum *datums1, PartitionRangeDatumKind *kind1, bool lower1, PartitionRangeBound *b2)
Definition: partbounds.c:3501
#define Assert(condition)
Definition: c.h:804
static int partition_range_bsearch(int partnatts, FmgrInfo *partsupfunc, Oid *partcollation, PartitionBoundInfo boundinfo, PartitionRangeBound *probe, int32 *cmpval)
Definition: partbounds.c:3666
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:111
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:827
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:828
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define elog(elevel,...)
Definition: elog.h:232
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1899
long val
Definition: informix.c:664
bool constisnull
Definition: primnodes.h:220

◆ compute_partition_hash_value()

uint64 compute_partition_hash_value ( int  partnatts,
FmgrInfo partsupfunc,
Oid partcollation,
Datum values,
bool isnull 
)

Definition at line 4740 of file partbounds.c.

References Assert, DatumGetUInt64, FunctionCall2Coll(), hash(), hash_combine64(), HASH_PARTITION_SEED, i, OidIsValid, and UInt64GetDatum.

Referenced by get_matching_hash_bounds(), and get_partition_for_tuple().

4742 {
4743  int i;
4744  uint64 rowHash = 0;
4746 
4747  for (i = 0; i < partnatts; i++)
4748  {
4749  /* Nulls are just ignored */
4750  if (!isnull[i])
4751  {
4752  Datum hash;
4753 
4754  Assert(OidIsValid(partsupfunc[i].fn_oid));
4755 
4756  /*
4757  * Compute hash for each datum value by calling respective
4758  * datatype-specific hash functions of each partition key
4759  * attribute.
4760  */
4761  hash = FunctionCall2Coll(&partsupfunc[i], partcollation[i],
4762  values[i], seed);
4763 
4764  /* Form a single 64-bit hash value */
4765  rowHash = hash_combine64(rowHash, DatumGetUInt64(hash));
4766  }
4767  }
4768 
4769  return rowHash;
4770 }
#define UInt64GetDatum(X)
Definition: postgres.h:692
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1148
static uint64 hash_combine64(uint64 a, uint64 b)
Definition: hashfn.h:80
#define OidIsValid(objectId)
Definition: c.h:710
uintptr_t Datum
Definition: postgres.h:411
#define DatumGetUInt64(X)
Definition: postgres.h:678
#define Assert(condition)
Definition: c.h:804
#define HASH_PARTITION_SEED
Definition: partition.h:20
static Datum values[MAXATTR]
Definition: bootstrap.c:156
int i
static unsigned hash(unsigned *uv, int n)
Definition: rege_dfa.c:715

◆ get_hash_partition_greatest_modulus()

int get_hash_partition_greatest_modulus ( PartitionBoundInfo  b)

Definition at line 3427 of file partbounds.c.

References Assert, PartitionBoundInfoData::nindexes, PARTITION_STRATEGY_HASH, and PartitionBoundInfoData::strategy.

3428 {
3429  Assert(bound && bound->strategy == PARTITION_STRATEGY_HASH);
3430  return bound->nindexes;
3431 }
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:826
#define Assert(condition)
Definition: c.h:804

◆ get_qual_from_partbound()

List* get_qual_from_partbound ( Relation  parent,
PartitionBoundSpec spec 
)

Definition at line 249 of file partbounds.c.

References Assert, elog, ERROR, get_qual_for_hash(), get_qual_for_list(), get_qual_for_range(), sort-test::key, NIL, PARTITION_STRATEGY_HASH, PARTITION_STRATEGY_LIST, PARTITION_STRATEGY_RANGE, RelationGetPartitionKey(), PartitionKeyData::strategy, and PartitionBoundSpec::strategy.

Referenced by ATExecAttachPartition(), and generate_partition_qual().

250 {
252  List *my_qual = NIL;
253 
254  Assert(key != NULL);
255 
256  switch (key->strategy)
257  {
260  my_qual = get_qual_for_hash(parent, spec);
261  break;
262 
265  my_qual = get_qual_for_list(parent, spec);
266  break;
267 
270  my_qual = get_qual_for_range(parent, spec, false);
271  break;
272 
273  default:
274  elog(ERROR, "unexpected partition strategy: %d",
275  (int) key->strategy);
276  }
277 
278  return my_qual;
279 }
#define NIL
Definition: pg_list.h:65
static List * get_qual_for_hash(Relation parent, PartitionBoundSpec *spec)
Definition: partbounds.c:3996
PartitionKey RelationGetPartitionKey(Relation rel)
Definition: partcache.c:54
#define ERROR
Definition: elog.h:46
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:826
static List * get_qual_for_range(Relation parent, PartitionBoundSpec *spec, bool for_default)
Definition: partbounds.c:4288
#define Assert(condition)
Definition: c.h:804
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:827
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:828
#define elog(elevel,...)
Definition: elog.h:232
Definition: pg_list.h:50
static List * get_qual_for_list(Relation parent, PartitionBoundSpec *spec)
Definition: partbounds.c:4079

◆ partition_bounds_copy()

PartitionBoundInfo partition_bounds_copy ( PartitionBoundInfo  src,
PartitionKey  key 
)

Definition at line 1010 of file partbounds.c.

References Assert, bms_copy(), datumCopy(), PartitionBoundInfoData::datums, PartitionBoundInfoData::default_index, generate_unaccent_rules::dest, i, PartitionBoundInfoData::indexes, PartitionBoundInfoData::interleaved_parts, PartitionBoundInfoData::kind, PartitionBoundInfoData::ndatums, PartitionBoundInfoData::nindexes, PartitionBoundInfoData::null_index, palloc(), PARTITION_RANGE_DATUM_VALUE, PARTITION_STRATEGY_HASH, PARTITION_STRATEGY_LIST, PARTITION_STRATEGY_RANGE, PartitionKeyData::partnatts, PartitionKeyData::parttypbyval, PartitionKeyData::parttyplen, PartitionKeyData::strategy, and PartitionBoundInfoData::strategy.

Referenced by RelationBuildPartitionDesc().

1012 {
1014  int i;
1015  int ndatums;
1016  int nindexes;
1017  int partnatts;
1018  bool hash_part;
1019  int natts;
1020  Datum *boundDatums;
1021 
1023 
1024  dest->strategy = src->strategy;
1025  ndatums = dest->ndatums = src->ndatums;
1026  nindexes = dest->nindexes = src->nindexes;
1027  partnatts = key->partnatts;
1028 
1029  /* List partitioned tables have only a single partition key. */
1030  Assert(key->strategy != PARTITION_STRATEGY_LIST || partnatts == 1);
1031 
1032  dest->datums = (Datum **) palloc(sizeof(Datum *) * ndatums);
1033 
1034  if (src->kind != NULL)
1035  {
1036  PartitionRangeDatumKind *boundKinds;
1037 
1038  /* only RANGE partition should have a non-NULL kind */
1040 
1041  dest->kind = (PartitionRangeDatumKind **) palloc(ndatums *
1042  sizeof(PartitionRangeDatumKind *));
1043 
1044  /*
1045  * In the loop below, to save from allocating a series of small arrays
1046  * for storing the PartitionRangeDatumKind, we allocate a single chunk
1047  * here and use a smaller portion of it for each datum.
1048  */
1049  boundKinds = (PartitionRangeDatumKind *) palloc(ndatums * partnatts *
1050  sizeof(PartitionRangeDatumKind));
1051 
1052  for (i = 0; i < ndatums; i++)
1053  {
1054  dest->kind[i] = &boundKinds[i * partnatts];
1055  memcpy(dest->kind[i], src->kind[i],
1056  sizeof(PartitionRangeDatumKind) * partnatts);
1057  }
1058  }
1059  else
1060  dest->kind = NULL;
1061 
1062  /* copy interleaved partitions for LIST partitioned tables */
1064 
1065  /*
1066  * For hash partitioning, datums array will have two elements - modulus
1067  * and remainder.
1068  */
1069  hash_part = (key->strategy == PARTITION_STRATEGY_HASH);
1070  natts = hash_part ? 2 : partnatts;
1071  boundDatums = palloc(ndatums * natts * sizeof(Datum));
1072 
1073  for (i = 0; i < ndatums; i++)
1074  {
1075  int j;
1076 
1077  dest->datums[i] = &boundDatums[i * natts];
1078 
1079  for (j = 0; j < natts; j++)
1080  {
1081  bool byval;
1082  int typlen;
1083 
1084  if (hash_part)
1085  {
1086  typlen = sizeof(int32); /* Always int4 */
1087  byval = true; /* int4 is pass-by-value */
1088  }
1089  else
1090  {
1091  byval = key->parttypbyval[j];
1092  typlen = key->parttyplen[j];
1093  }
1094 
1095  if (dest->kind == NULL ||
1096  dest->kind[i][j] == PARTITION_RANGE_DATUM_VALUE)
1097  dest->datums[i][j] = datumCopy(src->datums[i][j],
1098  byval, typlen);
1099  }
1100  }
1101 
1102  dest->indexes = (int *) palloc(sizeof(int) * nindexes);
1103  memcpy(dest->indexes, src->indexes, sizeof(int) * nindexes);
1104 
1105  dest->null_index = src->null_index;
1106  dest->default_index = src->default_index;
1107 
1108  return dest;
1109 }
PartitionRangeDatumKind ** kind
Definition: partbounds.h:82
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74
PartitionRangeDatumKind
Definition: parsenodes.h:862
Bitmapset * interleaved_parts
Definition: partbounds.h:85
signed int int32
Definition: c.h:429
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:131
uintptr_t Datum
Definition: postgres.h:411
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:826
bool * parttypbyval
Definition: partcache.h:44
#define Assert(condition)
Definition: c.h:804
int16 * parttyplen
Definition: partcache.h:43
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:827
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:828
void * palloc(Size size)
Definition: mcxt.c:1062
int i
struct PartitionBoundInfoData * PartitionBoundInfo
Definition: partdefs.h:16

◆ partition_bounds_create()

PartitionBoundInfo partition_bounds_create ( PartitionBoundSpec **  boundspecs,
int  nparts,
PartitionKey  key,
int **  mapping 
)

Definition at line 303 of file partbounds.c.

References Assert, create_hash_bounds(), create_list_bounds(), create_range_bounds(), elog, ERROR, i, palloc(), PARTITION_STRATEGY_HASH, PARTITION_STRATEGY_LIST, PARTITION_STRATEGY_RANGE, and PartitionKeyData::strategy.

Referenced by RelationBuildPartitionDesc().

305 {
306  int i;
307 
308  Assert(nparts > 0);
309 
310  /*
311  * For each partitioning method, we first convert the partition bounds
312  * from their parser node representation to the internal representation,
313  * along with any additional preprocessing (such as de-duplicating range
314  * bounds). Resulting bound datums are then added to the 'datums' array
315  * in PartitionBoundInfo. For each datum added, an integer indicating the
316  * canonical partition index is added to the 'indexes' array.
317  *
318  * For each bound, we remember its partition's position (0-based) in the
319  * original list to later map it to the canonical index.
320  */
321 
322  /*
323  * Initialize mapping array with invalid values, this is filled within
324  * each sub-routine below depending on the bound type.
325  */
326  *mapping = (int *) palloc(sizeof(int) * nparts);
327  for (i = 0; i < nparts; i++)
328  (*mapping)[i] = -1;
329 
330  switch (key->strategy)
331  {
333  return create_hash_bounds(boundspecs, nparts, key, mapping);
334 
336  return create_list_bounds(boundspecs, nparts, key, mapping);
337 
339  return create_range_bounds(boundspecs, nparts, key, mapping);
340 
341  default:
342  elog(ERROR, "unexpected partition strategy: %d",
343  (int) key->strategy);
344  break;
345  }
346 
347  Assert(false);
348  return NULL; /* keep compiler quiet */
349 }
#define ERROR
Definition: elog.h:46
static PartitionBoundInfo create_hash_bounds(PartitionBoundSpec **boundspecs, int nparts, PartitionKey key, int **mapping)
Definition: partbounds.c:356
static PartitionBoundInfo create_list_bounds(PartitionBoundSpec **boundspecs, int nparts, PartitionKey key, int **mapping)
Definition: partbounds.c:471
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:826
#define Assert(condition)
Definition: c.h:804
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:827
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:828
static PartitionBoundInfo create_range_bounds(PartitionBoundSpec **boundspecs, int nparts, PartitionKey key, int **mapping)
Definition: partbounds.c:685
void * palloc(Size size)
Definition: mcxt.c:1062
#define elog(elevel,...)
Definition: elog.h:232
int i

◆ partition_bounds_equal()

bool partition_bounds_equal ( int  partnatts,
int16 parttyplen,
bool parttypbyval,
PartitionBoundInfo  b1,
PartitionBoundInfo  b2 
)

Definition at line 904 of file partbounds.c.

References Assert, datumIsEqual(), PartitionBoundInfoData::datums, PartitionBoundInfoData::default_index, i, PartitionBoundInfoData::indexes, PartitionBoundInfoData::kind, PartitionBoundInfoData::ndatums, PartitionBoundInfoData::nindexes, PartitionBoundInfoData::null_index, PARTITION_RANGE_DATUM_VALUE, PARTITION_STRATEGY_HASH, and PartitionBoundInfoData::strategy.

Referenced by compute_partition_bounds().

906 {
907  int i;
908 
909  if (b1->strategy != b2->strategy)
910  return false;
911 
912  if (b1->ndatums != b2->ndatums)
913  return false;
914 
915  if (b1->nindexes != b2->nindexes)
916  return false;
917 
918  if (b1->null_index != b2->null_index)
919  return false;
920 
921  if (b1->default_index != b2->default_index)
922  return false;
923 
924  /* For all partition strategies, the indexes[] arrays have to match */
925  for (i = 0; i < b1->nindexes; i++)
926  {
927  if (b1->indexes[i] != b2->indexes[i])
928  return false;
929  }
930 
931  /* Finally, compare the datums[] arrays */
933  {
934  /*
935  * We arrange the partitions in the ascending order of their moduli
936  * and remainders. Also every modulus is factor of next larger
937  * modulus. Therefore we can safely store index of a given partition
938  * in indexes array at remainder of that partition. Also entries at
939  * (remainder + N * modulus) positions in indexes array are all same
940  * for (modulus, remainder) specification for any partition. Thus the
941  * datums arrays from the given bounds are the same, if and only if
942  * their indexes arrays are the same. So, it suffices to compare the
943  * indexes arrays.
944  *
945  * Nonetheless make sure that the bounds are indeed the same when the
946  * indexes match. Hash partition bound stores modulus and remainder
947  * at b1->datums[i][0] and b1->datums[i][1] position respectively.
948  */
949 #ifdef USE_ASSERT_CHECKING
950  for (i = 0; i < b1->ndatums; i++)
951  Assert((b1->datums[i][0] == b2->datums[i][0] &&
952  b1->datums[i][1] == b2->datums[i][1]));
953 #endif
954  }
955  else
956  {
957  for (i = 0; i < b1->ndatums; i++)
958  {
959  int j;
960 
961  for (j = 0; j < partnatts; j++)
962  {
963  /* For range partitions, the bounds might not be finite. */
964  if (b1->kind != NULL)
965  {
966  /* The different kinds of bound all differ from each other */
967  if (b1->kind[i][j] != b2->kind[i][j])
968  return false;
969 
970  /*
971  * Non-finite bounds are equal without further
972  * examination.
973  */
974  if (b1->kind[i][j] != PARTITION_RANGE_DATUM_VALUE)
975  continue;
976  }
977 
978  /*
979  * Compare the actual values. Note that it would be both
980  * incorrect and unsafe to invoke the comparison operator
981  * derived from the partitioning specification here. It would
982  * be incorrect because we want the relcache entry to be
983  * updated for ANY change to the partition bounds, not just
984  * those that the partitioning operator thinks are
985  * significant. It would be unsafe because we might reach
986  * this code in the context of an aborted transaction, and an
987  * arbitrary partitioning operator might not be safe in that
988  * context. datumIsEqual() should be simple enough to be
989  * safe.
990  */
991  if (!datumIsEqual(b1->datums[i][j], b2->datums[i][j],
992  parttypbyval[j], parttyplen[j]))
993  return false;
994  }
995  }
996  }
997  return true;
998 }
PartitionRangeDatumKind ** kind
Definition: partbounds.h:82
bool datumIsEqual(Datum value1, Datum value2, bool typByVal, int typLen)
Definition: datum.c:222
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:826
#define Assert(condition)
Definition: c.h:804
int i

◆ partition_bounds_merge()

PartitionBoundInfo partition_bounds_merge ( int  partnatts,
FmgrInfo partsupfunc,
Oid partcollation,
struct RelOptInfo outer_rel,
struct RelOptInfo inner_rel,
JoinType  jointype,
List **  outer_parts,
List **  inner_parts 
)

Definition at line 1126 of file partbounds.c.

References Assert, RelOptInfo::boundinfo, elog, ERROR, JOIN_ANTI, JOIN_FULL, JOIN_INNER, JOIN_LEFT, JOIN_SEMI, merge_list_bounds(), merge_range_bounds(), NIL, PARTITION_STRATEGY_HASH, PARTITION_STRATEGY_LIST, PARTITION_STRATEGY_RANGE, and PartitionBoundInfoData::strategy.

Referenced by compute_partition_bounds().

1131 {
1132  /*
1133  * Currently, this function is called only from try_partitionwise_join(),
1134  * so the join type should be INNER, LEFT, FULL, SEMI, or ANTI.
1135  */
1136  Assert(jointype == JOIN_INNER || jointype == JOIN_LEFT ||
1137  jointype == JOIN_FULL || jointype == JOIN_SEMI ||
1138  jointype == JOIN_ANTI);
1139 
1140  /* The partitioning strategies should be the same. */
1141  Assert(outer_rel->boundinfo->strategy == inner_rel->boundinfo->strategy);
1142 
1143  *outer_parts = *inner_parts = NIL;
1144  switch (outer_rel->boundinfo->strategy)
1145  {
1147 
1148  /*
1149  * For hash partitioned tables, we currently support partitioned
1150  * join only when they have exactly the same partition bounds.
1151  *
1152  * XXX: it might be possible to relax the restriction to support
1153  * cases where hash partitioned tables have missing partitions
1154  * and/or different moduli, but it's not clear if it would be
1155  * useful to support the former case since it's unusual to have
1156  * missing partitions. On the other hand, it would be useful to
1157  * support the latter case, but in that case, there is a high
1158  * probability that a partition on one side will match multiple
1159  * partitions on the other side, which is the scenario the current
1160  * implementation of partitioned join can't handle.
1161  */
1162  return NULL;
1163 
1165  return merge_list_bounds(partsupfunc,
1166  partcollation,
1167  outer_rel,
1168  inner_rel,
1169  jointype,
1170  outer_parts,
1171  inner_parts);
1172 
1174  return merge_range_bounds(partnatts,
1175  partsupfunc,
1176  partcollation,
1177  outer_rel,
1178  inner_rel,
1179  jointype,
1180  outer_parts,
1181  inner_parts);
1182 
1183  default:
1184  elog(ERROR, "unexpected partition strategy: %d",
1185  (int) outer_rel->boundinfo->strategy);
1186  return NULL; /* keep compiler quiet */
1187  }
1188 }
#define NIL
Definition: pg_list.h:65
static PartitionBoundInfo merge_list_bounds(FmgrInfo *partsupfunc, Oid *collations, RelOptInfo *outer_rel, RelOptInfo *inner_rel, JoinType jointype, List **outer_parts, List **inner_parts)
Definition: partbounds.c:1209
static PartitionBoundInfo merge_range_bounds(int partnatts, FmgrInfo *partsupfuncs, Oid *partcollations, RelOptInfo *outer_rel, RelOptInfo *inner_rel, JoinType jointype, List **outer_parts, List **inner_parts)
Definition: partbounds.c:1517
#define ERROR
Definition: elog.h:46
struct PartitionBoundInfoData * boundinfo
Definition: pathnodes.h:764
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:826
#define Assert(condition)
Definition: c.h:804
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:827
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:828
#define elog(elevel,...)
Definition: elog.h:232

◆ partition_hash_bsearch()

int partition_hash_bsearch ( PartitionBoundInfo  boundinfo,
int  modulus,
int  remainder 
)

Definition at line 3751 of file partbounds.c.

References DatumGetInt32, PartitionBoundInfoData::datums, PartitionBoundInfoData::ndatums, and partition_hbound_cmp().

Referenced by check_new_partition_bound().

3753 {
3754  int lo,
3755  hi,
3756  mid;
3757 
3758  lo = -1;
3759  hi = boundinfo->ndatums - 1;
3760  while (lo < hi)
3761  {
3762  int32 cmpval,
3763  bound_modulus,
3764  bound_remainder;
3765 
3766  mid = (lo + hi + 1) / 2;
3767  bound_modulus = DatumGetInt32(boundinfo->datums[mid][0]);
3768  bound_remainder = DatumGetInt32(boundinfo->datums[mid][1]);
3769  cmpval = partition_hbound_cmp(bound_modulus, bound_remainder,
3770  modulus, remainder);
3771  if (cmpval <= 0)
3772  {
3773  lo = mid;
3774 
3775  if (cmpval == 0)
3776  break;
3777  }
3778  else
3779  hi = mid - 1;
3780  }
3781 
3782  return lo;
3783 }
#define DatumGetInt32(X)
Definition: postgres.h:516
signed int int32
Definition: c.h:429
static int32 partition_hbound_cmp(int modulus1, int remainder1, int modulus2, int remainder2)
Definition: partbounds.c:3600

◆ partition_list_bsearch()

int partition_list_bsearch ( FmgrInfo partsupfunc,
Oid partcollation,
PartitionBoundInfo  boundinfo,
Datum  value,
bool is_equal 
)

Definition at line 3620 of file partbounds.c.

References DatumGetInt32, PartitionBoundInfoData::datums, FunctionCall2Coll(), and PartitionBoundInfoData::ndatums.

Referenced by check_new_partition_bound(), get_matching_list_bounds(), and get_partition_for_tuple().

3623 {
3624  int lo,
3625  hi,
3626  mid;
3627 
3628  lo = -1;
3629  hi = boundinfo->ndatums - 1;
3630  while (lo < hi)
3631  {
3632  int32 cmpval;
3633 
3634  mid = (lo + hi + 1) / 2;
3635  cmpval = DatumGetInt32(FunctionCall2Coll(&partsupfunc[0],
3636  partcollation[0],
3637  boundinfo->datums[mid][0],
3638  value));
3639  if (cmpval <= 0)
3640  {
3641  lo = mid;
3642  *is_equal = (cmpval == 0);
3643  if (*is_equal)
3644  break;
3645  }
3646  else
3647  hi = mid - 1;
3648  }
3649 
3650  return lo;
3651 }
#define DatumGetInt32(X)
Definition: postgres.h:516
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1148
signed int int32
Definition: c.h:429
static struct @143 value

◆ partition_range_datum_bsearch()

int partition_range_datum_bsearch ( FmgrInfo partsupfunc,
Oid partcollation,
PartitionBoundInfo  boundinfo,
int  nvalues,
Datum values,
bool is_equal 
)

Definition at line 3708 of file partbounds.c.

References PartitionBoundInfoData::datums, PartitionBoundInfoData::kind, PartitionBoundInfoData::ndatums, and partition_rbound_datum_cmp().

Referenced by get_matching_range_bounds(), and get_partition_for_tuple().

3711 {
3712  int lo,
3713  hi,
3714  mid;
3715 
3716  lo = -1;
3717  hi = boundinfo->ndatums - 1;
3718  while (lo < hi)
3719  {
3720  int32 cmpval;
3721 
3722  mid = (lo + hi + 1) / 2;
3723  cmpval = partition_rbound_datum_cmp(partsupfunc,
3724  partcollation,
3725  boundinfo->datums[mid],
3726  boundinfo->kind[mid],
3727  values,
3728  nvalues);
3729  if (cmpval <= 0)
3730  {
3731  lo = mid;
3732  *is_equal = (cmpval == 0);
3733 
3734  if (*is_equal)
3735  break;
3736  }
3737  else
3738  hi = mid - 1;
3739  }
3740 
3741  return lo;
3742 }
PartitionRangeDatumKind ** kind
Definition: partbounds.h:82
signed int int32
Definition: c.h:429
int32 partition_rbound_datum_cmp(FmgrInfo *partsupfunc, Oid *partcollation, Datum *rb_datums, PartitionRangeDatumKind *rb_kind, Datum *tuple_datums, int n_tuple_datums)
Definition: partbounds.c:3569
static Datum values[MAXATTR]
Definition: bootstrap.c:156

◆ partition_rbound_datum_cmp()

int32 partition_rbound_datum_cmp ( FmgrInfo partsupfunc,
Oid partcollation,
Datum rb_datums,
PartitionRangeDatumKind rb_kind,
Datum tuple_datums,
int  n_tuple_datums 
)

Definition at line 3569 of file partbounds.c.

References DatumGetInt32, FunctionCall2Coll(), i, PARTITION_RANGE_DATUM_MAXVALUE, and PARTITION_RANGE_DATUM_MINVALUE.

Referenced by get_matching_range_bounds(), and partition_range_datum_bsearch().

3572 {
3573  int i;
3574  int32 cmpval = -1;
3575 
3576  for (i = 0; i < n_tuple_datums; i++)
3577  {
3578  if (rb_kind[i] == PARTITION_RANGE_DATUM_MINVALUE)
3579  return -1;
3580  else if (rb_kind[i] == PARTITION_RANGE_DATUM_MAXVALUE)
3581  return 1;
3582 
3583  cmpval = DatumGetInt32(FunctionCall2Coll(&partsupfunc[i],
3584  partcollation[i],
3585  rb_datums[i],
3586  tuple_datums[i]));
3587  if (cmpval != 0)
3588  break;
3589  }
3590 
3591  return cmpval;
3592 }
#define DatumGetInt32(X)
Definition: postgres.h:516
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1148
signed int int32
Definition: c.h:429
int i

◆ partitions_are_ordered()

bool partitions_are_ordered ( PartitionBoundInfo  boundinfo,
Bitmapset live_parts 
)

Definition at line 2860 of file partbounds.c.

References Assert, bms_is_member(), bms_overlap(), PartitionBoundInfoData::default_index, PartitionBoundInfoData::interleaved_parts, partition_bound_has_default, PARTITION_STRATEGY_LIST, PARTITION_STRATEGY_RANGE, and PartitionBoundInfoData::strategy.

Referenced by build_partition_pathkeys(), and generate_orderedappend_paths().

2861 {
2862  Assert(boundinfo != NULL);
2863 
2864  switch (boundinfo->strategy)
2865  {
2867 
2868  /*
2869  * RANGE-type partitioning guarantees that the partitions can be
2870  * scanned in the order that they're defined in the PartitionDesc
2871  * to provide sequential, non-overlapping ranges of tuples.
2872  * However, if a DEFAULT partition exists and it's contained
2873  * within live_parts, then the partitions are not ordered.
2874  */
2875  if (!partition_bound_has_default(boundinfo) ||
2876  !bms_is_member(boundinfo->default_index, live_parts))
2877  return true;
2878  break;
2879 
2881 
2882  /*
2883  * LIST partitioned are ordered providing none of live_parts
2884  * overlap with the partitioned table's interleaved partitions.
2885  */
2886  if (!bms_overlap(live_parts, boundinfo->interleaved_parts))
2887  return true;
2888 
2889  break;
2890  default:
2891  /* HASH, or some other strategy */
2892  break;
2893  }
2894 
2895  return false;
2896 }
Bitmapset * interleaved_parts
Definition: partbounds.h:85
#define partition_bound_has_default(bi)
Definition: partbounds.h:97
#define Assert(condition)
Definition: c.h:804
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:827
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:494
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:828
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:427