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 RelOptInfo RelOptInfo
 
typedef struct PartitionBoundInfoData PartitionBoundInfoData
 

Functions

int get_hash_partition_greatest_modulus (PartitionBoundInfo bound)
 
uint64 compute_partition_hash_value (int partnatts, FmgrInfo *partsupfunc, const Oid *partcollation, const Datum *values, const bool *isnull)
 
Listget_qual_from_partbound (Relation parent, PartitionBoundSpec *spec)
 
PartitionBoundInfo partition_bounds_create (PartitionBoundSpec **boundspecs, int nparts, PartitionKey key, int **mapping)
 
bool partition_bounds_equal (int partnatts, int16 *parttyplen, bool *parttypbyval, PartitionBoundInfo b1, PartitionBoundInfo b2)
 
PartitionBoundInfo partition_bounds_copy (PartitionBoundInfo src, PartitionKey key)
 
PartitionBoundInfo partition_bounds_merge (int partnatts, FmgrInfo *partsupfunc, Oid *partcollation, RelOptInfo *outer_rel, RelOptInfo *inner_rel, JoinType jointype, List **outer_parts, List **inner_parts)
 
bool partitions_are_ordered (PartitionBoundInfo boundinfo, Bitmapset *live_parts)
 
void check_new_partition_bound (char *relname, Relation parent, PartitionBoundSpec *spec, ParseState *pstate)
 
void check_default_partition_contents (Relation parent, Relation default_rel, PartitionBoundSpec *new_spec)
 
int32 partition_rbound_datum_cmp (FmgrInfo *partsupfunc, Oid *partcollation, const Datum *rb_datums, PartitionRangeDatumKind *rb_kind, const 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, const Datum *values, bool *is_equal)
 
int partition_hash_bsearch (PartitionBoundInfo boundinfo, int modulus, int remainder)
 

Macro Definition Documentation

◆ partition_bound_accepts_nulls

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

Definition at line 98 of file partbounds.h.

◆ partition_bound_has_default

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

Definition at line 99 of file partbounds.h.

Typedef Documentation

◆ PartitionBoundInfoData

◆ RelOptInfo

typedef struct RelOptInfo RelOptInfo

Definition at line 18 of file partbounds.h.

Function Documentation

◆ check_default_partition_contents()

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

Definition at line 3243 of file partbounds.c.

