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)

Definition at line 98 of file partbounds.h.

◆ partition_bound_has_default

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

Definition at line 99 of file partbounds.h.

Typedef Documentation

◆ PartitionBoundInfoData

Function Documentation

◆ check_default_partition_contents()

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

Definition at line 3267 of file partbounds.c.

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

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().

◆ check_new_partition_bound()

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

Definition at line 2908 of file partbounds.c.

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

References Abs, Assert(), PartitionDescData::boundinfo, DatumGetInt32, 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, PartitionBoundInfoData::kind, lfirst_node, linitial, list_nth(), PartitionBoundSpec::listdatums, 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(), 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, RelationGetPartitionDesc(), RelationGetPartitionKey(), relname, PartitionBoundSpec::remainder, PartitionBoundSpec::strategy, PartitionBoundInfoData::strategy, upper(), PartitionBoundSpec::upperdatums, and val.

Referenced by ATExecAttachPartition(), and DefineRelation().

◆ compute_partition_hash_value()

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

Definition at line 4743 of file partbounds.c.

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

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

Referenced by get_matching_hash_bounds(), and get_partition_for_tuple().

◆ get_hash_partition_greatest_modulus()

int get_hash_partition_greatest_modulus ( PartitionBoundInfo  b)

Definition at line 3430 of file partbounds.c.

3431 {
3432  Assert(bound && bound->strategy == PARTITION_STRATEGY_HASH);
3433  return bound->nindexes;
3434 }

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

◆ get_qual_from_partbound()

List* get_qual_from_partbound ( Relation  parent,
PartitionBoundSpec spec 
)

Definition at line 249 of file partbounds.c.

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 }
static List * get_qual_for_hash(Relation parent, PartitionBoundSpec *spec)
Definition: partbounds.c:3999
#define NIL
Definition: pg_list.h:66

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(), and PartitionBoundSpec::strategy.

Referenced by ATExecAttachPartition(), and generate_partition_qual().

◆ partition_bounds_copy()

PartitionBoundInfo partition_bounds_copy ( PartitionBoundInfo  src,
PartitionKey  key 
)

Definition at line 1010 of file partbounds.c.

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 */
1039  Assert(key->strategy == PARTITION_STRATEGY_RANGE);
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 */
1063  dest->interleaved_parts = bms_copy(src->interleaved_parts);
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 }
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74
signed int int32
Definition: c.h:440
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:132
int j
Definition: isn.c:74
void * palloc(Size size)
Definition: mcxt.c:1068
@ PARTITION_RANGE_DATUM_VALUE
Definition: parsenodes.h:874
struct PartitionBoundInfoData * PartitionBoundInfo
Definition: partdefs.h:16
Bitmapset * interleaved_parts
Definition: partbounds.h:87

References Assert(), bms_copy(), datumCopy(), PartitionBoundInfoData::datums, PartitionBoundInfoData::default_index, generate_unaccent_rules::dest, i, PartitionBoundInfoData::indexes, PartitionBoundInfoData::interleaved_parts, j, sort-test::key, PartitionBoundInfoData::kind, PartitionBoundInfoData::ndatums, PartitionBoundInfoData::nindexes, PartitionBoundInfoData::null_index, palloc(), PARTITION_RANGE_DATUM_VALUE, PARTITION_STRATEGY_HASH, PARTITION_STRATEGY_LIST, PARTITION_STRATEGY_RANGE, and PartitionBoundInfoData::strategy.

Referenced by RelationBuildPartitionDesc().

◆ partition_bounds_create()

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

Definition at line 303 of file partbounds.c.

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 }
static PartitionBoundInfo create_list_bounds(PartitionBoundSpec **boundspecs, int nparts, PartitionKey key, int **mapping)
Definition: partbounds.c:471
static PartitionBoundInfo create_hash_bounds(PartitionBoundSpec **boundspecs, int nparts, PartitionKey key, int **mapping)
Definition: partbounds.c:356
static PartitionBoundInfo create_range_bounds(PartitionBoundSpec **boundspecs, int nparts, PartitionKey key, int **mapping)
Definition: partbounds.c:685

