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 rel, 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, int nparts)
 
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 3146 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().

3148 {
3149  List *new_part_constraints;
3150  List *def_part_constraints;
3151  List *all_parts;
3152  ListCell *lc;
3153 
3154  new_part_constraints = (new_spec->strategy == PARTITION_STRATEGY_LIST)
3155  ? get_qual_for_list(parent, new_spec)
3156  : get_qual_for_range(parent, new_spec, false);
3157  def_part_constraints =
3158  get_proposed_default_constraint(new_part_constraints);
3159 
3160  /*
3161  * Map the Vars in the constraint expression from parent's attnos to
3162  * default_rel's.
3163  */
3164  def_part_constraints =
3165  map_partition_varattnos(def_part_constraints, 1, default_rel,
3166  parent);
3167 
3168  /*
3169  * If the existing constraints on the default partition imply that it will
3170  * not contain any row that would belong to the new partition, we can
3171  * avoid scanning the default partition.
3172  */
3173  if (PartConstraintImpliedByRelConstraint(default_rel, def_part_constraints))
3174  {
3175  ereport(DEBUG1,
3176  (errmsg_internal("updated partition constraint for default partition \"%s\" is implied by existing constraints",
3177  RelationGetRelationName(default_rel))));
3178  return;
3179  }
3180 
3181  /*
3182  * Scan the default partition and its subpartitions, and check for rows
3183  * that do not satisfy the revised partition constraints.
3184  */
3185  if (default_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
3186  all_parts = find_all_inheritors(RelationGetRelid(default_rel),
3187  AccessExclusiveLock, NULL);
3188  else
3189  all_parts = list_make1_oid(RelationGetRelid(default_rel));
3190 
3191  foreach(lc, all_parts)
3192  {
3193  Oid part_relid = lfirst_oid(lc);
3194  Relation part_rel;
3195  Expr *partition_constraint;
3196  EState *estate;
3197  ExprState *partqualstate = NULL;
3198  Snapshot snapshot;
3199  ExprContext *econtext;
3200  TableScanDesc scan;
3201  MemoryContext oldCxt;
3202  TupleTableSlot *tupslot;
3203 
3204  /* Lock already taken above. */
3205  if (part_relid != RelationGetRelid(default_rel))
3206  {
3207  part_rel = table_open(part_relid, NoLock);
3208 
3209  /*
3210  * Map the Vars in the constraint expression from default_rel's
3211  * the sub-partition's.
3212  */
3213  partition_constraint = make_ands_explicit(def_part_constraints);
3214  partition_constraint = (Expr *)
3215  map_partition_varattnos((List *) partition_constraint, 1,
3216  part_rel, default_rel);
3217 
3218  /*
3219  * If the partition constraints on default partition child imply
3220  * that it will not contain any row that would belong to the new
3221  * partition, we can avoid scanning the child table.
3222  */
3224  def_part_constraints))
3225  {
3226  ereport(DEBUG1,
3227  (errmsg_internal("updated partition constraint for default partition \"%s\" is implied by existing constraints",
3228  RelationGetRelationName(part_rel))));
3229 
3230  table_close(part_rel, NoLock);
3231  continue;
3232  }
3233  }
3234  else
3235  {
3236  part_rel = default_rel;
3237  partition_constraint = make_ands_explicit(def_part_constraints);
3238  }
3239 
3240  /*
3241  * Only RELKIND_RELATION relations (i.e. leaf partitions) need to be
3242  * scanned.
3243  */
3244  if (part_rel->rd_rel->relkind != RELKIND_RELATION)
3245  {
3246  if (part_rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
3247  ereport(WARNING,
3248  (errcode(ERRCODE_CHECK_VIOLATION),
3249  errmsg("skipped scanning foreign table \"%s\" which is a partition of default partition \"%s\"",
3250  RelationGetRelationName(part_rel),
3251  RelationGetRelationName(default_rel))));
3252 
3253  if (RelationGetRelid(default_rel) != RelationGetRelid(part_rel))
3254  table_close(part_rel, NoLock);
3255 
3256  continue;
3257  }
3258 
3259  estate = CreateExecutorState();
3260 
3261  /* Build expression execution states for partition check quals */
3262  partqualstate = ExecPrepareExpr(partition_constraint, estate);
3263 
3264  econtext = GetPerTupleExprContext(estate);
3265  snapshot = RegisterSnapshot(GetLatestSnapshot());
3266  tupslot = table_slot_create(part_rel, &estate->es_tupleTable);
3267  scan = table_beginscan(part_rel, snapshot, 0, NULL);
3268 
3269  /*
3270  * Switch to per-tuple memory context and reset it for each tuple
3271  * produced, so we don't leak memory.
3272  */
3274 
3275  while (table_scan_getnextslot(scan, ForwardScanDirection, tupslot))
3276  {
3277  econtext->ecxt_scantuple = tupslot;
3278 
3279  if (!ExecCheck(partqualstate, econtext))
3280  ereport(ERROR,
3281  (errcode(ERRCODE_CHECK_VIOLATION),
3282  errmsg("updated partition constraint for default partition \"%s\" would be violated by some row",
3283  RelationGetRelationName(default_rel)),
3284  errtable(default_rel)));
3285 
3286  ResetExprContext(econtext);
3288  }
3289 
3290  MemoryContextSwitchTo(oldCxt);
3291  table_endscan(scan);
3292  UnregisterSnapshot(snapshot);
3294  FreeExecutorState(estate);
3295 
3296  if (RelationGetRelid(default_rel) != RelationGetRelid(part_rel))
3297  table_close(part_rel, NoLock); /* keep the lock until commit */
3298  }
3299 }
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:503
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:601
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:4169
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:226
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:815
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:5628
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:469
static List * get_qual_for_list(Relation parent, PartitionBoundSpec *spec)
Definition: partbounds.c:3960
#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:16890