3245{
3246 List *new_part_constraints;
3247 List *def_part_constraints;
3248 List *all_parts;
3249 ListCell *lc;
3250
3251 new_part_constraints = (new_spec->strategy == PARTITION_STRATEGY_LIST)
3252 ? get_qual_for_list(parent, new_spec)
3253 : get_qual_for_range(parent, new_spec, false);
3254 def_part_constraints =
3255 get_proposed_default_constraint(new_part_constraints);
3256
3257 /*
3258 * Map the Vars in the constraint expression from parent's attnos to
3259 * default_rel's.
3260 */
3261 def_part_constraints =
3262 map_partition_varattnos(def_part_constraints, 1, default_rel,
3263 parent);
3264
3265 /*
3266 * If the existing constraints on the default partition imply that it will
3267 * not contain any row that would belong to the new partition, we can
3268 * avoid scanning the default partition.
3269 */
3270 if (PartConstraintImpliedByRelConstraint(default_rel, def_part_constraints))
3271 {
3273 (errmsg_internal("updated partition constraint for default partition \"%s\" is implied by existing constraints",
3274 RelationGetRelationName(default_rel))));
3275 return;
3276 }
3277
3278 /*
3279 * Scan the default partition and its subpartitions, and check for rows
3280 * that do not satisfy the revised partition constraints.
3281 */
3282 if (default_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
3283 all_parts = find_all_inheritors(RelationGetRelid(default_rel),
3284 AccessExclusiveLock, NULL);
3285 else
3286 all_parts = list_make1_oid(RelationGetRelid(default_rel));
3287
3288 foreach(lc, all_parts)
3289 {
3290 Oid part_relid = lfirst_oid(lc);
3291 Relation part_rel;
3292 Expr *partition_constraint;
3293 EState *estate;
3294 ExprState *partqualstate = NULL;
3295 Snapshot snapshot;
3296 ExprContext *econtext;
3297 TableScanDesc scan;
3298 MemoryContext oldCxt;
3299 TupleTableSlot *tupslot;
3300
3301 /* Lock already taken above. */
3302 if (part_relid != RelationGetRelid(default_rel))
3303 {
3304 part_rel = table_open(part_relid, NoLock);
3305
3306 /*
3307 * Map the Vars in the constraint expression from default_rel's
3308 * the sub-partition's.
3309 */
3310 partition_constraint = make_ands_explicit(def_part_constraints);
3311 partition_constraint = (Expr *)
3312 map_partition_varattnos((List *) partition_constraint, 1,
3313 part_rel, default_rel);
3314
3315 /*
3316 * If the partition constraints on default partition child imply
3317 * that it will not contain any row that would belong to the new
3318 * partition, we can avoid scanning the child table.
3319 */
3321 def_part_constraints))
3322 {
3324 (errmsg_internal("updated partition constraint for default partition \"%s\" is implied by existing constraints",
3325 RelationGetRelationName(part_rel))));
3326
3327 table_close(part_rel, NoLock);
3328 continue;
3329 }
3330 }
3331 else
3332 {
3333 part_rel = default_rel;
3334 partition_constraint = make_ands_explicit(def_part_constraints);
3335 }
3336
3337 /*
3338 * Only RELKIND_RELATION relations (i.e. leaf partitions) need to be
3339 * scanned.
3340 */
3341 if (part_rel->rd_rel->relkind != RELKIND_RELATION)
3342 {
3343 if (part_rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
3345 (errcode(ERRCODE_CHECK_VIOLATION),
3346 errmsg("skipped scanning foreign table \"%s\" which is a partition of default partition \"%s\"",
3347 RelationGetRelationName(part_rel),
3348 RelationGetRelationName(default_rel))));
3349
3350 if (RelationGetRelid(default_rel) != RelationGetRelid(part_rel))
3351 table_close(part_rel, NoLock);
3352
3353 continue;
3354 }
3355
3356 estate = CreateExecutorState();
3357
3358 /* Build expression execution states for partition check quals */
3359 partqualstate = ExecPrepareExpr(partition_constraint, estate);
3360
3361 econtext = GetPerTupleExprContext(estate);
3362 snapshot = RegisterSnapshot(GetLatestSnapshot());
3363 tupslot = table_slot_create(part_rel, &estate->es_tupleTable);
3364 scan = table_beginscan(part_rel, snapshot, 0, NULL);
3365
3366 /*
3367 * Switch to per-tuple memory context and reset it for each tuple
3368 * produced, so we don't leak memory.
3369 */
3371
3372 while (table_scan_getnextslot(scan, ForwardScanDirection, tupslot))
3373 {
3374 econtext->ecxt_scantuple = tupslot;
3375
3376 if (!ExecCheck(partqualstate, econtext))
3377 ereport(ERROR,
3378 (errcode(ERRCODE_CHECK_VIOLATION),
3379 errmsg("updated partition constraint for default partition \"%s\" would be violated by some row",
3380 RelationGetRelationName(default_rel)),
3381 errtable(default_rel)));
3382
3383 ResetExprContext(econtext);
3385 }
3386
3387 MemoryContextSwitchTo(oldCxt);
3388 table_endscan(scan);
3389 UnregisterSnapshot(snapshot);
3391 FreeExecutorState(estate);
3392
3393 if (RelationGetRelid(default_rel) != RelationGetRelid(part_rel))
3394 table_close(part_rel, NoLock); /* keep the lock until commit */
3395 }
3396}
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1170
int errcode(int sqlerrcode)
Definition: elog.c:863
int errmsg(const char *fmt,...)
Definition: elog.c:1080
#define WARNING
Definition: elog.h:36
#define DEBUG1
Definition: elog.h:30
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:150
ExprState * ExecPrepareExpr(Expr *node, EState *estate)
Definition: execExpr.c:765
bool ExecCheck(ExprState *state, ExprContext *econtext)
Definition: execExpr.c:872
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1443
void FreeExecutorState(EState *estate)
Definition: execUtils.c:192
EState * CreateExecutorState(void)
Definition: execUtils.c:88
#define GetPerTupleExprContext(estate)
Definition: executor.h:656
#define ResetExprContext(econtext)
Definition: executor.h:650
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:661
#define NoLock
Definition: lockdefs.h:34
#define AccessExclusiveLock
Definition: lockdefs.h:43
Expr * make_ands_explicit(List *andclauses)
Definition: makefuncs.c:799
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:123
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
@ PARTITION_STRATEGY_LIST
Definition: parsenodes.h:900
static List * get_qual_for_list(Relation parent, PartitionBoundSpec *spec)
Definition: partbounds.c:4057
static List * get_qual_for_range(Relation parent, PartitionBoundSpec *spec, bool for_default)
Definition: partbounds.c:4266
List * map_partition_varattnos(List *expr, int fromrel_varno, Relation to_rel, Relation from_rel)
Definition: partition.c:222
List * get_proposed_default_constraint(List *new_part_constraints)
Definition: partition.c:370
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:255
#define list_make1_oid(x1)
Definition: pg_list.h:242
#define lfirst_oid(lc)
Definition: pg_list.h:174
unsigned int Oid
Definition: postgres_ext.h:32
#define RelationGetRelid(relation)
Definition: rel.h:515
#define RelationGetRelationName(relation)
Definition: rel.h:549
int errtable(Relation rel)
Definition: relcache.c:6049
@ ForwardScanDirection
Definition: sdir.h:28
Snapshot GetLatestSnapshot(void)
Definition: snapmgr.c:354
void UnregisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:866
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:824
List * es_tupleTable
Definition: execnodes.h:712
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:273
Definition: pg_list.h:54
Form_pg_class rd_rel
Definition: rel.h:111
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
TupleTableSlot * table_slot_create(Relation relation, List **reglist)
Definition: tableam.c:92
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:985
static bool table_scan_getnextslot(TableScanDesc sscan, ScanDirection direction, TupleTableSlot *slot)
Definition: tableam.h:1020
static TableScanDesc table_beginscan(Relation rel, Snapshot snapshot, int nkeys, ScanKeyData *key)
Definition: tableam.h:876
bool PartConstraintImpliedByRelConstraint(Relation scanrel, List *partConstraint)
Definition: tablecmds.c:20049

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

