PostgreSQL Source Code  git master
partbounds.h File Reference
#include "fmgr.h"
#include "nodes/parsenodes.h"
#include "nodes/pg_list.h"
#include "partitioning/partdefs.h"
#include "utils/relcache.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)
 
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 3101 of file partbounds.c.

References AccessExclusiveLock, CHECK_FOR_INTERRUPTS, CreateExecutorState(), DEBUG1, ExprContext::ecxt_scantuple, ereport, errcode(), errmsg(), 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().

3103 {
3104  List *new_part_constraints;
3105  List *def_part_constraints;
3106  List *all_parts;
3107  ListCell *lc;
3108 
3109  new_part_constraints = (new_spec->strategy == PARTITION_STRATEGY_LIST)
3110  ? get_qual_for_list(parent, new_spec)
3111  : get_qual_for_range(parent, new_spec, false);
3112  def_part_constraints =
3113  get_proposed_default_constraint(new_part_constraints);
3114 
3115  /*
3116  * Map the Vars in the constraint expression from parent's attnos to
3117  * default_rel's.
3118  */
3119  def_part_constraints =
3120  map_partition_varattnos(def_part_constraints, 1, default_rel,
3121  parent);
3122 
3123  /*
3124  * If the existing constraints on the default partition imply that it will
3125  * not contain any row that would belong to the new partition, we can
3126  * avoid scanning the default partition.
3127  */
3128  if (PartConstraintImpliedByRelConstraint(default_rel, def_part_constraints))
3129  {
3130  ereport(DEBUG1,
3131  (errmsg("updated partition constraint for default partition \"%s\" is implied by existing constraints",
3132  RelationGetRelationName(default_rel))));
3133  return;
3134  }
3135 
3136  /*
3137  * Scan the default partition and its subpartitions, and check for rows
3138  * that do not satisfy the revised partition constraints.
3139  */
3140  if (default_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
3141  all_parts = find_all_inheritors(RelationGetRelid(default_rel),
3142  AccessExclusiveLock, NULL);
3143  else
3144  all_parts = list_make1_oid(RelationGetRelid(default_rel));
3145 
3146  foreach(lc, all_parts)
3147  {
3148  Oid part_relid = lfirst_oid(lc);
3149  Relation part_rel;
3150  Expr *partition_constraint;
3151  EState *estate;
3152  ExprState *partqualstate = NULL;
3153  Snapshot snapshot;
3154  ExprContext *econtext;
3155  TableScanDesc scan;
3156  MemoryContext oldCxt;
3157  TupleTableSlot *tupslot;
3158 
3159  /* Lock already taken above. */
3160  if (part_relid != RelationGetRelid(default_rel))
3161  {
3162  part_rel = table_open(part_relid, NoLock);
3163 
3164  /*
3165  * Map the Vars in the constraint expression from default_rel's
3166  * the sub-partition's.
3167  */
3168  partition_constraint = make_ands_explicit(def_part_constraints);
3169  partition_constraint = (Expr *)
3170  map_partition_varattnos((List *) partition_constraint, 1,
3171  part_rel, default_rel);
3172 
3173  /*
3174  * If the partition constraints on default partition child imply
3175  * that it will not contain any row that would belong to the new
3176  * partition, we can avoid scanning the child table.
3177  */
3179  def_part_constraints))
3180  {
3181  ereport(DEBUG1,
3182  (errmsg("updated partition constraint for default partition \"%s\" is implied by existing constraints",
3183  RelationGetRelationName(part_rel))));
3184 
3185  table_close(part_rel, NoLock);
3186  continue;
3187  }
3188  }
3189  else
3190  {
3191  part_rel = default_rel;
3192  partition_constraint = make_ands_explicit(def_part_constraints);
3193  }
3194 
3195  /*
3196  * Only RELKIND_RELATION relations (i.e. leaf partitions) need to be
3197  * scanned.
3198  */
3199  if (part_rel->rd_rel->relkind != RELKIND_RELATION)
3200  {
3201  if (part_rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
3202  ereport(WARNING,
3203  (errcode(ERRCODE_CHECK_VIOLATION),
3204  errmsg("skipped scanning foreign table \"%s\" which is a partition of default partition \"%s\"",
3205  RelationGetRelationName(part_rel),
3206  RelationGetRelationName(default_rel))));
3207 
3208  if (RelationGetRelid(default_rel) != RelationGetRelid(part_rel))
3209  table_close(part_rel, NoLock);
3210 
3211  continue;
3212  }
3213 
3214  estate = CreateExecutorState();
3215 
3216  /* Build expression execution states for partition check quals */
3217  partqualstate = ExecPrepareExpr(partition_constraint, estate);
3218 
3219  econtext = GetPerTupleExprContext(estate);
3220  snapshot = RegisterSnapshot(GetLatestSnapshot());
3221  tupslot = table_slot_create(part_rel, &estate->es_tupleTable);
3222  scan = table_beginscan(part_rel, snapshot, 0, NULL);
3223 
3224  /*
3225  * Switch to per-tuple memory context and reset it for each tuple
3226  * produced, so we don't leak memory.
3227  */
3229 
3230  while (table_scan_getnextslot(scan, ForwardScanDirection, tupslot))
3231  {
3232  econtext->ecxt_scantuple = tupslot;
3233 
3234  if (!ExecCheck(partqualstate, econtext))
3235  ereport(ERROR,
3236  (errcode(ERRCODE_CHECK_VIOLATION),
3237  errmsg("updated partition constraint for default partition \"%s\" would be violated by some row",
3238  RelationGetRelationName(default_rel)),
3239  errtable(default_rel)));
3240 
3241  ResetExprContext(econtext);
3243  }
3244 
3245  MemoryContextSwitchTo(oldCxt);
3246  table_endscan(scan);
3247  UnregisterSnapshot(snapshot);
3249  FreeExecutorState(estate);
3250 
3251  if (RelationGetRelid(default_rel) != RelationGetRelid(part_rel))
3252  table_close(part_rel, NoLock); /* keep the lock until commit */
3253  }
3254 }
TupleTableSlot * table_slot_create(Relation relation, List **reglist)
Definition: tableam.c:77
#define DEBUG1
Definition: elog.h:25
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:865
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:610
static bool table_scan_getnextslot(TableScanDesc sscan, ScanDirection direction, TupleTableSlot *slot)
Definition: tableam.h:903
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:191
#define GetPerTupleExprContext(estate)
Definition: executor.h:507
#define ERROR
Definition: elog.h:43
static TableScanDesc table_beginscan(Relation rel, Snapshot snapshot, int nkeys, struct ScanKeyData *key)
Definition: tableam.h:754
#define NoLock
Definition: lockdefs.h:34
List * get_proposed_default_constraint(List *new_part_constraints)
Definition: partition.c:345
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1224
#define RelationGetRelationName(relation)
Definition: rel.h:490
EState * CreateExecutorState(void)
Definition: execUtils.c:89
void UnregisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:907
#define WARNING
Definition: elog.h:40
List * es_tupleTable
Definition: execnodes.h:557
Expr * make_ands_explicit(List *andclauses)
Definition: makefuncs.c:705
#define list_make1_oid(x1)
Definition: pg_list.h:249
#define ereport(elevel,...)
Definition: elog.h:144
static List * get_qual_for_range(Relation parent, PartitionBoundSpec *spec, bool for_default)
Definition: partbounds.c:4159
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:226
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:801
Snapshot GetLatestSnapshot(void)
Definition: snapmgr.c:381
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:512
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:862
#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:824
bool ExecCheck(ExprState *state, ExprContext *econtext)
Definition: execExpr.c:599
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
int errtable(Relation rel)
Definition: relcache.c:5489
List * map_partition_varattnos(List *expr, int fromrel_varno, Relation to_rel, Relation from_rel)
Definition: partition.c:198
#define RelationGetRelid(relation)
Definition: rel.h:456
static List * get_qual_for_list(Relation parent, PartitionBoundSpec *spec)
Definition: partbounds.c:3950
#define ResetExprContext(econtext)
Definition: executor.h:501
#define lfirst_oid(lc)
Definition: pg_list.h:192
bool PartConstraintImpliedByRelConstraint(Relation scanrel, List *partConstraint)
Definition: tablecmds.c:16008