References Assert(), create_hash_bounds(), create_list_bounds(), create_range_bounds(), elog(), ERROR, i, sort-test::key, palloc(), PARTITION_STRATEGY_HASH, PARTITION_STRATEGY_LIST, and PARTITION_STRATEGY_RANGE.

Referenced by RelationBuildPartitionDesc().

◆ 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.

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 }
bool datumIsEqual(Datum value1, Datum value2, bool typByVal, int typLen)
Definition: datum.c:223

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

Referenced by compute_partition_bounds().

◆ 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.

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 }
@ JOIN_SEMI
Definition: nodes.h:764
@ JOIN_FULL
Definition: nodes.h:752
@ JOIN_INNER
Definition: nodes.h:750
@ JOIN_LEFT
Definition: nodes.h:751
@ JOIN_ANTI
Definition: nodes.h:765
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
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
struct PartitionBoundInfoData * boundinfo
Definition: pathnodes.h:832

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().

◆ partition_hash_bsearch()

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

Definition at line 3754 of file partbounds.c.

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

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

Referenced by check_new_partition_bound().

◆ partition_list_bsearch()

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

Definition at line 3623 of file partbounds.c.

3626 {
3627  int lo,
3628  hi,
3629  mid;
3630 
3631  lo = -1;
3632  hi = boundinfo->ndatums - 1;
3633  while (lo < hi)
3634  {
3635  int32 cmpval;
3636 
3637  mid = (lo + hi + 1) / 2;
3638  cmpval = DatumGetInt32(FunctionCall2Coll(&partsupfunc[0],
3639  partcollation[0],
3640  boundinfo->datums[mid][0],
3641  value));
3642  if (cmpval <= 0)
3643  {
3644  lo = mid;
3645  *is_equal = (cmpval == 0);
3646  if (*is_equal)
3647  break;
3648  }
3649  else
3650  hi = mid - 1;
3651  }
3652 
3653  return lo;
3654 }
static struct @151 value

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

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

◆ 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 3711 of file partbounds.c.

3714 {
3715  int lo,
3716  hi,
3717  mid;
3718 
3719  lo = -1;
3720  hi = boundinfo->ndatums - 1;
3721  while (lo < hi)
3722  {
3723  int32 cmpval;
3724 
3725  mid = (lo + hi + 1) / 2;
3726  cmpval = partition_rbound_datum_cmp(partsupfunc,
3727  partcollation,
3728  boundinfo->datums[mid],
3729  boundinfo->kind[mid],
3730  values,
3731  nvalues);
3732  if (cmpval <= 0)
3733  {
3734  lo = mid;
3735  *is_equal = (cmpval == 0);
3736 
3737  if (*is_equal)
3738  break;
3739  }
3740  else
3741  hi = mid - 1;
3742  }
3743 
3744  return lo;
3745 }
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:3572

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

Referenced by get_matching_range_bounds(), and get_partition_for_tuple().

◆ 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 3572 of file partbounds.c.

3575 {
3576  int i;
3577  int32 cmpval = -1;
3578 
3579  for (i = 0; i < n_tuple_datums; i++)
3580  {
3581  if (rb_kind[i] == PARTITION_RANGE_DATUM_MINVALUE)
3582  return -1;
3583  else if (rb_kind[i] == PARTITION_RANGE_DATUM_MAXVALUE)
3584  return 1;
3585 
3586  cmpval = DatumGetInt32(FunctionCall2Coll(&partsupfunc[i],
3587  partcollation[i],
3588  rb_datums[i],
3589  tuple_datums[i]));
3590  if (cmpval != 0)
3591  break;
3592  }
3593 
3594  return cmpval;
3595 }
@ PARTITION_RANGE_DATUM_MAXVALUE
Definition: parsenodes.h:875
@ PARTITION_RANGE_DATUM_MINVALUE
Definition: parsenodes.h:873

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

Referenced by get_matching_range_bounds(), and partition_range_datum_bsearch().

◆ partitions_are_ordered()

bool partitions_are_ordered ( PartitionBoundInfo  boundinfo,
Bitmapset live_parts 
)

Definition at line 2863 of file partbounds.c.

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

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().