Referenced by DefineRelation().

◆ check_new_partition_bound()

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

Definition at line 2888 of file partbounds.c.

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

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

Referenced by ATExecAttachPartition(), and DefineRelation().

◆ compute_partition_hash_value()

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

Definition at line 4713 of file partbounds.c.

4715{
4716 int i;
4717 uint64 rowHash = 0;
4719
4720 for (i = 0; i < partnatts; i++)
4721 {
4722 /* Nulls are just ignored */
4723 if (!isnull[i])
4724 {
4725 Datum hash;
4726
4727 Assert(OidIsValid(partsupfunc[i].fn_oid));
4728
4729 /*
4730 * Compute hash for each datum value by calling respective
4731 * datatype-specific hash functions of each partition key
4732 * attribute.
4733 */
4734 hash = FunctionCall2Coll(&partsupfunc[i], partcollation[i],
4735 values[i], seed);
4736
4737 /* Form a single 64-bit hash value */
4738 rowHash = hash_combine64(rowHash, DatumGetUInt64(hash));
4739 }
4740 }
4741
4742 return rowHash;
4743}
static Datum values[MAXATTR]
Definition: bootstrap.c:153
uint64_t uint64
Definition: c.h:553
#define OidIsValid(objectId)
Definition: c.h:788
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1150
static uint64 hash_combine64(uint64 a, uint64 b)
Definition: hashfn.h:80
int i
Definition: isn.c:77
#define HASH_PARTITION_SEED
Definition: partition.h:20
static uint64 DatumGetUInt64(Datum X)
Definition: postgres.h:413
static Datum UInt64GetDatum(uint64 X)
Definition: postgres.h:423
static unsigned hash(unsigned *uv, int n)
Definition: rege_dfa.c:715

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