◆ check_new_partition_bound()

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

Definition at line 2809 of file partbounds.c.

References Assert, PartitionDescData::boundinfo, castNode, Const::constisnull, Const::constvalue, DatumGetInt32, PartitionBoundInfoData::datums, PartitionRangeBound::datums, PartitionBoundInfoData::default_index, elog, equal(), ereport, errcode(), errdetail(), errmsg(), ERROR, get_hash_partition_greatest_modulus(), get_range_partbound_string(), get_rel_name(), PartitionBoundInfoData::indexes, PartitionBoundSpec::is_default, sort-test::key, PartitionBoundInfoData::kind, PartitionRangeBound::kind, lfirst, PartitionBoundSpec::listdatums, PartitionBoundSpec::location, lower(), PartitionBoundSpec::lowerdatums, make_one_partition_rbound(), make_parsestate(), PartitionBoundSpec::modulus, PartitionBoundInfoData::ndatums, 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().

2811 {
2813  PartitionDesc partdesc = RelationGetPartitionDesc(parent);
2814  PartitionBoundInfo boundinfo = partdesc->boundinfo;
2815  ParseState *pstate = make_parsestate(NULL);
2816  int with = -1;
2817  bool overlap = false;
2818 
2819  if (spec->is_default)
2820  {
2821  /*
2822  * The default partition bound never conflicts with any other
2823  * partition's; if that's what we're attaching, the only possible
2824  * problem is that one already exists, so check for that and we're
2825  * done.
2826  */
2827  if (boundinfo == NULL || !partition_bound_has_default(boundinfo))
2828  return;
2829 
2830  /* Default partition already exists, error out. */
2831  ereport(ERROR,
2832  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2833  errmsg("partition \"%s\" conflicts with existing default partition \"%s\"",
2834  relname, get_rel_name(partdesc->oids[boundinfo->default_index])),
2835  parser_errposition(pstate, spec->location)));
2836  }
2837 
2838  switch (key->strategy)
2839  {
2841  {
2843  Assert(spec->remainder >= 0 && spec->remainder < spec->modulus);
2844 
2845  if (partdesc->nparts > 0)
2846  {
2847  Datum **datums = boundinfo->datums;
2848  int ndatums = boundinfo->ndatums;
2849  int greatest_modulus;
2850  int remainder;
2851  int offset;
2852  bool valid_modulus = true;
2853  int prev_modulus, /* Previous largest modulus */
2854  next_modulus; /* Next largest modulus */
2855 
2856  /*
2857  * Check rule that every modulus must be a factor of the
2858  * next larger modulus. For example, if you have a bunch
2859  * of partitions that all have modulus 5, you can add a
2860  * new partition with modulus 10 or a new partition with
2861  * modulus 15, but you cannot add both a partition with
2862  * modulus 10 and a partition with modulus 15, because 10
2863  * is not a factor of 15.
2864  *
2865  * Get the greatest (modulus, remainder) pair contained in
2866  * boundinfo->datums that is less than or equal to the
2867  * (spec->modulus, spec->remainder) pair.
2868  */
2869  offset = partition_hash_bsearch(boundinfo,
2870  spec->modulus,
2871  spec->remainder);
2872  if (offset < 0)
2873  {
2874  next_modulus = DatumGetInt32(datums[0][0]);
2875  valid_modulus = (next_modulus % spec->modulus) == 0;
2876  }
2877  else
2878  {
2879  prev_modulus = DatumGetInt32(datums[offset][0]);
2880  valid_modulus = (spec->modulus % prev_modulus) == 0;
2881 
2882  if (valid_modulus && (offset + 1) < ndatums)
2883  {
2884  next_modulus = DatumGetInt32(datums[offset + 1][0]);
2885  valid_modulus = (next_modulus % spec->modulus) == 0;
2886  }
2887  }
2888 
2889  if (!valid_modulus)
2890  ereport(ERROR,
2891  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2892  errmsg("every hash partition modulus must be a factor of the next larger modulus")));
2893 
2894  greatest_modulus = get_hash_partition_greatest_modulus(boundinfo);
2895  remainder = spec->remainder;
2896 
2897  /*
2898  * Normally, the lowest remainder that could conflict with
2899  * the new partition is equal to the remainder specified
2900  * for the new partition, but when the new partition has a
2901  * modulus higher than any used so far, we need to adjust.
2902  */
2903  if (remainder >= greatest_modulus)
2904  remainder = remainder % greatest_modulus;
2905 
2906  /* Check every potentially-conflicting remainder. */
2907  do
2908  {
2909  if (boundinfo->indexes[remainder] != -1)
2910  {
2911  overlap = true;
2912  with = boundinfo->indexes[remainder];
2913  break;
2914  }
2915  remainder += spec->modulus;
2916  } while (remainder < greatest_modulus);
2917  }
2918 
2919  break;
2920  }
2921 
2923  {
2925 
2926  if (partdesc->nparts > 0)
2927  {
2928  ListCell *cell;
2929 
2930  Assert(boundinfo &&
2931  boundinfo->strategy == PARTITION_STRATEGY_LIST &&
2932  (boundinfo->ndatums > 0 ||
2933  partition_bound_accepts_nulls(boundinfo) ||
2934  partition_bound_has_default(boundinfo)));
2935 
2936  foreach(cell, spec->listdatums)
2937  {
2938  Const *val = castNode(Const, lfirst(cell));
2939 
2940  if (!val->constisnull)
2941  {
2942  int offset;
2943  bool equal;
2944 
2945  offset = partition_list_bsearch(&key->partsupfunc[0],
2946  key->partcollation,
2947  boundinfo,
2948  val->constvalue,
2949  &equal);
2950  if (offset >= 0 && equal)
2951  {
2952  overlap = true;
2953  with = boundinfo->indexes[offset];
2954  break;
2955  }
2956  }
2957  else if (partition_bound_accepts_nulls(boundinfo))
2958  {
2959  overlap = true;
2960  with = boundinfo->null_index;
2961  break;
2962  }
2963  }
2964  }
2965 
2966  break;
2967  }
2968 
2970  {
2972  *upper;
2973 
2975  lower = make_one_partition_rbound(key, -1, spec->lowerdatums, true);
2976  upper = make_one_partition_rbound(key, -1, spec->upperdatums, false);
2977 
2978  /*
2979  * First check if the resulting range would be empty with
2980  * specified lower and upper bounds
2981  */
2983  key->partcollation, lower->datums,
2984  lower->kind, true, upper) >= 0)
2985  {
2986  ereport(ERROR,
2987  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2988  errmsg("empty range bound specified for partition \"%s\"",
2989  relname),
2990  errdetail("Specified lower bound %s is greater than or equal to upper bound %s.",
2993  parser_errposition(pstate, spec->location)));
2994  }
2995 
2996  if (partdesc->nparts > 0)
2997  {
2998  int offset;
2999  bool equal;
3000 
3001  Assert(boundinfo &&
3002  boundinfo->strategy == PARTITION_STRATEGY_RANGE &&
3003  (boundinfo->ndatums > 0 ||
3004  partition_bound_has_default(boundinfo)));
3005 
3006  /*
3007  * Test whether the new lower bound (which is treated
3008  * inclusively as part of the new partition) lies inside
3009  * an existing partition, or in a gap.
3010  *
3011  * If it's inside an existing partition, the bound at
3012  * offset + 1 will be the upper bound of that partition,
3013  * and its index will be >= 0.
3014  *
3015  * If it's in a gap, the bound at offset + 1 will be the
3016  * lower bound of the next partition, and its index will
3017  * be -1. This is also true if there is no next partition,
3018  * since the index array is initialised with an extra -1
3019  * at the end.
3020  */
3021  offset = partition_range_bsearch(key->partnatts,
3022  key->partsupfunc,
3023  key->partcollation,
3024  boundinfo, lower,
3025  &equal);
3026 
3027  if (boundinfo->indexes[offset + 1] < 0)
3028  {
3029  /*
3030  * Check that the new partition will fit in the gap.
3031  * For it to fit, the new upper bound must be less
3032  * than or equal to the lower bound of the next
3033  * partition, if there is one.
3034  */
3035  if (offset + 1 < boundinfo->ndatums)
3036  {
3037  int32 cmpval;
3038  Datum *datums;
3040  bool is_lower;
3041 
3042  datums = boundinfo->datums[offset + 1];
3043  kind = boundinfo->kind[offset + 1];
3044  is_lower = (boundinfo->indexes[offset + 1] == -1);
3045 
3046  cmpval = partition_rbound_cmp(key->partnatts,
3047  key->partsupfunc,
3048  key->partcollation,
3049  datums, kind,
3050  is_lower, upper);
3051  if (cmpval < 0)
3052  {
3053  /*
3054  * The new partition overlaps with the
3055  * existing partition between offset + 1 and
3056  * offset + 2.
3057  */
3058  overlap = true;
3059  with = boundinfo->indexes[offset + 2];
3060  }
3061  }
3062  }
3063  else
3064  {
3065  /*
3066  * The new partition overlaps with the existing
3067  * partition between offset and offset + 1.
3068  */
3069  overlap = true;
3070  with = boundinfo->indexes[offset + 1];
3071  }
3072  }
3073 
3074  break;
3075  }
3076 
3077  default:
3078  elog(ERROR, "unexpected partition strategy: %d",
3079  (int) key->strategy);
3080  }
3081 
3082  if (overlap)
3083  {
3084  Assert(with >= 0);
3085  ereport(ERROR,
3086  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3087  errmsg("partition \"%s\" would overlap partition \"%s\"",
3088  relname, get_rel_name(partdesc->oids[with])),
3089  parser_errposition(pstate, spec->location)));
3090  }
3091 }
Datum constvalue
Definition: primnodes.h:214
PartitionRangeDatumKind ** kind
Definition: partbounds.h:65
static int partition_range_bsearch(int partnatts, FmgrInfo *partsupfunc, Oid *partcollation, PartitionBoundInfo boundinfo, PartitionRangeBound *probe, bool *is_equal)
Definition: partbounds.c:3495
PartitionRangeDatumKind * kind
Definition: partbounds.c:68
#define DatumGetInt32(X)
Definition: postgres.h:472
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:3033
Datum lower(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:43
FmgrInfo * partsupfunc
Definition: partcache.h:35
#define castNode(_type_, nodeptr)
Definition: nodes.h:598
PartitionRangeDatumKind
Definition: parsenodes.h:836
int errcode(int sqlerrcode)
Definition: elog.c:610
Datum upper(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:74
PartitionKey RelationGetPartitionKey(Relation rel)
Definition: partcache.c:54
NameData relname
Definition: pg_class.h:38
signed int int32
Definition: c.h:355
PartitionBoundInfo boundinfo
Definition: partdesc.h:29
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:43
static PartitionRangeBound * make_one_partition_rbound(PartitionKey key, int index, List *datums, bool lower)
Definition: partbounds.c:3281
#define ERROR
Definition: elog.h:43
int get_hash_partition_greatest_modulus(PartitionBoundInfo bound)
Definition: partbounds.c:3264
int errdetail(const char *fmt,...)
Definition: elog.c:957
PartitionDesc RelationGetPartitionDesc(Relation rel)
Definition: partdesc.c:65
#define partition_bound_has_default(bi)
Definition: partbounds.h:76
int partition_hash_bsearch(PartitionBoundInfo boundinfo, int modulus, int remainder)
Definition: partbounds.c:3584
char * get_range_partbound_string(List *bound_datums)
Definition: ruleutils.c:11387
Oid * partcollation
Definition: partcache.h:38
uintptr_t Datum
Definition: postgres.h:367
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:800
#define partition_bound_accepts_nulls(bi)
Definition: partbounds.h:75
int partition_list_bsearch(FmgrInfo *partsupfunc, Oid *partcollation, PartitionBoundInfo boundinfo, Datum value, bool *is_equal)
Definition: partbounds.c:3452
#define ereport(elevel,...)
Definition: elog.h:144
static int32 partition_rbound_cmp(int partnatts, FmgrInfo *partsupfunc, Oid *partcollation, Datum *datums1, PartitionRangeDatumKind *kind1, bool lower1, PartitionRangeBound *b2)
Definition: partbounds.c:3337
#define Assert(condition)
Definition: c.h:738
#define lfirst(lc)
Definition: pg_list.h:190
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:110
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:801
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:802
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1791
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 4615 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().

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

◆ get_hash_partition_greatest_modulus()

int get_hash_partition_greatest_modulus ( PartitionBoundInfo  b)

Definition at line 3264 of file partbounds.c.

References Assert, DatumGetInt32, PartitionBoundInfoData::datums, PartitionBoundInfoData::ndatums, PARTITION_STRATEGY_HASH, and PartitionBoundInfoData::strategy.

Referenced by check_new_partition_bound(), get_matching_hash_bounds(), get_partition_bound_num_indexes(), get_partition_for_tuple(), and partition_bounds_equal().

3265 {
3266  Assert(bound && bound->strategy == PARTITION_STRATEGY_HASH);
3267  Assert(bound->datums && bound->ndatums > 0);
3268  Assert(DatumGetInt32(bound->datums[bound->ndatums - 1][0]) > 0);
3269 
3270  return DatumGetInt32(bound->datums[bound->ndatums - 1][0]);
3271 }
#define DatumGetInt32(X)
Definition: postgres.h:472
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:800
#define Assert(condition)
Definition: c.h:738

◆ get_qual_from_partbound()

List* get_qual_from_partbound ( Relation  rel,
Relation  parent,
PartitionBoundSpec spec 
)

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

252 {
254  List *my_qual = NIL;
255 
256  Assert(key != NULL);
257 
258  switch (key->strategy)
259  {
262  my_qual = get_qual_for_hash(parent, spec);
263  break;
264 
267  my_qual = get_qual_for_list(parent, spec);
268  break;
269 
272  my_qual = get_qual_for_range(parent, spec, false);
273  break;
274 
275  default:
276  elog(ERROR, "unexpected partition strategy: %d",
277  (int) key->strategy);
278  }
279 
280  return my_qual;
281 }
#define NIL
Definition: pg_list.h:65
static List * get_qual_for_hash(Relation parent, PartitionBoundSpec *spec)
Definition: partbounds.c:3867
PartitionKey RelationGetPartitionKey(Relation rel)
Definition: partcache.c:54
#define ERROR
Definition: elog.h:43
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:800
static List * get_qual_for_range(Relation parent, PartitionBoundSpec *spec, bool for_default)
Definition: partbounds.c:4159
#define Assert(condition)
Definition: c.h:738
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:801
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:802
#define elog(elevel,...)
Definition: elog.h:214
Definition: pg_list.h:50
static List * get_qual_for_list(Relation parent, PartitionBoundSpec *spec)
Definition: partbounds.c:3950

◆ partition_bounds_copy()

PartitionBoundInfo partition_bounds_copy ( PartitionBoundInfo  src,
PartitionKey  key 
)

Definition at line 917 of file partbounds.c.

References Assert, datumCopy(), PartitionBoundInfoData::datums, PartitionBoundInfoData::default_index, generate_unaccent_rules::dest, get_partition_bound_num_indexes(), i, PartitionBoundInfoData::indexes, PartitionBoundInfoData::kind, PartitionBoundInfoData::ndatums, 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().

919 {
921  int i;
922  int ndatums;
923  int partnatts;
924  int num_indexes;
925  bool hash_part;
926  int natts;
927 
929 
930  dest->strategy = src->strategy;
931  ndatums = dest->ndatums = src->ndatums;
932  partnatts = key->partnatts;
933 
934  num_indexes = get_partition_bound_num_indexes(src);
935 
936  /* List partitioned tables have only a single partition key. */
937  Assert(key->strategy != PARTITION_STRATEGY_LIST || partnatts == 1);
938 
939  dest->datums = (Datum **) palloc(sizeof(Datum *) * ndatums);
940 
941  if (src->kind != NULL)
942  {
943  dest->kind = (PartitionRangeDatumKind **) palloc(ndatums *
944  sizeof(PartitionRangeDatumKind *));
945  for (i = 0; i < ndatums; i++)
946  {
947  dest->kind[i] = (PartitionRangeDatumKind *) palloc(partnatts *
948  sizeof(PartitionRangeDatumKind));
949 
950  memcpy(dest->kind[i], src->kind[i],
951  sizeof(PartitionRangeDatumKind) * key->partnatts);
952  }
953  }
954  else
955  dest->kind = NULL;
956 
957  /*
958  * For hash partitioning, datums array will have two elements - modulus
959  * and remainder.
960  */
961  hash_part = (key->strategy == PARTITION_STRATEGY_HASH);
962  natts = hash_part ? 2 : partnatts;
963 
964  for (i = 0; i < ndatums; i++)
965  {
966  int j;
967 
968  dest->datums[i] = (Datum *) palloc(sizeof(Datum) * natts);
969 
970  for (j = 0; j < natts; j++)
971  {
972  bool byval;
973  int typlen;
974 
975  if (hash_part)
976  {
977  typlen = sizeof(int32); /* Always int4 */
978  byval = true; /* int4 is pass-by-value */
979  }
980  else
981  {
982  byval = key->parttypbyval[j];
983  typlen = key->parttyplen[j];
984  }
985 
986  if (dest->kind == NULL ||
987  dest->kind[i][j] == PARTITION_RANGE_DATUM_VALUE)
988  dest->datums[i][j] = datumCopy(src->datums[i][j],
989  byval, typlen);
990  }
991  }
992 
993  dest->indexes = (int *) palloc(sizeof(int) * num_indexes);
994  memcpy(dest->indexes, src->indexes, sizeof(int) * num_indexes);
995 
996  dest->null_index = src->null_index;
997  dest->default_index = src->default_index;
998 
999  return dest;
1000 }
PartitionRangeDatumKind ** kind
Definition: partbounds.h:65
PartitionRangeDatumKind
Definition: parsenodes.h:836
signed int int32
Definition: c.h:355
static int get_partition_bound_num_indexes(PartitionBoundInfo b)
Definition: partbounds.c:3673
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:800
bool * parttypbyval
Definition: partcache.h:44
#define Assert(condition)
Definition: c.h:738
int16 * parttyplen
Definition: partcache.h:43
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:801
void * palloc(Size size)
Definition: mcxt.c:949
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 305 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().

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

◆ partition_bounds_equal()

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

Definition at line 799 of file partbounds.c.

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

Referenced by compute_partition_bounds().

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

1022 {
1023  PartitionBoundInfo outer_binfo = outer_rel->boundinfo;
1024 
1025  /*
1026  * Currently, this function is called only from try_partitionwise_join(),
1027  * so the join type should be INNER, LEFT, FULL, SEMI, or ANTI.
1028  */
1029  Assert(jointype == JOIN_INNER || jointype == JOIN_LEFT ||
1030  jointype == JOIN_FULL || jointype == JOIN_SEMI ||
1031  jointype == JOIN_ANTI);
1032 
1033  /* The partitioning strategies should be the same. */
1034  Assert(outer_binfo->strategy == inner_rel->boundinfo->strategy);
1035 
1036  *outer_parts = *inner_parts = NIL;
1037  switch (outer_binfo->strategy)
1038  {
1040 
1041  /*
1042  * For hash partitioned tables, we currently support partitioned
1043  * join only when they have exactly the same partition bounds.
1044  *
1045  * XXX: it might be possible to relax the restriction to support
1046  * cases where hash partitioned tables have missing partitions
1047  * and/or different moduli, but it's not clear if it would be
1048  * useful to support the former case since it's unusual to have
1049  * missing partitions. On the other hand, it would be useful to
1050  * support the latter case, but in that case, there is a high
1051  * probability that a partition on one side will match multiple
1052  * partitions on the other side, which is the scenario the current
1053  * implementation of partitioned join can't handle.
1054  */
1055  return NULL;
1056 
1058  return merge_list_bounds(partsupfunc,
1059  partcollation,
1060  outer_rel,
1061  inner_rel,
1062  jointype,
1063  outer_parts,
1064  inner_parts);
1065 
1067  return merge_range_bounds(partnatts,
1068  partsupfunc,
1069  partcollation,
1070  outer_rel,
1071  inner_rel,
1072  jointype,
1073  outer_parts,
1074  inner_parts);
1075 
1076  default:
1077  elog(ERROR, "unexpected partition strategy: %d",
1078  (int) outer_binfo->strategy);
1079  return NULL; /* keep compiler quiet */
1080  }
1081 }
#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:1102
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:1410
#define ERROR
Definition: elog.h:43
struct PartitionBoundInfoData * boundinfo
Definition: pathnodes.h:746
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:800
#define Assert(condition)
Definition: c.h:738
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:801
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:802
#define elog(elevel,...)
Definition: elog.h:214

◆ partition_hash_bsearch()

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

Definition at line 3584 of file partbounds.c.

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

Referenced by check_new_partition_bound().

3586 {
3587  int lo,
3588  hi,
3589  mid;
3590 
3591  lo = -1;
3592  hi = boundinfo->ndatums - 1;
3593  while (lo < hi)
3594  {
3595  int32 cmpval,
3596  bound_modulus,
3597  bound_remainder;
3598 
3599  mid = (lo + hi + 1) / 2;
3600  bound_modulus = DatumGetInt32(boundinfo->datums[mid][0]);
3601  bound_remainder = DatumGetInt32(boundinfo->datums[mid][1]);
3602  cmpval = partition_hbound_cmp(bound_modulus, bound_remainder,
3603  modulus, remainder);
3604  if (cmpval <= 0)
3605  {
3606  lo = mid;
3607 
3608  if (cmpval == 0)
3609  break;
3610  }
3611  else
3612  hi = mid - 1;
3613  }
3614 
3615  return lo;
3616 }
#define DatumGetInt32(X)
Definition: postgres.h:472
signed int int32
Definition: c.h:355
static int32 partition_hbound_cmp(int modulus1, int remainder1, int modulus2, int remainder2)
Definition: partbounds.c:3432

◆ partition_list_bsearch()

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

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

3455 {
3456  int lo,
3457  hi,
3458  mid;
3459 
3460  lo = -1;
3461  hi = boundinfo->ndatums - 1;
3462  while (lo < hi)
3463  {
3464  int32 cmpval;
3465 
3466  mid = (lo + hi + 1) / 2;
3467  cmpval = DatumGetInt32(FunctionCall2Coll(&partsupfunc[0],
3468  partcollation[0],
3469  boundinfo->datums[mid][0],
3470  value));
3471  if (cmpval <= 0)
3472  {
3473  lo = mid;
3474  *is_equal = (cmpval == 0);
3475  if (*is_equal)
3476  break;
3477  }
3478  else
3479  hi = mid - 1;
3480  }
3481 
3482  return lo;
3483 }
#define DatumGetInt32(X)
Definition: postgres.h:472
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1152
signed int int32
Definition: c.h:355
static struct @143 value

◆ partition_range_datum_bsearch()

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

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

3544 {
3545  int lo,
3546  hi,
3547  mid;
3548 
3549  lo = -1;
3550  hi = boundinfo->ndatums - 1;
3551  while (lo < hi)
3552  {
3553  int32 cmpval;
3554 
3555  mid = (lo + hi + 1) / 2;
3556  cmpval = partition_rbound_datum_cmp(partsupfunc,
3557  partcollation,
3558  boundinfo->datums[mid],
3559  boundinfo->kind[mid],
3560  values,
3561  nvalues);
3562  if (cmpval <= 0)
3563  {
3564  lo = mid;
3565  *is_equal = (cmpval == 0);
3566 
3567  if (*is_equal)
3568  break;
3569  }
3570  else
3571  hi = mid - 1;
3572  }
3573 
3574  return lo;
3575 }
PartitionRangeDatumKind ** kind
Definition: partbounds.h:65
signed int int32
Definition: c.h:355
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:3401
static Datum values[MAXATTR]
Definition: bootstrap.c:167

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

3404 {
3405  int i;
3406  int32 cmpval = -1;
3407 
3408  for (i = 0; i < n_tuple_datums; i++)
3409  {
3410  if (rb_kind[i] == PARTITION_RANGE_DATUM_MINVALUE)
3411  return -1;
3412  else if (rb_kind[i] == PARTITION_RANGE_DATUM_MAXVALUE)
3413  return 1;
3414 
3415  cmpval = DatumGetInt32(FunctionCall2Coll(&partsupfunc[i],
3416  partcollation[i],
3417  rb_datums[i],
3418  tuple_datums[i]));
3419  if (cmpval != 0)
3420  break;
3421  }
3422 
3423  return cmpval;
3424 }
#define DatumGetInt32(X)
Definition: postgres.h:472
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1152
signed int int32
Definition: c.h:355
int i

◆ partitions_are_ordered()

bool partitions_are_ordered ( PartitionBoundInfo  boundinfo,
int  nparts 
)

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

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