◆ check_new_partition_bound()

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

Definition at line 2797 of file partbounds.c.

References Abs, Assert, PartitionDescData::boundinfo, castNode, 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, 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().

2799 {
2801  PartitionDesc partdesc = RelationGetPartitionDesc(parent, false);
2802  PartitionBoundInfo boundinfo = partdesc->boundinfo;
2803  int with = -1;
2804  bool overlap = false;
2805  int overlap_location = -1;
2806 
2807  if (spec->is_default)
2808  {
2809  /*
2810  * The default partition bound never conflicts with any other
2811  * partition's; if that's what we're attaching, the only possible
2812  * problem is that one already exists, so check for that and we're
2813  * done.
2814  */
2815  if (boundinfo == NULL || !partition_bound_has_default(boundinfo))
2816  return;
2817 
2818  /* Default partition already exists, error out. */
2819  ereport(ERROR,
2820  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2821  errmsg("partition \"%s\" conflicts with existing default partition \"%s\"",
2822  relname, get_rel_name(partdesc->oids[boundinfo->default_index])),
2823  parser_errposition(pstate, spec->location)));
2824  }
2825 
2826  switch (key->strategy)
2827  {
2829  {
2831  Assert(spec->remainder >= 0 && spec->remainder < spec->modulus);
2832 
2833  if (partdesc->nparts > 0)
2834  {
2835  int greatest_modulus;
2836  int remainder;
2837  int offset;
2838 
2839  /*
2840  * Check rule that every modulus must be a factor of the
2841  * next larger modulus. For example, if you have a bunch
2842  * of partitions that all have modulus 5, you can add a
2843  * new partition with modulus 10 or a new partition with
2844  * modulus 15, but you cannot add both a partition with
2845  * modulus 10 and a partition with modulus 15, because 10
2846  * is not a factor of 15.
2847  */
2848 
2849  /*
2850  * Get the greatest (modulus, remainder) pair contained in
2851  * boundinfo->datums that is less than or equal to the
2852  * (spec->modulus, spec->remainder) pair.
2853  */
2854  offset = partition_hash_bsearch(boundinfo,
2855  spec->modulus,
2856  spec->remainder);
2857  if (offset < 0)
2858  {
2859  int next_modulus;
2860 
2861  /*
2862  * All existing moduli are greater or equal, so the
2863  * new one must be a factor of the smallest one, which
2864  * is first in the boundinfo.
2865  */
2866  next_modulus = DatumGetInt32(boundinfo->datums[0][0]);
2867  if (next_modulus % spec->modulus != 0)
2868  ereport(ERROR,
2869  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2870  errmsg("every hash partition modulus must be a factor of the next larger modulus"),
2871  errdetail("The new modulus %d is not a factor of %d, the modulus of existing partition \"%s\".",
2872  spec->modulus, next_modulus,
2873  get_rel_name(partdesc->oids[boundinfo->indexes[0]]))));
2874  }
2875  else
2876  {
2877  int prev_modulus;
2878 
2879  /*
2880  * We found the largest modulus less than or equal to
2881  * ours.
2882  */
2883  prev_modulus = DatumGetInt32(boundinfo->datums[offset][0]);
2884 
2885  if (spec->modulus % prev_modulus != 0)
2886  ereport(ERROR,
2887  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2888  errmsg("every hash partition modulus must be a factor of the next larger modulus"),
2889  errdetail("The new modulus %d is not divisible by %d, the modulus of existing partition \"%s\".",
2890  spec->modulus,
2891  prev_modulus,
2892  get_rel_name(partdesc->oids[boundinfo->indexes[offset]]))));
2893 
2894  if (offset + 1 < boundinfo->ndatums)
2895  {
2896  int next_modulus;
2897 
2898  /* Look at the next higher modulus */
2899  next_modulus = DatumGetInt32(boundinfo->datums[offset + 1][0]);
2900 
2901  if (next_modulus % spec->modulus != 0)
2902  ereport(ERROR,
2903  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2904  errmsg("every hash partition modulus must be a factor of the next larger modulus"),
2905  errdetail("The new modulus %d is not a factor of %d, the modulus of existing partition \"%s\".",
2906  spec->modulus, next_modulus,
2907  get_rel_name(partdesc->oids[boundinfo->indexes[offset + 1]]))));
2908  }
2909  }
2910 
2911  greatest_modulus = boundinfo->nindexes;
2912  remainder = spec->remainder;
2913 
2914  /*
2915  * Normally, the lowest remainder that could conflict with
2916  * the new partition is equal to the remainder specified
2917  * for the new partition, but when the new partition has a
2918  * modulus higher than any used so far, we need to adjust.
2919  */
2920  if (remainder >= greatest_modulus)
2921  remainder = remainder % greatest_modulus;
2922 
2923  /* Check every potentially-conflicting remainder. */
2924  do
2925  {
2926  if (boundinfo->indexes[remainder] != -1)
2927  {
2928  overlap = true;
2929  overlap_location = spec->location;
2930  with = boundinfo->indexes[remainder];
2931  break;
2932  }
2933  remainder += spec->modulus;
2934  } while (remainder < greatest_modulus);
2935  }
2936 
2937  break;
2938  }
2939 
2941  {
2943 
2944  if (partdesc->nparts > 0)
2945  {
2946  ListCell *cell;
2947 
2948  Assert(boundinfo &&
2949  boundinfo->strategy == PARTITION_STRATEGY_LIST &&
2950  (boundinfo->ndatums > 0 ||
2951  partition_bound_accepts_nulls(boundinfo) ||
2952  partition_bound_has_default(boundinfo)));
2953 
2954  foreach(cell, spec->listdatums)
2955  {
2956  Const *val = castNode(Const, lfirst(cell));
2957 
2958  overlap_location = val->location;
2959  if (!val->constisnull)
2960  {
2961  int offset;
2962  bool equal;
2963 
2964  offset = partition_list_bsearch(&key->partsupfunc[0],
2965  key->partcollation,
2966  boundinfo,
2967  val->constvalue,
2968  &equal);
2969  if (offset >= 0 && equal)
2970  {
2971  overlap = true;
2972  with = boundinfo->indexes[offset];
2973  break;
2974  }
2975  }
2976  else if (partition_bound_accepts_nulls(boundinfo))
2977  {
2978  overlap = true;
2979  with = boundinfo->null_index;
2980  break;
2981  }
2982  }
2983  }
2984 
2985  break;
2986  }
2987 
2989  {
2991  *upper;
2992  int cmpval;
2993 
2995  lower = make_one_partition_rbound(key, -1, spec->lowerdatums, true);
2996  upper = make_one_partition_rbound(key, -1, spec->upperdatums, false);
2997 
2998  /*
2999  * First check if the resulting range would be empty with
3000  * specified lower and upper bounds. partition_rbound_cmp
3001  * cannot return zero here, since the lower-bound flags are
3002  * different.
3003  */
3004  cmpval = partition_rbound_cmp(key->partnatts,
3005  key->partsupfunc,
3006  key->partcollation,
3007  lower->datums, lower->kind,
3008  true, upper);
3009  Assert(cmpval != 0);
3010  if (cmpval > 0)
3011  {
3012  /* Point to problematic key in the lower datums list. */
3013  PartitionRangeDatum *datum = list_nth(spec->lowerdatums,
3014  cmpval - 1);
3015 
3016  ereport(ERROR,
3017  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3018  errmsg("empty range bound specified for partition \"%s\"",
3019  relname),
3020  errdetail("Specified lower bound %s is greater than or equal to upper bound %s.",
3023  parser_errposition(pstate, datum->location)));
3024  }
3025 
3026  if (partdesc->nparts > 0)
3027  {
3028  int offset;
3029 
3030  Assert(boundinfo &&
3031  boundinfo->strategy == PARTITION_STRATEGY_RANGE &&
3032  (boundinfo->ndatums > 0 ||
3033  partition_bound_has_default(boundinfo)));
3034 
3035  /*
3036  * Test whether the new lower bound (which is treated
3037  * inclusively as part of the new partition) lies inside
3038  * an existing partition, or in a gap.
3039  *
3040  * If it's inside an existing partition, the bound at
3041  * offset + 1 will be the upper bound of that partition,
3042  * and its index will be >= 0.
3043  *
3044  * If it's in a gap, the bound at offset + 1 will be the
3045  * lower bound of the next partition, and its index will
3046  * be -1. This is also true if there is no next partition,
3047  * since the index array is initialised with an extra -1
3048  * at the end.
3049  */
3050  offset = partition_range_bsearch(key->partnatts,
3051  key->partsupfunc,
3052  key->partcollation,
3053  boundinfo, lower,
3054  &cmpval);
3055 
3056  if (boundinfo->indexes[offset + 1] < 0)
3057  {
3058  /*
3059  * Check that the new partition will fit in the gap.
3060  * For it to fit, the new upper bound must be less
3061  * than or equal to the lower bound of the next
3062  * partition, if there is one.
3063  */
3064  if (offset + 1 < boundinfo->ndatums)
3065  {
3066  Datum *datums;
3068  bool is_lower;
3069 
3070  datums = boundinfo->datums[offset + 1];
3071  kind = boundinfo->kind[offset + 1];
3072  is_lower = (boundinfo->indexes[offset + 1] == -1);
3073 
3074  cmpval = partition_rbound_cmp(key->partnatts,
3075  key->partsupfunc,
3076  key->partcollation,
3077  datums, kind,
3078  is_lower, upper);
3079  if (cmpval < 0)
3080  {
3081  /*
3082  * Point to problematic key in the upper
3083  * datums list.
3084  */
3085  PartitionRangeDatum *datum =
3086  list_nth(spec->upperdatums, Abs(cmpval) - 1);
3087 
3088  /*
3089  * The new partition overlaps with the
3090  * existing partition between offset + 1 and
3091  * offset + 2.
3092  */
3093  overlap = true;
3094  overlap_location = datum->location;
3095  with = boundinfo->indexes[offset + 2];
3096  }
3097  }
3098  }
3099  else
3100  {
3101  /*
3102  * The new partition overlaps with the existing
3103  * partition between offset and offset + 1.
3104  */
3105  PartitionRangeDatum *datum;
3106 
3107  /*
3108  * Point to problematic key in the lower datums list;
3109  * if we have equality, point to the first one.
3110  */
3111  datum = cmpval == 0 ? linitial(spec->lowerdatums) :
3112  list_nth(spec->lowerdatums, Abs(cmpval) - 1);
3113  overlap = true;
3114  overlap_location = datum->location;
3115  with = boundinfo->indexes[offset + 1];
3116  }
3117  }
3118 
3119  break;
3120  }
3121 
3122  default:
3123  elog(ERROR, "unexpected partition strategy: %d",
3124  (int) key->strategy);
3125  }
3126 
3127  if (overlap)
3128  {
3129  Assert(with >= 0);
3130  ereport(ERROR,
3131  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3132  errmsg("partition \"%s\" would overlap partition \"%s\"",
3133  relname, get_rel_name(partdesc->oids[with])),
3134  parser_errposition(pstate, overlap_location)));
3135  }
3136 }
Datum constvalue
Definition: primnodes.h:219
PartitionRangeDatumKind ** kind
Definition: partbounds.h:70
PartitionRangeDatumKind * kind
Definition: partbounds.c:68
#define DatumGetInt32(X)
Definition: postgres.h:516
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:3113
Datum lower(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:46
FmgrInfo * partsupfunc
Definition: partcache.h:35
#define castNode(_type_, nodeptr)
Definition: nodes.h:608
PartitionRangeDatumKind
Definition: parsenodes.h:850
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:3323
#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
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:82
int partition_hash_bsearch(PartitionBoundInfo boundinfo, int modulus, int remainder)
Definition: partbounds.c:3633
char * get_range_partbound_string(List *bound_datums)
Definition: ruleutils.c:11970
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:814
#define partition_bound_accepts_nulls(bi)
Definition: partbounds.h:81
int partition_list_bsearch(FmgrInfo *partsupfunc, Oid *partcollation, PartitionBoundInfo boundinfo, Datum value, bool *is_equal)
Definition: partbounds.c:3502
#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:3383
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
static int partition_range_bsearch(int partnatts, FmgrInfo *partsupfunc, Oid *partcollation, PartitionBoundInfo boundinfo, PartitionRangeBound *probe, int32 *cmpval)
Definition: partbounds.c:3548
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:111
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:815
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:816
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 4621 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().

4623 {
4624  int i;
4625  uint64 rowHash = 0;
4627 
4628  for (i = 0; i < partnatts; i++)
4629  {
4630  /* Nulls are just ignored */
4631  if (!isnull[i])
4632  {
4633  Datum hash;
4634 
4635  Assert(OidIsValid(partsupfunc[i].fn_oid));
4636 
4637  /*
4638  * Compute hash for each datum value by calling respective
4639  * datatype-specific hash functions of each partition key
4640  * attribute.
4641  */
4642  hash = FunctionCall2Coll(&partsupfunc[i], partcollation[i],
4643  values[i], seed);
4644 
4645  /* Form a single 64-bit hash value */
4646  rowHash = hash_combine64(rowHash, DatumGetUInt64(hash));
4647  }
4648  }
4649 
4650  return rowHash;
4651 }
#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:166
int i
static unsigned hash(unsigned *uv, int n)
Definition: rege_dfa.c:719

◆ get_hash_partition_greatest_modulus()

int get_hash_partition_greatest_modulus ( PartitionBoundInfo  b)

Definition at line 3309 of file partbounds.c.

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

3310 {
3311  Assert(bound && bound->strategy == PARTITION_STRATEGY_HASH);
3312  return bound->nindexes;
3313 }
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:814
#define Assert(condition)
Definition: c.h:804

◆ get_qual_from_partbound()

List* get_qual_from_partbound ( Relation  rel,
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().

251 {
253  List *my_qual = NIL;
254 
255  Assert(key != NULL);
256 
257  switch (key->strategy)
258  {
261  my_qual = get_qual_for_hash(parent, spec);
262  break;
263 
266  my_qual = get_qual_for_list(parent, spec);
267  break;
268 
271  my_qual = get_qual_for_range(parent, spec, false);
272  break;
273 
274  default:
275  elog(ERROR, "unexpected partition strategy: %d",
276  (int) key->strategy);
277  }
278 
279  return my_qual;
280 }
#define NIL
Definition: pg_list.h:65
static List * get_qual_for_hash(Relation parent, PartitionBoundSpec *spec)
Definition: partbounds.c:3877
PartitionKey RelationGetPartitionKey(Relation rel)
Definition: partcache.c:54
#define ERROR
Definition: elog.h:46
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:814
static List * get_qual_for_range(Relation parent, PartitionBoundSpec *spec, bool for_default)
Definition: partbounds.c:4169
#define Assert(condition)
Definition: c.h:804
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:815
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:816
#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:3960

◆ partition_bounds_copy()

PartitionBoundInfo partition_bounds_copy ( PartitionBoundInfo  src,
PartitionKey  key 
)

Definition at line 907 of file partbounds.c.

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

Referenced by RelationBuildPartitionDesc().

909 {
911  int i;
912  int ndatums;
913  int nindexes;
914  int partnatts;
915  bool hash_part;
916  int natts;
917 
919 
920  dest->strategy = src->strategy;
921  ndatums = dest->ndatums = src->ndatums;
922  nindexes = dest->nindexes = src->nindexes;
923  partnatts = key->partnatts;
924 
925  /* List partitioned tables have only a single partition key. */
926  Assert(key->strategy != PARTITION_STRATEGY_LIST || partnatts == 1);
927 
928  dest->datums = (Datum **) palloc(sizeof(Datum *) * ndatums);
929 
930  if (src->kind != NULL)
931  {
932  dest->kind = (PartitionRangeDatumKind **) palloc(ndatums *
933  sizeof(PartitionRangeDatumKind *));
934  for (i = 0; i < ndatums; i++)
935  {
936  dest->kind[i] = (PartitionRangeDatumKind *) palloc(partnatts *
937  sizeof(PartitionRangeDatumKind));
938 
939  memcpy(dest->kind[i], src->kind[i],
940  sizeof(PartitionRangeDatumKind) * key->partnatts);
941  }
942  }
943  else
944  dest->kind = NULL;
945 
946  /*
947  * For hash partitioning, datums array will have two elements - modulus
948  * and remainder.
949  */
950  hash_part = (key->strategy == PARTITION_STRATEGY_HASH);
951  natts = hash_part ? 2 : partnatts;
952 
953  for (i = 0; i < ndatums; i++)
954  {
955  int j;
956 
957  dest->datums[i] = (Datum *) palloc(sizeof(Datum) * natts);
958 
959  for (j = 0; j < natts; j++)
960  {
961  bool byval;
962  int typlen;
963 
964  if (hash_part)
965  {
966  typlen = sizeof(int32); /* Always int4 */
967  byval = true; /* int4 is pass-by-value */
968  }
969  else
970  {
971  byval = key->parttypbyval[j];
972  typlen = key->parttyplen[j];
973  }
974 
975  if (dest->kind == NULL ||
976  dest->kind[i][j] == PARTITION_RANGE_DATUM_VALUE)
977  dest->datums[i][j] = datumCopy(src->datums[i][j],
978  byval, typlen);
979  }
980  }
981 
982  dest->indexes = (int *) palloc(sizeof(int) * nindexes);
983  memcpy(dest->indexes, src->indexes, sizeof(int) * nindexes);
984 
985  dest->null_index = src->null_index;
986  dest->default_index = src->default_index;
987 
988  return dest;
989 }
PartitionRangeDatumKind ** kind
Definition: partbounds.h:70
PartitionRangeDatumKind
Definition: parsenodes.h:850
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:814
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:815
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 304 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().

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

803 {
804  int i;
805 
806  if (b1->strategy != b2->strategy)
807  return false;
808 
809  if (b1->ndatums != b2->ndatums)
810  return false;
811 
812  if (b1->nindexes != b2->nindexes)
813  return false;
814 
815  if (b1->null_index != b2->null_index)
816  return false;
817 
818  if (b1->default_index != b2->default_index)
819  return false;
820 
821  /* For all partition strategies, the indexes[] arrays have to match */
822  for (i = 0; i < b1->nindexes; i++)
823  {
824  if (b1->indexes[i] != b2->indexes[i])
825  return false;
826  }
827 
828  /* Finally, compare the datums[] arrays */
830  {
831  /*
832  * We arrange the partitions in the ascending order of their moduli
833  * and remainders. Also every modulus is factor of next larger
834  * modulus. Therefore we can safely store index of a given partition
835  * in indexes array at remainder of that partition. Also entries at
836  * (remainder + N * modulus) positions in indexes array are all same
837  * for (modulus, remainder) specification for any partition. Thus the
838  * datums arrays from the given bounds are the same, if and only if
839  * their indexes arrays are the same. So, it suffices to compare the
840  * indexes arrays.
841  *
842  * Nonetheless make sure that the bounds are indeed the same when the
843  * indexes match. Hash partition bound stores modulus and remainder
844  * at b1->datums[i][0] and b1->datums[i][1] position respectively.
845  */
846 #ifdef USE_ASSERT_CHECKING
847  for (i = 0; i < b1->ndatums; i++)
848  Assert((b1->datums[i][0] == b2->datums[i][0] &&
849  b1->datums[i][1] == b2->datums[i][1]));
850 #endif
851  }
852  else
853  {
854  for (i = 0; i < b1->ndatums; i++)
855  {
856  int j;
857 
858  for (j = 0; j < partnatts; j++)
859  {
860  /* For range partitions, the bounds might not be finite. */
861  if (b1->kind != NULL)
862  {
863  /* The different kinds of bound all differ from each other */
864  if (b1->kind[i][j] != b2->kind[i][j])
865  return false;
866 
867  /*
868  * Non-finite bounds are equal without further
869  * examination.
870  */
871  if (b1->kind[i][j] != PARTITION_RANGE_DATUM_VALUE)
872  continue;
873  }
874 
875  /*
876  * Compare the actual values. Note that it would be both
877  * incorrect and unsafe to invoke the comparison operator
878  * derived from the partitioning specification here. It would
879  * be incorrect because we want the relcache entry to be
880  * updated for ANY change to the partition bounds, not just
881  * those that the partitioning operator thinks are
882  * significant. It would be unsafe because we might reach
883  * this code in the context of an aborted transaction, and an
884  * arbitrary partitioning operator might not be safe in that
885  * context. datumIsEqual() should be simple enough to be
886  * safe.
887  */
888  if (!datumIsEqual(b1->datums[i][j], b2->datums[i][j],
889  parttypbyval[j], parttyplen[j]))
890  return false;
891  }
892  }
893  }
894  return true;
895 }
PartitionRangeDatumKind ** kind
Definition: partbounds.h:70
bool datumIsEqual(Datum value1, Datum value2, bool typByVal, int typLen)
Definition: datum.c:222
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:814
#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 1006 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().

1011 {
1012  /*
1013  * Currently, this function is called only from try_partitionwise_join(),
1014  * so the join type should be INNER, LEFT, FULL, SEMI, or ANTI.
1015  */
1016  Assert(jointype == JOIN_INNER || jointype == JOIN_LEFT ||
1017  jointype == JOIN_FULL || jointype == JOIN_SEMI ||
1018  jointype == JOIN_ANTI);
1019 
1020  /* The partitioning strategies should be the same. */
1021  Assert(outer_rel->boundinfo->strategy == inner_rel->boundinfo->strategy);
1022 
1023  *outer_parts = *inner_parts = NIL;
1024  switch (outer_rel->boundinfo->strategy)
1025  {
1027 
1028  /*
1029  * For hash partitioned tables, we currently support partitioned
1030  * join only when they have exactly the same partition bounds.
1031  *
1032  * XXX: it might be possible to relax the restriction to support
1033  * cases where hash partitioned tables have missing partitions
1034  * and/or different moduli, but it's not clear if it would be
1035  * useful to support the former case since it's unusual to have
1036  * missing partitions. On the other hand, it would be useful to
1037  * support the latter case, but in that case, there is a high
1038  * probability that a partition on one side will match multiple
1039  * partitions on the other side, which is the scenario the current
1040  * implementation of partitioned join can't handle.
1041  */
1042  return NULL;
1043 
1045  return merge_list_bounds(partsupfunc,
1046  partcollation,
1047  outer_rel,
1048  inner_rel,
1049  jointype,
1050  outer_parts,
1051  inner_parts);
1052 
1054  return merge_range_bounds(partnatts,
1055  partsupfunc,
1056  partcollation,
1057  outer_rel,
1058  inner_rel,
1059  jointype,
1060  outer_parts,
1061  inner_parts);
1062 
1063  default:
1064  elog(ERROR, "unexpected partition strategy: %d",
1065  (int) outer_rel->boundinfo->strategy);
1066  return NULL; /* keep compiler quiet */
1067  }
1068 }
#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:1089
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:1397
#define ERROR
Definition: elog.h:46
struct PartitionBoundInfoData * boundinfo
Definition: pathnodes.h:759
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:814
#define Assert(condition)
Definition: c.h:804
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:815
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:816
#define elog(elevel,...)
Definition: elog.h:232

◆ partition_hash_bsearch()

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

Definition at line 3633 of file partbounds.c.

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

Referenced by check_new_partition_bound().

3635 {
3636  int lo,
3637  hi,
3638  mid;
3639 
3640  lo = -1;
3641  hi = boundinfo->ndatums - 1;
3642  while (lo < hi)
3643  {
3644  int32 cmpval,
3645  bound_modulus,
3646  bound_remainder;
3647 
3648  mid = (lo + hi + 1) / 2;
3649  bound_modulus = DatumGetInt32(boundinfo->datums[mid][0]);
3650  bound_remainder = DatumGetInt32(boundinfo->datums[mid][1]);
3651  cmpval = partition_hbound_cmp(bound_modulus, bound_remainder,
3652  modulus, remainder);
3653  if (cmpval <= 0)
3654  {
3655  lo = mid;
3656 
3657  if (cmpval == 0)
3658  break;
3659  }
3660  else
3661  hi = mid - 1;
3662  }
3663 
3664  return lo;
3665 }
#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:3482

◆ partition_list_bsearch()

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

Definition at line 3502 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().

3505 {
3506  int lo,
3507  hi,
3508  mid;
3509 
3510  lo = -1;
3511  hi = boundinfo->ndatums - 1;
3512  while (lo < hi)
3513  {
3514  int32 cmpval;
3515 
3516  mid = (lo + hi + 1) / 2;
3517  cmpval = DatumGetInt32(FunctionCall2Coll(&partsupfunc[0],
3518  partcollation[0],
3519  boundinfo->datums[mid][0],
3520  value));
3521  if (cmpval <= 0)
3522  {
3523  lo = mid;
3524  *is_equal = (cmpval == 0);
3525  if (*is_equal)
3526  break;
3527  }
3528  else
3529  hi = mid - 1;
3530  }
3531 
3532  return lo;
3533 }
static struct @142 value
#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

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

3593 {
3594  int lo,
3595  hi,
3596  mid;
3597 
3598  lo = -1;
3599  hi = boundinfo->ndatums - 1;
3600  while (lo < hi)
3601  {
3602  int32 cmpval;
3603 
3604  mid = (lo + hi + 1) / 2;
3605  cmpval = partition_rbound_datum_cmp(partsupfunc,
3606  partcollation,
3607  boundinfo->datums[mid],
3608  boundinfo->kind[mid],
3609  values,
3610  nvalues);
3611  if (cmpval <= 0)
3612  {
3613  lo = mid;
3614  *is_equal = (cmpval == 0);
3615 
3616  if (*is_equal)
3617  break;
3618  }
3619  else
3620  hi = mid - 1;
3621  }
3622 
3623  return lo;
3624 }
PartitionRangeDatumKind ** kind
Definition: partbounds.h:70
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:3451
static Datum values[MAXATTR]
Definition: bootstrap.c:166

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

3454 {
3455  int i;
3456  int32 cmpval = -1;
3457 
3458  for (i = 0; i < n_tuple_datums; i++)
3459  {
3460  if (rb_kind[i] == PARTITION_RANGE_DATUM_MINVALUE)
3461  return -1;
3462  else if (rb_kind[i] == PARTITION_RANGE_DATUM_MAXVALUE)
3463  return 1;
3464 
3465  cmpval = DatumGetInt32(FunctionCall2Coll(&partsupfunc[i],
3466  partcollation[i],
3467  rb_datums[i],
3468  tuple_datums[i]));
3469  if (cmpval != 0)
3470  break;
3471  }
3472 
3473  return cmpval;
3474 }
#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,
int  nparts 
)

Definition at line 2738 of file partbounds.c.

References Assert, PartitionBoundInfoData::ndatums, partition_bound_accepts_nulls, partition_bound_has_default, PARTITION_STRATEGY_LIST, PARTITION_STRATEGY_RANGE, and PartitionBoundInfoData::strategy.

Referenced by build_partition_pathkeys(), and generate_orderedappend_paths().

2739 {
2740  Assert(boundinfo != NULL);
2741 
2742  switch (boundinfo->strategy)
2743  {
2745 
2746  /*
2747  * RANGE-type partitioning guarantees that the partitions can be
2748  * scanned in the order that they're defined in the PartitionDesc
2749  * to provide sequential, non-overlapping ranges of tuples.
2750  * However, if a DEFAULT partition exists then it doesn't work, as
2751  * that could contain tuples from either below or above the
2752  * defined range, or tuples belonging to gaps between partitions.
2753  */
2754  if (!partition_bound_has_default(boundinfo))
2755  return true;
2756  break;
2757 
2759 
2760  /*
2761  * LIST partitioning can also guarantee ordering, but only if the
2762  * partitions don't accept interleaved values. We could likely
2763  * check for this by looping over the PartitionBound's indexes
2764  * array to check that the indexes are in order. For now, let's
2765  * just keep it simple and just accept LIST partitioning when
2766  * there's no DEFAULT partition, exactly one value per partition,
2767  * and optionally a NULL partition that does not accept any other
2768  * values. Such a NULL partition will come last in the
2769  * PartitionDesc, and the other partitions will be properly
2770  * ordered. This is a cheap test to make as it does not require
2771  * any per-partition processing. Maybe we'd like to handle more
2772  * complex cases in the future.
2773  */
2774  if (partition_bound_has_default(boundinfo))
2775  return false;
2776 
2777  if (boundinfo->ndatums + partition_bound_accepts_nulls(boundinfo)
2778  == nparts)
2779  return true;
2780  break;
2781 
2782  default:
2783  /* HASH, or some other strategy */
2784  break;
2785  }
2786 
2787  return false;
2788 }
#define partition_bound_has_default(bi)
Definition: partbounds.h:82
#define partition_bound_accepts_nulls(bi)
Definition: partbounds.h:81
#define Assert(condition)
Definition: c.h:804
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:815
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:816