Referenced by get_matching_hash_bounds(), and get_partition_for_tuple().

◆ get_hash_partition_greatest_modulus()

int get_hash_partition_greatest_modulus ( PartitionBoundInfo  bound)

Definition at line 3406 of file partbounds.c.

3407{
3408 Assert(bound && bound->strategy == PARTITION_STRATEGY_HASH);
3409 return bound->nindexes;
3410}

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

◆ get_qual_from_partbound()

List * get_qual_from_partbound ( Relation  parent,
PartitionBoundSpec spec 
)

Definition at line 249 of file partbounds.c.

250{
252 List *my_qual = NIL;
253
254 Assert(key != NULL);
255
256 switch (key->strategy)
257 {
260 my_qual = get_qual_for_hash(parent, spec);
261 break;
262
265 my_qual = get_qual_for_list(parent, spec);
266 break;
267
270 my_qual = get_qual_for_range(parent, spec, false);
271 break;
272 }
273
274 return my_qual;
275}
static List * get_qual_for_hash(Relation parent, PartitionBoundSpec *spec)
Definition: partbounds.c:3974
#define NIL
Definition: pg_list.h:68

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

Referenced by ATExecAttachPartition(), and generate_partition_qual().

◆ partition_bounds_copy()

PartitionBoundInfo partition_bounds_copy ( PartitionBoundInfo  src,
PartitionKey  key 
)

Definition at line 994 of file partbounds.c.

