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

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

◆ 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);
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  /* We found the largest modulus less than or equal to ours. */
2880  prev_modulus = DatumGetInt32(boundinfo->datums[offset][0]);
2881 
2882  if (spec->modulus % prev_modulus != 0)
2883  ereport(ERROR,
2884  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2885  errmsg("every hash partition modulus must be a factor of the next larger modulus"),
2886  errdetail("The new modulus %d is not divisible by %d, the modulus of existing partition \"%s\".",
2887  spec->modulus,
2888  prev_modulus,
2889  get_rel_name(partdesc->oids[boundinfo->indexes[offset]]))));
2890 
2891  if (offset + 1 < boundinfo->ndatums)
2892  {
2893  int next_modulus;
2894 
2895  /* Look at the next higher modulus */
2896  next_modulus = DatumGetInt32(boundinfo->datums[offset + 1][0]);
2897 
2898  if (next_modulus % spec->modulus != 0)
2899  ereport(ERROR,
2900  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2901  errmsg("every hash partition modulus must be a factor of the next larger modulus"),
2902  errdetail("The new modulus %d is not factor of %d, the modulus of existing partition \"%s\".",
2903  spec->modulus, next_modulus,
2904  get_rel_name(partdesc->oids[boundinfo->indexes[offset + 1]]))));
2905  }
2906  }
2907 
2908  greatest_modulus = boundinfo->nindexes;
2909  remainder = spec->remainder;
2910 
2911  /*
2912  * Normally, the lowest remainder that could conflict with
2913  * the new partition is equal to the remainder specified
2914  * for the new partition, but when the new partition has a
2915  * modulus higher than any used so far, we need to adjust.
2916  */
2917  if (remainder >= greatest_modulus)
2918  remainder = remainder % greatest_modulus;
2919 
2920  /* Check every potentially-conflicting remainder. */
2921  do
2922  {
2923  if (boundinfo->indexes[remainder] != -1)
2924  {
2925  overlap = true;
2926  overlap_location = spec->location;
2927  with = boundinfo->indexes[remainder];
2928  break;
2929  }
2930  remainder += spec->modulus;
2931  } while (remainder < greatest_modulus);
2932  }
2933 
2934  break;
2935  }
2936 
2938  {
2940 
2941  if (partdesc->nparts > 0)
2942  {
2943  ListCell *cell;
2944 
2945  Assert(boundinfo &&
2946  boundinfo->strategy == PARTITION_STRATEGY_LIST &&
2947  (boundinfo->ndatums > 0 ||
2948  partition_bound_accepts_nulls(boundinfo) ||
2949  partition_bound_has_default(boundinfo)));
2950 
2951  foreach(cell, spec->listdatums)
2952  {
2953  Const *val = castNode(Const, lfirst(cell));
2954 
2955  overlap_location = val->location;
2956  if (!val->constisnull)
2957  {
2958  int offset;
2959  bool equal;
2960 
2961  offset = partition_list_bsearch(&key->partsupfunc[0],
2962  key->partcollation,
2963  boundinfo,
2964  val->constvalue,
2965  &equal);
2966  if (offset >= 0 && equal)
2967  {
2968  overlap = true;
2969  with = boundinfo->indexes[offset];
2970  break;
2971  }
2972  }
2973  else if (partition_bound_accepts_nulls(boundinfo))
2974  {
2975  overlap = true;
2976  with = boundinfo->null_index;
2977  break;
2978  }
2979  }
2980  }
2981 
2982  break;
2983  }
2984 
2986  {
2988  *upper;
2989  int cmpval;
2990 
2992  lower = make_one_partition_rbound(key, -1, spec->lowerdatums, true);
2993  upper = make_one_partition_rbound(key, -1, spec->upperdatums, false);
2994 
2995  /*
2996  * First check if the resulting range would be empty with
2997  * specified lower and upper bounds. partition_rbound_cmp
2998  * cannot return zero here, since the lower-bound flags are
2999  * different.
3000  */
3001  cmpval = partition_rbound_cmp(key->partnatts,
3002  key->partsupfunc,
3003  key->partcollation,
3004  lower->datums, lower->kind,
3005  true, upper);
3006  Assert(cmpval != 0);
3007  if (cmpval > 0)
3008  {
3009  /* Point to problematic key in the lower datums list. */
3010  PartitionRangeDatum *datum = list_nth(spec->lowerdatums,
3011  cmpval - 1);
3012 
3013  ereport(ERROR,
3014  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3015  errmsg("empty range bound specified for partition \"%s\"",
3016  relname),
3017  errdetail("Specified lower bound %s is greater than or equal to upper bound %s.",
3020  parser_errposition(pstate, datum->location)));
3021  }
3022 
3023  if (partdesc->nparts > 0)
3024  {
3025  int offset;
3026 
3027  Assert(boundinfo &&
3028  boundinfo->strategy == PARTITION_STRATEGY_RANGE &&
3029  (boundinfo->ndatums > 0 ||
3030  partition_bound_has_default(boundinfo)));
3031 
3032  /*
3033  * Test whether the new lower bound (which is treated
3034  * inclusively as part of the new partition) lies inside
3035  * an existing partition, or in a gap.
3036  *
3037  * If it's inside an existing partition, the bound at
3038  * offset + 1 will be the upper bound of that partition,
3039  * and its index will be >= 0.
3040  *
3041  * If it's in a gap, the bound at offset + 1 will be the
3042  * lower bound of the next partition, and its index will
3043  * be -1. This is also true if there is no next partition,
3044  * since the index array is initialised with an extra -1
3045  * at the end.
3046  */
3047  offset = partition_range_bsearch(key->partnatts,
3048  key->partsupfunc,
3049  key->partcollation,
3050  boundinfo, lower,
3051  &cmpval);
3052 
3053  if (boundinfo->indexes[offset + 1] < 0)
3054  {
3055  /*
3056  * Check that the new partition will fit in the gap.
3057  * For it to fit, the new upper bound must be less
3058  * than or equal to the lower bound of the next
3059  * partition, if there is one.
3060  */
3061  if (offset + 1 < boundinfo->ndatums)
3062  {
3063  Datum *datums;
3065  bool is_lower;
3066 
3067  datums = boundinfo->datums[offset + 1];
3068  kind = boundinfo->kind[offset + 1];
3069  is_lower = (boundinfo->indexes[offset + 1] == -1);
3070 
3071  cmpval = partition_rbound_cmp(key->partnatts,
3072  key->partsupfunc,
3073  key->partcollation,
3074  datums, kind,
3075  is_lower, upper);
3076  if (cmpval < 0)
3077  {
3078  /*
3079  * Point to problematic key in the upper
3080  * datums list.
3081  */
3082  PartitionRangeDatum *datum =
3083  list_nth(spec->upperdatums, Abs(cmpval) - 1);
3084 
3085  /*
3086  * The new partition overlaps with the
3087  * existing partition between offset + 1 and
3088  * offset + 2.
3089  */
3090  overlap = true;
3091  overlap_location = datum->location;
3092  with = boundinfo->indexes[offset + 2];
3093  }
3094  }
3095  }
3096  else
3097  {
3098  /*
3099  * The new partition overlaps with the existing
3100  * partition between offset and offset + 1.
3101  */
3102  PartitionRangeDatum *datum;
3103 
3104  /*
3105  * Point to problematic key in the lower datums list;
3106  * if we have equality, point to the first one.
3107  */
3108  datum = cmpval == 0 ? linitial(spec->lowerdatums) :
3109  list_nth(spec->lowerdatums, Abs(cmpval) - 1);
3110  overlap = true;
3111  overlap_location = datum->location;
3112  with = boundinfo->indexes[offset + 1];
3113  }
3114  }
3115 
3116  break;
3117  }
3118 
3119  default:
3120  elog(ERROR, "unexpected partition strategy: %d",
3121  (int) key->strategy);
3122  }
3123 
3124  if (overlap)
3125  {
3126  Assert(with >= 0);
3127  ereport(ERROR,
3128  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3129  errmsg("partition \"%s\" would overlap partition \"%s\"",
3130  relname, get_rel_name(partdesc->oids[with])),
3131  parser_errposition(pstate, overlap_location)));
3132  }
3133 }
Datum constvalue
Definition: primnodes.h:214
PartitionRangeDatumKind ** kind
Definition: partbounds.h:70
PartitionRangeDatumKind * kind
Definition: partbounds.c:68
#define DatumGetInt32(X)
Definition: postgres.h:472
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:3073
Datum lower(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:46
FmgrInfo * partsupfunc
Definition: partcache.h:35
#define castNode(_type_, nodeptr)
Definition: nodes.h:602
PartitionRangeDatumKind
Definition: parsenodes.h:837
int errcode(int sqlerrcode)
Definition: elog.c:704
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:29
#define Abs(x)
Definition: c.h:992
static PartitionRangeBound * make_one_partition_rbound(PartitionKey key, int index, List *datums, bool lower)
Definition: partbounds.c:3320
#define linitial(l)
Definition: pg_list.h:174
#define ERROR
Definition: elog.h:45
static void * list_nth(const List *list, int n)
Definition: pg_list.h:278
int errdetail(const char *fmt,...)
Definition: elog.c:1048
PartitionDesc RelationGetPartitionDesc(Relation rel)
Definition: partdesc.c:64
#define partition_bound_has_default(bi)
Definition: partbounds.h:82
int partition_hash_bsearch(PartitionBoundInfo boundinfo, int modulus, int remainder)
Definition: partbounds.c:3630
char * get_range_partbound_string(List *bound_datums)
Definition: ruleutils.c:11640
Oid * partcollation
Definition: partcache.h:38
int location
Definition: primnodes.h:221
uintptr_t Datum
Definition: postgres.h:367
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:801
#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:3499
#define ereport(elevel,...)
Definition: elog.h:155
static int32 partition_rbound_cmp(int partnatts, FmgrInfo *partsupfunc, Oid *partcollation, Datum *datums1, PartitionRangeDatumKind *kind1, bool lower1, PartitionRangeBound *b2)
Definition: partbounds.c:3380
#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:3545
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:111
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:802
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:803
int errmsg(const char *fmt,...)
Definition: elog.c:915
#define elog(elevel,...)
Definition: elog.h:228
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1899
long val
Definition: informix.c:664
bool constisnull
Definition: primnodes.h:215

◆ compute_partition_hash_value()

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

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

4619 {
4620  int i;
4621  uint64 rowHash = 0;
4623 
4624  for (i = 0; i < partnatts; i++)
4625  {
4626  /* Nulls are just ignored */
4627  if (!isnull[i])
4628  {
4629  Datum hash;
4630 
4631  Assert(OidIsValid(partsupfunc[i].fn_oid));
4632 
4633  /*
4634  * Compute hash for each datum value by calling respective
4635  * datatype-specific hash functions of each partition key
4636  * attribute.
4637  */
4638  hash = FunctionCall2Coll(&partsupfunc[i], partcollation[i],
4639  values[i], seed);
4640 
4641  /* Form a single 64-bit hash value */
4642  rowHash = hash_combine64(rowHash, DatumGetUInt64(hash));
4643  }
4644  }
4645 
4646  return rowHash;
4647 }
#define UInt64GetDatum(X)
Definition: postgres.h:648
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1151
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:367
#define DatumGetUInt64(X)
Definition: postgres.h:634
#define Assert(condition)
Definition: c.h:804
#define HASH_PARTITION_SEED
Definition: partition.h:20
static Datum values[MAXATTR]
Definition: bootstrap.c:165
int i
static unsigned hash(unsigned *uv, int n)
Definition: rege_dfa.c:717

◆ get_hash_partition_greatest_modulus()

int get_hash_partition_greatest_modulus ( PartitionBoundInfo  b)

Definition at line 3306 of file partbounds.c.

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

3307 {
3308  Assert(bound && bound->strategy == PARTITION_STRATEGY_HASH);
3309  return bound->nindexes;
3310 }
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:801
#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:3873
PartitionKey RelationGetPartitionKey(Relation rel)
Definition: partcache.c:54
#define ERROR
Definition: elog.h:45
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:801
static List * get_qual_for_range(Relation parent, PartitionBoundSpec *spec, bool for_default)
Definition: partbounds.c:4165
#define Assert(condition)
Definition: c.h:804
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:802
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:803
#define elog(elevel,...)
Definition: elog.h:228
Definition: pg_list.h:50
static List * get_qual_for_list(Relation parent, PartitionBoundSpec *spec)
Definition: partbounds.c:3956

◆ 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:837
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:367
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:801
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:802
void * palloc(Size size)
Definition: mcxt.c:950
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:45
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:801
#define Assert(condition)
Definition: c.h:804
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:802
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:803
static PartitionBoundInfo create_range_bounds(PartitionBoundSpec **boundspecs, int nparts, PartitionKey key, int **mapping)
Definition: partbounds.c:598
void * palloc(Size size)
Definition: mcxt.c:950
#define elog(elevel,...)
Definition: elog.h:228
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:801
#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:45
struct PartitionBoundInfoData * boundinfo
Definition: pathnodes.h:753
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:801
#define Assert(condition)
Definition: c.h:804
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:802
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:803
#define elog(elevel,...)
Definition: elog.h:228

◆ partition_hash_bsearch()

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

Definition at line 3630 of file partbounds.c.

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

Referenced by check_new_partition_bound().

3632 {
3633  int lo,
3634  hi,
3635  mid;
3636 
3637  lo = -1;
3638  hi = boundinfo->ndatums - 1;
3639  while (lo < hi)
3640  {
3641  int32 cmpval,
3642  bound_modulus,
3643  bound_remainder;
3644 
3645  mid = (lo + hi + 1) / 2;
3646  bound_modulus = DatumGetInt32(boundinfo->datums[mid][0]);
3647  bound_remainder = DatumGetInt32(boundinfo->datums[mid][1]);
3648  cmpval = partition_hbound_cmp(bound_modulus, bound_remainder,
3649  modulus, remainder);
3650  if (cmpval <= 0)
3651  {
3652  lo = mid;
3653 
3654  if (cmpval == 0)
3655  break;
3656  }
3657  else
3658  hi = mid - 1;
3659  }
3660 
3661  return lo;
3662 }
#define DatumGetInt32(X)
Definition: postgres.h:472
signed int int32
Definition: c.h:429
static int32 partition_hbound_cmp(int modulus1, int remainder1, int modulus2, int remainder2)
Definition: partbounds.c:3479

◆ partition_list_bsearch()

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

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

3502 {
3503  int lo,
3504  hi,
3505  mid;
3506 
3507  lo = -1;
3508  hi = boundinfo->ndatums - 1;
3509  while (lo < hi)
3510  {
3511  int32 cmpval;
3512 
3513  mid = (lo + hi + 1) / 2;
3514  cmpval = DatumGetInt32(FunctionCall2Coll(&partsupfunc[0],
3515  partcollation[0],
3516  boundinfo->datums[mid][0],
3517  value));
3518  if (cmpval <= 0)
3519  {
3520  lo = mid;
3521  *is_equal = (cmpval == 0);
3522  if (*is_equal)
3523  break;
3524  }
3525  else
3526  hi = mid - 1;
3527  }
3528 
3529  return lo;
3530 }
#define DatumGetInt32(X)
Definition: postgres.h:472
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1151
signed int int32
Definition: c.h:429
static struct @141 value

◆ partition_range_datum_bsearch()

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

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

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

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

3451 {
3452  int i;
3453  int32 cmpval = -1;
3454 
3455  for (i = 0; i < n_tuple_datums; i++)
3456  {
3457  if (rb_kind[i] == PARTITION_RANGE_DATUM_MINVALUE)
3458  return -1;
3459  else if (rb_kind[i] == PARTITION_RANGE_DATUM_MAXVALUE)
3460  return 1;
3461 
3462  cmpval = DatumGetInt32(FunctionCall2Coll(&partsupfunc[i],
3463  partcollation[i],
3464  rb_datums[i],
3465  tuple_datums[i]));
3466  if (cmpval != 0)
3467  break;
3468  }
3469 
3470  return cmpval;
3471 }
#define DatumGetInt32(X)
Definition: postgres.h:472
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1151
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:802
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:803