996{
998 int i;
999 int ndatums;
1000 int nindexes;
1001 int partnatts;
1002
1004
1005 dest->strategy = src->strategy;
1006 ndatums = dest->ndatums = src->ndatums;
1007 nindexes = dest->nindexes = src->nindexes;
1008 partnatts = key->partnatts;
1009
1010 /* List partitioned tables have only a single partition key. */
1011 Assert(key->strategy != PARTITION_STRATEGY_LIST || partnatts == 1);
1012
1013 dest->datums = palloc_array(Datum *, ndatums);
1014
1015 if (src->kind != NULL && ndatums > 0)
1016 {
1017 PartitionRangeDatumKind *boundKinds;
1018
1019 /* only RANGE partition should have a non-NULL kind */
1020 Assert(key->strategy == PARTITION_STRATEGY_RANGE);
1021
1022 dest->kind = (PartitionRangeDatumKind **) palloc(ndatums *
1023 sizeof(PartitionRangeDatumKind *));
1024
1025 /*
1026 * In the loop below, to save from allocating a series of small arrays
1027 * for storing the PartitionRangeDatumKind, we allocate a single chunk
1028 * here and use a smaller portion of it for each datum.
1029 */
1030 boundKinds = (PartitionRangeDatumKind *) palloc(ndatums * partnatts *
1031 sizeof(PartitionRangeDatumKind));
1032
1033 for (i = 0; i < ndatums; i++)
1034 {
1035 dest->kind[i] = &boundKinds[i * partnatts];
1036 memcpy(dest->kind[i], src->kind[i],
1037 sizeof(PartitionRangeDatumKind) * partnatts);
1038 }
1039 }
1040 else
1041 dest->kind = NULL;
1042
1043 /* copy interleaved partitions for LIST partitioned tables */
1044 dest->interleaved_parts = bms_copy(src->interleaved_parts);
1045
1046 /*
1047 * For hash partitioning, datums array will have two elements - modulus
1048 * and remainder.
1049 */
1050 if (ndatums > 0)
1051 {
1052 bool hash_part = (key->strategy == PARTITION_STRATEGY_HASH);
1053 int natts = hash_part ? 2 : partnatts;
1054 Datum *boundDatums = palloc(ndatums * natts * sizeof(Datum));
1055
1056 for (i = 0; i < ndatums; i++)
1057 {
1058 int j;
1059
1060 dest->datums[i] = &boundDatums[i * natts];
1061
1062 for (j = 0; j < natts; j++)
1063 {
1064 if (dest->kind == NULL ||
1066 {
1067 bool byval;
1068 int typlen;
1069
1070 if (hash_part)
1071 {
1072 typlen = sizeof(int32); /* Always int4 */
1073 byval = true; /* int4 is pass-by-value */
1074 }
1075 else
1076 {
1077 byval = key->parttypbyval[j];
1078 typlen = key->parttyplen[j];
1079 }
1080 dest->datums[i][j] = datumCopy(src->datums[i][j],
1081 byval, typlen);
1082 }
1083 }
1084 }
1085 }
1086
1087 dest->indexes = palloc_array(int, nindexes);
1088 memcpy(dest->indexes, src->indexes, sizeof(int) * nindexes);
1089
1090 dest->null_index = src->null_index;
1091 dest->default_index = src->default_index;
1092
1093 return dest;
1094}
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:122
int32_t int32
Definition: c.h:548
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:132
#define palloc_object(type)
Definition: fe_memutils.h:74
#define palloc_array(type, count)
Definition: fe_memutils.h:76
int j
Definition: isn.c:78
void * palloc(Size size)
Definition: mcxt.c:1365
@ PARTITION_RANGE_DATUM_VALUE
Definition: parsenodes.h:953
struct PartitionBoundInfoData * PartitionBoundInfo
Definition: partdefs.h:16
Bitmapset * interleaved_parts
Definition: partbounds.h:87

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

Referenced by RelationBuildPartitionDesc().

◆ partition_bounds_create()

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

Definition at line 299 of file partbounds.c.

301{
302 int i;
303
304 Assert(nparts > 0);
305
306 /*
307 * For each partitioning method, we first convert the partition bounds
308 * from their parser node representation to the internal representation,
309 * along with any additional preprocessing (such as de-duplicating range
310 * bounds). Resulting bound datums are then added to the 'datums' array
311 * in PartitionBoundInfo. For each datum added, an integer indicating the
312 * canonical partition index is added to the 'indexes' array.
313 *
314 * For each bound, we remember its partition's position (0-based) in the
315 * original list to later map it to the canonical index.
316 */
317
318 /*
319 * Initialize mapping array with invalid values, this is filled within
320 * each sub-routine below depending on the bound type.
321 */
322 *mapping = palloc_array(int, nparts);
323 for (i = 0; i < nparts; i++)
324 (*mapping)[i] = -1;
325
326 switch (key->strategy)
327 {
329 return create_hash_bounds(boundspecs, nparts, key, mapping);
330
332 return create_list_bounds(boundspecs, nparts, key, mapping);
333
335 return create_range_bounds(boundspecs, nparts, key, mapping);
336 }
337
338 Assert(false);
339 return NULL; /* keep compiler quiet */
340}
static PartitionBoundInfo create_list_bounds(PartitionBoundSpec **boundspecs, int nparts, PartitionKey key, int **mapping)
Definition: partbounds.c:460
static PartitionBoundInfo create_hash_bounds(PartitionBoundSpec **boundspecs, int nparts, PartitionKey key, int **mapping)
Definition: partbounds.c:347
static PartitionBoundInfo create_range_bounds(PartitionBoundSpec **boundspecs, int nparts, PartitionKey key, int **mapping)
Definition: partbounds.c:674

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

Referenced by RelationBuildPartitionDesc().

◆ partition_bounds_equal()

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

Definition at line 888 of file partbounds.c.

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

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

Referenced by compute_partition_bounds().

◆ partition_bounds_merge()

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

Definition at line 1111 of file partbounds.c.

1116{
1117 /*
1118 * Currently, this function is called only from try_partitionwise_join(),
1119 * so the join type should be INNER, LEFT, FULL, SEMI, or ANTI.
1120 */
1121 Assert(jointype == JOIN_INNER || jointype == JOIN_LEFT ||
1122 jointype == JOIN_FULL || jointype == JOIN_SEMI ||
1123 jointype == JOIN_ANTI);
1124
1125 /* The partitioning strategies should be the same. */
1126 Assert(outer_rel->boundinfo->strategy == inner_rel->boundinfo->strategy);
1127
1128 *outer_parts = *inner_parts = NIL;
1129 switch (outer_rel->boundinfo->strategy)
1130 {
1132
1133 /*
1134 * For hash partitioned tables, we currently support partitioned
1135 * join only when they have exactly the same partition bounds.
1136 *
1137 * XXX: it might be possible to relax the restriction to support
1138 * cases where hash partitioned tables have missing partitions
1139 * and/or different moduli, but it's not clear if it would be
1140 * useful to support the former case since it's unusual to have
1141 * missing partitions. On the other hand, it would be useful to
1142 * support the latter case, but in that case, there is a high
1143 * probability that a partition on one side will match multiple
1144 * partitions on the other side, which is the scenario the current
1145 * implementation of partitioned join can't handle.
1146 */
1147 return NULL;
1148
1150 return merge_list_bounds(partsupfunc,
1151 partcollation,
1152 outer_rel,
1153 inner_rel,
1154 jointype,
1155 outer_parts,
1156 inner_parts);
1157
1159 return merge_range_bounds(partnatts,
1160 partsupfunc,
1161 partcollation,
1162 outer_rel,
1163 inner_rel,
1164 jointype,
1165 outer_parts,
1166 inner_parts);
1167 }
1168
1169 return NULL;
1170}
@ JOIN_SEMI
Definition: nodes.h:317
@ JOIN_FULL
Definition: nodes.h:305
@ JOIN_INNER
Definition: nodes.h:303
@ JOIN_LEFT
Definition: nodes.h:304
@ JOIN_ANTI
Definition: nodes.h:318
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:1499
static PartitionBoundInfo merge_list_bounds(FmgrInfo *partsupfunc, Oid *partcollation, RelOptInfo *outer_rel, RelOptInfo *inner_rel, JoinType jointype, List **outer_parts, List **inner_parts)
Definition: partbounds.c:1191

References Assert(), JOIN_ANTI, JOIN_FULL, JOIN_INNER, JOIN_LEFT, JOIN_SEMI, merge_list_bounds(), merge_range_bounds(), NIL, PARTITION_STRATEGY_HASH, PARTITION_STRATEGY_LIST, and PARTITION_STRATEGY_RANGE.

Referenced by compute_partition_bounds().

◆ partition_hash_bsearch()

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

Definition at line 3729 of file partbounds.c.

3731{
3732 int lo,
3733 hi,
3734 mid;
3735
3736 lo = -1;
3737 hi = boundinfo->ndatums - 1;
3738 while (lo < hi)
3739 {
3740 int32 cmpval,
3741 bound_modulus,
3742 bound_remainder;
3743
3744 mid = (lo + hi + 1) / 2;
3745 bound_modulus = DatumGetInt32(boundinfo->datums[mid][0]);
3746 bound_remainder = DatumGetInt32(boundinfo->datums[mid][1]);
3747 cmpval = partition_hbound_cmp(bound_modulus, bound_remainder,
3748 modulus, remainder);
3749 if (cmpval <= 0)
3750 {
3751 lo = mid;
3752
3753 if (cmpval == 0)
3754 break;
3755 }
3756 else
3757 hi = mid - 1;
3758 }
3759
3760 return lo;
3761}
static int32 partition_hbound_cmp(int modulus1, int remainder1, int modulus2, int remainder2)
Definition: partbounds.c:3578

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

Referenced by check_new_partition_bound().

◆ partition_list_bsearch()

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

Definition at line 3598 of file partbounds.c.

3601{
3602 int lo,
3603 hi,
3604 mid;
3605
3606 lo = -1;
3607 hi = boundinfo->ndatums - 1;
3608 while (lo < hi)
3609 {
3610 int32 cmpval;
3611
3612 mid = (lo + hi + 1) / 2;
3613 cmpval = DatumGetInt32(FunctionCall2Coll(&partsupfunc[0],
3614 partcollation[0],
3615 boundinfo->datums[mid][0],
3616 value));
3617 if (cmpval <= 0)
3618 {
3619 lo = mid;
3620 *is_equal = (cmpval == 0);
3621 if (*is_equal)
3622 break;
3623 }
3624 else
3625 hi = mid - 1;
3626 }
3627
3628 return lo;
3629}
static struct @171 value

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

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

◆ partition_range_datum_bsearch()

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

Definition at line 3686 of file partbounds.c.

3689{
3690 int lo,
3691 hi,
3692 mid;
3693
3694 lo = -1;
3695 hi = boundinfo->ndatums - 1;
3696 while (lo < hi)
3697 {
3698 int32 cmpval;
3699
3700 mid = (lo + hi + 1) / 2;
3701 cmpval = partition_rbound_datum_cmp(partsupfunc,
3702 partcollation,
3703 boundinfo->datums[mid],
3704 boundinfo->kind[mid],
3705 values,
3706 nvalues);
3707 if (cmpval <= 0)
3708 {
3709 lo = mid;
3710 *is_equal = (cmpval == 0);
3711
3712 if (*is_equal)
3713 break;
3714 }
3715 else
3716 hi = mid - 1;
3717 }
3718
3719 return lo;
3720}
int32 partition_rbound_datum_cmp(FmgrInfo *partsupfunc, Oid *partcollation, const Datum *rb_datums, PartitionRangeDatumKind *rb_kind, const Datum *tuple_datums, int n_tuple_datums)
Definition: partbounds.c:3547

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

Referenced by get_matching_range_bounds(), and get_partition_for_tuple().

◆ partition_rbound_datum_cmp()

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

Definition at line 3547 of file partbounds.c.

3550{
3551 int i;
3552 int32 cmpval = -1;
3553
3554 for (i = 0; i < n_tuple_datums; i++)
3555 {
3556 if (rb_kind[i] == PARTITION_RANGE_DATUM_MINVALUE)
3557 return -1;
3558 else if (rb_kind[i] == PARTITION_RANGE_DATUM_MAXVALUE)
3559 return 1;
3560
3561 cmpval = DatumGetInt32(FunctionCall2Coll(&partsupfunc[i],
3562 partcollation[i],
3563 rb_datums[i],
3564 tuple_datums[i]));
3565 if (cmpval != 0)
3566 break;
3567 }
3568
3569 return cmpval;
3570}
@ PARTITION_RANGE_DATUM_MAXVALUE
Definition: parsenodes.h:954
@ PARTITION_RANGE_DATUM_MINVALUE
Definition: parsenodes.h:952

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

Referenced by get_matching_range_bounds(), get_partition_for_tuple(), and partition_range_datum_bsearch().

◆ partitions_are_ordered()

bool partitions_are_ordered ( PartitionBoundInfo  boundinfo,
Bitmapset live_parts 
)

Definition at line 2844 of file partbounds.c.

2845{
2846 Assert(boundinfo != NULL);
2847
2848 switch (boundinfo->strategy)
2849 {
2851
2852 /*
2853 * RANGE-type partitioning guarantees that the partitions can be
2854 * scanned in the order that they're defined in the PartitionDesc
2855 * to provide sequential, non-overlapping ranges of tuples.
2856 * However, if a DEFAULT partition exists and it's contained
2857 * within live_parts, then the partitions are not ordered.
2858 */
2859 if (!partition_bound_has_default(boundinfo) ||
2860 !bms_is_member(boundinfo->default_index, live_parts))
2861 return true;
2862 break;
2863
2865
2866 /*
2867 * LIST partitioned are ordered providing none of live_parts
2868 * overlap with the partitioned table's interleaved partitions.
2869 */
2870 if (!bms_overlap(live_parts, boundinfo->interleaved_parts))
2871 return true;
2872
2873 break;
2875 break;
2876 }
2877
2878 return false;
2879}
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:510
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:581

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

Referenced by build_partition_pathkeys(), and generate_orderedappend_paths().