Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * partbounds.c
4 : * Support routines for manipulating partition bounds
5 : *
6 : * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
7 : * Portions Copyright (c) 1994, Regents of the University of California
8 : *
9 : * IDENTIFICATION
10 : * src/backend/partitioning/partbounds.c
11 : *
12 : *-------------------------------------------------------------------------
13 : */
14 :
15 : #include "postgres.h"
16 :
17 : #include "access/relation.h"
18 : #include "access/table.h"
19 : #include "access/tableam.h"
20 : #include "catalog/partition.h"
21 : #include "catalog/pg_inherits.h"
22 : #include "catalog/pg_type.h"
23 : #include "commands/tablecmds.h"
24 : #include "common/hashfn.h"
25 : #include "executor/executor.h"
26 : #include "miscadmin.h"
27 : #include "nodes/makefuncs.h"
28 : #include "nodes/nodeFuncs.h"
29 : #include "nodes/pathnodes.h"
30 : #include "parser/parse_coerce.h"
31 : #include "partitioning/partbounds.h"
32 : #include "partitioning/partdesc.h"
33 : #include "partitioning/partprune.h"
34 : #include "utils/array.h"
35 : #include "utils/builtins.h"
36 : #include "utils/datum.h"
37 : #include "utils/fmgroids.h"
38 : #include "utils/lsyscache.h"
39 : #include "utils/partcache.h"
40 : #include "utils/ruleutils.h"
41 : #include "utils/snapmgr.h"
42 : #include "utils/syscache.h"
43 :
44 : /*
45 : * When qsort'ing partition bounds after reading from the catalog, each bound
46 : * is represented with one of the following structs.
47 : */
48 :
49 : /* One bound of a hash partition */
50 : typedef struct PartitionHashBound
51 : {
52 : int modulus;
53 : int remainder;
54 : int index;
55 : } PartitionHashBound;
56 :
57 : /* One value coming from some (index'th) list partition */
58 : typedef struct PartitionListValue
59 : {
60 : int index;
61 : Datum value;
62 : } PartitionListValue;
63 :
64 : /* One bound of a range partition */
65 : typedef struct PartitionRangeBound
66 : {
67 : int index;
68 : Datum *datums; /* range bound datums */
69 : PartitionRangeDatumKind *kind; /* the kind of each datum */
70 : bool lower; /* this is the lower (vs upper) bound */
71 : } PartitionRangeBound;
72 :
73 : /*
74 : * Mapping from partitions of a joining relation to partitions of a join
75 : * relation being computed (a.k.a merged partitions)
76 : */
77 : typedef struct PartitionMap
78 : {
79 : int nparts; /* number of partitions */
80 : int *merged_indexes; /* indexes of merged partitions */
81 : bool *merged; /* flags to indicate whether partitions are
82 : * merged with non-dummy partitions */
83 : bool did_remapping; /* did we re-map partitions? */
84 : int *old_indexes; /* old indexes of merged partitions if
85 : * did_remapping */
86 : } PartitionMap;
87 :
88 : /* Macro for comparing two range bounds */
89 : #define compare_range_bounds(partnatts, partsupfunc, partcollations, \
90 : bound1, bound2) \
91 : (partition_rbound_cmp(partnatts, partsupfunc, partcollations, \
92 : (bound1)->datums, (bound1)->kind, (bound1)->lower, \
93 : bound2))
94 :
95 : static int32 qsort_partition_hbound_cmp(const void *a, const void *b);
96 : static int32 qsort_partition_list_value_cmp(const void *a, const void *b,
97 : void *arg);
98 : static int32 qsort_partition_rbound_cmp(const void *a, const void *b,
99 : void *arg);
100 : static PartitionBoundInfo create_hash_bounds(PartitionBoundSpec **boundspecs,
101 : int nparts, PartitionKey key, int **mapping);
102 : static PartitionBoundInfo create_list_bounds(PartitionBoundSpec **boundspecs,
103 : int nparts, PartitionKey key, int **mapping);
104 : static PartitionBoundInfo create_range_bounds(PartitionBoundSpec **boundspecs,
105 : int nparts, PartitionKey key, int **mapping);
106 : static PartitionBoundInfo merge_list_bounds(FmgrInfo *partsupfunc,
107 : Oid *partcollation,
108 : RelOptInfo *outer_rel,
109 : RelOptInfo *inner_rel,
110 : JoinType jointype,
111 : List **outer_parts,
112 : List **inner_parts);
113 : static PartitionBoundInfo merge_range_bounds(int partnatts,
114 : FmgrInfo *partsupfuncs,
115 : Oid *partcollations,
116 : RelOptInfo *outer_rel,
117 : RelOptInfo *inner_rel,
118 : JoinType jointype,
119 : List **outer_parts,
120 : List **inner_parts);
121 : static void init_partition_map(RelOptInfo *rel, PartitionMap *map);
122 : static void free_partition_map(PartitionMap *map);
123 : static bool is_dummy_partition(RelOptInfo *rel, int part_index);
124 : static int merge_matching_partitions(PartitionMap *outer_map,
125 : PartitionMap *inner_map,
126 : int outer_index,
127 : int inner_index,
128 : int *next_index);
129 : static int process_outer_partition(PartitionMap *outer_map,
130 : PartitionMap *inner_map,
131 : bool outer_has_default,
132 : bool inner_has_default,
133 : int outer_index,
134 : int inner_default,
135 : JoinType jointype,
136 : int *next_index,
137 : int *default_index);
138 : static int process_inner_partition(PartitionMap *outer_map,
139 : PartitionMap *inner_map,
140 : bool outer_has_default,
141 : bool inner_has_default,
142 : int inner_index,
143 : int outer_default,
144 : JoinType jointype,
145 : int *next_index,
146 : int *default_index);
147 : static void merge_null_partitions(PartitionMap *outer_map,
148 : PartitionMap *inner_map,
149 : bool outer_has_null,
150 : bool inner_has_null,
151 : int outer_null,
152 : int inner_null,
153 : JoinType jointype,
154 : int *next_index,
155 : int *null_index);
156 : static void merge_default_partitions(PartitionMap *outer_map,
157 : PartitionMap *inner_map,
158 : bool outer_has_default,
159 : bool inner_has_default,
160 : int outer_default,
161 : int inner_default,
162 : JoinType jointype,
163 : int *next_index,
164 : int *default_index);
165 : static int merge_partition_with_dummy(PartitionMap *map, int index,
166 : int *next_index);
167 : static void fix_merged_indexes(PartitionMap *outer_map,
168 : PartitionMap *inner_map,
169 : int nmerged, List *merged_indexes);
170 : static void generate_matching_part_pairs(RelOptInfo *outer_rel,
171 : RelOptInfo *inner_rel,
172 : PartitionMap *outer_map,
173 : PartitionMap *inner_map,
174 : int nmerged,
175 : List **outer_parts,
176 : List **inner_parts);
177 : static PartitionBoundInfo build_merged_partition_bounds(char strategy,
178 : List *merged_datums,
179 : List *merged_kinds,
180 : List *merged_indexes,
181 : int null_index,
182 : int default_index);
183 : static int get_range_partition(RelOptInfo *rel,
184 : PartitionBoundInfo bi,
185 : int *lb_pos,
186 : PartitionRangeBound *lb,
187 : PartitionRangeBound *ub);
188 : static int get_range_partition_internal(PartitionBoundInfo bi,
189 : int *lb_pos,
190 : PartitionRangeBound *lb,
191 : PartitionRangeBound *ub);
192 : static bool compare_range_partitions(int partnatts, FmgrInfo *partsupfuncs,
193 : Oid *partcollations,
194 : PartitionRangeBound *outer_lb,
195 : PartitionRangeBound *outer_ub,
196 : PartitionRangeBound *inner_lb,
197 : PartitionRangeBound *inner_ub,
198 : int *lb_cmpval, int *ub_cmpval);
199 : static void get_merged_range_bounds(int partnatts, FmgrInfo *partsupfuncs,
200 : Oid *partcollations, JoinType jointype,
201 : PartitionRangeBound *outer_lb,
202 : PartitionRangeBound *outer_ub,
203 : PartitionRangeBound *inner_lb,
204 : PartitionRangeBound *inner_ub,
205 : int lb_cmpval, int ub_cmpval,
206 : PartitionRangeBound *merged_lb,
207 : PartitionRangeBound *merged_ub);
208 : static void add_merged_range_bounds(int partnatts, FmgrInfo *partsupfuncs,
209 : Oid *partcollations,
210 : PartitionRangeBound *merged_lb,
211 : PartitionRangeBound *merged_ub,
212 : int merged_index,
213 : List **merged_datums,
214 : List **merged_kinds,
215 : List **merged_indexes);
216 : static PartitionRangeBound *make_one_partition_rbound(PartitionKey key, int index,
217 : List *datums, bool lower);
218 : static int32 partition_hbound_cmp(int modulus1, int remainder1, int modulus2,
219 : int remainder2);
220 : static int32 partition_rbound_cmp(int partnatts, FmgrInfo *partsupfunc,
221 : Oid *partcollation, Datum *datums1,
222 : PartitionRangeDatumKind *kind1, bool lower1,
223 : PartitionRangeBound *b2);
224 : static int partition_range_bsearch(int partnatts, FmgrInfo *partsupfunc,
225 : Oid *partcollation,
226 : PartitionBoundInfo boundinfo,
227 : PartitionRangeBound *probe, int32 *cmpval);
228 : static Expr *make_partition_op_expr(PartitionKey key, int keynum,
229 : uint16 strategy, Expr *arg1, Expr *arg2);
230 : static Oid get_partition_operator(PartitionKey key, int col,
231 : StrategyNumber strategy, bool *need_relabel);
232 : static List *get_qual_for_hash(Relation parent, PartitionBoundSpec *spec);
233 : static List *get_qual_for_list(Relation parent, PartitionBoundSpec *spec);
234 : static List *get_qual_for_range(Relation parent, PartitionBoundSpec *spec,
235 : bool for_default);
236 : static void get_range_key_properties(PartitionKey key, int keynum,
237 : PartitionRangeDatum *ldatum,
238 : PartitionRangeDatum *udatum,
239 : ListCell **partexprs_item,
240 : Expr **keyCol,
241 : Const **lower_val, Const **upper_val);
242 : static List *get_range_nulltest(PartitionKey key);
243 :
244 : /*
245 : * get_qual_from_partbound
246 : * Given a parser node for partition bound, return the list of executable
247 : * expressions as partition constraint
248 : */
249 : List *
634 john.naylor 250 GIC 2485 : get_qual_from_partbound(Relation parent, PartitionBoundSpec *spec)
1821 alvherre 251 ECB : {
1821 alvherre 252 GIC 2485 : PartitionKey key = RelationGetPartitionKey(parent);
1821 alvherre 253 CBC 2485 : List *my_qual = NIL;
1821 alvherre 254 ECB :
1821 alvherre 255 GIC 2485 : Assert(key != NULL);
1821 alvherre 256 ECB :
1821 alvherre 257 GIC 2485 : switch (key->strategy)
1821 alvherre 258 ECB : {
1821 alvherre 259 GIC 76 : case PARTITION_STRATEGY_HASH:
1821 alvherre 260 CBC 76 : Assert(spec->strategy == PARTITION_STRATEGY_HASH);
261 76 : my_qual = get_qual_for_hash(parent, spec);
262 76 : break;
1821 alvherre 263 ECB :
1821 alvherre 264 GIC 1115 : case PARTITION_STRATEGY_LIST:
1821 alvherre 265 CBC 1115 : Assert(spec->strategy == PARTITION_STRATEGY_LIST);
266 1115 : my_qual = get_qual_for_list(parent, spec);
267 1115 : break;
1821 alvherre 268 ECB :
1821 alvherre 269 GIC 1294 : case PARTITION_STRATEGY_RANGE:
1821 alvherre 270 CBC 1294 : Assert(spec->strategy == PARTITION_STRATEGY_RANGE);
271 1294 : my_qual = get_qual_for_range(parent, spec, false);
272 1294 : break;
273 : }
274 :
1821 alvherre 275 GIC 2485 : return my_qual;
276 : }
277 :
278 : /*
279 : * partition_bounds_create
280 : * Build a PartitionBoundInfo struct from a list of PartitionBoundSpec
281 : * nodes
282 : *
283 : * This function creates a PartitionBoundInfo and fills the values of its
284 : * various members based on the input list. Importantly, 'datums' array will
285 : * contain Datum representation of individual bounds (possibly after
286 : * de-duplication as in case of range bounds), sorted in a canonical order
287 : * defined by qsort_partition_* functions of respective partitioning methods.
288 : * 'indexes' array will contain as many elements as there are bounds (specific
289 : * exceptions to this rule are listed in the function body), which represent
290 : * the 0-based canonical positions of partitions.
291 : *
292 : * Upon return from this function, *mapping is set to an array of
293 : * list_length(boundspecs) elements, each of which maps the original index of
294 : * a partition to its canonical index.
295 : *
296 : * Note: The objects returned by this function are wholly allocated in the
1607 michael 297 ECB : * current memory context.
298 : */
299 : PartitionBoundInfo
1602 rhaas 300 GIC 7269 : partition_bounds_create(PartitionBoundSpec **boundspecs, int nparts,
301 : PartitionKey key, int **mapping)
1607 michael 302 ECB : {
303 : int i;
304 :
1607 michael 305 GIC 7269 : Assert(nparts > 0);
306 :
307 : /*
308 : * For each partitioning method, we first convert the partition bounds
309 : * from their parser node representation to the internal representation,
310 : * along with any additional preprocessing (such as de-duplicating range
311 : * bounds). Resulting bound datums are then added to the 'datums' array
312 : * in PartitionBoundInfo. For each datum added, an integer indicating the
313 : * canonical partition index is added to the 'indexes' array.
314 : *
315 : * For each bound, we remember its partition's position (0-based) in the
316 : * original list to later map it to the canonical index.
317 : */
318 :
319 : /*
1607 michael 320 ECB : * Initialize mapping array with invalid values, this is filled within
321 : * each sub-routine below depending on the bound type.
322 : */
1607 michael 323 GIC 7269 : *mapping = (int *) palloc(sizeof(int) * nparts);
1607 michael 324 CBC 21818 : for (i = 0; i < nparts; i++)
1607 michael 325 GIC 14549 : (*mapping)[i] = -1;
1607 michael 326 ECB :
1607 michael 327 CBC 7269 : switch (key->strategy)
328 : {
329 351 : case PARTITION_STRATEGY_HASH:
1602 rhaas 330 351 : return create_hash_bounds(boundspecs, nparts, key, mapping);
331 :
1607 michael 332 3664 : case PARTITION_STRATEGY_LIST:
1602 rhaas 333 3664 : return create_list_bounds(boundspecs, nparts, key, mapping);
334 :
1607 michael 335 GIC 3254 : case PARTITION_STRATEGY_RANGE:
1602 rhaas 336 GBC 3254 : return create_range_bounds(boundspecs, nparts, key, mapping);
337 : }
338 :
1607 michael 339 UIC 0 : Assert(false);
1607 michael 340 ECB : return NULL; /* keep compiler quiet */
341 : }
342 :
343 : /*
344 : * create_hash_bounds
345 : * Create a PartitionBoundInfo for a hash partitioned table
346 : */
347 : static PartitionBoundInfo
1602 rhaas 348 GIC 351 : create_hash_bounds(PartitionBoundSpec **boundspecs, int nparts,
349 : PartitionKey key, int **mapping)
1607 michael 350 ECB : {
351 : PartitionBoundInfo boundinfo;
352 : PartitionHashBound *hbounds;
1602 rhaas 353 : int i;
1607 michael 354 : int greatest_modulus;
355 : Datum *boundDatums;
356 :
357 : boundinfo = (PartitionBoundInfoData *)
1607 michael 358 GIC 351 : palloc0(sizeof(PartitionBoundInfoData));
359 351 : boundinfo->strategy = key->strategy;
1607 michael 360 ECB : /* No special hash partitions. */
1607 michael 361 GIC 351 : boundinfo->null_index = -1;
1607 michael 362 CBC 351 : boundinfo->default_index = -1;
363 :
642 drowley 364 ECB : hbounds = (PartitionHashBound *)
642 drowley 365 GBC 351 : palloc(nparts * sizeof(PartitionHashBound));
366 :
1607 michael 367 ECB : /* Convert from node to the internal representation */
1602 rhaas 368 CBC 1042 : for (i = 0; i < nparts; i++)
1607 michael 369 ECB : {
1602 rhaas 370 GIC 691 : PartitionBoundSpec *spec = boundspecs[i];
371 :
1607 michael 372 691 : if (spec->strategy != PARTITION_STRATEGY_HASH)
1607 michael 373 LBC 0 : elog(ERROR, "invalid strategy in partition bound spec");
374 :
642 drowley 375 GIC 691 : hbounds[i].modulus = spec->modulus;
376 691 : hbounds[i].remainder = spec->remainder;
642 drowley 377 CBC 691 : hbounds[i].index = i;
378 : }
1607 michael 379 ECB :
380 : /* Sort all the bounds in ascending order */
642 drowley 381 CBC 351 : qsort(hbounds, nparts, sizeof(PartitionHashBound),
1607 michael 382 ECB : qsort_partition_hbound_cmp);
383 :
384 : /* After sorting, moduli are now stored in ascending order. */
642 drowley 385 CBC 351 : greatest_modulus = hbounds[nparts - 1].modulus;
1607 michael 386 ECB :
642 drowley 387 GIC 351 : boundinfo->ndatums = nparts;
388 351 : boundinfo->datums = (Datum **) palloc0(nparts * sizeof(Datum *));
389 351 : boundinfo->kind = NULL;
614 390 351 : boundinfo->interleaved_parts = NULL;
801 tgl 391 351 : boundinfo->nindexes = greatest_modulus;
1607 michael 392 351 : boundinfo->indexes = (int *) palloc(greatest_modulus * sizeof(int));
1607 michael 393 CBC 2752 : for (i = 0; i < greatest_modulus; i++)
1607 michael 394 GIC 2401 : boundinfo->indexes[i] = -1;
395 :
396 : /*
397 : * In the loop below, to save from allocating a series of small datum
398 : * arrays, here we just allocate a single array and below we'll just
399 : * assign a portion of this array per partition.
642 drowley 400 ECB : */
642 drowley 401 GIC 351 : boundDatums = (Datum *) palloc(nparts * 2 * sizeof(Datum));
642 drowley 402 ECB :
1607 michael 403 : /*
404 : * For hash partitioning, there are as many datums (modulus and remainder
405 : * pairs) as there are partitions. Indexes are simply values ranging from
406 : * 0 to (nparts - 1).
407 : */
1607 michael 408 GIC 1042 : for (i = 0; i < nparts; i++)
1607 michael 409 ECB : {
642 drowley 410 GIC 691 : int modulus = hbounds[i].modulus;
411 691 : int remainder = hbounds[i].remainder;
1607 michael 412 ECB :
642 drowley 413 CBC 691 : boundinfo->datums[i] = &boundDatums[i * 2];
1607 michael 414 691 : boundinfo->datums[i][0] = Int32GetDatum(modulus);
1607 michael 415 GIC 691 : boundinfo->datums[i][1] = Int32GetDatum(remainder);
416 :
1607 michael 417 CBC 1619 : while (remainder < greatest_modulus)
418 : {
1607 michael 419 ECB : /* overlap? */
1607 michael 420 GIC 928 : Assert(boundinfo->indexes[remainder] == -1);
1607 michael 421 CBC 928 : boundinfo->indexes[remainder] = i;
1607 michael 422 GIC 928 : remainder += modulus;
423 : }
424 :
642 drowley 425 691 : (*mapping)[hbounds[i].index] = i;
426 : }
1607 michael 427 351 : pfree(hbounds);
428 :
1607 michael 429 CBC 351 : return boundinfo;
430 : }
431 :
642 drowley 432 ECB : /*
433 : * get_non_null_list_datum_count
434 : * Counts the number of non-null Datums in each partition.
435 : */
436 : static int
642 drowley 437 GIC 3664 : get_non_null_list_datum_count(PartitionBoundSpec **boundspecs, int nparts)
642 drowley 438 ECB : {
439 : int i;
642 drowley 440 CBC 3664 : int count = 0;
441 :
442 10826 : for (i = 0; i < nparts; i++)
642 drowley 443 ECB : {
444 : ListCell *lc;
445 :
642 drowley 446 GIC 17393 : foreach(lc, boundspecs[i]->listdatums)
642 drowley 447 ECB : {
629 peter 448 GIC 10231 : Const *val = lfirst_node(Const, lc);
449 :
642 drowley 450 10231 : if (!val->constisnull)
451 9964 : count++;
452 : }
453 : }
454 :
642 drowley 455 CBC 3664 : return count;
456 : }
457 :
458 : /*
459 : * create_list_bounds
460 : * Create a PartitionBoundInfo for a list partitioned table
461 : */
462 : static PartitionBoundInfo
1602 rhaas 463 3664 : create_list_bounds(PartitionBoundSpec **boundspecs, int nparts,
1602 rhaas 464 ECB : PartitionKey key, int **mapping)
1607 michael 465 : {
466 : PartitionBoundInfo boundinfo;
467 : PartitionListValue *all_values;
468 : int i;
642 drowley 469 : int j;
470 : int ndatums;
1607 michael 471 GIC 3664 : int next_index = 0;
1607 michael 472 CBC 3664 : int default_index = -1;
473 3664 : int null_index = -1;
474 : Datum *boundDatums;
1607 michael 475 ECB :
476 : boundinfo = (PartitionBoundInfoData *)
1607 michael 477 CBC 3664 : palloc0(sizeof(PartitionBoundInfoData));
1607 michael 478 GIC 3664 : boundinfo->strategy = key->strategy;
479 : /* Will be set correctly below. */
1607 michael 480 CBC 3664 : boundinfo->null_index = -1;
1607 michael 481 GIC 3664 : boundinfo->default_index = -1;
1607 michael 482 ECB :
642 drowley 483 GIC 3664 : ndatums = get_non_null_list_datum_count(boundspecs, nparts);
484 : all_values = (PartitionListValue *)
642 drowley 485 CBC 3664 : palloc(ndatums * sizeof(PartitionListValue));
642 drowley 486 EUB :
487 : /* Create a unified list of non-null values across all partitions. */
642 drowley 488 GIC 10826 : for (j = 0, i = 0; i < nparts; i++)
489 : {
1602 rhaas 490 7162 : PartitionBoundSpec *spec = boundspecs[i];
491 : ListCell *c;
492 :
1607 michael 493 CBC 7162 : if (spec->strategy != PARTITION_STRATEGY_LIST)
1607 michael 494 UIC 0 : elog(ERROR, "invalid strategy in partition bound spec");
1607 michael 495 ECB :
496 : /*
497 : * Note the index of the partition bound spec for the default
498 : * partition. There's no datum to add to the list on non-null datums
499 : * for this partition.
500 : */
1607 michael 501 CBC 7162 : if (spec->is_default)
502 : {
503 420 : default_index = i;
1607 michael 504 GIC 420 : continue;
1607 michael 505 ECB : }
506 :
1607 michael 507 CBC 16973 : foreach(c, spec->listdatums)
508 : {
629 peter 509 GIC 10231 : Const *val = lfirst_node(Const, c);
510 :
1607 michael 511 10231 : if (!val->constisnull)
512 : {
642 drowley 513 9964 : all_values[j].index = i;
514 9964 : all_values[j].value = val->constvalue;
642 drowley 515 CBC 9964 : j++;
1607 michael 516 EUB : }
1607 michael 517 ECB : else
518 : {
519 : /*
520 : * Never put a null into the values array; save the index of
521 : * the partition that stores nulls, instead.
522 : */
1607 michael 523 CBC 267 : if (null_index != -1)
1607 michael 524 UIC 0 : elog(ERROR, "found null more than once");
1607 michael 525 CBC 267 : null_index = i;
526 : }
527 : }
1607 michael 528 ECB : }
529 :
642 drowley 530 : /* ensure we found a Datum for every slot in the all_values array */
642 drowley 531 CBC 3664 : Assert(j == ndatums);
1607 michael 532 ECB :
642 drowley 533 CBC 3664 : qsort_arg(all_values, ndatums, sizeof(PartitionListValue),
534 : qsort_partition_list_value_cmp, key);
535 :
1607 michael 536 GIC 3664 : boundinfo->ndatums = ndatums;
537 3664 : boundinfo->datums = (Datum **) palloc0(ndatums * sizeof(Datum *));
642 drowley 538 3664 : boundinfo->kind = NULL;
614 539 3664 : boundinfo->interleaved_parts = NULL;
801 tgl 540 CBC 3664 : boundinfo->nindexes = ndatums;
1607 michael 541 GIC 3664 : boundinfo->indexes = (int *) palloc(ndatums * sizeof(int));
542 :
543 : /*
544 : * In the loop below, to save from allocating a series of small datum
545 : * arrays, here we just allocate a single array and below we'll just
546 : * assign a portion of this array per datum.
547 : */
642 drowley 548 CBC 3664 : boundDatums = (Datum *) palloc(ndatums * sizeof(Datum));
549 :
1607 michael 550 ECB : /*
551 : * Copy values. Canonical indexes are values ranging from 0 to (nparts -
552 : * 1) assigned to each partition such that all datums of a given partition
553 : * receive the same value. The value for a given partition is the index of
554 : * that partition's smallest datum in the all_values[] array.
555 : */
1607 michael 556 GIC 13628 : for (i = 0; i < ndatums; i++)
557 : {
642 drowley 558 CBC 9964 : int orig_index = all_values[i].index;
1607 michael 559 ECB :
642 drowley 560 GIC 9964 : boundinfo->datums[i] = &boundDatums[i];
642 drowley 561 CBC 19928 : boundinfo->datums[i][0] = datumCopy(all_values[i].value,
1607 michael 562 GIC 9964 : key->parttypbyval[0],
563 9964 : key->parttyplen[0]);
1607 michael 564 ECB :
565 : /* If the old index has no mapping, assign one */
1607 michael 566 GIC 9964 : if ((*mapping)[orig_index] == -1)
567 6646 : (*mapping)[orig_index] = next_index++;
568 :
569 9964 : boundinfo->indexes[i] = (*mapping)[orig_index];
570 : }
571 :
642 drowley 572 3664 : pfree(all_values);
573 :
1607 michael 574 ECB : /*
575 : * Set the canonical value for null_index, if any.
576 : *
577 : * It is possible that the null-accepting partition has not been assigned
578 : * an index yet, which could happen if such partition accepts only null
579 : * and hence not handled in the above loop which only looked at non-null
580 : * values.
581 : */
1607 michael 582 GIC 3664 : if (null_index != -1)
1607 michael 583 ECB : {
1607 michael 584 GIC 267 : Assert(null_index >= 0);
585 267 : if ((*mapping)[null_index] == -1)
586 96 : (*mapping)[null_index] = next_index++;
587 267 : boundinfo->null_index = (*mapping)[null_index];
588 : }
589 :
1607 michael 590 ECB : /* Set the canonical value for default_index, if any. */
1607 michael 591 CBC 3664 : if (default_index != -1)
1607 michael 592 ECB : {
593 : /*
594 : * The default partition accepts any value not specified in the lists
595 : * of other partitions, hence it should not get mapped index while
596 : * assigning those for non-null datums.
597 : */
1607 michael 598 GIC 420 : Assert(default_index >= 0);
599 420 : Assert((*mapping)[default_index] == -1);
600 420 : (*mapping)[default_index] = next_index++;
601 420 : boundinfo->default_index = (*mapping)[default_index];
602 : }
603 :
604 : /*
605 : * Calculate interleaved partitions. Here we look for partitions which
606 : * might be interleaved with other partitions and set a bit in
614 drowley 607 ECB : * interleaved_parts for any partitions which may be interleaved with
608 : * another partition.
609 : */
610 :
611 : /*
612 : * There must be multiple partitions to have any interleaved partitions,
613 : * otherwise there's nothing to interleave with.
614 : */
614 drowley 615 CBC 3664 : if (nparts > 1)
614 drowley 616 ECB : {
617 : /*
618 : * Short-circuit check to see if only 1 Datum is allowed per
619 : * partition. When this is true there's no need to do the more
620 : * expensive checks to look for interleaved values.
621 : */
614 drowley 622 GIC 2185 : if (boundinfo->ndatums +
623 2185 : partition_bound_accepts_nulls(boundinfo) +
624 2185 : partition_bound_has_default(boundinfo) != nparts)
625 : {
614 drowley 626 CBC 849 : int last_index = -1;
627 :
614 drowley 628 ECB : /*
629 : * Since the indexes array is sorted in Datum order, if any
630 : * partitions are interleaved then it will show up by the
631 : * partition indexes not being in ascending order. Here we check
632 : * for that and record all partitions that are out of order.
633 : */
614 drowley 634 GIC 5964 : for (i = 0; i < boundinfo->nindexes; i++)
635 : {
636 5115 : int index = boundinfo->indexes[i];
637 :
638 5115 : if (index < last_index)
614 drowley 639 CBC 308 : boundinfo->interleaved_parts = bms_add_member(boundinfo->interleaved_parts,
614 drowley 640 ECB : index);
641 :
642 : /*
643 : * Otherwise, if the null_index exists in the indexes array,
270 644 : * then the NULL partition must also allow some other Datum,
645 : * therefore it's "interleaved".
646 : */
270 drowley 647 GIC 4807 : else if (partition_bound_accepts_nulls(boundinfo) &&
648 1419 : index == boundinfo->null_index)
614 649 378 : boundinfo->interleaved_parts = bms_add_member(boundinfo->interleaved_parts,
650 : index);
651 :
652 5115 : last_index = index;
653 : }
614 drowley 654 ECB : }
655 :
656 : /*
657 : * The DEFAULT partition is the "catch-all" partition that can contain
658 : * anything that does not belong to any other partition. If there are
659 : * any other partitions then the DEFAULT partition must be marked as
660 : * interleaved.
661 : */
614 drowley 662 CBC 2185 : if (partition_bound_has_default(boundinfo))
614 drowley 663 GIC 362 : boundinfo->interleaved_parts = bms_add_member(boundinfo->interleaved_parts,
664 : boundinfo->default_index);
665 : }
666 :
667 :
668 : /* All partitions must now have been assigned canonical indexes. */
1602 rhaas 669 3664 : Assert(next_index == nparts);
1607 michael 670 CBC 3664 : return boundinfo;
671 : }
672 :
673 : /*
1607 michael 674 ECB : * create_range_bounds
675 : * Create a PartitionBoundInfo for a range partitioned table
676 : */
677 : static PartitionBoundInfo
1602 rhaas 678 GIC 3254 : create_range_bounds(PartitionBoundSpec **boundspecs, int nparts,
679 : PartitionKey key, int **mapping)
1607 michael 680 ECB : {
681 : PartitionBoundInfo boundinfo;
1607 michael 682 CBC 3254 : PartitionRangeBound **rbounds = NULL;
683 : PartitionRangeBound **all_bounds,
684 : *prev;
685 : int i,
686 : k,
642 drowley 687 ECB : partnatts;
1607 michael 688 CBC 3254 : int ndatums = 0;
1607 michael 689 GIC 3254 : int default_index = -1;
1607 michael 690 CBC 3254 : int next_index = 0;
691 : Datum *boundDatums;
642 drowley 692 ECB : PartitionRangeDatumKind *boundKinds;
693 :
694 : boundinfo = (PartitionBoundInfoData *)
1607 michael 695 CBC 3254 : palloc0(sizeof(PartitionBoundInfoData));
1607 michael 696 GIC 3254 : boundinfo->strategy = key->strategy;
697 : /* There is no special null-accepting range partition. */
1607 michael 698 CBC 3254 : boundinfo->null_index = -1;
1607 michael 699 ECB : /* Will be set correctly below. */
1607 michael 700 GIC 3254 : boundinfo->default_index = -1;
1607 michael 701 ECB :
702 : all_bounds = (PartitionRangeBound **)
1607 michael 703 GIC 3254 : palloc0(2 * nparts * sizeof(PartitionRangeBound *));
704 :
1607 michael 705 ECB : /* Create a unified list of range bounds across all the partitions. */
1602 rhaas 706 GBC 3254 : ndatums = 0;
1602 rhaas 707 GIC 9950 : for (i = 0; i < nparts; i++)
708 : {
709 6696 : PartitionBoundSpec *spec = boundspecs[i];
710 : PartitionRangeBound *lower,
711 : *upper;
712 :
1607 michael 713 CBC 6696 : if (spec->strategy != PARTITION_STRATEGY_RANGE)
1607 michael 714 UIC 0 : elog(ERROR, "invalid strategy in partition bound spec");
1607 michael 715 ECB :
716 : /*
717 : * Note the index of the partition bound spec for the default
718 : * partition. There's no datum to add to the all_bounds array for
719 : * this partition.
720 : */
1607 michael 721 CBC 6696 : if (spec->is_default)
1607 michael 722 ECB : {
1602 rhaas 723 GIC 380 : default_index = i;
1607 michael 724 380 : continue;
1607 michael 725 ECB : }
726 :
1607 michael 727 GIC 6316 : lower = make_one_partition_rbound(key, i, spec->lowerdatums, true);
728 6316 : upper = make_one_partition_rbound(key, i, spec->upperdatums, false);
1607 michael 729 CBC 6316 : all_bounds[ndatums++] = lower;
1607 michael 730 GIC 6316 : all_bounds[ndatums++] = upper;
731 : }
732 :
733 3254 : Assert(ndatums == nparts * 2 ||
734 : (default_index != -1 && ndatums == (nparts - 1) * 2));
735 :
1607 michael 736 ECB : /* Sort all the bounds in ascending order */
1607 michael 737 CBC 3254 : qsort_arg(all_bounds, ndatums,
1607 michael 738 ECB : sizeof(PartitionRangeBound *),
739 : qsort_partition_rbound_cmp,
740 : key);
741 :
742 : /* Save distinct bounds from all_bounds into rbounds. */
743 : rbounds = (PartitionRangeBound **)
1607 michael 744 GIC 3254 : palloc(ndatums * sizeof(PartitionRangeBound *));
745 3254 : k = 0;
1607 michael 746 CBC 3254 : prev = NULL;
1607 michael 747 GIC 15886 : for (i = 0; i < ndatums; i++)
748 : {
749 12632 : PartitionRangeBound *cur = all_bounds[i];
1607 michael 750 CBC 12632 : bool is_distinct = false;
751 : int j;
1607 michael 752 ECB :
753 : /* Is the current bound distinct from the previous one? */
1607 michael 754 GIC 17156 : for (j = 0; j < key->partnatts; j++)
755 : {
756 : Datum cmpval;
757 :
758 14506 : if (prev == NULL || cur->kind[j] != prev->kind[j])
759 : {
760 3899 : is_distinct = true;
1607 michael 761 CBC 3899 : break;
1607 michael 762 ECB : }
763 :
764 : /*
765 : * If the bounds are both MINVALUE or MAXVALUE, stop now and treat
766 : * them as equal, since any values after this point must be
767 : * ignored.
768 : */
1607 michael 769 GIC 10607 : if (cur->kind[j] != PARTITION_RANGE_DATUM_VALUE)
1607 michael 770 CBC 93 : break;
1607 michael 771 ECB :
1607 michael 772 GIC 10514 : cmpval = FunctionCall2Coll(&key->partsupfunc[j],
773 10514 : key->partcollation[j],
774 10514 : cur->datums[j],
775 10514 : prev->datums[j]);
776 10514 : if (DatumGetInt32(cmpval) != 0)
777 : {
778 5990 : is_distinct = true;
1607 michael 779 CBC 5990 : break;
1607 michael 780 ECB : }
781 : }
782 :
783 : /*
784 : * Only if the bound is distinct save it into a temporary array, i.e,
785 : * rbounds which is later copied into boundinfo datums array.
786 : */
1607 michael 787 GIC 12632 : if (is_distinct)
1607 michael 788 CBC 9889 : rbounds[k++] = all_bounds[i];
789 :
1607 michael 790 GIC 12632 : prev = cur;
791 : }
792 :
642 drowley 793 3254 : pfree(all_bounds);
794 :
795 : /* Update ndatums to hold the count of distinct datums. */
1607 michael 796 3254 : ndatums = k;
797 :
1607 michael 798 ECB : /*
799 : * Add datums to boundinfo. Canonical indexes are values ranging from 0
800 : * to nparts - 1, assigned in that order to each partition's upper bound.
801 : * For 'datums' elements that are lower bounds, there is -1 in the
802 : * 'indexes' array to signify that no partition exists for the values less
803 : * than such a bound and greater than or equal to the previous upper
804 : * bound.
805 : */
1607 michael 806 GIC 3254 : boundinfo->ndatums = ndatums;
807 3254 : boundinfo->datums = (Datum **) palloc0(ndatums * sizeof(Datum *));
808 3254 : boundinfo->kind = (PartitionRangeDatumKind **)
1607 michael 809 CBC 3254 : palloc(ndatums *
1607 michael 810 ECB : sizeof(PartitionRangeDatumKind *));
614 drowley 811 GIC 3254 : boundinfo->interleaved_parts = NULL;
812 :
813 : /*
814 : * For range partitioning, an additional value of -1 is stored as the last
815 : * element of the indexes[] array.
816 : */
801 tgl 817 3254 : boundinfo->nindexes = ndatums + 1;
1607 michael 818 CBC 3254 : boundinfo->indexes = (int *) palloc((ndatums + 1) * sizeof(int));
1607 michael 819 ECB :
642 drowley 820 : /*
821 : * In the loop below, to save from allocating a series of small arrays,
822 : * here we just allocate a single array for Datums and another for
823 : * PartitionRangeDatumKinds, below we'll just assign a portion of these
824 : * arrays in each loop.
825 : */
642 drowley 826 GIC 3254 : partnatts = key->partnatts;
642 drowley 827 CBC 3254 : boundDatums = (Datum *) palloc(ndatums * partnatts * sizeof(Datum));
828 3254 : boundKinds = (PartitionRangeDatumKind *) palloc(ndatums * partnatts *
642 drowley 829 ECB : sizeof(PartitionRangeDatumKind));
830 :
1607 michael 831 CBC 13143 : for (i = 0; i < ndatums; i++)
1607 michael 832 ECB : {
833 : int j;
834 :
642 drowley 835 CBC 9889 : boundinfo->datums[i] = &boundDatums[i * partnatts];
836 9889 : boundinfo->kind[i] = &boundKinds[i * partnatts];
642 drowley 837 GIC 22542 : for (j = 0; j < partnatts; j++)
838 : {
1607 michael 839 12653 : if (rbounds[i]->kind[j] == PARTITION_RANGE_DATUM_VALUE)
840 11412 : boundinfo->datums[i][j] =
841 11412 : datumCopy(rbounds[i]->datums[j],
842 11412 : key->parttypbyval[j],
843 11412 : key->parttyplen[j]);
844 12653 : boundinfo->kind[i][j] = rbounds[i]->kind[j];
845 : }
846 :
1607 michael 847 ECB : /*
848 : * There is no mapping for invalid indexes.
849 : *
850 : * Any lower bounds in the rbounds array have invalid indexes
851 : * assigned, because the values between the previous bound (if there
852 : * is one) and this (lower) bound are not part of the range of any
853 : * existing partition.
854 : */
1607 michael 855 CBC 9889 : if (rbounds[i]->lower)
1607 michael 856 GIC 3573 : boundinfo->indexes[i] = -1;
1607 michael 857 ECB : else
858 : {
1607 michael 859 GIC 6316 : int orig_index = rbounds[i]->index;
860 :
1607 michael 861 ECB : /* If the old index has no mapping, assign one */
1607 michael 862 GIC 6316 : if ((*mapping)[orig_index] == -1)
863 6316 : (*mapping)[orig_index] = next_index++;
1607 michael 864 ECB :
1607 michael 865 GIC 6316 : boundinfo->indexes[i] = (*mapping)[orig_index];
1607 michael 866 ECB : }
867 : }
868 :
642 drowley 869 GIC 3254 : pfree(rbounds);
870 :
871 : /* Set the canonical value for default_index, if any. */
1607 michael 872 CBC 3254 : if (default_index != -1)
1607 michael 873 ECB : {
1607 michael 874 GIC 380 : Assert(default_index >= 0 && (*mapping)[default_index] == -1);
875 380 : (*mapping)[default_index] = next_index++;
1607 michael 876 CBC 380 : boundinfo->default_index = (*mapping)[default_index];
1607 michael 877 ECB : }
878 :
879 : /* The extra -1 element. */
1607 michael 880 GIC 3254 : Assert(i == ndatums);
881 3254 : boundinfo->indexes[i] = -1;
882 :
883 : /* All partitions must now have been assigned canonical indexes. */
884 3254 : Assert(next_index == nparts);
885 3254 : return boundinfo;
886 : }
887 :
888 : /*
1821 alvherre 889 ECB : * Are two partition bound collections logically equal?
890 : *
891 : * Used in the keep logic of relcache.c (ie, in RelationClearRelation()).
892 : * This is also useful when b1 and b2 are bound collections of two separate
893 : * relations, respectively, because PartitionBoundInfo is a canonical
894 : * representation of partition bounds.
1821 alvherre 895 EUB : */
896 : bool
1821 alvherre 897 CBC 726 : partition_bounds_equal(int partnatts, int16 *parttyplen, bool *parttypbyval,
1821 alvherre 898 ECB : PartitionBoundInfo b1, PartitionBoundInfo b2)
899 : {
900 : int i;
1821 alvherre 901 EUB :
1821 alvherre 902 GIC 726 : if (b1->strategy != b2->strategy)
1821 alvherre 903 LBC 0 : return false;
1821 alvherre 904 ECB :
1821 alvherre 905 GIC 726 : if (b1->ndatums != b2->ndatums)
1821 alvherre 906 CBC 111 : return false;
1821 alvherre 907 EUB :
801 tgl 908 GIC 615 : if (b1->nindexes != b2->nindexes)
801 tgl 909 UIC 0 : return false;
801 tgl 910 ECB :
1821 alvherre 911 GIC 615 : if (b1->null_index != b2->null_index)
1821 alvherre 912 CBC 36 : return false;
1821 alvherre 913 ECB :
1821 alvherre 914 GIC 579 : if (b1->default_index != b2->default_index)
1821 alvherre 915 UIC 0 : return false;
916 :
801 tgl 917 ECB : /* For all partition strategies, the indexes[] arrays have to match */
801 tgl 918 GIC 3487 : for (i = 0; i < b1->nindexes; i++)
919 : {
920 2932 : if (b1->indexes[i] != b2->indexes[i])
1821 alvherre 921 24 : return false;
922 : }
923 :
924 : /* Finally, compare the datums[] arrays */
801 tgl 925 555 : if (b1->strategy == PARTITION_STRATEGY_HASH)
926 : {
927 : /*
928 : * We arrange the partitions in the ascending order of their moduli
929 : * and remainders. Also every modulus is factor of next larger
930 : * modulus. Therefore we can safely store index of a given partition
931 : * in indexes array at remainder of that partition. Also entries at
932 : * (remainder + N * modulus) positions in indexes array are all same
933 : * for (modulus, remainder) specification for any partition. Thus the
934 : * datums arrays from the given bounds are the same, if and only if
801 tgl 935 ECB : * their indexes arrays are the same. So, it suffices to compare the
936 : * indexes arrays.
937 : *
938 : * Nonetheless make sure that the bounds are indeed the same when the
939 : * indexes match. Hash partition bound stores modulus and remainder
940 : * at b1->datums[i][0] and b1->datums[i][1] position respectively.
941 : */
942 : #ifdef USE_ASSERT_CHECKING
1821 alvherre 943 GIC 96 : for (i = 0; i < b1->ndatums; i++)
944 72 : Assert((b1->datums[i][0] == b2->datums[i][0] &&
945 : b1->datums[i][1] == b2->datums[i][1]));
1821 alvherre 946 ECB : #endif
947 : }
948 : else
949 : {
1821 alvherre 950 GIC 2482 : for (i = 0; i < b1->ndatums; i++)
951 : {
1821 alvherre 952 ECB : int j;
1821 alvherre 953 EUB :
1821 alvherre 954 GIC 4019 : for (j = 0; j < partnatts; j++)
955 : {
956 : /* For range partitions, the bounds might not be finite. */
957 2068 : if (b1->kind != NULL)
958 : {
1821 alvherre 959 ECB : /* The different kinds of bound all differ from each other */
1821 alvherre 960 GBC 1531 : if (b1->kind[i][j] != b2->kind[i][j])
1821 alvherre 961 UIC 0 : return false;
962 :
963 : /*
964 : * Non-finite bounds are equal without further
965 : * examination.
966 : */
1821 alvherre 967 GIC 1531 : if (b1->kind[i][j] != PARTITION_RANGE_DATUM_VALUE)
1821 alvherre 968 UIC 0 : continue;
969 : }
970 :
971 : /*
972 : * Compare the actual values. Note that it would be both
973 : * incorrect and unsafe to invoke the comparison operator
974 : * derived from the partitioning specification here. It would
975 : * be incorrect because we want the relcache entry to be
1821 alvherre 976 ECB : * updated for ANY change to the partition bounds, not just
977 : * those that the partitioning operator thinks are
978 : * significant. It would be unsafe because we might reach
979 : * this code in the context of an aborted transaction, and an
980 : * arbitrary partitioning operator might not be safe in that
981 : * context. datumIsEqual() should be simple enough to be
982 : * safe.
983 : */
1821 alvherre 984 GIC 2068 : if (!datumIsEqual(b1->datums[i][j], b2->datums[i][j],
985 2068 : parttypbyval[j], parttyplen[j]))
986 93 : return false;
987 : }
988 : }
989 : }
990 462 : return true;
991 : }
992 :
993 : /*
994 : * Return a copy of given PartitionBoundInfo structure. The data types of bounds
1821 alvherre 995 ECB : * are described by given partition key specification.
996 : *
997 : * Note: it's important that this function and its callees not do any catalog
998 : * access, nor anything else that would result in allocating memory other than
999 : * the returned data structure. Since this is called in a long-lived context,
1000 : * that would result in unwanted memory leaks.
1001 : */
1002 : PartitionBoundInfo
1821 alvherre 1003 GIC 7269 : partition_bounds_copy(PartitionBoundInfo src,
1004 : PartitionKey key)
1005 : {
1006 : PartitionBoundInfo dest;
1821 alvherre 1007 ECB : int i;
1008 : int ndatums;
801 tgl 1009 : int nindexes;
1821 alvherre 1010 : int partnatts;
1143 efujita 1011 : bool hash_part;
1012 : int natts;
1013 : Datum *boundDatums;
1014 :
1821 alvherre 1015 CBC 7269 : dest = (PartitionBoundInfo) palloc(sizeof(PartitionBoundInfoData));
1016 :
1017 7269 : dest->strategy = src->strategy;
1821 alvherre 1018 GIC 7269 : ndatums = dest->ndatums = src->ndatums;
801 tgl 1019 CBC 7269 : nindexes = dest->nindexes = src->nindexes;
1821 alvherre 1020 GIC 7269 : partnatts = key->partnatts;
1021 :
1022 : /* List partitioned tables have only a single partition key. */
1023 7269 : Assert(key->strategy != PARTITION_STRATEGY_LIST || partnatts == 1);
1821 alvherre 1024 ECB :
1821 alvherre 1025 GIC 7269 : dest->datums = (Datum **) palloc(sizeof(Datum *) * ndatums);
1821 alvherre 1026 ECB :
1821 alvherre 1027 GIC 7269 : if (src->kind != NULL)
1028 : {
1029 : PartitionRangeDatumKind *boundKinds;
1030 :
1031 : /* only RANGE partition should have a non-NULL kind */
642 drowley 1032 3254 : Assert(key->strategy == PARTITION_STRATEGY_RANGE);
1033 :
1821 alvherre 1034 CBC 3254 : dest->kind = (PartitionRangeDatumKind **) palloc(ndatums *
1035 : sizeof(PartitionRangeDatumKind *));
1036 :
642 drowley 1037 ECB : /*
1038 : * In the loop below, to save from allocating a series of small arrays
1039 : * for storing the PartitionRangeDatumKind, we allocate a single chunk
1040 : * here and use a smaller portion of it for each datum.
1041 : */
642 drowley 1042 GIC 3254 : boundKinds = (PartitionRangeDatumKind *) palloc(ndatums * partnatts *
1043 : sizeof(PartitionRangeDatumKind));
1044 :
1821 alvherre 1045 CBC 13143 : for (i = 0; i < ndatums; i++)
1046 : {
642 drowley 1047 GIC 9889 : dest->kind[i] = &boundKinds[i * partnatts];
1821 alvherre 1048 CBC 9889 : memcpy(dest->kind[i], src->kind[i],
1049 : sizeof(PartitionRangeDatumKind) * partnatts);
1050 : }
1051 : }
1052 : else
1821 alvherre 1053 GIC 4015 : dest->kind = NULL;
1821 alvherre 1054 ECB :
614 drowley 1055 : /* copy interleaved partitions for LIST partitioned tables */
614 drowley 1056 CBC 7269 : dest->interleaved_parts = bms_copy(src->interleaved_parts);
1057 :
1143 efujita 1058 ECB : /*
1059 : * For hash partitioning, datums array will have two elements - modulus
1060 : * and remainder.
1061 : */
1143 efujita 1062 CBC 7269 : hash_part = (key->strategy == PARTITION_STRATEGY_HASH);
1143 efujita 1063 GIC 7269 : natts = hash_part ? 2 : partnatts;
642 drowley 1064 CBC 7269 : boundDatums = palloc(ndatums * natts * sizeof(Datum));
1065 :
1821 alvherre 1066 GIC 27813 : for (i = 0; i < ndatums; i++)
1067 : {
1068 : int j;
1821 alvherre 1069 ECB :
642 drowley 1070 GIC 20544 : dest->datums[i] = &boundDatums[i * natts];
1821 alvherre 1071 ECB :
1821 alvherre 1072 CBC 44543 : for (j = 0; j < natts; j++)
1073 : {
1074 : bool byval;
1075 : int typlen;
1821 alvherre 1076 ECB :
1821 alvherre 1077 CBC 23999 : if (hash_part)
1078 : {
1821 alvherre 1079 GIC 1382 : typlen = sizeof(int32); /* Always int4 */
1821 alvherre 1080 CBC 1382 : byval = true; /* int4 is pass-by-value */
1821 alvherre 1081 ECB : }
1082 : else
1083 : {
1821 alvherre 1084 GIC 22617 : byval = key->parttypbyval[j];
1085 22617 : typlen = key->parttyplen[j];
1086 : }
1821 alvherre 1087 ECB :
1821 alvherre 1088 CBC 23999 : if (dest->kind == NULL ||
1821 alvherre 1089 GIC 12653 : dest->kind[i][j] == PARTITION_RANGE_DATUM_VALUE)
1821 alvherre 1090 CBC 22758 : dest->datums[i][j] = datumCopy(src->datums[i][j],
1821 alvherre 1091 ECB : byval, typlen);
1092 : }
1093 : }
1094 :
801 tgl 1095 GIC 7269 : dest->indexes = (int *) palloc(sizeof(int) * nindexes);
1096 7269 : memcpy(dest->indexes, src->indexes, sizeof(int) * nindexes);
1097 :
1821 alvherre 1098 7269 : dest->null_index = src->null_index;
1099 7269 : dest->default_index = src->default_index;
1100 :
1101 7269 : return dest;
1102 : }
1103 :
1104 : /*
1105 : * partition_bounds_merge
1106 : * Check to see whether every partition of 'outer_rel' matches/overlaps
1107 : * one partition of 'inner_rel' at most, and vice versa; and if so, build
1108 : * and return the partition bounds for a join relation between the rels,
1109 : * generating two lists of the matching/overlapping partitions, which are
1110 : * returned to *outer_parts and *inner_parts respectively.
1096 efujita 1111 ECB : *
1112 : * The lists contain the same number of partitions, and the partitions at the
1113 : * same positions in the lists indicate join pairs used for partitioned join.
1114 : * If a partition on one side matches/overlaps multiple partitions on the other
1115 : * side, this function returns NULL, setting *outer_parts and *inner_parts to
1116 : * NIL.
1117 : */
1118 : PartitionBoundInfo
1096 efujita 1119 GIC 423 : partition_bounds_merge(int partnatts,
1120 : FmgrInfo *partsupfunc, Oid *partcollation,
1096 efujita 1121 ECB : RelOptInfo *outer_rel, RelOptInfo *inner_rel,
1122 : JoinType jointype,
1123 : List **outer_parts, List **inner_parts)
1124 : {
1125 : /*
1126 : * Currently, this function is called only from try_partitionwise_join(),
1127 : * so the join type should be INNER, LEFT, FULL, SEMI, or ANTI.
1128 : */
1096 efujita 1129 CBC 423 : Assert(jointype == JOIN_INNER || jointype == JOIN_LEFT ||
1130 : jointype == JOIN_FULL || jointype == JOIN_SEMI ||
1096 efujita 1131 EUB : jointype == JOIN_ANTI);
1132 :
1133 : /* The partitioning strategies should be the same. */
941 efujita 1134 GIC 423 : Assert(outer_rel->boundinfo->strategy == inner_rel->boundinfo->strategy);
1135 :
1096 1136 423 : *outer_parts = *inner_parts = NIL;
941 1137 423 : switch (outer_rel->boundinfo->strategy)
1138 : {
1096 efujita 1139 UIC 0 : case PARTITION_STRATEGY_HASH:
1140 :
1141 : /*
1142 : * For hash partitioned tables, we currently support partitioned
1143 : * join only when they have exactly the same partition bounds.
1144 : *
1145 : * XXX: it might be possible to relax the restriction to support
1146 : * cases where hash partitioned tables have missing partitions
1096 efujita 1147 EUB : * and/or different moduli, but it's not clear if it would be
1148 : * useful to support the former case since it's unusual to have
1096 efujita 1149 ECB : * missing partitions. On the other hand, it would be useful to
1150 : * support the latter case, but in that case, there is a high
1151 : * probability that a partition on one side will match multiple
1152 : * partitions on the other side, which is the scenario the current
1153 : * implementation of partitioned join can't handle.
1154 : */
1096 efujita 1155 UIC 0 : return NULL;
1156 :
1096 efujita 1157 GIC 243 : case PARTITION_STRATEGY_LIST:
1096 efujita 1158 CBC 243 : return merge_list_bounds(partsupfunc,
1096 efujita 1159 ECB : partcollation,
1160 : outer_rel,
1161 : inner_rel,
1162 : jointype,
1163 : outer_parts,
1164 : inner_parts);
1165 :
1096 efujita 1166 GIC 180 : case PARTITION_STRATEGY_RANGE:
1167 180 : return merge_range_bounds(partnatts,
1168 : partsupfunc,
1096 efujita 1169 EUB : partcollation,
1170 : outer_rel,
1171 : inner_rel,
1172 : jointype,
1173 : outer_parts,
1174 : inner_parts);
1175 : }
1176 :
157 alvherre 1177 UNC 0 : return NULL;
1178 : }
1179 :
1180 : /*
1181 : * merge_list_bounds
1182 : * Create the partition bounds for a join relation between list
1183 : * partitioned tables, if possible
1184 : *
1185 : * In this function we try to find sets of matching partitions from both sides
1186 : * by comparing list values stored in their partition bounds. Since the list
1187 : * values appear in the ascending order, an algorithm similar to merge join is
1096 efujita 1188 ECB : * used for that. If a partition on one side doesn't have a matching
1189 : * partition on the other side, the algorithm tries to match it with the
1190 : * default partition on the other side if any; if not, the algorithm tries to
1191 : * match it with a dummy partition on the other side if it's on the
1192 : * non-nullable side of an outer join. Also, if both sides have the default
1193 : * partitions, the algorithm tries to match them with each other. We give up
1194 : * if the algorithm finds a partition matching multiple partitions on the
1195 : * other side, which is the scenario the current implementation of partitioned
1196 : * join can't handle.
1197 : */
1198 : static PartitionBoundInfo
1096 efujita 1199 CBC 243 : merge_list_bounds(FmgrInfo *partsupfunc, Oid *partcollation,
1096 efujita 1200 ECB : RelOptInfo *outer_rel, RelOptInfo *inner_rel,
1201 : JoinType jointype,
1202 : List **outer_parts, List **inner_parts)
1203 : {
1096 efujita 1204 GIC 243 : PartitionBoundInfo merged_bounds = NULL;
1205 243 : PartitionBoundInfo outer_bi = outer_rel->boundinfo;
1096 efujita 1206 CBC 243 : PartitionBoundInfo inner_bi = inner_rel->boundinfo;
1207 243 : bool outer_has_default = partition_bound_has_default(outer_bi);
1208 243 : bool inner_has_default = partition_bound_has_default(inner_bi);
1209 243 : int outer_default = outer_bi->default_index;
1210 243 : int inner_default = inner_bi->default_index;
1096 efujita 1211 GIC 243 : bool outer_has_null = partition_bound_accepts_nulls(outer_bi);
1096 efujita 1212 CBC 243 : bool inner_has_null = partition_bound_accepts_nulls(inner_bi);
1096 efujita 1213 ECB : PartitionMap outer_map;
1214 : PartitionMap inner_map;
1215 : int outer_pos;
1216 : int inner_pos;
1096 efujita 1217 CBC 243 : int next_index = 0;
1096 efujita 1218 GIC 243 : int null_index = -1;
1096 efujita 1219 CBC 243 : int default_index = -1;
1220 243 : List *merged_datums = NIL;
1096 efujita 1221 GIC 243 : List *merged_indexes = NIL;
1222 :
1223 243 : Assert(*outer_parts == NIL);
1224 243 : Assert(*inner_parts == NIL);
1225 243 : Assert(outer_bi->strategy == inner_bi->strategy &&
1096 efujita 1226 ECB : outer_bi->strategy == PARTITION_STRATEGY_LIST);
1227 : /* List partitioning doesn't require kinds. */
1096 efujita 1228 CBC 243 : Assert(!outer_bi->kind && !inner_bi->kind);
1096 efujita 1229 EUB :
1096 efujita 1230 GIC 243 : init_partition_map(outer_rel, &outer_map);
1231 243 : init_partition_map(inner_rel, &inner_map);
1232 :
1233 : /*
1234 : * If the default partitions (if any) have been proven empty, deem them
1235 : * non-existent.
1236 : */
1237 243 : if (outer_has_default && is_dummy_partition(outer_rel, outer_default))
1096 efujita 1238 CBC 12 : outer_has_default = false;
1239 243 : if (inner_has_default && is_dummy_partition(inner_rel, inner_default))
1096 efujita 1240 UIC 0 : inner_has_default = false;
1096 efujita 1241 ECB :
1242 : /*
1243 : * Merge partitions from both sides. In each iteration we compare a pair
1244 : * of list values, one from each side, and decide whether the
1245 : * corresponding partitions match or not. If the two values match
1060 tgl 1246 : * exactly, move to the next pair of list values, otherwise move to the
1247 : * next list value on the side with a smaller list value.
1248 : */
1096 efujita 1249 CBC 243 : outer_pos = inner_pos = 0;
1096 efujita 1250 GIC 1911 : while (outer_pos < outer_bi->ndatums || inner_pos < inner_bi->ndatums)
1251 : {
1252 1692 : int outer_index = -1;
1253 1692 : int inner_index = -1;
1254 : Datum *outer_datums;
1096 efujita 1255 ECB : Datum *inner_datums;
1256 : int cmpval;
1096 efujita 1257 GIC 1692 : Datum *merged_datum = NULL;
1096 efujita 1258 CBC 1692 : int merged_index = -1;
1096 efujita 1259 ECB :
1096 efujita 1260 GIC 1692 : if (outer_pos < outer_bi->ndatums)
1261 : {
1096 efujita 1262 ECB : /*
1263 : * If the partition on the outer side has been proven empty,
1264 : * ignore it and move to the next datum on the outer side.
1265 : */
1096 efujita 1266 GIC 1668 : outer_index = outer_bi->indexes[outer_pos];
1267 1668 : if (is_dummy_partition(outer_rel, outer_index))
1096 efujita 1268 ECB : {
1096 efujita 1269 CBC 84 : outer_pos++;
1096 efujita 1270 GIC 84 : continue;
1096 efujita 1271 EUB : }
1272 : }
1096 efujita 1273 GIC 1608 : if (inner_pos < inner_bi->ndatums)
1274 : {
1275 : /*
1276 : * If the partition on the inner side has been proven empty,
1060 tgl 1277 ECB : * ignore it and move to the next datum on the inner side.
1096 efujita 1278 : */
1096 efujita 1279 CBC 1608 : inner_index = inner_bi->indexes[inner_pos];
1280 1608 : if (is_dummy_partition(inner_rel, inner_index))
1281 : {
1096 efujita 1282 UIC 0 : inner_pos++;
1283 0 : continue;
1284 : }
1285 : }
1286 :
1287 : /* Get the list values. */
1096 efujita 1288 GIC 3216 : outer_datums = outer_pos < outer_bi->ndatums ?
1289 1608 : outer_bi->datums[outer_pos] : NULL;
1290 3216 : inner_datums = inner_pos < inner_bi->ndatums ?
1096 efujita 1291 CBC 1608 : inner_bi->datums[inner_pos] : NULL;
1096 efujita 1292 ECB :
1293 : /*
1096 efujita 1294 EUB : * We run this loop till both sides finish. This allows us to avoid
1295 : * duplicating code to handle the remaining values on the side which
1296 : * finishes later. For that we set the comparison parameter cmpval in
1060 tgl 1297 ECB : * such a way that it appears as if the side which finishes earlier
1298 : * has an extra value higher than any other value on the unfinished
1299 : * side. That way we advance the values on the unfinished side till
1300 : * all of its values are exhausted.
1301 : */
1096 efujita 1302 GIC 1608 : if (outer_pos >= outer_bi->ndatums)
1303 24 : cmpval = 1;
1096 efujita 1304 CBC 1584 : else if (inner_pos >= inner_bi->ndatums)
1096 efujita 1305 UIC 0 : cmpval = -1;
1306 : else
1096 efujita 1307 ECB : {
1096 efujita 1308 CBC 1584 : Assert(outer_datums != NULL && inner_datums != NULL);
1309 1584 : cmpval = DatumGetInt32(FunctionCall2Coll(&partsupfunc[0],
1096 efujita 1310 ECB : partcollation[0],
1311 : outer_datums[0],
1312 : inner_datums[0]));
1313 : }
1314 :
1096 efujita 1315 GIC 1608 : if (cmpval == 0)
1096 efujita 1316 ECB : {
1317 : /* Two list values match exactly. */
1096 efujita 1318 GIC 822 : Assert(outer_pos < outer_bi->ndatums);
1096 efujita 1319 CBC 822 : Assert(inner_pos < inner_bi->ndatums);
1320 822 : Assert(outer_index >= 0);
1096 efujita 1321 GIC 822 : Assert(inner_index >= 0);
1096 efujita 1322 ECB :
1323 : /*
1324 : * Try merging both partitions. If successful, add the list value
1325 : * and index of the merged partition below.
1326 : */
1096 efujita 1327 GIC 822 : merged_index = merge_matching_partitions(&outer_map, &inner_map,
1096 efujita 1328 ECB : outer_index, inner_index,
1329 : &next_index);
1096 efujita 1330 GIC 822 : if (merged_index == -1)
1096 efujita 1331 CBC 15 : goto cleanup;
1332 :
1096 efujita 1333 GIC 807 : merged_datum = outer_datums;
1334 :
1335 : /* Move to the next pair of list values. */
1336 807 : outer_pos++;
1337 807 : inner_pos++;
1338 : }
1096 efujita 1339 CBC 786 : else if (cmpval < 0)
1340 : {
1341 : /* A list value missing from the inner side. */
1342 318 : Assert(outer_pos < outer_bi->ndatums);
1096 efujita 1343 ECB :
1344 : /*
1345 : * If the inner side has the default partition, or this is an
1346 : * outer join, try to assign a merged partition to the outer
1347 : * partition (see process_outer_partition()). Otherwise, the
1348 : * outer partition will not contribute to the result.
1349 : */
1096 efujita 1350 GIC 318 : if (inner_has_default || IS_OUTER_JOIN(jointype))
1351 : {
1352 : /* Get the outer partition. */
1096 efujita 1353 CBC 204 : outer_index = outer_bi->indexes[outer_pos];
1354 204 : Assert(outer_index >= 0);
1355 204 : merged_index = process_outer_partition(&outer_map,
1356 : &inner_map,
1357 : outer_has_default,
1358 : inner_has_default,
1096 efujita 1359 ECB : outer_index,
1360 : inner_default,
1361 : jointype,
1362 : &next_index,
1363 : &default_index);
1096 efujita 1364 CBC 204 : if (merged_index == -1)
1365 3 : goto cleanup;
1096 efujita 1366 GIC 201 : merged_datum = outer_datums;
1367 : }
1368 :
1369 : /* Move to the next list value on the outer side. */
1370 315 : outer_pos++;
1371 : }
1372 : else
1096 efujita 1373 ECB : {
1374 : /* A list value missing from the outer side. */
1096 efujita 1375 GIC 468 : Assert(cmpval > 0);
1096 efujita 1376 CBC 468 : Assert(inner_pos < inner_bi->ndatums);
1096 efujita 1377 ECB :
1378 : /*
1379 : * If the outer side has the default partition, or this is a FULL
1380 : * join, try to assign a merged partition to the inner partition
1381 : * (see process_inner_partition()). Otherwise, the inner
1382 : * partition will not contribute to the result.
1383 : */
1096 efujita 1384 GIC 468 : if (outer_has_default || jointype == JOIN_FULL)
1385 : {
1386 : /* Get the inner partition. */
1096 efujita 1387 CBC 126 : inner_index = inner_bi->indexes[inner_pos];
1388 126 : Assert(inner_index >= 0);
1389 126 : merged_index = process_inner_partition(&outer_map,
1390 : &inner_map,
1391 : outer_has_default,
1392 : inner_has_default,
1096 efujita 1393 ECB : inner_index,
1394 : outer_default,
1395 : jointype,
1396 : &next_index,
1397 : &default_index);
1096 efujita 1398 GIC 126 : if (merged_index == -1)
1399 6 : goto cleanup;
1096 efujita 1400 CBC 120 : merged_datum = inner_datums;
1401 : }
1096 efujita 1402 ECB :
1403 : /* Move to the next list value on the inner side. */
1096 efujita 1404 GIC 462 : inner_pos++;
1405 : }
1406 :
1407 : /*
1408 : * If we assigned a merged partition, add the list value and index of
1409 : * the merged partition if appropriate.
1410 : */
1096 efujita 1411 CBC 1584 : if (merged_index >= 0 && merged_index != default_index)
1096 efujita 1412 ECB : {
1096 efujita 1413 GBC 1092 : merged_datums = lappend(merged_datums, merged_datum);
1096 efujita 1414 CBC 1092 : merged_indexes = lappend_int(merged_indexes, merged_index);
1096 efujita 1415 ECB : }
1096 efujita 1416 EUB : }
1417 :
1418 : /*
1096 efujita 1419 ECB : * If the NULL partitions (if any) have been proven empty, deem them
1420 : * non-existent.
1421 : */
1096 efujita 1422 GIC 315 : if (outer_has_null &&
1423 96 : is_dummy_partition(outer_rel, outer_bi->null_index))
1096 efujita 1424 UIC 0 : outer_has_null = false;
1096 efujita 1425 CBC 315 : if (inner_has_null &&
1096 efujita 1426 GIC 96 : is_dummy_partition(inner_rel, inner_bi->null_index))
1096 efujita 1427 UIC 0 : inner_has_null = false;
1096 efujita 1428 ECB :
1429 : /* Merge the NULL partitions if any. */
1096 efujita 1430 GIC 219 : if (outer_has_null || inner_has_null)
1431 108 : merge_null_partitions(&outer_map, &inner_map,
1432 : outer_has_null, inner_has_null,
1433 : outer_bi->null_index, inner_bi->null_index,
1096 efujita 1434 ECB : jointype, &next_index, &null_index);
1435 : else
1096 efujita 1436 GIC 111 : Assert(null_index == -1);
1096 efujita 1437 ECB :
1438 : /* Merge the default partitions if any. */
1096 efujita 1439 GIC 219 : if (outer_has_default || inner_has_default)
1096 efujita 1440 CBC 48 : merge_default_partitions(&outer_map, &inner_map,
1441 : outer_has_default, inner_has_default,
1096 efujita 1442 ECB : outer_default, inner_default,
1443 : jointype, &next_index, &default_index);
1444 : else
1096 efujita 1445 GIC 171 : Assert(default_index == -1);
1446 :
1447 : /* If we have merged partitions, create the partition bounds. */
1096 efujita 1448 CBC 219 : if (next_index > 0)
1449 : {
1450 : /* Fix the merged_indexes list if necessary. */
1096 efujita 1451 GIC 219 : if (outer_map.did_remapping || inner_map.did_remapping)
1096 efujita 1452 ECB : {
1096 efujita 1453 CBC 24 : Assert(jointype == JOIN_FULL);
1454 24 : fix_merged_indexes(&outer_map, &inner_map,
1096 efujita 1455 ECB : next_index, merged_indexes);
1456 : }
1457 :
1458 : /* Use maps to match partitions from inputs. */
1096 efujita 1459 GIC 219 : generate_matching_part_pairs(outer_rel, inner_rel,
1460 : &outer_map, &inner_map,
1461 : next_index,
1462 : outer_parts, inner_parts);
1463 219 : Assert(*outer_parts != NIL);
1096 efujita 1464 CBC 219 : Assert(*inner_parts != NIL);
1096 efujita 1465 GIC 219 : Assert(list_length(*outer_parts) == list_length(*inner_parts));
1466 219 : Assert(list_length(*outer_parts) <= next_index);
1096 efujita 1467 ECB :
1468 : /* Make a PartitionBoundInfo struct to return. */
1096 efujita 1469 CBC 219 : merged_bounds = build_merged_partition_bounds(outer_bi->strategy,
1096 efujita 1470 ECB : merged_datums,
1471 : NIL,
1472 : merged_indexes,
1473 : null_index,
1474 : default_index);
1096 efujita 1475 GIC 219 : Assert(merged_bounds);
1476 : }
1477 :
1478 219 : cleanup:
1479 : /* Free local memory before returning. */
1480 243 : list_free(merged_datums);
1481 243 : list_free(merged_indexes);
1482 243 : free_partition_map(&outer_map);
1483 243 : free_partition_map(&inner_map);
1484 :
1485 243 : return merged_bounds;
1486 : }
1487 :
1488 : /*
1489 : * merge_range_bounds
1490 : * Create the partition bounds for a join relation between range
1491 : * partitioned tables, if possible
1492 : *
1493 : * In this function we try to find sets of overlapping partitions from both
1494 : * sides by comparing ranges stored in their partition bounds. Since the
1495 : * ranges appear in the ascending order, an algorithm similar to merge join is
1096 efujita 1496 ECB : * used for that. If a partition on one side doesn't have an overlapping
1497 : * partition on the other side, the algorithm tries to match it with the
1498 : * default partition on the other side if any; if not, the algorithm tries to
1499 : * match it with a dummy partition on the other side if it's on the
1500 : * non-nullable side of an outer join. Also, if both sides have the default
1501 : * partitions, the algorithm tries to match them with each other. We give up
1502 : * if the algorithm finds a partition overlapping multiple partitions on the
1503 : * other side, which is the scenario the current implementation of partitioned
1504 : * join can't handle.
1505 : */
1506 : static PartitionBoundInfo
1096 efujita 1507 CBC 180 : merge_range_bounds(int partnatts, FmgrInfo *partsupfuncs,
1096 efujita 1508 ECB : Oid *partcollations,
1509 : RelOptInfo *outer_rel, RelOptInfo *inner_rel,
1510 : JoinType jointype,
1511 : List **outer_parts, List **inner_parts)
1512 : {
1096 efujita 1513 GIC 180 : PartitionBoundInfo merged_bounds = NULL;
1514 180 : PartitionBoundInfo outer_bi = outer_rel->boundinfo;
1515 180 : PartitionBoundInfo inner_bi = inner_rel->boundinfo;
1516 180 : bool outer_has_default = partition_bound_has_default(outer_bi);
1517 180 : bool inner_has_default = partition_bound_has_default(inner_bi);
1518 180 : int outer_default = outer_bi->default_index;
1096 efujita 1519 CBC 180 : int inner_default = inner_bi->default_index;
1096 efujita 1520 ECB : PartitionMap outer_map;
1521 : PartitionMap inner_map;
1522 : int outer_index;
1523 : int inner_index;
1524 : int outer_lb_pos;
1525 : int inner_lb_pos;
1526 : PartitionRangeBound outer_lb;
1527 : PartitionRangeBound outer_ub;
1528 : PartitionRangeBound inner_lb;
1529 : PartitionRangeBound inner_ub;
1096 efujita 1530 CBC 180 : int next_index = 0;
1531 180 : int default_index = -1;
1096 efujita 1532 GIC 180 : List *merged_datums = NIL;
1533 180 : List *merged_kinds = NIL;
1534 180 : List *merged_indexes = NIL;
1535 :
1536 180 : Assert(*outer_parts == NIL);
1096 efujita 1537 CBC 180 : Assert(*inner_parts == NIL);
1538 180 : Assert(outer_bi->strategy == inner_bi->strategy &&
1096 efujita 1539 ECB : outer_bi->strategy == PARTITION_STRATEGY_RANGE);
1096 efujita 1540 EUB :
1096 efujita 1541 GIC 180 : init_partition_map(outer_rel, &outer_map);
1542 180 : init_partition_map(inner_rel, &inner_map);
1543 :
1544 : /*
1545 : * If the default partitions (if any) have been proven empty, deem them
1546 : * non-existent.
1547 : */
1548 180 : if (outer_has_default && is_dummy_partition(outer_rel, outer_default))
1549 6 : outer_has_default = false;
1550 180 : if (inner_has_default && is_dummy_partition(inner_rel, inner_default))
1096 efujita 1551 LBC 0 : inner_has_default = false;
1096 efujita 1552 ECB :
1553 : /*
1554 : * Merge partitions from both sides. In each iteration we compare a pair
1555 : * of ranges, one from each side, and decide whether the corresponding
1556 : * partitions match or not. If the two ranges overlap, move to the next
1557 : * pair of ranges, otherwise move to the next range on the side with a
1558 : * lower range. outer_lb_pos/inner_lb_pos keep track of the positions of
1559 : * lower bounds in the datums arrays in the outer/inner
1560 : * PartitionBoundInfos respectively.
1561 : */
1096 efujita 1562 CBC 180 : outer_lb_pos = inner_lb_pos = 0;
1563 180 : outer_index = get_range_partition(outer_rel, outer_bi, &outer_lb_pos,
1564 : &outer_lb, &outer_ub);
1096 efujita 1565 GIC 180 : inner_index = get_range_partition(inner_rel, inner_bi, &inner_lb_pos,
1566 : &inner_lb, &inner_ub);
1567 642 : while (outer_index >= 0 || inner_index >= 0)
1568 : {
1569 : bool overlap;
1570 : int ub_cmpval;
1571 : int lb_cmpval;
1572 495 : PartitionRangeBound merged_lb = {-1, NULL, NULL, true};
1573 495 : PartitionRangeBound merged_ub = {-1, NULL, NULL, false};
1096 efujita 1574 CBC 495 : int merged_index = -1;
1575 :
1096 efujita 1576 ECB : /*
1577 : * We run this loop till both sides finish. This allows us to avoid
1578 : * duplicating code to handle the remaining ranges on the side which
1579 : * finishes later. For that we set the comparison parameter cmpval in
1060 tgl 1580 : * such a way that it appears as if the side which finishes earlier
1581 : * has an extra range higher than any other range on the unfinished
1582 : * side. That way we advance the ranges on the unfinished side till
1583 : * all of its ranges are exhausted.
1096 efujita 1584 : */
1096 efujita 1585 GIC 495 : if (outer_index == -1)
1586 : {
1096 efujita 1587 CBC 45 : overlap = false;
1096 efujita 1588 GIC 45 : lb_cmpval = 1;
1589 45 : ub_cmpval = 1;
1590 : }
1591 450 : else if (inner_index == -1)
1592 : {
1096 efujita 1593 CBC 18 : overlap = false;
1096 efujita 1594 GIC 18 : lb_cmpval = -1;
1595 18 : ub_cmpval = -1;
1596 : }
1597 : else
1598 432 : overlap = compare_range_partitions(partnatts, partsupfuncs,
1599 : partcollations,
1600 : &outer_lb, &outer_ub,
1096 efujita 1601 ECB : &inner_lb, &inner_ub,
1602 : &lb_cmpval, &ub_cmpval);
1603 :
1096 efujita 1604 CBC 495 : if (overlap)
1096 efujita 1605 ECB : {
1606 : /* Two ranges overlap; form a join pair. */
1607 :
1608 : PartitionRangeBound save_outer_ub;
1609 : PartitionRangeBound save_inner_ub;
1610 :
1611 : /* Both partitions should not have been merged yet. */
1096 efujita 1612 CBC 414 : Assert(outer_index >= 0);
1096 efujita 1613 GIC 414 : Assert(outer_map.merged_indexes[outer_index] == -1 &&
1614 : outer_map.merged[outer_index] == false);
1096 efujita 1615 CBC 414 : Assert(inner_index >= 0);
1096 efujita 1616 GIC 414 : Assert(inner_map.merged_indexes[inner_index] == -1 &&
1617 : inner_map.merged[inner_index] == false);
1096 efujita 1618 ECB :
1619 : /*
1620 : * Get the index of the merged partition. Both partitions aren't
1621 : * merged yet, so the partitions should be merged successfully.
1622 : */
1096 efujita 1623 GIC 414 : merged_index = merge_matching_partitions(&outer_map, &inner_map,
1624 : outer_index, inner_index,
1625 : &next_index);
1096 efujita 1626 CBC 414 : Assert(merged_index >= 0);
1096 efujita 1627 ECB :
1628 : /* Get the range bounds of the merged partition. */
1096 efujita 1629 GIC 414 : get_merged_range_bounds(partnatts, partsupfuncs,
1096 efujita 1630 ECB : partcollations, jointype,
1631 : &outer_lb, &outer_ub,
1632 : &inner_lb, &inner_ub,
1633 : lb_cmpval, ub_cmpval,
1634 : &merged_lb, &merged_ub);
1635 :
1636 : /* Save the upper bounds of both partitions for use below. */
1096 efujita 1637 GIC 414 : save_outer_ub = outer_ub;
1638 414 : save_inner_ub = inner_ub;
1639 :
1640 : /* Move to the next pair of ranges. */
1641 414 : outer_index = get_range_partition(outer_rel, outer_bi, &outer_lb_pos,
1096 efujita 1642 ECB : &outer_lb, &outer_ub);
1096 efujita 1643 CBC 414 : inner_index = get_range_partition(inner_rel, inner_bi, &inner_lb_pos,
1644 : &inner_lb, &inner_ub);
1096 efujita 1645 ECB :
1646 : /*
1647 : * If the range of a partition on one side overlaps the range of
1648 : * the next partition on the other side, that will cause the
1649 : * partition on one side to match at least two partitions on the
1650 : * other side, which is the case that we currently don't support
1651 : * partitioned join for; give up.
1652 : */
1096 efujita 1653 GIC 516 : if (ub_cmpval > 0 && inner_index >= 0 &&
1654 102 : compare_range_bounds(partnatts, partsupfuncs, partcollations,
1655 : &save_outer_ub, &inner_lb) > 0)
1656 30 : goto cleanup;
1096 efujita 1657 CBC 429 : if (ub_cmpval < 0 && outer_index >= 0 &&
1658 33 : compare_range_bounds(partnatts, partsupfuncs, partcollations,
1096 efujita 1659 ECB : &outer_lb, &save_inner_ub) < 0)
1096 efujita 1660 GIC 9 : goto cleanup;
1096 efujita 1661 ECB :
1662 : /*
1663 : * A row from a non-overlapping portion (if any) of a partition on
1664 : * one side might find its join partner in the default partition
1665 : * (if any) on the other side, causing the same situation as
1060 tgl 1666 : * above; give up in that case.
1096 efujita 1667 : */
1096 efujita 1668 GIC 387 : if ((outer_has_default && (lb_cmpval > 0 || ub_cmpval < 0)) ||
1669 12 : (inner_has_default && (lb_cmpval < 0 || ub_cmpval > 0)))
1670 3 : goto cleanup;
1671 : }
1672 81 : else if (ub_cmpval < 0)
1673 : {
1674 : /* A non-overlapping outer range. */
1675 :
1096 efujita 1676 ECB : /* The outer partition should not have been merged yet. */
1096 efujita 1677 GIC 18 : Assert(outer_index >= 0);
1096 efujita 1678 CBC 18 : Assert(outer_map.merged_indexes[outer_index] == -1 &&
1679 : outer_map.merged[outer_index] == false);
1680 :
1681 : /*
1682 : * If the inner side has the default partition, or this is an
1683 : * outer join, try to assign a merged partition to the outer
1684 : * partition (see process_outer_partition()). Otherwise, the
1685 : * outer partition will not contribute to the result.
1686 : */
1687 18 : if (inner_has_default || IS_OUTER_JOIN(jointype))
1096 efujita 1688 EUB : {
1096 efujita 1689 CBC 12 : merged_index = process_outer_partition(&outer_map,
1096 efujita 1690 ECB : &inner_map,
1691 : outer_has_default,
1692 : inner_has_default,
1693 : outer_index,
1694 : inner_default,
1695 : jointype,
1696 : &next_index,
1697 : &default_index);
1096 efujita 1698 GIC 12 : if (merged_index == -1)
1096 efujita 1699 UIC 0 : goto cleanup;
1096 efujita 1700 CBC 12 : merged_lb = outer_lb;
1096 efujita 1701 GIC 12 : merged_ub = outer_ub;
1702 : }
1096 efujita 1703 ECB :
1704 : /* Move to the next range on the outer side. */
1096 efujita 1705 GIC 18 : outer_index = get_range_partition(outer_rel, outer_bi, &outer_lb_pos,
1706 : &outer_lb, &outer_ub);
1707 : }
1708 : else
1709 : {
1710 : /* A non-overlapping inner range. */
1711 63 : Assert(ub_cmpval > 0);
1712 :
1096 efujita 1713 ECB : /* The inner partition should not have been merged yet. */
1096 efujita 1714 GIC 63 : Assert(inner_index >= 0);
1096 efujita 1715 CBC 63 : Assert(inner_map.merged_indexes[inner_index] == -1 &&
1716 : inner_map.merged[inner_index] == false);
1717 :
1718 : /*
1719 : * If the outer side has the default partition, or this is a FULL
1720 : * join, try to assign a merged partition to the inner partition
1721 : * (see process_inner_partition()). Otherwise, the inner
1722 : * partition will not contribute to the result.
1723 : */
1724 63 : if (outer_has_default || jointype == JOIN_FULL)
1096 efujita 1725 ECB : {
1096 efujita 1726 CBC 33 : merged_index = process_inner_partition(&outer_map,
1096 efujita 1727 ECB : &inner_map,
1728 : outer_has_default,
1729 : inner_has_default,
1730 : inner_index,
1731 : outer_default,
1732 : jointype,
1733 : &next_index,
1734 : &default_index);
1096 efujita 1735 GIC 33 : if (merged_index == -1)
1736 3 : goto cleanup;
1737 30 : merged_lb = inner_lb;
1738 30 : merged_ub = inner_ub;
1096 efujita 1739 ECB : }
1740 :
1741 : /* Move to the next range on the inner side. */
1096 efujita 1742 GIC 60 : inner_index = get_range_partition(inner_rel, inner_bi, &inner_lb_pos,
1743 : &inner_lb, &inner_ub);
1744 : }
1745 :
1746 : /*
1060 tgl 1747 ECB : * If we assigned a merged partition, add the range bounds and index
1748 : * of the merged partition if appropriate.
1749 : */
1096 efujita 1750 GIC 462 : if (merged_index >= 0 && merged_index != default_index)
1751 408 : add_merged_range_bounds(partnatts, partsupfuncs, partcollations,
1752 : &merged_lb, &merged_ub, merged_index,
1096 efujita 1753 ECB : &merged_datums, &merged_kinds,
1754 : &merged_indexes);
1755 : }
1756 :
1757 : /* Merge the default partitions if any. */
1096 efujita 1758 GIC 147 : if (outer_has_default || inner_has_default)
1759 30 : merge_default_partitions(&outer_map, &inner_map,
1760 : outer_has_default, inner_has_default,
1761 : outer_default, inner_default,
1096 efujita 1762 ECB : jointype, &next_index, &default_index);
1763 : else
1096 efujita 1764 GIC 117 : Assert(default_index == -1);
1765 :
1096 efujita 1766 ECB : /* If we have merged partitions, create the partition bounds. */
1096 efujita 1767 GIC 147 : if (next_index > 0)
1768 : {
1769 : /*
1096 efujita 1770 ECB : * Unlike the case of list partitioning, we wouldn't have re-merged
1771 : * partitions, so did_remapping should be left alone.
1772 : */
1096 efujita 1773 CBC 147 : Assert(!outer_map.did_remapping);
1096 efujita 1774 GIC 147 : Assert(!inner_map.did_remapping);
1775 :
1096 efujita 1776 ECB : /* Use maps to match partitions from inputs. */
1096 efujita 1777 GIC 147 : generate_matching_part_pairs(outer_rel, inner_rel,
1778 : &outer_map, &inner_map,
1779 : next_index,
1780 : outer_parts, inner_parts);
1781 147 : Assert(*outer_parts != NIL);
1096 efujita 1782 CBC 147 : Assert(*inner_parts != NIL);
1096 efujita 1783 GIC 147 : Assert(list_length(*outer_parts) == list_length(*inner_parts));
1784 147 : Assert(list_length(*outer_parts) == next_index);
1096 efujita 1785 ECB :
1786 : /* Make a PartitionBoundInfo struct to return. */
1096 efujita 1787 CBC 147 : merged_bounds = build_merged_partition_bounds(outer_bi->strategy,
1096 efujita 1788 ECB : merged_datums,
1789 : merged_kinds,
1790 : merged_indexes,
1791 : -1,
1792 : default_index);
1096 efujita 1793 CBC 147 : Assert(merged_bounds);
1794 : }
1795 :
1096 efujita 1796 GIC 147 : cleanup:
1797 : /* Free local memory before returning. */
1798 180 : list_free(merged_datums);
1799 180 : list_free(merged_kinds);
1800 180 : list_free(merged_indexes);
1096 efujita 1801 CBC 180 : free_partition_map(&outer_map);
1096 efujita 1802 GIC 180 : free_partition_map(&inner_map);
1096 efujita 1803 ECB :
1096 efujita 1804 GIC 180 : return merged_bounds;
1805 : }
1096 efujita 1806 ECB :
1807 : /*
1808 : * init_partition_map
1809 : * Initialize a PartitionMap struct for given relation
1810 : */
1811 : static void
1096 efujita 1812 GIC 846 : init_partition_map(RelOptInfo *rel, PartitionMap *map)
1096 efujita 1813 ECB : {
1096 efujita 1814 CBC 846 : int nparts = rel->nparts;
1815 : int i;
1096 efujita 1816 ECB :
1096 efujita 1817 GIC 846 : map->nparts = nparts;
1818 846 : map->merged_indexes = (int *) palloc(sizeof(int) * nparts);
1819 846 : map->merged = (bool *) palloc(sizeof(bool) * nparts);
1820 846 : map->did_remapping = false;
1821 846 : map->old_indexes = (int *) palloc(sizeof(int) * nparts);
1096 efujita 1822 CBC 3435 : for (i = 0; i < nparts; i++)
1823 : {
1824 2589 : map->merged_indexes[i] = map->old_indexes[i] = -1;
1825 2589 : map->merged[i] = false;
1096 efujita 1826 ECB : }
1096 efujita 1827 CBC 846 : }
1828 :
1829 : /*
1830 : * free_partition_map
1831 : */
1832 : static void
1833 846 : free_partition_map(PartitionMap *map)
1834 : {
1096 efujita 1835 GIC 846 : pfree(map->merged_indexes);
1836 846 : pfree(map->merged);
1096 efujita 1837 CBC 846 : pfree(map->old_indexes);
1838 846 : }
1096 efujita 1839 ECB :
1840 : /*
1841 : * is_dummy_partition --- has partition been proven empty?
1842 : */
1843 : static bool
1096 efujita 1844 GIC 4572 : is_dummy_partition(RelOptInfo *rel, int part_index)
1845 : {
1846 : RelOptInfo *part_rel;
1847 :
1848 4572 : Assert(part_index >= 0);
1849 4572 : part_rel = rel->part_rels[part_index];
1850 4572 : if (part_rel == NULL || IS_DUMMY_REL(part_rel))
1851 126 : return true;
1096 efujita 1852 CBC 4446 : return false;
1853 : }
1854 :
1855 : /*
1856 : * merge_matching_partitions
1857 : * Try to merge given outer/inner partitions, and return the index of a
1858 : * merged partition produced from them if successful, -1 otherwise
1859 : *
1096 efujita 1860 ECB : * If the merged partition is newly created, *next_index is incremented.
1861 : */
1862 : static int
1096 efujita 1863 CBC 1359 : merge_matching_partitions(PartitionMap *outer_map, PartitionMap *inner_map,
1096 efujita 1864 ECB : int outer_index, int inner_index, int *next_index)
1865 : {
1866 : int outer_merged_index;
1867 : int inner_merged_index;
1868 : bool outer_merged;
1869 : bool inner_merged;
1870 :
1096 efujita 1871 CBC 1359 : Assert(outer_index >= 0 && outer_index < outer_map->nparts);
1096 efujita 1872 GIC 1359 : outer_merged_index = outer_map->merged_indexes[outer_index];
1873 1359 : outer_merged = outer_map->merged[outer_index];
1874 1359 : Assert(inner_index >= 0 && inner_index < inner_map->nparts);
1875 1359 : inner_merged_index = inner_map->merged_indexes[inner_index];
1876 1359 : inner_merged = inner_map->merged[inner_index];
1877 :
1878 : /*
1879 : * Handle cases where we have already assigned a merged partition to each
1096 efujita 1880 ECB : * of the given partitions.
1881 : */
1096 efujita 1882 CBC 1359 : if (outer_merged_index >= 0 && inner_merged_index >= 0)
1096 efujita 1883 ECB : {
1884 : /*
1885 : * If the merged partitions are the same, no need to do anything;
1886 : * return the index of the merged partitions. Otherwise, if each of
1887 : * the given partitions has been merged with a dummy partition on the
1888 : * other side, re-map them to either of the two merged partitions.
1889 : * Otherwise, they can't be merged, so return -1.
1890 : */
1096 efujita 1891 GIC 330 : if (outer_merged_index == inner_merged_index)
1892 : {
1893 276 : Assert(outer_merged);
1894 276 : Assert(inner_merged);
1096 efujita 1895 CBC 276 : return outer_merged_index;
1896 : }
1897 54 : if (!outer_merged && !inner_merged)
1096 efujita 1898 ECB : {
1899 : /*
1900 : * This can only happen for a list-partitioning case. We re-map
1901 : * them to the merged partition with the smaller of the two merged
1902 : * indexes to preserve the property that the canonical order of
1903 : * list partitions is determined by the indexes assigned to the
1904 : * smallest list value of each partition.
1905 : */
1096 efujita 1906 CBC 51 : if (outer_merged_index < inner_merged_index)
1096 efujita 1907 ECB : {
1096 efujita 1908 CBC 27 : outer_map->merged[outer_index] = true;
1909 27 : inner_map->merged_indexes[inner_index] = outer_merged_index;
1910 27 : inner_map->merged[inner_index] = true;
1911 27 : inner_map->did_remapping = true;
1096 efujita 1912 GIC 27 : inner_map->old_indexes[inner_index] = inner_merged_index;
1913 27 : return outer_merged_index;
1096 efujita 1914 ECB : }
1915 : else
1916 : {
1096 efujita 1917 GIC 24 : inner_map->merged[inner_index] = true;
1096 efujita 1918 CBC 24 : outer_map->merged_indexes[outer_index] = inner_merged_index;
1096 efujita 1919 GIC 24 : outer_map->merged[outer_index] = true;
1920 24 : outer_map->did_remapping = true;
1921 24 : outer_map->old_indexes[outer_index] = outer_merged_index;
1922 24 : return inner_merged_index;
1923 : }
1924 : }
1925 3 : return -1;
1096 efujita 1926 ECB : }
1927 :
1928 : /* At least one of the given partitions should not have yet been merged. */
1096 efujita 1929 GIC 1029 : Assert(outer_merged_index == -1 || inner_merged_index == -1);
1096 efujita 1930 ECB :
1931 : /*
1932 : * If neither of them has been merged, merge them. Otherwise, if one has
941 1933 : * been merged with a dummy partition on the other side (and the other
1096 1934 : * hasn't yet been merged with anything), re-merge them. Otherwise, they
1935 : * can't be merged, so return -1.
1936 : */
1096 efujita 1937 CBC 1029 : if (outer_merged_index == -1 && inner_merged_index == -1)
1938 : {
1060 tgl 1939 879 : int merged_index = *next_index;
1940 :
1096 efujita 1941 879 : Assert(!outer_merged);
1942 879 : Assert(!inner_merged);
1943 879 : outer_map->merged_indexes[outer_index] = merged_index;
1944 879 : outer_map->merged[outer_index] = true;
1945 879 : inner_map->merged_indexes[inner_index] = merged_index;
1946 879 : inner_map->merged[inner_index] = true;
1096 efujita 1947 GIC 879 : *next_index = *next_index + 1;
1096 efujita 1948 CBC 879 : return merged_index;
1949 : }
1096 efujita 1950 GBC 150 : if (outer_merged_index >= 0 && !outer_map->merged[outer_index])
1096 efujita 1951 EUB : {
1096 efujita 1952 GBC 132 : Assert(inner_merged_index == -1);
1953 132 : Assert(!inner_merged);
1954 132 : inner_map->merged_indexes[inner_index] = outer_merged_index;
1955 132 : inner_map->merged[inner_index] = true;
1096 efujita 1956 GIC 132 : outer_map->merged[outer_index] = true;
1096 efujita 1957 CBC 132 : return outer_merged_index;
1958 : }
1096 efujita 1959 GIC 18 : if (inner_merged_index >= 0 && !inner_map->merged[inner_index])
1960 : {
1096 efujita 1961 UIC 0 : Assert(outer_merged_index == -1);
1962 0 : Assert(!outer_merged);
1963 0 : outer_map->merged_indexes[outer_index] = inner_merged_index;
1964 0 : outer_map->merged[outer_index] = true;
1965 0 : inner_map->merged[inner_index] = true;
1966 0 : return inner_merged_index;
1967 : }
1096 efujita 1968 GIC 18 : return -1;
1969 : }
1096 efujita 1970 ECB :
1971 : /*
1972 : * process_outer_partition
1973 : * Try to assign given outer partition a merged partition, and return the
1974 : * index of the merged partition if successful, -1 otherwise
1975 : *
1976 : * If the partition is newly created, *next_index is incremented. Also, if it
1977 : * is the default partition of the join relation, *default_index is set to the
1978 : * index if not already done.
1979 : */
1980 : static int
1096 efujita 1981 GIC 216 : process_outer_partition(PartitionMap *outer_map,
1096 efujita 1982 ECB : PartitionMap *inner_map,
1983 : bool outer_has_default,
1984 : bool inner_has_default,
1985 : int outer_index,
1986 : int inner_default,
1987 : JoinType jointype,
1988 : int *next_index,
1989 : int *default_index)
1990 : {
1060 tgl 1991 GIC 216 : int merged_index = -1;
1096 efujita 1992 ECB :
1096 efujita 1993 GIC 216 : Assert(outer_index >= 0);
1096 efujita 1994 ECB :
1995 : /*
1996 : * If the inner side has the default partition, a row from the outer
1997 : * partition might find its join partner in the default partition; try
1998 : * merging the outer partition with the default partition. Otherwise,
1999 : * this should be an outer join, in which case the outer partition has to
2000 : * be scanned all the way anyway; merge the outer partition with a dummy
2001 : * partition on the other side.
2002 : */
1096 efujita 2003 CBC 216 : if (inner_has_default)
1096 efujita 2004 EUB : {
1096 efujita 2005 GIC 3 : Assert(inner_default >= 0);
1096 efujita 2006 ECB :
2007 : /*
2008 : * If the outer side has the default partition as well, the default
1060 tgl 2009 : * partition on the inner side will have two matching partitions on
2010 : * the other side: the outer partition and the default partition on
2011 : * the outer side. Partitionwise join doesn't handle this scenario
2012 : * yet.
2013 : */
1096 efujita 2014 GIC 3 : if (outer_has_default)
1096 efujita 2015 UIC 0 : return -1;
2016 :
1096 efujita 2017 GIC 3 : merged_index = merge_matching_partitions(outer_map, inner_map,
2018 : outer_index, inner_default,
2019 : next_index);
1096 efujita 2020 GBC 3 : if (merged_index == -1)
1096 efujita 2021 GIC 3 : return -1;
1096 efujita 2022 EUB :
2023 : /*
2024 : * If this is a FULL join, the default partition on the inner side has
1060 tgl 2025 : * to be scanned all the way anyway, so the resulting partition will
2026 : * contain all key values from the default partition, which any other
2027 : * partition of the join relation will not contain. Thus the
2028 : * resulting partition will act as the default partition of the join
2029 : * relation; record the index in *default_index if not already done.
1096 efujita 2030 ECB : */
1096 efujita 2031 LBC 0 : if (jointype == JOIN_FULL)
2032 : {
1096 efujita 2033 UIC 0 : if (*default_index == -1)
1096 efujita 2034 LBC 0 : *default_index = merged_index;
1096 efujita 2035 ECB : else
1096 efujita 2036 LBC 0 : Assert(*default_index == merged_index);
2037 : }
2038 : }
1096 efujita 2039 ECB : else
2040 : {
1096 efujita 2041 GIC 213 : Assert(IS_OUTER_JOIN(jointype));
2042 213 : Assert(jointype != JOIN_RIGHT);
2043 :
2044 : /* If we have already assigned a partition, no need to do anything. */
2045 213 : merged_index = outer_map->merged_indexes[outer_index];
2046 213 : if (merged_index == -1)
2047 201 : merged_index = merge_partition_with_dummy(outer_map, outer_index,
2048 : next_index);
2049 : }
2050 213 : return merged_index;
2051 : }
1096 efujita 2052 ECB :
2053 : /*
2054 : * process_inner_partition
2055 : * Try to assign given inner partition a merged partition, and return the
2056 : * index of the merged partition if successful, -1 otherwise
2057 : *
2058 : * If the partition is newly created, *next_index is incremented. Also, if it
2059 : * is the default partition of the join relation, *default_index is set to the
2060 : * index if not already done.
2061 : */
2062 : static int
1096 efujita 2063 GIC 159 : process_inner_partition(PartitionMap *outer_map,
1096 efujita 2064 ECB : PartitionMap *inner_map,
2065 : bool outer_has_default,
2066 : bool inner_has_default,
2067 : int inner_index,
2068 : int outer_default,
2069 : JoinType jointype,
2070 : int *next_index,
2071 : int *default_index)
2072 : {
1060 tgl 2073 GIC 159 : int merged_index = -1;
1096 efujita 2074 ECB :
1096 efujita 2075 GIC 159 : Assert(inner_index >= 0);
1096 efujita 2076 ECB :
2077 : /*
2078 : * If the outer side has the default partition, a row from the inner
2079 : * partition might find its join partner in the default partition; try
2080 : * merging the inner partition with the default partition. Otherwise,
2081 : * this should be a FULL join, in which case the inner partition has to be
2082 : * scanned all the way anyway; merge the inner partition with a dummy
2083 : * partition on the other side.
2084 : */
1096 efujita 2085 CBC 159 : if (outer_has_default)
1096 efujita 2086 ECB : {
1096 efujita 2087 GIC 102 : Assert(outer_default >= 0);
1096 efujita 2088 ECB :
2089 : /*
2090 : * If the inner side has the default partition as well, the default
1060 tgl 2091 : * partition on the outer side will have two matching partitions on
2092 : * the other side: the inner partition and the default partition on
2093 : * the inner side. Partitionwise join doesn't handle this scenario
2094 : * yet.
2095 : */
1096 efujita 2096 GIC 102 : if (inner_has_default)
2097 6 : return -1;
2098 :
2099 96 : merged_index = merge_matching_partitions(outer_map, inner_map,
2100 : outer_default, inner_index,
2101 : next_index);
1096 efujita 2102 CBC 96 : if (merged_index == -1)
1096 efujita 2103 GIC 3 : return -1;
1096 efujita 2104 ECB :
2105 : /*
2106 : * If this is an outer join, the default partition on the outer side
2107 : * has to be scanned all the way anyway, so the resulting partition
2108 : * will contain all key values from the default partition, which any
2109 : * other partition of the join relation will not contain. Thus the
2110 : * resulting partition will act as the default partition of the join
2111 : * relation; record the index in *default_index if not already done.
2112 : */
1096 efujita 2113 CBC 93 : if (IS_OUTER_JOIN(jointype))
2114 : {
1096 efujita 2115 GIC 54 : Assert(jointype != JOIN_RIGHT);
1096 efujita 2116 CBC 54 : if (*default_index == -1)
2117 36 : *default_index = merged_index;
1096 efujita 2118 ECB : else
1096 efujita 2119 GIC 18 : Assert(*default_index == merged_index);
2120 : }
1096 efujita 2121 ECB : }
2122 : else
2123 : {
1096 efujita 2124 GIC 57 : Assert(jointype == JOIN_FULL);
2125 :
2126 : /* If we have already assigned a partition, no need to do anything. */
2127 57 : merged_index = inner_map->merged_indexes[inner_index];
2128 57 : if (merged_index == -1)
2129 57 : merged_index = merge_partition_with_dummy(inner_map, inner_index,
2130 : next_index);
2131 : }
2132 150 : return merged_index;
2133 : }
2134 :
2135 : /*
2136 : * merge_null_partitions
1096 efujita 2137 ECB : * Merge the NULL partitions from a join's outer and inner sides.
2138 : *
2139 : * If the merged partition produced from them is the NULL partition of the join
2140 : * relation, *null_index is set to the index of the merged partition.
2141 : *
2142 : * Note: We assume here that the join clause for a partitioned join is strict
2143 : * because have_partkey_equi_join() requires that the corresponding operator
2144 : * be mergejoinable, and we currently assume that mergejoinable operators are
2145 : * strict (see MJEvalOuterValues()/MJEvalInnerValues()).
2146 : */
2147 : static void
1096 efujita 2148 CBC 108 : merge_null_partitions(PartitionMap *outer_map,
2149 : PartitionMap *inner_map,
1096 efujita 2150 ECB : bool outer_has_null,
2151 : bool inner_has_null,
2152 : int outer_null,
2153 : int inner_null,
2154 : JoinType jointype,
2155 : int *next_index,
2156 : int *null_index)
2157 : {
1060 tgl 2158 GIC 108 : bool consider_outer_null = false;
1060 tgl 2159 CBC 108 : bool consider_inner_null = false;
1096 efujita 2160 ECB :
1096 efujita 2161 CBC 108 : Assert(outer_has_null || inner_has_null);
1096 efujita 2162 GIC 108 : Assert(*null_index == -1);
1096 efujita 2163 ECB :
2164 : /*
2165 : * Check whether the NULL partitions have already been merged and if so,
2166 : * set the consider_outer_null/consider_inner_null flags.
2167 : */
1096 efujita 2168 GIC 108 : if (outer_has_null)
2169 : {
2170 96 : Assert(outer_null >= 0 && outer_null < outer_map->nparts);
1096 efujita 2171 CBC 96 : if (outer_map->merged_indexes[outer_null] == -1)
2172 42 : consider_outer_null = true;
2173 : }
2174 108 : if (inner_has_null)
2175 : {
2176 96 : Assert(inner_null >= 0 && inner_null < inner_map->nparts);
1096 efujita 2177 GIC 96 : if (inner_map->merged_indexes[inner_null] == -1)
2178 60 : consider_inner_null = true;
2179 : }
2180 :
2181 : /* If both flags are set false, we don't need to do anything. */
2182 108 : if (!consider_outer_null && !consider_inner_null)
2183 36 : return;
2184 :
2185 72 : if (consider_outer_null && !consider_inner_null)
1096 efujita 2186 ECB : {
1096 efujita 2187 GIC 12 : Assert(outer_has_null);
1096 efujita 2188 ECB :
2189 : /*
2190 : * If this is an outer join, the NULL partition on the outer side has
2191 : * to be scanned all the way anyway; merge the NULL partition with a
2192 : * dummy partition on the other side. In that case
1060 tgl 2193 : * consider_outer_null means that the NULL partition only contains
2194 : * NULL values as the key values, so the merged partition will do so;
2195 : * treat it as the NULL partition of the join relation.
2196 : */
1096 efujita 2197 GIC 12 : if (IS_OUTER_JOIN(jointype))
2198 : {
2199 6 : Assert(jointype != JOIN_RIGHT);
2200 6 : *null_index = merge_partition_with_dummy(outer_map, outer_null,
2201 : next_index);
2202 : }
2203 : }
2204 60 : else if (!consider_outer_null && consider_inner_null)
1096 efujita 2205 ECB : {
1096 efujita 2206 GBC 30 : Assert(inner_has_null);
2207 :
2208 : /*
2209 : * If this is a FULL join, the NULL partition on the inner side has to
2210 : * be scanned all the way anyway; merge the NULL partition with a
1060 tgl 2211 ECB : * dummy partition on the other side. In that case
2212 : * consider_inner_null means that the NULL partition only contains
2213 : * NULL values as the key values, so the merged partition will do so;
2214 : * treat it as the NULL partition of the join relation.
2215 : */
1096 efujita 2216 GIC 30 : if (jointype == JOIN_FULL)
1096 efujita 2217 UIC 0 : *null_index = merge_partition_with_dummy(inner_map, inner_null,
2218 : next_index);
2219 : }
2220 : else
2221 : {
1096 efujita 2222 GIC 30 : Assert(consider_outer_null && consider_inner_null);
2223 30 : Assert(outer_has_null);
2224 30 : Assert(inner_has_null);
2225 :
2226 : /*
2227 : * If this is an outer join, the NULL partition on the outer side (and
1096 efujita 2228 ECB : * that on the inner side if this is a FULL join) have to be scanned
2229 : * all the way anyway, so merge them. Note that each of the NULL
2230 : * partitions isn't merged yet, so they should be merged successfully.
2231 : * Like the above, each of the NULL partitions only contains NULL
2232 : * values as the key values, so the merged partition will do so; treat
2233 : * it as the NULL partition of the join relation.
2234 : *
2235 : * Note: if this an INNER/SEMI join, the join clause will never be
2236 : * satisfied by two NULL values (see comments above), so both the NULL
2237 : * partitions can be eliminated.
2238 : */
1096 efujita 2239 GIC 30 : if (IS_OUTER_JOIN(jointype))
2240 : {
2241 24 : Assert(jointype != JOIN_RIGHT);
2242 24 : *null_index = merge_matching_partitions(outer_map, inner_map,
2243 : outer_null, inner_null,
2244 : next_index);
2245 24 : Assert(*null_index >= 0);
2246 : }
1096 efujita 2247 ECB : }
2248 : }
2249 :
2250 : /*
2251 : * merge_default_partitions
2252 : * Merge the default partitions from a join's outer and inner sides.
2253 : *
2254 : * If the merged partition produced from them is the default partition of the
2255 : * join relation, *default_index is set to the index of the merged partition.
2256 : */
2257 : static void
1096 efujita 2258 CBC 78 : merge_default_partitions(PartitionMap *outer_map,
2259 : PartitionMap *inner_map,
1096 efujita 2260 ECB : bool outer_has_default,
2261 : bool inner_has_default,
2262 : int outer_default,
2263 : int inner_default,
2264 : JoinType jointype,
2265 : int *next_index,
2266 : int *default_index)
2267 : {
1060 tgl 2268 CBC 78 : int outer_merged_index = -1;
1060 tgl 2269 GIC 78 : int inner_merged_index = -1;
1096 efujita 2270 ECB :
1096 efujita 2271 CBC 78 : Assert(outer_has_default || inner_has_default);
2272 :
2273 : /* Get the merged partition indexes for the default partitions. */
2274 78 : if (outer_has_default)
2275 : {
1096 efujita 2276 GIC 60 : Assert(outer_default >= 0 && outer_default < outer_map->nparts);
2277 60 : outer_merged_index = outer_map->merged_indexes[outer_default];
2278 : }
2279 78 : if (inner_has_default)
2280 : {
2281 18 : Assert(inner_default >= 0 && inner_default < inner_map->nparts);
2282 18 : inner_merged_index = inner_map->merged_indexes[inner_default];
2283 : }
1096 efujita 2284 ECB :
1096 efujita 2285 GIC 78 : if (outer_has_default && !inner_has_default)
1096 efujita 2286 ECB : {
2287 : /*
2288 : * If this is an outer join, the default partition on the outer side
1096 efujita 2289 EUB : * has to be scanned all the way anyway; if we have not yet assigned a
1060 tgl 2290 : * partition, merge the default partition with a dummy partition on
2291 : * the other side. The merged partition will act as the default
2292 : * partition of the join relation (see comments in
2293 : * process_inner_partition()).
2294 : */
1096 efujita 2295 CBC 60 : if (IS_OUTER_JOIN(jointype))
2296 : {
1096 efujita 2297 GIC 36 : Assert(jointype != JOIN_RIGHT);
1096 efujita 2298 CBC 36 : if (outer_merged_index == -1)
2299 : {
1096 efujita 2300 LBC 0 : Assert(*default_index == -1);
1096 efujita 2301 UIC 0 : *default_index = merge_partition_with_dummy(outer_map,
2302 : outer_default,
2303 : next_index);
2304 : }
2305 : else
1096 efujita 2306 GIC 36 : Assert(*default_index == outer_merged_index);
2307 : }
2308 : else
2309 24 : Assert(*default_index == -1);
1096 efujita 2310 ECB : }
1096 efujita 2311 GIC 18 : else if (!outer_has_default && inner_has_default)
1096 efujita 2312 EUB : {
2313 : /*
1060 tgl 2314 : * If this is a FULL join, the default partition on the inner side has
2315 : * to be scanned all the way anyway; if we have not yet assigned a
2316 : * partition, merge the default partition with a dummy partition on
2317 : * the other side. The merged partition will act as the default
2318 : * partition of the join relation (see comments in
2319 : * process_outer_partition()).
1096 efujita 2320 : */
1096 efujita 2321 GIC 18 : if (jointype == JOIN_FULL)
2322 : {
1096 efujita 2323 LBC 0 : if (inner_merged_index == -1)
2324 : {
1096 efujita 2325 UIC 0 : Assert(*default_index == -1);
2326 0 : *default_index = merge_partition_with_dummy(inner_map,
1096 efujita 2327 EUB : inner_default,
2328 : next_index);
2329 : }
2330 : else
1096 efujita 2331 UIC 0 : Assert(*default_index == inner_merged_index);
2332 : }
2333 : else
1096 efujita 2334 GIC 18 : Assert(*default_index == -1);
2335 : }
1096 efujita 2336 EUB : else
2337 : {
1096 efujita 2338 UBC 0 : Assert(outer_has_default && inner_has_default);
1096 efujita 2339 EUB :
2340 : /*
2341 : * The default partitions have to be joined with each other, so merge
2342 : * them. Note that each of the default partitions isn't merged yet
2343 : * (see, process_outer_partition()/process_innerer_partition()), so
2344 : * they should be merged successfully. The merged partition will act
2345 : * as the default partition of the join relation.
1096 efujita 2346 ECB : */
1096 efujita 2347 UIC 0 : Assert(outer_merged_index == -1);
2348 0 : Assert(inner_merged_index == -1);
2349 0 : Assert(*default_index == -1);
2350 0 : *default_index = merge_matching_partitions(outer_map,
2351 : inner_map,
2352 : outer_default,
2353 : inner_default,
2354 : next_index);
2355 0 : Assert(*default_index >= 0);
2356 : }
1096 efujita 2357 CBC 78 : }
2358 :
1096 efujita 2359 ECB : /*
2360 : * merge_partition_with_dummy
2361 : * Assign given partition a new partition of a join relation
2362 : *
2363 : * Note: The caller assumes that the given partition doesn't have a non-dummy
2364 : * matching partition on the other side, but if the given partition finds the
2365 : * matching partition later, we will adjust the assignment.
2366 : */
2367 : static int
1096 efujita 2368 GIC 264 : merge_partition_with_dummy(PartitionMap *map, int index, int *next_index)
2369 : {
1060 tgl 2370 264 : int merged_index = *next_index;
2371 :
1096 efujita 2372 264 : Assert(index >= 0 && index < map->nparts);
2373 264 : Assert(map->merged_indexes[index] == -1);
2374 264 : Assert(!map->merged[index]);
1096 efujita 2375 CBC 264 : map->merged_indexes[index] = merged_index;
2376 : /* Leave the merged flag alone! */
1096 efujita 2377 GIC 264 : *next_index = *next_index + 1;
2378 264 : return merged_index;
2379 : }
2380 :
2381 : /*
2382 : * fix_merged_indexes
1096 efujita 2383 ECB : * Adjust merged indexes of re-merged partitions
2384 : */
2385 : static void
1096 efujita 2386 CBC 24 : fix_merged_indexes(PartitionMap *outer_map, PartitionMap *inner_map,
1096 efujita 2387 ECB : int nmerged, List *merged_indexes)
2388 : {
2389 : int *new_indexes;
2390 : int merged_index;
2391 : int i;
2392 : ListCell *lc;
2393 :
1096 efujita 2394 CBC 24 : Assert(nmerged > 0);
1096 efujita 2395 ECB :
1096 efujita 2396 CBC 24 : new_indexes = (int *) palloc(sizeof(int) * nmerged);
1096 efujita 2397 GIC 156 : for (i = 0; i < nmerged; i++)
2398 132 : new_indexes[i] = -1;
1096 efujita 2399 ECB :
2400 : /* Build the mapping of old merged indexes to new merged indexes. */
1096 efujita 2401 CBC 24 : if (outer_map->did_remapping)
2402 : {
2403 105 : for (i = 0; i < outer_map->nparts; i++)
1096 efujita 2404 ECB : {
1096 efujita 2405 CBC 81 : merged_index = outer_map->old_indexes[i];
1096 efujita 2406 GIC 81 : if (merged_index >= 0)
2407 24 : new_indexes[merged_index] = outer_map->merged_indexes[i];
2408 : }
2409 : }
1096 efujita 2410 CBC 24 : if (inner_map->did_remapping)
2411 : {
2412 105 : for (i = 0; i < inner_map->nparts; i++)
1096 efujita 2413 ECB : {
1096 efujita 2414 CBC 81 : merged_index = inner_map->old_indexes[i];
2415 81 : if (merged_index >= 0)
1096 efujita 2416 GIC 24 : new_indexes[merged_index] = inner_map->merged_indexes[i];
2417 : }
1096 efujita 2418 ECB : }
2419 :
2420 : /* Fix the merged_indexes list using the mapping. */
1096 efujita 2421 GIC 219 : foreach(lc, merged_indexes)
2422 : {
2423 195 : merged_index = lfirst_int(lc);
2424 195 : Assert(merged_index >= 0);
2425 195 : if (new_indexes[merged_index] >= 0)
2426 48 : lfirst_int(lc) = new_indexes[merged_index];
2427 : }
2428 :
1096 efujita 2429 CBC 24 : pfree(new_indexes);
1096 efujita 2430 GIC 24 : }
2431 :
2432 : /*
2433 : * generate_matching_part_pairs
1096 efujita 2434 ECB : * Generate a pair of lists of partitions that produce merged partitions
2435 : *
2436 : * The lists of partitions are built in the order of merged partition indexes,
2437 : * and returned in *outer_parts and *inner_parts.
2438 : */
2439 : static void
1096 efujita 2440 GIC 366 : generate_matching_part_pairs(RelOptInfo *outer_rel, RelOptInfo *inner_rel,
1096 efujita 2441 ECB : PartitionMap *outer_map, PartitionMap *inner_map,
2442 : int nmerged,
2443 : List **outer_parts, List **inner_parts)
2444 : {
1096 efujita 2445 CBC 366 : int outer_nparts = outer_map->nparts;
2446 366 : int inner_nparts = inner_map->nparts;
1096 efujita 2447 ECB : int *outer_indexes;
2448 : int *inner_indexes;
2449 : int max_nparts;
2450 : int i;
2451 :
1096 efujita 2452 CBC 366 : Assert(nmerged > 0);
2453 366 : Assert(*outer_parts == NIL);
2454 366 : Assert(*inner_parts == NIL);
2455 :
2456 366 : outer_indexes = (int *) palloc(sizeof(int) * nmerged);
1096 efujita 2457 GIC 366 : inner_indexes = (int *) palloc(sizeof(int) * nmerged);
1096 efujita 2458 CBC 1398 : for (i = 0; i < nmerged; i++)
1096 efujita 2459 GIC 1032 : outer_indexes[i] = inner_indexes[i] = -1;
1096 efujita 2460 ECB :
2461 : /* Set pairs of matching partitions. */
1096 efujita 2462 CBC 366 : Assert(outer_nparts == outer_rel->nparts);
2463 366 : Assert(inner_nparts == inner_rel->nparts);
1096 efujita 2464 GIC 366 : max_nparts = Max(outer_nparts, inner_nparts);
2465 1530 : for (i = 0; i < max_nparts; i++)
1096 efujita 2466 ECB : {
1096 efujita 2467 GIC 1164 : if (i < outer_nparts)
1096 efujita 2468 ECB : {
1060 tgl 2469 GIC 1110 : int merged_index = outer_map->merged_indexes[i];
1096 efujita 2470 ECB :
1096 efujita 2471 GIC 1110 : if (merged_index >= 0)
1096 efujita 2472 ECB : {
1096 efujita 2473 CBC 978 : Assert(merged_index < nmerged);
1096 efujita 2474 GIC 978 : outer_indexes[merged_index] = i;
2475 : }
2476 : }
2477 1164 : if (i < inner_nparts)
2478 : {
1060 tgl 2479 CBC 1122 : int merged_index = inner_map->merged_indexes[i];
2480 :
1096 efujita 2481 1122 : if (merged_index >= 0)
1096 efujita 2482 ECB : {
1096 efujita 2483 GIC 960 : Assert(merged_index < nmerged);
2484 960 : inner_indexes[merged_index] = i;
2485 : }
2486 : }
2487 : }
2488 :
2489 : /* Build the list pairs. */
1096 efujita 2490 CBC 1398 : for (i = 0; i < nmerged; i++)
1096 efujita 2491 ECB : {
1096 efujita 2492 GIC 1032 : int outer_index = outer_indexes[i];
1096 efujita 2493 CBC 1032 : int inner_index = inner_indexes[i];
1096 efujita 2494 ECB :
2495 : /*
1060 tgl 2496 : * If both partitions are dummy, it means the merged partition that
2497 : * had been assigned to the outer/inner partition was removed when
2498 : * re-merging the outer/inner partition in
2499 : * merge_matching_partitions(); ignore the merged partition.
1096 efujita 2500 : */
1096 efujita 2501 CBC 1032 : if (outer_index == -1 && inner_index == -1)
1096 efujita 2502 GIC 48 : continue;
2503 :
2504 1962 : *outer_parts = lappend(*outer_parts, outer_index >= 0 ?
2505 978 : outer_rel->part_rels[outer_index] : NULL);
2506 1944 : *inner_parts = lappend(*inner_parts, inner_index >= 0 ?
2507 960 : inner_rel->part_rels[inner_index] : NULL);
1096 efujita 2508 ECB : }
2509 :
1096 efujita 2510 GIC 366 : pfree(outer_indexes);
2511 366 : pfree(inner_indexes);
2512 366 : }
1096 efujita 2513 ECB :
2514 : /*
2515 : * build_merged_partition_bounds
2516 : * Create a PartitionBoundInfo struct from merged partition bounds
2517 : */
2518 : static PartitionBoundInfo
1096 efujita 2519 CBC 366 : build_merged_partition_bounds(char strategy, List *merged_datums,
2520 : List *merged_kinds, List *merged_indexes,
1096 efujita 2521 ECB : int null_index, int default_index)
2522 : {
2523 : PartitionBoundInfo merged_bounds;
1096 efujita 2524 CBC 366 : int ndatums = list_length(merged_datums);
2525 : int pos;
1096 efujita 2526 ECB : ListCell *lc;
2527 :
1096 efujita 2528 CBC 366 : merged_bounds = (PartitionBoundInfo) palloc(sizeof(PartitionBoundInfoData));
2529 366 : merged_bounds->strategy = strategy;
2530 366 : merged_bounds->ndatums = ndatums;
1096 efujita 2531 ECB :
1096 efujita 2532 CBC 366 : merged_bounds->datums = (Datum **) palloc(sizeof(Datum *) * ndatums);
2533 366 : pos = 0;
1096 efujita 2534 GIC 2022 : foreach(lc, merged_datums)
2535 1656 : merged_bounds->datums[pos++] = (Datum *) lfirst(lc);
1096 efujita 2536 ECB :
1096 efujita 2537 CBC 366 : if (strategy == PARTITION_STRATEGY_RANGE)
2538 : {
1096 efujita 2539 GIC 147 : Assert(list_length(merged_kinds) == ndatums);
2540 147 : merged_bounds->kind = (PartitionRangeDatumKind **)
1096 efujita 2541 CBC 147 : palloc(sizeof(PartitionRangeDatumKind *) * ndatums);
2542 147 : pos = 0;
2543 780 : foreach(lc, merged_kinds)
1096 efujita 2544 GIC 633 : merged_bounds->kind[pos++] = (PartitionRangeDatumKind *) lfirst(lc);
2545 :
2546 : /* There are ndatums+1 indexes in the case of range partitioning. */
1096 efujita 2547 CBC 147 : merged_indexes = lappend_int(merged_indexes, -1);
1096 efujita 2548 GIC 147 : ndatums++;
1096 efujita 2549 ECB : }
2550 : else
2551 : {
1096 efujita 2552 CBC 219 : Assert(strategy == PARTITION_STRATEGY_LIST);
2553 219 : Assert(merged_kinds == NIL);
2554 219 : merged_bounds->kind = NULL;
2555 : }
1096 efujita 2556 ECB :
555 drowley 2557 : /* interleaved_parts is always NULL for join relations. */
555 drowley 2558 GIC 366 : merged_bounds->interleaved_parts = NULL;
555 drowley 2559 ECB :
1096 efujita 2560 GIC 366 : Assert(list_length(merged_indexes) == ndatums);
801 tgl 2561 366 : merged_bounds->nindexes = ndatums;
1096 efujita 2562 366 : merged_bounds->indexes = (int *) palloc(sizeof(int) * ndatums);
2563 366 : pos = 0;
2564 2169 : foreach(lc, merged_indexes)
2565 1803 : merged_bounds->indexes[pos++] = lfirst_int(lc);
2566 :
2567 366 : merged_bounds->null_index = null_index;
2568 366 : merged_bounds->default_index = default_index;
2569 :
2570 366 : return merged_bounds;
1096 efujita 2571 ECB : }
2572 :
2573 : /*
2574 : * get_range_partition
2575 : * Get the next non-dummy partition of a range-partitioned relation,
2576 : * returning the index of that partition
2577 : *
2578 : * *lb and *ub are set to the lower and upper bounds of that partition
2579 : * respectively, and *lb_pos is advanced to the next lower bound, if any.
2580 : */
2581 : static int
1096 efujita 2582 GIC 1266 : get_range_partition(RelOptInfo *rel,
1096 efujita 2583 ECB : PartitionBoundInfo bi,
2584 : int *lb_pos,
2585 : PartitionRangeBound *lb,
2586 : PartitionRangeBound *ub)
2587 : {
2588 : int part_index;
2589 :
1096 efujita 2590 GIC 1266 : Assert(bi->strategy == PARTITION_STRATEGY_RANGE);
2591 :
1060 tgl 2592 ECB : do
2593 : {
1096 efujita 2594 GIC 1290 : part_index = get_range_partition_internal(bi, lb_pos, lb, ub);
2595 1290 : if (part_index == -1)
2596 315 : return -1;
2597 975 : } while (is_dummy_partition(rel, part_index));
1096 efujita 2598 ECB :
1096 efujita 2599 CBC 951 : return part_index;
2600 : }
2601 :
1096 efujita 2602 ECB : static int
1096 efujita 2603 GIC 1290 : get_range_partition_internal(PartitionBoundInfo bi,
2604 : int *lb_pos,
1096 efujita 2605 ECB : PartitionRangeBound *lb,
2606 : PartitionRangeBound *ub)
2607 : {
2608 : /* Return the index as -1 if we've exhausted all lower bounds. */
1096 efujita 2609 GIC 1290 : if (*lb_pos >= bi->ndatums)
1096 efujita 2610 CBC 315 : return -1;
1096 efujita 2611 ECB :
2612 : /* A lower bound should have at least one more bound after it. */
1096 efujita 2613 CBC 975 : Assert(*lb_pos + 1 < bi->ndatums);
2614 :
2615 : /* Set the lower bound. */
2616 975 : lb->index = bi->indexes[*lb_pos];
1096 efujita 2617 GIC 975 : lb->datums = bi->datums[*lb_pos];
2618 975 : lb->kind = bi->kind[*lb_pos];
2619 975 : lb->lower = true;
2620 : /* Set the upper bound. */
2621 975 : ub->index = bi->indexes[*lb_pos + 1];
1096 efujita 2622 CBC 975 : ub->datums = bi->datums[*lb_pos + 1];
2623 975 : ub->kind = bi->kind[*lb_pos + 1];
1096 efujita 2624 GIC 975 : ub->lower = false;
2625 :
2626 : /* The index assigned to an upper bound should be valid. */
2627 975 : Assert(ub->index >= 0);
2628 :
2629 : /*
2630 : * Advance the position to the next lower bound. If there are no bounds
1096 efujita 2631 ECB : * left beyond the upper bound, we have reached the last lower bound.
2632 : */
1096 efujita 2633 GIC 975 : if (*lb_pos + 2 >= bi->ndatums)
1096 efujita 2634 CBC 342 : *lb_pos = bi->ndatums;
2635 : else
2636 : {
1096 efujita 2637 ECB : /*
2638 : * If the index assigned to the bound next to the upper bound isn't
2639 : * valid, that is the next lower bound; else, the upper bound is also
2640 : * the lower bound of the next range partition.
2641 : */
1096 efujita 2642 GIC 633 : if (bi->indexes[*lb_pos + 2] < 0)
2643 237 : *lb_pos = *lb_pos + 2;
2644 : else
2645 396 : *lb_pos = *lb_pos + 1;
2646 : }
2647 :
2648 975 : return ub->index;
2649 : }
2650 :
2651 : /*
1096 efujita 2652 ECB : * compare_range_partitions
2653 : * Compare the bounds of two range partitions, and return true if the
2654 : * two partitions overlap, false otherwise
2655 : *
2656 : * *lb_cmpval is set to -1, 0, or 1 if the outer partition's lower bound is
2657 : * lower than, equal to, or higher than the inner partition's lower bound
2658 : * respectively. Likewise, *ub_cmpval is set to -1, 0, or 1 if the outer
2659 : * partition's upper bound is lower than, equal to, or higher than the inner
2660 : * partition's upper bound respectively.
2661 : */
2662 : static bool
1096 efujita 2663 GIC 432 : compare_range_partitions(int partnatts, FmgrInfo *partsupfuncs,
1096 efujita 2664 ECB : Oid *partcollations,
2665 : PartitionRangeBound *outer_lb,
2666 : PartitionRangeBound *outer_ub,
1096 efujita 2667 EUB : PartitionRangeBound *inner_lb,
2668 : PartitionRangeBound *inner_ub,
2669 : int *lb_cmpval, int *ub_cmpval)
2670 : {
2671 : /*
2672 : * Check if the outer partition's upper bound is lower than the inner
2673 : * partition's lower bound; if so the partitions aren't overlapping.
2674 : */
1096 efujita 2675 GIC 432 : if (compare_range_bounds(partnatts, partsupfuncs, partcollations,
1096 efujita 2676 ECB : outer_ub, inner_lb) < 0)
2677 : {
1096 efujita 2678 UIC 0 : *lb_cmpval = -1;
1096 efujita 2679 LBC 0 : *ub_cmpval = -1;
2680 0 : return false;
1096 efujita 2681 ECB : }
2682 :
2683 : /*
2684 : * Check if the outer partition's lower bound is higher than the inner
2685 : * partition's upper bound; if so the partitions aren't overlapping.
2686 : */
1096 efujita 2687 CBC 432 : if (compare_range_bounds(partnatts, partsupfuncs, partcollations,
2688 : outer_lb, inner_ub) > 0)
1096 efujita 2689 ECB : {
1096 efujita 2690 GIC 18 : *lb_cmpval = 1;
2691 18 : *ub_cmpval = 1;
2692 18 : return false;
2693 : }
2694 :
2695 : /* All other cases indicate overlapping partitions. */
2696 414 : *lb_cmpval = compare_range_bounds(partnatts, partsupfuncs, partcollations,
2697 : outer_lb, inner_lb);
2698 414 : *ub_cmpval = compare_range_bounds(partnatts, partsupfuncs, partcollations,
2699 : outer_ub, inner_ub);
2700 414 : return true;
1096 efujita 2701 ECB : }
2702 :
2703 : /*
2704 : * get_merged_range_bounds
2705 : * Given the bounds of range partitions to be joined, determine the bounds
2706 : * of a merged partition produced from the range partitions
2707 : *
2708 : * *merged_lb and *merged_ub are set to the lower and upper bounds of the
2709 : * merged partition.
2710 : */
2711 : static void
1096 efujita 2712 GIC 414 : get_merged_range_bounds(int partnatts, FmgrInfo *partsupfuncs,
1096 efujita 2713 ECB : Oid *partcollations, JoinType jointype,
2714 : PartitionRangeBound *outer_lb,
2715 : PartitionRangeBound *outer_ub,
2716 : PartitionRangeBound *inner_lb,
2717 : PartitionRangeBound *inner_ub,
1060 tgl 2718 : int lb_cmpval, int ub_cmpval,
2719 : PartitionRangeBound *merged_lb,
2720 : PartitionRangeBound *merged_ub)
2721 : {
1096 efujita 2722 GIC 414 : Assert(compare_range_bounds(partnatts, partsupfuncs, partcollations,
2723 : outer_lb, inner_lb) == lb_cmpval);
2724 414 : Assert(compare_range_bounds(partnatts, partsupfuncs, partcollations,
2725 : outer_ub, inner_ub) == ub_cmpval);
2726 :
1096 efujita 2727 CBC 414 : switch (jointype)
1096 efujita 2728 ECB : {
1096 efujita 2729 CBC 216 : case JOIN_INNER:
2730 : case JOIN_SEMI:
1096 efujita 2731 ECB :
2732 : /*
2733 : * An INNER/SEMI join will have the rows that fit both sides, so
2734 : * the lower bound of the merged partition will be the higher of
2735 : * the two lower bounds, and the upper bound of the merged
2736 : * partition will be the lower of the two upper bounds.
2737 : */
1096 efujita 2738 GIC 216 : *merged_lb = (lb_cmpval > 0) ? *outer_lb : *inner_lb;
1096 efujita 2739 CBC 216 : *merged_ub = (ub_cmpval < 0) ? *outer_ub : *inner_ub;
2740 216 : break;
1096 efujita 2741 ECB :
1096 efujita 2742 GIC 162 : case JOIN_LEFT:
1096 efujita 2743 ECB : case JOIN_ANTI:
2744 :
2745 : /*
2746 : * A LEFT/ANTI join will have all the rows from the outer side, so
2747 : * the bounds of the merged partition will be the same as the
2748 : * outer bounds.
2749 : */
1096 efujita 2750 GIC 162 : *merged_lb = *outer_lb;
1096 efujita 2751 CBC 162 : *merged_ub = *outer_ub;
2752 162 : break;
1096 efujita 2753 ECB :
1096 efujita 2754 GIC 36 : case JOIN_FULL:
1096 efujita 2755 EUB :
2756 : /*
2757 : * A FULL join will have all the rows from both sides, so the
1060 tgl 2758 ECB : * lower bound of the merged partition will be the lower of the
2759 : * two lower bounds, and the upper bound of the merged partition
2760 : * will be the higher of the two upper bounds.
2761 : */
1096 efujita 2762 GIC 36 : *merged_lb = (lb_cmpval < 0) ? *outer_lb : *inner_lb;
2763 36 : *merged_ub = (ub_cmpval > 0) ? *outer_ub : *inner_ub;
2764 36 : break;
1096 efujita 2765 ECB :
1096 efujita 2766 UIC 0 : default:
2767 0 : elog(ERROR, "unrecognized join type: %d", (int) jointype);
2768 : }
1096 efujita 2769 GIC 414 : }
2770 :
2771 : /*
2772 : * add_merged_range_bounds
2773 : * Add the bounds of a merged partition to the lists of range bounds
2774 : */
2775 : static void
1096 efujita 2776 CBC 408 : add_merged_range_bounds(int partnatts, FmgrInfo *partsupfuncs,
2777 : Oid *partcollations,
2778 : PartitionRangeBound *merged_lb,
1096 efujita 2779 ECB : PartitionRangeBound *merged_ub,
2780 : int merged_index,
2781 : List **merged_datums,
2782 : List **merged_kinds,
2783 : List **merged_indexes)
2784 : {
2785 : int cmpval;
2786 :
1096 efujita 2787 CBC 408 : if (!*merged_datums)
1096 efujita 2788 ECB : {
2789 : /* First merged partition */
1096 efujita 2790 GIC 165 : Assert(!*merged_kinds);
2791 165 : Assert(!*merged_indexes);
1096 efujita 2792 CBC 165 : cmpval = 1;
1096 efujita 2793 ECB : }
2794 : else
2795 : {
2796 : PartitionRangeBound prev_ub;
2797 :
1096 efujita 2798 GIC 243 : Assert(*merged_datums);
2799 243 : Assert(*merged_kinds);
2800 243 : Assert(*merged_indexes);
2801 :
2802 : /* Get the last upper bound. */
1096 efujita 2803 CBC 243 : prev_ub.index = llast_int(*merged_indexes);
1096 efujita 2804 GIC 243 : prev_ub.datums = (Datum *) llast(*merged_datums);
2805 243 : prev_ub.kind = (PartitionRangeDatumKind *) llast(*merged_kinds);
1096 efujita 2806 CBC 243 : prev_ub.lower = false;
2807 :
2808 : /*
2809 : * We pass lower1 = false to partition_rbound_cmp() to prevent it from
2810 : * considering the last upper bound to be smaller than the lower bound
2811 : * of the merged partition when the values of the two range bounds
2812 : * compare equal.
2813 : */
1096 efujita 2814 GIC 243 : cmpval = partition_rbound_cmp(partnatts, partsupfuncs, partcollations,
1096 efujita 2815 ECB : merged_lb->datums, merged_lb->kind,
2816 : false, &prev_ub);
1096 efujita 2817 CBC 243 : Assert(cmpval >= 0);
1096 efujita 2818 ECB : }
2819 :
2820 : /*
2821 : * If the lower bound is higher than the last upper bound, add the lower
2822 : * bound with the index as -1 indicating that that is a lower bound; else,
2823 : * the last upper bound will be reused as the lower bound of the merged
2824 : * partition, so skip this.
2825 : */
1096 efujita 2826 CBC 408 : if (cmpval > 0)
2827 : {
1096 efujita 2828 GIC 288 : *merged_datums = lappend(*merged_datums, merged_lb->datums);
2829 288 : *merged_kinds = lappend(*merged_kinds, merged_lb->kind);
2830 288 : *merged_indexes = lappend_int(*merged_indexes, -1);
2831 : }
2832 :
2833 : /* Add the upper bound and index of the merged partition. */
2834 408 : *merged_datums = lappend(*merged_datums, merged_ub->datums);
2835 408 : *merged_kinds = lappend(*merged_kinds, merged_ub->kind);
2836 408 : *merged_indexes = lappend_int(*merged_indexes, merged_index);
2837 408 : }
2838 :
2839 : /*
2840 : * partitions_are_ordered
2841 : * Determine whether the partitions described by 'boundinfo' are ordered,
1465 tgl 2842 ECB : * that is partitions appearing earlier in the PartitionDesc sequence
2843 : * contain partition keys strictly less than those appearing later.
2844 : * Also, if NULL values are possible, they must come in the last
2845 : * partition defined in the PartitionDesc. 'live_parts' marks which
614 drowley 2846 : * partitions we should include when checking the ordering. Partitions
2847 : * that do not appear in 'live_parts' are ignored.
1465 tgl 2848 : *
2849 : * If out of order, or there is insufficient info to know the order,
2850 : * then we return false.
2851 : */
2852 : bool
614 drowley 2853 GIC 33219 : partitions_are_ordered(PartitionBoundInfo boundinfo, Bitmapset *live_parts)
2854 : {
1465 tgl 2855 33219 : Assert(boundinfo != NULL);
2856 :
1465 tgl 2857 CBC 33219 : switch (boundinfo->strategy)
1465 tgl 2858 ECB : {
1465 tgl 2859 CBC 22112 : case PARTITION_STRATEGY_RANGE:
1465 tgl 2860 ECB :
2861 : /*
2862 : * RANGE-type partitioning guarantees that the partitions can be
2863 : * scanned in the order that they're defined in the PartitionDesc
2864 : * to provide sequential, non-overlapping ranges of tuples.
2865 : * However, if a DEFAULT partition exists and it's contained
2866 : * within live_parts, then the partitions are not ordered.
2867 : */
614 drowley 2868 CBC 22112 : if (!partition_bound_has_default(boundinfo) ||
2869 1472 : !bms_is_member(boundinfo->default_index, live_parts))
1465 tgl 2870 GIC 21486 : return true;
1465 tgl 2871 CBC 626 : break;
1465 tgl 2872 ECB :
1465 tgl 2873 CBC 10848 : case PARTITION_STRATEGY_LIST:
2874 :
2875 : /*
614 drowley 2876 ECB : * LIST partitioned are ordered providing none of live_parts
2877 : * overlap with the partitioned table's interleaved partitions.
2878 : */
614 drowley 2879 GIC 10848 : if (!bms_overlap(live_parts, boundinfo->interleaved_parts))
1465 tgl 2880 10065 : return true;
2881 :
614 drowley 2882 783 : break;
157 alvherre 2883 GNC 259 : case PARTITION_STRATEGY_HASH:
1465 tgl 2884 GIC 259 : break;
1465 tgl 2885 ECB : }
2886 :
1465 tgl 2887 GIC 1668 : return false;
1465 tgl 2888 ECB : }
2889 :
1821 alvherre 2890 : /*
2891 : * check_new_partition_bound
2892 : *
2893 : * Checks if the new partition's bound overlaps any of the existing partitions
2894 : * of parent. Also performs additional checks as necessary per strategy.
2895 : */
2896 : void
1821 alvherre 2897 GIC 4459 : check_new_partition_bound(char *relname, Relation parent,
2898 : PartitionBoundSpec *spec, ParseState *pstate)
2899 : {
2900 4459 : PartitionKey key = RelationGetPartitionKey(parent);
717 2901 4459 : PartitionDesc partdesc = RelationGetPartitionDesc(parent, false);
1821 2902 4459 : PartitionBoundInfo boundinfo = partdesc->boundinfo;
1821 alvherre 2903 CBC 4459 : int with = -1;
2904 4459 : bool overlap = false;
928 tgl 2905 GIC 4459 : int overlap_location = -1;
2906 :
1821 alvherre 2907 CBC 4459 : if (spec->is_default)
2908 : {
2909 : /*
2910 : * The default partition bound never conflicts with any other
2911 : * partition's; if that's what we're attaching, the only possible
2912 : * problem is that one already exists, so check for that and we're
2913 : * done.
1821 alvherre 2914 ECB : */
1821 alvherre 2915 GIC 263 : if (boundinfo == NULL || !partition_bound_has_default(boundinfo))
1821 alvherre 2916 CBC 251 : return;
2917 :
1821 alvherre 2918 ECB : /* Default partition already exists, error out. */
1821 alvherre 2919 CBC 12 : ereport(ERROR,
2920 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1821 alvherre 2921 ECB : errmsg("partition \"%s\" conflicts with existing default partition \"%s\"",
2922 : relname, get_rel_name(partdesc->oids[boundinfo->default_index])),
2923 : parser_errposition(pstate, spec->location)));
2924 : }
2925 :
1821 alvherre 2926 GIC 4196 : switch (key->strategy)
2927 : {
2928 272 : case PARTITION_STRATEGY_HASH:
2929 : {
2930 272 : Assert(spec->strategy == PARTITION_STRATEGY_HASH);
2931 272 : Assert(spec->remainder >= 0 && spec->remainder < spec->modulus);
2932 :
2933 272 : if (partdesc->nparts > 0)
2934 : {
2935 : int greatest_modulus;
2936 : int remainder;
2937 : int offset;
2938 :
2939 : /*
2940 : * Check rule that every modulus must be a factor of the
2941 : * next larger modulus. (For example, if you have a bunch
2942 : * of partitions that all have modulus 5, you can add a
2943 : * new partition with modulus 10 or a new partition with
2944 : * modulus 15, but you cannot add both a partition with
1821 alvherre 2945 ECB : * modulus 10 and a partition with modulus 15, because 10
2946 : * is not a factor of 15.) We need only check the next
2947 : * smaller and next larger existing moduli, relying on
649 tgl 2948 : * previous enforcement of this rule to be sure that the
2949 : * rest are in line.
2950 : */
2951 :
2952 : /*
2953 : * Get the greatest (modulus, remainder) pair contained in
2954 : * boundinfo->datums that is less than or equal to the
2955 : * (spec->modulus, spec->remainder) pair.
2956 : */
1821 alvherre 2957 CBC 174 : offset = partition_hash_bsearch(boundinfo,
1821 alvherre 2958 ECB : spec->modulus,
2959 : spec->remainder);
1821 alvherre 2960 GIC 174 : if (offset < 0)
2961 : {
2962 : int next_modulus;
2963 :
2964 : /*
2965 : * All existing moduli are greater or equal, so the
2966 : * new one must be a factor of the smallest one, which
2967 : * is first in the boundinfo.
2968 : */
776 peter 2969 7 : next_modulus = DatumGetInt32(boundinfo->datums[0][0]);
2970 7 : if (next_modulus % spec->modulus != 0)
2971 3 : ereport(ERROR,
2972 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2973 : errmsg("every hash partition modulus must be a factor of the next larger modulus"),
2974 : errdetail("The new modulus %d is not a factor of %d, the modulus of existing partition \"%s\".",
776 peter 2975 ECB : spec->modulus, next_modulus,
2976 : get_rel_name(partdesc->oids[0]))));
1821 alvherre 2977 : }
2978 : else
2979 : {
2980 : int prev_modulus;
2981 :
2982 : /*
2983 : * We found the largest (modulus, remainder) pair less
2984 : * than or equal to the new one. That modulus must be
2985 : * a divisor of, or equal to, the new modulus.
697 tgl 2986 : */
776 peter 2987 GIC 167 : prev_modulus = DatumGetInt32(boundinfo->datums[offset][0]);
2988 :
2989 167 : if (spec->modulus % prev_modulus != 0)
2990 3 : ereport(ERROR,
2991 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2992 : errmsg("every hash partition modulus must be a factor of the next larger modulus"),
2993 : errdetail("The new modulus %d is not divisible by %d, the modulus of existing partition \"%s\".",
2994 : spec->modulus,
2995 : prev_modulus,
2996 : get_rel_name(partdesc->oids[offset]))));
776 peter 2997 ECB :
776 peter 2998 GIC 164 : if (offset + 1 < boundinfo->ndatums)
1821 alvherre 2999 ECB : {
776 peter 3000 : int next_modulus;
3001 :
3002 : /*
3003 : * Look at the next higher (modulus, remainder)
3004 : * pair. That could have the same modulus and a
3005 : * larger remainder than the new pair, in which
3006 : * case we're good. If it has a larger modulus,
3007 : * the new modulus must divide that one.
3008 : */
776 peter 3009 CBC 15 : next_modulus = DatumGetInt32(boundinfo->datums[offset + 1][0]);
776 peter 3010 ECB :
776 peter 3011 GIC 15 : if (next_modulus % spec->modulus != 0)
3012 3 : ereport(ERROR,
3013 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3014 : errmsg("every hash partition modulus must be a factor of the next larger modulus"),
3015 : errdetail("The new modulus %d is not a factor of %d, the modulus of existing partition \"%s\".",
3016 : spec->modulus, next_modulus,
3017 : get_rel_name(partdesc->oids[offset + 1]))));
1821 alvherre 3018 ECB : }
3019 : }
3020 :
801 tgl 3021 GIC 165 : greatest_modulus = boundinfo->nindexes;
1821 alvherre 3022 165 : remainder = spec->remainder;
3023 :
1821 alvherre 3024 ECB : /*
3025 : * Normally, the lowest remainder that could conflict with
3026 : * the new partition is equal to the remainder specified
3027 : * for the new partition, but when the new partition has a
3028 : * modulus higher than any used so far, we need to adjust.
3029 : */
1821 alvherre 3030 GIC 165 : if (remainder >= greatest_modulus)
1821 alvherre 3031 CBC 6 : remainder = remainder % greatest_modulus;
1821 alvherre 3032 ECB :
3033 : /* Check every potentially-conflicting remainder. */
3034 : do
3035 : {
1821 alvherre 3036 GIC 228 : if (boundinfo->indexes[remainder] != -1)
3037 : {
1821 alvherre 3038 CBC 12 : overlap = true;
928 tgl 3039 GIC 12 : overlap_location = spec->location;
1821 alvherre 3040 CBC 12 : with = boundinfo->indexes[remainder];
1821 alvherre 3041 GIC 12 : break;
1821 alvherre 3042 ECB : }
1821 alvherre 3043 GIC 216 : remainder += spec->modulus;
3044 216 : } while (remainder < greatest_modulus);
3045 : }
1821 alvherre 3046 ECB :
1821 alvherre 3047 GIC 263 : break;
3048 : }
3049 :
3050 2093 : case PARTITION_STRATEGY_LIST:
3051 : {
1821 alvherre 3052 CBC 2093 : Assert(spec->strategy == PARTITION_STRATEGY_LIST);
3053 :
3054 2093 : if (partdesc->nparts > 0)
3055 : {
1821 alvherre 3056 ECB : ListCell *cell;
3057 :
1821 alvherre 3058 GIC 1091 : Assert(boundinfo &&
3059 : boundinfo->strategy == PARTITION_STRATEGY_LIST &&
3060 : (boundinfo->ndatums > 0 ||
3061 : partition_bound_accepts_nulls(boundinfo) ||
1821 alvherre 3062 ECB : partition_bound_has_default(boundinfo)));
3063 :
1821 alvherre 3064 GIC 2679 : foreach(cell, spec->listdatums)
3065 : {
629 peter 3066 1600 : Const *val = lfirst_node(Const, cell);
1821 alvherre 3067 ECB :
928 tgl 3068 GIC 1600 : overlap_location = val->location;
1821 alvherre 3069 CBC 1600 : if (!val->constisnull)
1821 alvherre 3070 ECB : {
3071 : int offset;
3072 : bool equal;
3073 :
1821 alvherre 3074 CBC 1543 : offset = partition_list_bsearch(&key->partsupfunc[0],
3075 : key->partcollation,
1821 alvherre 3076 ECB : boundinfo,
3077 : val->constvalue,
3078 : &equal);
1821 alvherre 3079 GIC 1543 : if (offset >= 0 && equal)
3080 : {
3081 9 : overlap = true;
3082 9 : with = boundinfo->indexes[offset];
1821 alvherre 3083 CBC 9 : break;
3084 : }
3085 : }
3086 57 : else if (partition_bound_accepts_nulls(boundinfo))
3087 : {
1821 alvherre 3088 GIC 3 : overlap = true;
3089 3 : with = boundinfo->null_index;
3090 3 : break;
3091 : }
1821 alvherre 3092 ECB : }
3093 : }
3094 :
1821 alvherre 3095 GIC 2093 : break;
3096 : }
3097 :
3098 1831 : case PARTITION_STRATEGY_RANGE:
3099 : {
3100 : PartitionRangeBound *lower,
3101 : *upper;
928 tgl 3102 ECB : int cmpval;
3103 :
1821 alvherre 3104 GIC 1831 : Assert(spec->strategy == PARTITION_STRATEGY_RANGE);
1761 tgl 3105 1831 : lower = make_one_partition_rbound(key, -1, spec->lowerdatums, true);
3106 1831 : upper = make_one_partition_rbound(key, -1, spec->upperdatums, false);
1821 alvherre 3107 ECB :
3108 : /*
3109 : * First check if the resulting range would be empty with
3110 : * specified lower and upper bounds. partition_rbound_cmp
891 tgl 3111 : * cannot return zero here, since the lower-bound flags are
3112 : * different.
3113 : */
928 tgl 3114 CBC 1831 : cmpval = partition_rbound_cmp(key->partnatts,
3115 : key->partsupfunc,
3116 : key->partcollation,
3117 : lower->datums, lower->kind,
3118 : true, upper);
891 tgl 3119 GIC 1831 : Assert(cmpval != 0);
3120 1831 : if (cmpval > 0)
3121 : {
3122 : /* Point to problematic key in the lower datums list. */
928 3123 6 : PartitionRangeDatum *datum = list_nth(spec->lowerdatums,
928 tgl 3124 ECB : cmpval - 1);
3125 :
1821 alvherre 3126 GIC 6 : ereport(ERROR,
3127 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1821 alvherre 3128 ECB : errmsg("empty range bound specified for partition \"%s\"",
3129 : relname),
3130 : errdetail("Specified lower bound %s is greater than or equal to upper bound %s.",
3131 : get_range_partbound_string(spec->lowerdatums),
3132 : get_range_partbound_string(spec->upperdatums)),
3133 : parser_errposition(pstate, datum->location)));
3134 : }
3135 :
1821 alvherre 3136 GIC 1825 : if (partdesc->nparts > 0)
3137 : {
3138 : int offset;
3139 :
3140 1014 : Assert(boundinfo &&
3141 : boundinfo->strategy == PARTITION_STRATEGY_RANGE &&
3142 : (boundinfo->ndatums > 0 ||
3143 : partition_bound_has_default(boundinfo)));
3144 :
3145 : /*
3146 : * Test whether the new lower bound (which is treated
3147 : * inclusively as part of the new partition) lies inside
1821 alvherre 3148 ECB : * an existing partition, or in a gap.
3149 : *
3150 : * If it's inside an existing partition, the bound at
3151 : * offset + 1 will be the upper bound of that partition,
3152 : * and its index will be >= 0.
3153 : *
3154 : * If it's in a gap, the bound at offset + 1 will be the
3155 : * lower bound of the next partition, and its index will
3156 : * be -1. This is also true if there is no next partition,
3157 : * since the index array is initialised with an extra -1
3158 : * at the end.
3159 : */
1821 alvherre 3160 GIC 1014 : offset = partition_range_bsearch(key->partnatts,
3161 : key->partsupfunc,
1821 alvherre 3162 ECB : key->partcollation,
3163 : boundinfo, lower,
3164 : &cmpval);
3165 :
1821 alvherre 3166 GIC 1014 : if (boundinfo->indexes[offset + 1] < 0)
3167 : {
1821 alvherre 3168 ECB : /*
3169 : * Check that the new partition will fit in the gap.
3170 : * For it to fit, the new upper bound must be less
3171 : * than or equal to the lower bound of the next
3172 : * partition, if there is one.
3173 : */
1821 alvherre 3174 GIC 996 : if (offset + 1 < boundinfo->ndatums)
3175 : {
3176 : Datum *datums;
1821 alvherre 3177 ECB : PartitionRangeDatumKind *kind;
3178 : bool is_lower;
3179 :
1821 alvherre 3180 GIC 45 : datums = boundinfo->datums[offset + 1];
3181 45 : kind = boundinfo->kind[offset + 1];
3182 45 : is_lower = (boundinfo->indexes[offset + 1] == -1);
3183 :
1821 alvherre 3184 CBC 45 : cmpval = partition_rbound_cmp(key->partnatts,
3185 : key->partsupfunc,
3186 : key->partcollation,
3187 : datums, kind,
3188 : is_lower, upper);
1821 alvherre 3189 GIC 45 : if (cmpval < 0)
3190 : {
928 tgl 3191 ECB : /*
891 3192 : * Point to problematic key in the upper
928 3193 : * datums list.
3194 : */
3195 : PartitionRangeDatum *datum =
184 peter 3196 GNC 6 : list_nth(spec->upperdatums, abs(cmpval) - 1);
3197 :
3198 : /*
3199 : * The new partition overlaps with the
3200 : * existing partition between offset + 1 and
3201 : * offset + 2.
3202 : */
1821 alvherre 3203 GIC 6 : overlap = true;
928 tgl 3204 6 : overlap_location = datum->location;
1821 alvherre 3205 6 : with = boundinfo->indexes[offset + 2];
3206 : }
3207 : }
3208 : }
1821 alvherre 3209 ECB : else
3210 : {
3211 : /*
3212 : * The new partition overlaps with the existing
3213 : * partition between offset and offset + 1.
3214 : */
3215 : PartitionRangeDatum *datum;
3216 :
928 tgl 3217 : /*
3218 : * Point to problematic key in the lower datums list;
3219 : * if we have equality, point to the first one.
3220 : */
928 tgl 3221 CBC 18 : datum = cmpval == 0 ? linitial(spec->lowerdatums) :
184 peter 3222 GNC 9 : list_nth(spec->lowerdatums, abs(cmpval) - 1);
1821 alvherre 3223 CBC 18 : overlap = true;
928 tgl 3224 18 : overlap_location = datum->location;
1821 alvherre 3225 GIC 18 : with = boundinfo->indexes[offset + 1];
3226 : }
3227 : }
3228 :
3229 1825 : break;
3230 : }
3231 : }
3232 :
3233 4181 : if (overlap)
3234 : {
3235 48 : Assert(with >= 0);
1821 alvherre 3236 CBC 48 : ereport(ERROR,
3237 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3238 : errmsg("partition \"%s\" would overlap partition \"%s\"",
3239 : relname, get_rel_name(partdesc->oids[with])),
3240 : parser_errposition(pstate, overlap_location)));
3241 : }
3242 : }
3243 :
1821 alvherre 3244 ECB : /*
1761 tgl 3245 : * check_default_partition_contents
1821 alvherre 3246 : *
3247 : * This function checks if there exists a row in the default partition that
3248 : * would properly belong to the new partition being added. If it finds one,
3249 : * it throws an error.
3250 : */
3251 : void
1761 tgl 3252 GIC 162 : check_default_partition_contents(Relation parent, Relation default_rel,
3253 : PartitionBoundSpec *new_spec)
3254 : {
1821 alvherre 3255 ECB : List *new_part_constraints;
3256 : List *def_part_constraints;
3257 : List *all_parts;
3258 : ListCell *lc;
3259 :
1821 alvherre 3260 GIC 324 : new_part_constraints = (new_spec->strategy == PARTITION_STRATEGY_LIST)
3261 69 : ? get_qual_for_list(parent, new_spec)
3262 162 : : get_qual_for_range(parent, new_spec, false);
1821 alvherre 3263 ECB : def_part_constraints =
1821 alvherre 3264 GIC 162 : get_proposed_default_constraint(new_part_constraints);
1378 tgl 3265 ECB :
3266 : /*
3267 : * Map the Vars in the constraint expression from parent's attnos to
1381 alvherre 3268 : * default_rel's.
3269 : */
3270 : def_part_constraints =
1378 tgl 3271 GIC 162 : map_partition_varattnos(def_part_constraints, 1, default_rel,
3272 : parent);
3273 :
3274 : /*
1821 alvherre 3275 ECB : * If the existing constraints on the default partition imply that it will
3276 : * not contain any row that would belong to the new partition, we can
3277 : * avoid scanning the default partition.
3278 : */
1821 alvherre 3279 CBC 162 : if (PartConstraintImpliedByRelConstraint(default_rel, def_part_constraints))
3280 : {
1310 tgl 3281 7 : ereport(DEBUG1,
3282 : (errmsg_internal("updated partition constraint for default partition \"%s\" is implied by existing constraints",
697 tgl 3283 ECB : RelationGetRelationName(default_rel))));
1821 alvherre 3284 GIC 7 : return;
3285 : }
3286 :
1821 alvherre 3287 ECB : /*
3288 : * Scan the default partition and its subpartitions, and check for rows
3289 : * that do not satisfy the revised partition constraints.
3290 : */
1821 alvherre 3291 GIC 155 : if (default_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
3292 26 : all_parts = find_all_inheritors(RelationGetRelid(default_rel),
3293 : AccessExclusiveLock, NULL);
3294 : else
1821 alvherre 3295 CBC 129 : all_parts = list_make1_oid(RelationGetRelid(default_rel));
3296 :
3297 372 : foreach(lc, all_parts)
3298 : {
1821 alvherre 3299 GIC 226 : Oid part_relid = lfirst_oid(lc);
3300 : Relation part_rel;
3301 : Expr *partition_constraint;
3302 : EState *estate;
1821 alvherre 3303 CBC 226 : ExprState *partqualstate = NULL;
3304 : Snapshot snapshot;
1821 alvherre 3305 ECB : ExprContext *econtext;
3306 : TableScanDesc scan;
3307 : MemoryContext oldCxt;
3308 : TupleTableSlot *tupslot;
3309 :
3310 : /* Lock already taken above. */
1821 alvherre 3311 GIC 226 : if (part_relid != RelationGetRelid(default_rel))
3312 : {
1539 andres 3313 CBC 71 : part_rel = table_open(part_relid, NoLock);
3314 :
3315 : /*
1381 alvherre 3316 ECB : * Map the Vars in the constraint expression from default_rel's
3317 : * the sub-partition's.
3318 : */
1381 alvherre 3319 GIC 71 : partition_constraint = make_ands_explicit(def_part_constraints);
1381 alvherre 3320 ECB : partition_constraint = (Expr *)
1381 alvherre 3321 CBC 71 : map_partition_varattnos((List *) partition_constraint, 1,
3322 : part_rel, default_rel);
3323 :
3324 : /*
3325 : * If the partition constraints on default partition child imply
1821 alvherre 3326 ECB : * that it will not contain any row that would belong to the new
3327 : * partition, we can avoid scanning the child table.
3328 : */
1821 alvherre 3329 GIC 71 : if (PartConstraintImpliedByRelConstraint(part_rel,
3330 : def_part_constraints))
3331 : {
1310 tgl 3332 4 : ereport(DEBUG1,
3333 : (errmsg_internal("updated partition constraint for default partition \"%s\" is implied by existing constraints",
697 tgl 3334 ECB : RelationGetRelationName(part_rel))));
3335 :
1539 andres 3336 CBC 4 : table_close(part_rel, NoLock);
1821 alvherre 3337 GBC 4 : continue;
3338 : }
3339 : }
3340 : else
3341 : {
1821 alvherre 3342 GIC 155 : part_rel = default_rel;
1381 alvherre 3343 CBC 155 : partition_constraint = make_ands_explicit(def_part_constraints);
1381 alvherre 3344 EUB : }
3345 :
1821 alvherre 3346 ECB : /*
3347 : * Only RELKIND_RELATION relations (i.e. leaf partitions) need to be
3348 : * scanned.
3349 : */
1821 alvherre 3350 GIC 222 : if (part_rel->rd_rel->relkind != RELKIND_RELATION)
3351 : {
1821 alvherre 3352 CBC 26 : if (part_rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1821 alvherre 3353 UIC 0 : ereport(WARNING,
1821 alvherre 3354 ECB : (errcode(ERRCODE_CHECK_VIOLATION),
3355 : errmsg("skipped scanning foreign table \"%s\" which is a partition of default partition \"%s\"",
3356 : RelationGetRelationName(part_rel),
3357 : RelationGetRelationName(default_rel))));
3358 :
1821 alvherre 3359 GIC 26 : if (RelationGetRelid(default_rel) != RelationGetRelid(part_rel))
1539 andres 3360 UIC 0 : table_close(part_rel, NoLock);
3361 :
1821 alvherre 3362 GIC 26 : continue;
1821 alvherre 3363 ECB : }
3364 :
1821 alvherre 3365 CBC 196 : estate = CreateExecutorState();
3366 :
1821 alvherre 3367 ECB : /* Build expression execution states for partition check quals */
1821 alvherre 3368 GIC 196 : partqualstate = ExecPrepareExpr(partition_constraint, estate);
1821 alvherre 3369 ECB :
1821 alvherre 3370 CBC 196 : econtext = GetPerTupleExprContext(estate);
1821 alvherre 3371 GIC 196 : snapshot = RegisterSnapshot(GetLatestSnapshot());
1490 andres 3372 196 : tupslot = table_slot_create(part_rel, &estate->es_tupleTable);
3373 196 : scan = table_beginscan(part_rel, snapshot, 0, NULL);
3374 :
3375 : /*
1821 alvherre 3376 ECB : * Switch to per-tuple memory context and reset it for each tuple
3377 : * produced, so we don't leak memory.
3378 : */
1821 alvherre 3379 GIC 196 : oldCxt = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
1821 alvherre 3380 ECB :
1490 andres 3381 CBC 416 : while (table_scan_getnextslot(scan, ForwardScanDirection, tupslot))
1821 alvherre 3382 ECB : {
1821 alvherre 3383 CBC 33 : econtext->ecxt_scantuple = tupslot;
1821 alvherre 3384 ECB :
1821 alvherre 3385 GIC 33 : if (!ExecCheck(partqualstate, econtext))
1821 alvherre 3386 CBC 9 : ereport(ERROR,
1821 alvherre 3387 ECB : (errcode(ERRCODE_CHECK_VIOLATION),
3388 : errmsg("updated partition constraint for default partition \"%s\" would be violated by some row",
3389 : RelationGetRelationName(default_rel)),
3390 : errtable(default_rel)));
3391 :
1821 alvherre 3392 GIC 24 : ResetExprContext(econtext);
3393 24 : CHECK_FOR_INTERRUPTS();
3394 : }
3395 :
3396 187 : MemoryContextSwitchTo(oldCxt);
1490 andres 3397 187 : table_endscan(scan);
1821 alvherre 3398 187 : UnregisterSnapshot(snapshot);
1821 alvherre 3399 GBC 187 : ExecDropSingleTupleTableSlot(tupslot);
1821 alvherre 3400 GIC 187 : FreeExecutorState(estate);
1821 alvherre 3401 EUB :
1821 alvherre 3402 GBC 187 : if (RelationGetRelid(default_rel) != RelationGetRelid(part_rel))
1539 andres 3403 GIC 67 : table_close(part_rel, NoLock); /* keep the lock until commit */
3404 : }
3405 : }
3406 :
3407 : /*
3408 : * get_hash_partition_greatest_modulus
3409 : *
3410 : * Returns the greatest modulus of the hash partition bound.
3411 : * This is no longer used in the core code, but we keep it around
3412 : * in case external modules are using it.
1821 alvherre 3413 ECB : */
3414 : int
1821 alvherre 3415 UIC 0 : get_hash_partition_greatest_modulus(PartitionBoundInfo bound)
3416 : {
3417 0 : Assert(bound && bound->strategy == PARTITION_STRATEGY_HASH);
801 tgl 3418 0 : return bound->nindexes;
1821 alvherre 3419 ECB : }
3420 :
3421 : /*
1761 tgl 3422 : * make_one_partition_rbound
1821 alvherre 3423 : *
3424 : * Return a PartitionRangeBound given a list of PartitionRangeDatum elements
3425 : * and a flag telling whether the bound is lower or not. Made into a function
3426 : * because there are multiple sites that want to use this facility.
3427 : */
1607 michael 3428 : static PartitionRangeBound *
1761 tgl 3429 CBC 16294 : make_one_partition_rbound(PartitionKey key, int index, List *datums, bool lower)
3430 : {
1821 alvherre 3431 ECB : PartitionRangeBound *bound;
3432 : ListCell *lc;
3433 : int i;
3434 :
1821 alvherre 3435 GIC 16294 : Assert(datums != NIL);
1821 alvherre 3436 ECB :
1821 alvherre 3437 GIC 16294 : bound = (PartitionRangeBound *) palloc0(sizeof(PartitionRangeBound));
1821 alvherre 3438 CBC 16294 : bound->index = index;
1821 alvherre 3439 GIC 16294 : bound->datums = (Datum *) palloc0(key->partnatts * sizeof(Datum));
1821 alvherre 3440 CBC 16294 : bound->kind = (PartitionRangeDatumKind *) palloc0(key->partnatts *
1821 alvherre 3441 EUB : sizeof(PartitionRangeDatumKind));
1821 alvherre 3442 CBC 16294 : bound->lower = lower;
3443 :
1821 alvherre 3444 GIC 16294 : i = 0;
1821 alvherre 3445 CBC 37210 : foreach(lc, datums)
3446 : {
629 peter 3447 GIC 20916 : PartitionRangeDatum *datum = lfirst_node(PartitionRangeDatum, lc);
1821 alvherre 3448 ECB :
3449 : /* What's contained in this range datum? */
1821 alvherre 3450 GIC 20916 : bound->kind[i] = datum->kind;
3451 :
3452 20916 : if (datum->kind == PARTITION_RANGE_DATUM_VALUE)
3453 : {
3454 19234 : Const *val = castNode(Const, datum->value);
3455 :
3456 19234 : if (val->constisnull)
1821 alvherre 3457 UIC 0 : elog(ERROR, "invalid range bound datum");
1821 alvherre 3458 GIC 19234 : bound->datums[i] = val->constvalue;
3459 : }
3460 :
3461 20916 : i++;
3462 : }
3463 :
3464 16294 : return bound;
3465 : }
3466 :
3467 : /*
3468 : * partition_rbound_cmp
3469 : *
3470 : * For two range bounds this decides whether the 1st one (specified by
3471 : * datums1, kind1, and lower1) is <, =, or > the bound specified in *b2.
3472 : *
928 tgl 3473 ECB : * 0 is returned if they are equal, otherwise a non-zero integer whose sign
3474 : * indicates the ordering, and whose absolute value gives the 1-based
3475 : * partition key number of the first mismatching column.
3476 : *
3477 : * partnatts, partsupfunc and partcollation give the number of attributes in the
1821 alvherre 3478 : * bounds to be compared, comparison function to be used and the collations of
3479 : * attributes, respectively.
3480 : *
3481 : * Note that if the values of the two range bounds compare equal, then we take
3482 : * into account whether they are upper or lower bounds, and an upper bound is
3483 : * considered to be smaller than a lower bound. This is important to the way
3484 : * that RelationBuildPartitionDesc() builds the PartitionBoundInfoData
3485 : * structure, which only stores the upper bound of a common boundary between
3486 : * two contiguous partitions.
3487 : */
1607 michael 3488 : static int32
1821 alvherre 3489 GIC 17167 : partition_rbound_cmp(int partnatts, FmgrInfo *partsupfunc,
3490 : Oid *partcollation,
3491 : Datum *datums1, PartitionRangeDatumKind *kind1,
3492 : bool lower1, PartitionRangeBound *b2)
3493 : {
928 tgl 3494 17167 : int32 colnum = 0;
1821 alvherre 3495 17167 : int32 cmpval = 0; /* placate compiler */
1821 alvherre 3496 ECB : int i;
1821 alvherre 3497 CBC 17167 : Datum *datums2 = b2->datums;
3498 17167 : PartitionRangeDatumKind *kind2 = b2->kind;
3499 17167 : bool lower2 = b2->lower;
1821 alvherre 3500 ECB :
1821 alvherre 3501 GIC 24689 : for (i = 0; i < partnatts; i++)
3502 : {
3503 : /* Track column number in case we need it for result */
928 tgl 3504 20050 : colnum++;
3505 :
3506 : /*
1821 alvherre 3507 ECB : * First, handle cases where the column is unbounded, which should not
3508 : * invoke the comparison procedure, and should not consider any later
3509 : * columns. Note that the PartitionRangeDatumKind enum elements
3510 : * compare the same way as the values they represent.
3511 : */
1821 alvherre 3512 CBC 20050 : if (kind1[i] < kind2[i])
928 tgl 3513 968 : return -colnum;
1821 alvherre 3514 19082 : else if (kind1[i] > kind2[i])
928 tgl 3515 3 : return colnum;
1821 alvherre 3516 GIC 19079 : else if (kind1[i] != PARTITION_RANGE_DATUM_VALUE)
3517 : {
3518 : /*
3519 : * The column bounds are both MINVALUE or both MAXVALUE. No later
3520 : * columns should be considered, but we still need to compare
3521 : * whether they are upper or lower bounds.
3522 : */
3523 129 : break;
891 tgl 3524 ECB : }
1821 alvherre 3525 :
1821 alvherre 3526 GIC 18950 : cmpval = DatumGetInt32(FunctionCall2Coll(&partsupfunc[i],
1821 alvherre 3527 CBC 18950 : partcollation[i],
1821 alvherre 3528 GIC 18950 : datums1[i],
3529 18950 : datums2[i]));
3530 18950 : if (cmpval != 0)
3531 11428 : break;
3532 : }
3533 :
3534 : /*
3535 : * If the comparison is anything other than equal, we're done. If they
3536 : * compare equal though, we still have to consider whether the boundaries
3537 : * are inclusive or exclusive. Exclusive one is considered smaller of the
3538 : * two.
3539 : */
3540 16196 : if (cmpval == 0 && lower1 != lower2)
1821 alvherre 3541 CBC 3703 : cmpval = lower1 ? 1 : -1;
3542 :
928 tgl 3543 GIC 16196 : return cmpval == 0 ? 0 : (cmpval < 0 ? -colnum : colnum);
3544 : }
3545 :
1821 alvherre 3546 ECB : /*
3547 : * partition_rbound_datum_cmp
3548 : *
3549 : * Return whether range bound (specified in rb_datums and rb_kind)
3550 : * is <, =, or > partition key of tuple (tuple_datums)
3551 : *
3552 : * n_tuple_datums, partsupfunc and partcollation give number of attributes in
3553 : * the bounds to be compared, comparison function to be used and the collations
3554 : * of attributes resp.
3555 : */
3556 : int32
1821 alvherre 3557 CBC 777926 : partition_rbound_datum_cmp(FmgrInfo *partsupfunc, Oid *partcollation,
1821 alvherre 3558 ECB : Datum *rb_datums, PartitionRangeDatumKind *rb_kind,
3559 : Datum *tuple_datums, int n_tuple_datums)
3560 : {
3561 : int i;
1821 alvherre 3562 GIC 777926 : int32 cmpval = -1;
1821 alvherre 3563 ECB :
1821 alvherre 3564 GIC 812589 : for (i = 0; i < n_tuple_datums; i++)
3565 : {
3566 780788 : if (rb_kind[i] == PARTITION_RANGE_DATUM_MINVALUE)
3567 34191 : return -1;
3568 746597 : else if (rb_kind[i] == PARTITION_RANGE_DATUM_MAXVALUE)
3569 34341 : return 1;
3570 :
3571 712256 : cmpval = DatumGetInt32(FunctionCall2Coll(&partsupfunc[i],
1821 alvherre 3572 CBC 712256 : partcollation[i],
1821 alvherre 3573 GIC 712256 : rb_datums[i],
1821 alvherre 3574 CBC 712256 : tuple_datums[i]));
3575 712256 : if (cmpval != 0)
3576 677593 : break;
1821 alvherre 3577 ECB : }
3578 :
1821 alvherre 3579 CBC 709394 : return cmpval;
1821 alvherre 3580 EUB : }
3581 :
3582 : /*
3583 : * partition_hbound_cmp
3584 : *
3585 : * Compares modulus first, then remainder if modulus is equal.
3586 : */
3587 : static int32
1821 alvherre 3588 GIC 605 : partition_hbound_cmp(int modulus1, int remainder1, int modulus2, int remainder2)
3589 : {
3590 605 : if (modulus1 < modulus2)
3591 87 : return -1;
1821 alvherre 3592 CBC 518 : if (modulus1 > modulus2)
1821 alvherre 3593 GIC 30 : return 1;
3594 488 : if (modulus1 == modulus2 && remainder1 != remainder2)
3595 488 : return (remainder1 > remainder2) ? 1 : -1;
1821 alvherre 3596 UIC 0 : return 0;
3597 : }
3598 :
3599 : /*
1821 alvherre 3600 ECB : * partition_list_bsearch
3601 : * Returns the index of the greatest bound datum that is less than equal
3602 : * to the given value or -1 if all of the bound datums are greater
3603 : *
3604 : * *is_equal is set to true if the bound datum at the returned index is equal
3605 : * to the input value.
3606 : */
3607 : int
1821 alvherre 3608 GIC 47779 : partition_list_bsearch(FmgrInfo *partsupfunc, Oid *partcollation,
1821 alvherre 3609 ECB : PartitionBoundInfo boundinfo,
3610 : Datum value, bool *is_equal)
3611 : {
3612 : int lo,
3613 : hi,
3614 : mid;
3615 :
1821 alvherre 3616 CBC 47779 : lo = -1;
1821 alvherre 3617 GIC 47779 : hi = boundinfo->ndatums - 1;
3618 111766 : while (lo < hi)
1821 alvherre 3619 ECB : {
3620 : int32 cmpval;
3621 :
1821 alvherre 3622 CBC 108133 : mid = (lo + hi + 1) / 2;
1821 alvherre 3623 GIC 108133 : cmpval = DatumGetInt32(FunctionCall2Coll(&partsupfunc[0],
3624 : partcollation[0],
3625 108133 : boundinfo->datums[mid][0],
3626 : value));
3627 108133 : if (cmpval <= 0)
3628 : {
3629 85565 : lo = mid;
3630 85565 : *is_equal = (cmpval == 0);
3631 85565 : if (*is_equal)
3632 44146 : break;
3633 : }
3634 : else
3635 22568 : hi = mid - 1;
3636 : }
3637 :
1821 alvherre 3638 CBC 47779 : return lo;
3639 : }
3640 :
3641 : /*
3642 : * partition_range_bsearch
3643 : * Returns the index of the greatest range bound that is less than or
3644 : * equal to the given range bound or -1 if all of the range bounds are
3645 : * greater
3646 : *
928 tgl 3647 ECB : * Upon return from this function, *cmpval is set to 0 if the bound at the
3648 : * returned index matches the input range bound exactly, otherwise a
3649 : * non-zero integer whose sign indicates the ordering, and whose absolute
3650 : * value gives the 1-based partition key number of the first mismatching
3651 : * column.
1821 alvherre 3652 : */
3653 : static int
1821 alvherre 3654 CBC 1014 : partition_range_bsearch(int partnatts, FmgrInfo *partsupfunc,
1821 alvherre 3655 ECB : Oid *partcollation,
3656 : PartitionBoundInfo boundinfo,
3657 : PartitionRangeBound *probe, int32 *cmpval)
3658 : {
3659 : int lo,
3660 : hi,
3661 : mid;
3662 :
1821 alvherre 3663 GIC 1014 : lo = -1;
3664 1014 : hi = boundinfo->ndatums - 1;
1821 alvherre 3665 CBC 3178 : while (lo < hi)
3666 : {
1821 alvherre 3667 GIC 2173 : mid = (lo + hi + 1) / 2;
928 tgl 3668 CBC 4346 : *cmpval = partition_rbound_cmp(partnatts, partsupfunc,
3669 : partcollation,
928 tgl 3670 GIC 2173 : boundinfo->datums[mid],
3671 2173 : boundinfo->kind[mid],
3672 2173 : (boundinfo->indexes[mid] == -1),
3673 : probe);
3674 2173 : if (*cmpval <= 0)
3675 : {
1821 alvherre 3676 2104 : lo = mid;
928 tgl 3677 2104 : if (*cmpval == 0)
1821 alvherre 3678 9 : break;
3679 : }
1821 alvherre 3680 ECB : else
1821 alvherre 3681 GIC 69 : hi = mid - 1;
3682 : }
3683 :
3684 1014 : return lo;
3685 : }
3686 :
3687 : /*
928 tgl 3688 ECB : * partition_range_datum_bsearch
1821 alvherre 3689 : * Returns the index of the greatest range bound that is less than or
3690 : * equal to the given tuple or -1 if all of the range bounds are greater
3691 : *
3692 : * *is_equal is set to true if the range bound at the returned index is equal
3693 : * to the input tuple.
3694 : */
3695 : int
1821 alvherre 3696 GIC 246513 : partition_range_datum_bsearch(FmgrInfo *partsupfunc, Oid *partcollation,
1821 alvherre 3697 ECB : PartitionBoundInfo boundinfo,
3698 : int nvalues, Datum *values, bool *is_equal)
3699 : {
3700 : int lo,
3701 : hi,
3702 : mid;
3703 :
1821 alvherre 3704 CBC 246513 : lo = -1;
1821 alvherre 3705 GIC 246513 : hi = boundinfo->ndatums - 1;
1821 alvherre 3706 CBC 759195 : while (lo < hi)
1821 alvherre 3707 ECB : {
3708 : int32 cmpval;
3709 :
1821 alvherre 3710 CBC 540668 : mid = (lo + hi + 1) / 2;
1821 alvherre 3711 GIC 540668 : cmpval = partition_rbound_datum_cmp(partsupfunc,
3712 : partcollation,
1821 alvherre 3713 CBC 540668 : boundinfo->datums[mid],
1821 alvherre 3714 GIC 540668 : boundinfo->kind[mid],
3715 : values,
3716 : nvalues);
3717 540668 : if (cmpval <= 0)
3718 : {
3719 311310 : lo = mid;
3720 311310 : *is_equal = (cmpval == 0);
3721 :
3722 311310 : if (*is_equal)
1821 alvherre 3723 CBC 27986 : break;
3724 : }
3725 : else
1821 alvherre 3726 GIC 229358 : hi = mid - 1;
3727 : }
3728 :
3729 246513 : return lo;
1821 alvherre 3730 ECB : }
3731 :
3732 : /*
3733 : * partition_hash_bsearch
3734 : * Returns the index of the greatest (modulus, remainder) pair that is
3735 : * less than or equal to the given (modulus, remainder) pair or -1 if
3736 : * all of them are greater
3737 : */
3738 : int
1821 alvherre 3739 CBC 174 : partition_hash_bsearch(PartitionBoundInfo boundinfo,
1821 alvherre 3740 ECB : int modulus, int remainder)
3741 : {
3742 : int lo,
3743 : hi,
3744 : mid;
3745 :
1821 alvherre 3746 GIC 174 : lo = -1;
1821 alvherre 3747 CBC 174 : hi = boundinfo->ndatums - 1;
1821 alvherre 3748 GBC 424 : while (lo < hi)
3749 : {
3750 : int32 cmpval,
1821 alvherre 3751 ECB : bound_modulus,
3752 : bound_remainder;
3753 :
1821 alvherre 3754 CBC 250 : mid = (lo + hi + 1) / 2;
1821 alvherre 3755 GIC 250 : bound_modulus = DatumGetInt32(boundinfo->datums[mid][0]);
3756 250 : bound_remainder = DatumGetInt32(boundinfo->datums[mid][1]);
3757 250 : cmpval = partition_hbound_cmp(bound_modulus, bound_remainder,
3758 : modulus, remainder);
3759 250 : if (cmpval <= 0)
3760 : {
3761 219 : lo = mid;
3762 :
1821 alvherre 3763 CBC 219 : if (cmpval == 0)
1821 alvherre 3764 UIC 0 : break;
1821 alvherre 3765 ECB : }
3766 : else
1821 alvherre 3767 GIC 31 : hi = mid - 1;
1821 alvherre 3768 ECB : }
3769 :
1821 alvherre 3770 GIC 174 : return lo;
3771 : }
3772 :
3773 : /*
3774 : * qsort_partition_hbound_cmp
3775 : *
3776 : * Hash bounds are sorted by modulus, then by remainder.
3777 : */
1607 michael 3778 ECB : static int32
1607 michael 3779 GIC 355 : qsort_partition_hbound_cmp(const void *a, const void *b)
1607 michael 3780 ECB : {
420 tgl 3781 CBC 355 : const PartitionHashBound *h1 = (const PartitionHashBound *) a;
3782 355 : const PartitionHashBound *h2 = (const PartitionHashBound *) b;
3783 :
1607 michael 3784 710 : return partition_hbound_cmp(h1->modulus, h1->remainder,
3785 355 : h2->modulus, h2->remainder);
3786 : }
3787 :
3788 : /*
3789 : * qsort_partition_list_value_cmp
3790 : *
3791 : * Compare two list partition bound datums.
3792 : */
3793 : static int32
1607 michael 3794 GIC 9953 : qsort_partition_list_value_cmp(const void *a, const void *b, void *arg)
1607 michael 3795 ECB : {
420 tgl 3796 GIC 9953 : Datum val1 = ((const PartitionListValue *) a)->value,
420 tgl 3797 CBC 9953 : val2 = ((const PartitionListValue *) b)->value;
1607 michael 3798 9953 : PartitionKey key = (PartitionKey) arg;
1607 michael 3799 ECB :
1607 michael 3800 GIC 9953 : return DatumGetInt32(FunctionCall2Coll(&key->partsupfunc[0],
1607 michael 3801 CBC 9953 : key->partcollation[0],
3802 : val1, val2));
3803 : }
3804 :
3805 : /*
3806 : * qsort_partition_rbound_cmp
3807 : *
3808 : * Used when sorting range bounds across all range partitions.
3809 : */
3810 : static int32
1607 michael 3811 GIC 10220 : qsort_partition_rbound_cmp(const void *a, const void *b, void *arg)
3812 : {
3813 10220 : PartitionRangeBound *b1 = (*(PartitionRangeBound *const *) a);
3814 10220 : PartitionRangeBound *b2 = (*(PartitionRangeBound *const *) b);
3815 10220 : PartitionKey key = (PartitionKey) arg;
3816 :
891 tgl 3817 CBC 10220 : return compare_range_bounds(key->partnatts, key->partsupfunc,
3818 : key->partcollation,
3819 : b1, b2);
3820 : }
3821 :
3822 : /*
3823 : * get_partition_operator
3824 : *
3825 : * Return oid of the operator of the given strategy for the given partition
1734 alvherre 3826 ECB : * key column. It is assumed that the partitioning key is of the same type as
3827 : * the chosen partitioning opclass, or at least binary-compatible. In the
3828 : * latter case, *need_relabel is set to true if the opclass is not of a
3829 : * polymorphic type (indicating a RelabelType node needed on top), otherwise
3830 : * false.
1821 alvherre 3831 EUB : */
3832 : static Oid
1821 alvherre 3833 GIC 6268 : get_partition_operator(PartitionKey key, int col, StrategyNumber strategy,
3834 : bool *need_relabel)
3835 : {
3836 : Oid operoid;
3837 :
3838 : /*
3839 : * Get the operator in the partitioning opfamily using the opclass'
1734 alvherre 3840 ECB : * declared input type as both left- and righttype.
1821 3841 : */
1821 alvherre 3842 CBC 6268 : operoid = get_opfamily_member(key->partopfamily[col],
1734 alvherre 3843 GIC 6268 : key->partopcintype[col],
1734 alvherre 3844 CBC 6268 : key->partopcintype[col],
3845 : strategy);
1734 alvherre 3846 GIC 6268 : if (!OidIsValid(operoid))
1734 alvherre 3847 UIC 0 : elog(ERROR, "missing operator %d(%u,%u) in partition opfamily %u",
3848 : strategy, key->partopcintype[col], key->partopcintype[col],
3849 : key->partopfamily[col]);
3850 :
3851 : /*
3852 : * If the partition key column is not of the same type as the operator
1734 alvherre 3853 ECB : * class and not polymorphic, tell caller to wrap the non-Const expression
3854 : * in a RelabelType. This matches what parse_coerce.c does.
3855 : */
1734 alvherre 3856 GIC 12567 : *need_relabel = (key->parttypid[col] != key->partopcintype[col] &&
1734 alvherre 3857 CBC 6296 : key->partopcintype[col] != RECORDOID &&
3858 28 : !IsPolymorphicType(key->partopcintype[col]));
3859 :
1821 alvherre 3860 GIC 6268 : return operoid;
1821 alvherre 3861 ECB : }
3862 :
3863 : /*
3864 : * make_partition_op_expr
3865 : * Returns an Expr for the given partition key column with arg1 and
3866 : * arg2 as its leftop and rightop, respectively
3867 : */
3868 : static Expr *
1821 alvherre 3869 CBC 6268 : make_partition_op_expr(PartitionKey key, int keynum,
1821 alvherre 3870 ECB : uint16 strategy, Expr *arg1, Expr *arg2)
3871 : {
3872 : Oid operoid;
1821 alvherre 3873 GIC 6268 : bool need_relabel = false;
1821 alvherre 3874 CBC 6268 : Expr *result = NULL;
3875 :
3876 : /* Get the correct btree operator for this partitioning column */
1821 alvherre 3877 GIC 6268 : operoid = get_partition_operator(key, keynum, strategy, &need_relabel);
1821 alvherre 3878 ECB :
3879 : /*
3880 : * Chosen operator may be such that the non-Const operand needs to be
3881 : * coerced, so apply the same; see the comment in
3882 : * get_partition_operator().
3883 : */
1821 alvherre 3884 GIC 6268 : if (!IsA(arg1, Const) &&
1821 alvherre 3885 CBC 4709 : (need_relabel ||
3886 4686 : key->partcollation[keynum] != key->parttypcoll[keynum]))
1821 alvherre 3887 GIC 23 : arg1 = (Expr *) makeRelabelType(arg1,
1821 alvherre 3888 CBC 23 : key->partopcintype[keynum],
1821 alvherre 3889 ECB : -1,
1821 alvherre 3890 CBC 23 : key->partcollation[keynum],
3891 : COERCE_EXPLICIT_CAST);
3892 :
3893 : /* Generate the actual expression */
1821 alvherre 3894 GIC 6268 : switch (key->strategy)
1821 alvherre 3895 ECB : {
1821 alvherre 3896 CBC 1153 : case PARTITION_STRATEGY_LIST:
1821 alvherre 3897 ECB : {
1821 alvherre 3898 CBC 1153 : List *elems = (List *) arg2;
3899 1153 : int nelems = list_length(elems);
1821 alvherre 3900 ECB :
1821 alvherre 3901 CBC 1153 : Assert(nelems >= 1);
3902 1153 : Assert(keynum == 0);
3903 :
1821 alvherre 3904 GIC 1543 : if (nelems > 1 &&
1821 alvherre 3905 CBC 390 : !type_is_array(key->parttypid[keynum]))
3906 387 : {
1821 alvherre 3907 ECB : ArrayExpr *arrexpr;
3908 : ScalarArrayOpExpr *saopexpr;
3909 :
3910 : /* Construct an ArrayExpr for the right-hand inputs */
1821 alvherre 3911 CBC 387 : arrexpr = makeNode(ArrayExpr);
3912 387 : arrexpr->array_typeid =
3913 387 : get_array_type(key->parttypid[keynum]);
1821 alvherre 3914 GIC 387 : arrexpr->array_collid = key->parttypcoll[keynum];
1821 alvherre 3915 CBC 387 : arrexpr->element_typeid = key->parttypid[keynum];
1821 alvherre 3916 GIC 387 : arrexpr->elements = elems;
3917 387 : arrexpr->multidims = false;
3918 387 : arrexpr->location = -1;
1821 alvherre 3919 ECB :
3920 : /* Build leftop = ANY (rightop) */
1821 alvherre 3921 GIC 387 : saopexpr = makeNode(ScalarArrayOpExpr);
1821 alvherre 3922 CBC 387 : saopexpr->opno = operoid;
1821 alvherre 3923 GIC 387 : saopexpr->opfuncid = get_opcode(operoid);
731 drowley 3924 CBC 387 : saopexpr->hashfuncid = InvalidOid;
641 drowley 3925 GIC 387 : saopexpr->negfuncid = InvalidOid;
1821 alvherre 3926 387 : saopexpr->useOr = true;
1821 alvherre 3927 CBC 387 : saopexpr->inputcollid = key->partcollation[keynum];
1821 alvherre 3928 GIC 387 : saopexpr->args = list_make2(arg1, arrexpr);
3929 387 : saopexpr->location = -1;
3930 :
3931 387 : result = (Expr *) saopexpr;
1821 alvherre 3932 ECB : }
3933 : else
3934 : {
1821 alvherre 3935 GIC 766 : List *elemops = NIL;
1821 alvherre 3936 ECB : ListCell *lc;
3937 :
1821 alvherre 3938 CBC 1535 : foreach(lc, elems)
3939 : {
1821 alvherre 3940 GIC 769 : Expr *elem = lfirst(lc),
1821 alvherre 3941 ECB : *elemop;
3942 :
1821 alvherre 3943 GIC 769 : elemop = make_opclause(operoid,
3944 : BOOLOID,
3945 : false,
3946 : arg1, elem,
1821 alvherre 3947 ECB : InvalidOid,
1821 alvherre 3948 CBC 769 : key->partcollation[keynum]);
1821 alvherre 3949 GIC 769 : elemops = lappend(elemops, elemop);
1821 alvherre 3950 EUB : }
3951 :
1821 alvherre 3952 GIC 766 : result = nelems > 1 ? makeBoolExpr(OR_EXPR, elemops, -1) : linitial(elemops);
3953 : }
3954 1153 : break;
1821 alvherre 3955 ECB : }
3956 :
1821 alvherre 3957 GIC 5115 : case PARTITION_STRATEGY_RANGE:
3958 5115 : result = make_opclause(operoid,
3959 : BOOLOID,
3960 : false,
3961 : arg1, arg2,
3962 : InvalidOid,
3963 5115 : key->partcollation[keynum]);
3964 5115 : break;
3965 :
157 alvherre 3966 UNC 0 : case PARTITION_STRATEGY_HASH:
3967 0 : Assert(false);
1821 alvherre 3968 ECB : break;
3969 : }
3970 :
1821 alvherre 3971 GIC 6268 : return result;
3972 : }
3973 :
3974 : /*
3975 : * get_qual_for_hash
3976 : *
3977 : * Returns a CHECK constraint expression to use as a hash partition's
3978 : * constraint, given the parent relation and partition bound structure.
3979 : *
1821 alvherre 3980 ECB : * The partition constraint for a hash partition is always a call to the
3981 : * built-in function satisfies_hash_partition().
3982 : */
3983 : static List *
1821 alvherre 3984 GIC 76 : get_qual_for_hash(Relation parent, PartitionBoundSpec *spec)
3985 : {
3986 76 : PartitionKey key = RelationGetPartitionKey(parent);
3987 : FuncExpr *fexpr;
1821 alvherre 3988 ECB : Node *relidConst;
3989 : Node *modulusConst;
3990 : Node *remainderConst;
3991 : List *args;
3992 : ListCell *partexprs_item;
3993 : int i;
3994 :
3995 : /* Fixed arguments. */
1821 alvherre 3996 CBC 76 : relidConst = (Node *) makeConst(OIDOID,
3997 : -1,
3998 : InvalidOid,
3999 : sizeof(Oid),
4000 : ObjectIdGetDatum(RelationGetRelid(parent)),
4001 : false,
4002 : true);
4003 :
4004 76 : modulusConst = (Node *) makeConst(INT4OID,
1821 alvherre 4005 ECB : -1,
4006 : InvalidOid,
4007 : sizeof(int32),
4008 : Int32GetDatum(spec->modulus),
4009 : false,
4010 : true);
4011 :
1821 alvherre 4012 GIC 76 : remainderConst = (Node *) makeConst(INT4OID,
1821 alvherre 4013 ECB : -1,
4014 : InvalidOid,
4015 : sizeof(int32),
4016 : Int32GetDatum(spec->remainder),
4017 : false,
4018 : true);
4019 :
1821 alvherre 4020 GIC 76 : args = list_make3(relidConst, modulusConst, remainderConst);
4021 76 : partexprs_item = list_head(key->partexprs);
4022 :
4023 : /* Add an argument for each key column. */
1821 alvherre 4024 CBC 161 : for (i = 0; i < key->partnatts; i++)
1821 alvherre 4025 ECB : {
4026 : Node *keyCol;
4027 :
4028 : /* Left operand */
1821 alvherre 4029 GIC 85 : if (key->partattrs[i] != 0)
4030 : {
1821 alvherre 4031 CBC 82 : keyCol = (Node *) makeVar(1,
1821 alvherre 4032 GIC 82 : key->partattrs[i],
4033 82 : key->parttypid[i],
4034 82 : key->parttypmod[i],
4035 82 : key->parttypcoll[i],
4036 : 0);
4037 : }
1821 alvherre 4038 ECB : else
4039 : {
1821 alvherre 4040 GIC 3 : keyCol = (Node *) copyObject(lfirst(partexprs_item));
1364 tgl 4041 3 : partexprs_item = lnext(key->partexprs, partexprs_item);
4042 : }
4043 :
1821 alvherre 4044 85 : args = lappend(args, keyCol);
4045 : }
4046 :
4047 76 : fexpr = makeFuncExpr(F_SATISFIES_HASH_PARTITION,
4048 : BOOLOID,
4049 : args,
4050 : InvalidOid,
1821 alvherre 4051 ECB : InvalidOid,
4052 : COERCE_EXPLICIT_CALL);
4053 :
1821 alvherre 4054 GIC 76 : return list_make1(fexpr);
4055 : }
4056 :
4057 : /*
4058 : * get_qual_for_list
1821 alvherre 4059 ECB : *
4060 : * Returns an implicit-AND list of expressions to use as a list partition's
4061 : * constraint, given the parent relation and partition bound structure.
4062 : *
4063 : * The function returns NIL for a default partition when it's the only
4064 : * partition since in that case there is no constraint.
4065 : */
4066 : static List *
1821 alvherre 4067 GIC 1184 : get_qual_for_list(Relation parent, PartitionBoundSpec *spec)
4068 : {
1821 alvherre 4069 CBC 1184 : PartitionKey key = RelationGetPartitionKey(parent);
1821 alvherre 4070 ECB : List *result;
4071 : Expr *keyCol;
4072 : Expr *opexpr;
4073 : NullTest *nulltest;
4074 : ListCell *cell;
1821 alvherre 4075 GIC 1184 : List *elems = NIL;
4076 1184 : bool list_has_null = false;
1821 alvherre 4077 ECB :
4078 : /*
4079 : * Only single-column list partitioning is supported, so we are worried
4080 : * only about the partition key with index 0.
4081 : */
1821 alvherre 4082 GIC 1184 : Assert(key->partnatts == 1);
4083 :
1821 alvherre 4084 ECB : /* Construct Var or expression representing the partition column */
1821 alvherre 4085 GIC 1184 : if (key->partattrs[0] != 0)
4086 1139 : keyCol = (Expr *) makeVar(1,
1821 alvherre 4087 CBC 1139 : key->partattrs[0],
4088 1139 : key->parttypid[0],
4089 1139 : key->parttypmod[0],
1821 alvherre 4090 GIC 1139 : key->parttypcoll[0],
1821 alvherre 4091 ECB : 0);
4092 : else
1821 alvherre 4093 CBC 45 : keyCol = (Expr *) copyObject(linitial(key->partexprs));
4094 :
1821 alvherre 4095 ECB : /*
4096 : * For default list partition, collect datums for all the partitions. The
4097 : * default partition constraint should check that the partition key is
4098 : * equal to none of those.
4099 : */
1821 alvherre 4100 GIC 1184 : if (spec->is_default)
4101 : {
4102 : int i;
1821 alvherre 4103 CBC 116 : int ndatums = 0;
717 4104 116 : PartitionDesc pdesc = RelationGetPartitionDesc(parent, false);
1821 alvherre 4105 GIC 116 : PartitionBoundInfo boundinfo = pdesc->boundinfo;
1821 alvherre 4106 ECB :
1821 alvherre 4107 GIC 116 : if (boundinfo)
4108 : {
4109 116 : ndatums = boundinfo->ndatums;
4110 :
4111 116 : if (partition_bound_accepts_nulls(boundinfo))
4112 24 : list_has_null = true;
4113 : }
4114 :
1821 alvherre 4115 ECB : /*
4116 : * If default is the only partition, there need not be any partition
4117 : * constraint on it.
4118 : */
1821 alvherre 4119 CBC 116 : if (ndatums == 0 && !list_has_null)
4120 19 : return NIL;
1821 alvherre 4121 ECB :
1821 alvherre 4122 GIC 495 : for (i = 0; i < ndatums; i++)
1821 alvherre 4123 ECB : {
4124 : Const *val;
4125 :
4126 : /*
4127 : * Construct Const from known-not-null datum. We must be careful
4128 : * to copy the value, because our result has to be able to outlive
4129 : * the relcache entry we're copying from.
4130 : */
1821 alvherre 4131 GIC 796 : val = makeConst(key->parttypid[0],
4132 398 : key->parttypmod[0],
1821 alvherre 4133 CBC 398 : key->parttypcoll[0],
1821 alvherre 4134 GIC 398 : key->parttyplen[0],
1821 alvherre 4135 CBC 398 : datumCopy(*boundinfo->datums[i],
1821 alvherre 4136 GIC 398 : key->parttypbyval[0],
1821 alvherre 4137 CBC 398 : key->parttyplen[0]),
1821 alvherre 4138 ECB : false, /* isnull */
1821 alvherre 4139 GIC 398 : key->parttypbyval[0]);
1821 alvherre 4140 ECB :
1821 alvherre 4141 GIC 398 : elems = lappend(elems, val);
4142 : }
4143 : }
1821 alvherre 4144 ECB : else
4145 : {
4146 : /*
4147 : * Create list of Consts for the allowed values, excluding any nulls.
4148 : */
1821 alvherre 4149 GIC 2690 : foreach(cell, spec->listdatums)
1821 alvherre 4150 ECB : {
629 peter 4151 GIC 1622 : Const *val = lfirst_node(Const, cell);
4152 :
1821 alvherre 4153 1622 : if (val->constisnull)
4154 27 : list_has_null = true;
4155 : else
4156 1595 : elems = lappend(elems, copyObject(val));
4157 : }
4158 : }
1821 alvherre 4159 ECB :
1821 alvherre 4160 GIC 1165 : if (elems)
4161 : {
1821 alvherre 4162 ECB : /*
4163 : * Generate the operator expression from the non-null partition
4164 : * values.
4165 : */
1821 alvherre 4166 GIC 1153 : opexpr = make_partition_op_expr(key, 0, BTEqualStrategyNumber,
4167 : keyCol, (Expr *) elems);
4168 : }
1821 alvherre 4169 ECB : else
4170 : {
4171 : /*
4172 : * If there are no partition values, we don't need an operator
4173 : * expression.
4174 : */
1821 alvherre 4175 CBC 12 : opexpr = NULL;
4176 : }
4177 :
1821 alvherre 4178 GIC 1165 : if (!list_has_null)
4179 : {
4180 : /*
4181 : * Gin up a "col IS NOT NULL" test that will be ANDed with the main
4182 : * expression. This might seem redundant, but the partition routing
1821 alvherre 4183 ECB : * machinery needs it.
4184 : */
1821 alvherre 4185 CBC 1114 : nulltest = makeNode(NullTest);
4186 1114 : nulltest->arg = keyCol;
4187 1114 : nulltest->nulltesttype = IS_NOT_NULL;
1821 alvherre 4188 GIC 1114 : nulltest->argisrow = false;
1821 alvherre 4189 CBC 1114 : nulltest->location = -1;
4190 :
1821 alvherre 4191 GIC 1114 : result = opexpr ? list_make2(nulltest, opexpr) : list_make1(nulltest);
4192 : }
1821 alvherre 4193 ECB : else
4194 : {
4195 : /*
4196 : * Gin up a "col IS NULL" test that will be OR'd with the main
4197 : * expression.
4198 : */
1821 alvherre 4199 GIC 51 : nulltest = makeNode(NullTest);
4200 51 : nulltest->arg = keyCol;
4201 51 : nulltest->nulltesttype = IS_NULL;
4202 51 : nulltest->argisrow = false;
4203 51 : nulltest->location = -1;
4204 :
4205 51 : if (opexpr)
1821 alvherre 4206 ECB : {
4207 : Expr *or;
4208 :
1821 alvherre 4209 CBC 39 : or = makeBoolExpr(OR_EXPR, list_make2(nulltest, opexpr), -1);
1821 alvherre 4210 GIC 39 : result = list_make1(or);
4211 : }
1821 alvherre 4212 ECB : else
1821 alvherre 4213 GIC 12 : result = list_make1(nulltest);
4214 : }
4215 :
4216 : /*
4217 : * Note that, in general, applying NOT to a constraint expression doesn't
4218 : * necessarily invert the set of rows it accepts, because NOT (NULL) is
4219 : * NULL. However, the partition constraints we construct here never
4220 : * evaluate to NULL, so applying NOT works as intended.
4221 : */
4222 1165 : if (spec->is_default)
4223 : {
4224 97 : result = list_make1(make_ands_explicit(result));
4225 97 : result = list_make1(makeBoolExpr(NOT_EXPR, result, -1));
4226 : }
4227 :
4228 1165 : return result;
4229 : }
4230 :
4231 : /*
4232 : * get_qual_for_range
4233 : *
4234 : * Returns an implicit-AND list of expressions to use as a range partition's
4235 : * constraint, given the parent relation and partition bound structure.
4236 : *
4237 : * For a multi-column range partition key, say (a, b, c), with (al, bl, cl)
4238 : * as the lower bound tuple and (au, bu, cu) as the upper bound tuple, we
4239 : * generate an expression tree of the following form:
4240 : *
4241 : * (a IS NOT NULL) and (b IS NOT NULL) and (c IS NOT NULL)
4242 : * AND
4243 : * (a > al OR (a = al AND b > bl) OR (a = al AND b = bl AND c >= cl))
4244 : * AND
4245 : * (a < au OR (a = au AND b < bu) OR (a = au AND b = bu AND c < cu))
4246 : *
4247 : * It is often the case that a prefix of lower and upper bound tuples contains
4248 : * the same values, for example, (al = au), in which case, we will emit an
4249 : * expression tree of the following form:
4250 : *
4251 : * (a IS NOT NULL) and (b IS NOT NULL) and (c IS NOT NULL)
4252 : * AND
4253 : * (a = al)
4254 : * AND
4255 : * (b > bl OR (b = bl AND c >= cl))
4256 : * AND
4257 : * (b < bu OR (b = bu AND c < cu))
4258 : *
4259 : * If a bound datum is either MINVALUE or MAXVALUE, these expressions are
1821 alvherre 4260 ECB : * simplified using the fact that any value is greater than MINVALUE and less
4261 : * than MAXVALUE. So, for example, if cu = MAXVALUE, c < cu is automatically
4262 : * true, and we need not emit any expression for it, and the last line becomes
4263 : *
4264 : * (b < bu) OR (b = bu), which is simplified to (b <= bu)
4265 : *
4266 : * In most common cases with only one partition column, say a, the following
4267 : * expression tree will be generated: a IS NOT NULL AND a >= al AND a < au
4268 : *
4269 : * For default partition, it returns the negation of the constraints of all
4270 : * the other partitions.
4271 : *
4272 : * External callers should pass for_default as false; we set it to true only
4273 : * when recursing.
4274 : */
4275 : static List *
1821 alvherre 4276 GIC 1590 : get_qual_for_range(Relation parent, PartitionBoundSpec *spec,
4277 : bool for_default)
4278 : {
4279 1590 : List *result = NIL;
4280 : ListCell *cell1,
4281 : *cell2,
4282 : *partexprs_item,
4283 : *partexprs_item_saved;
4284 : int i,
1821 alvherre 4285 ECB : j;
4286 : PartitionRangeDatum *ldatum,
4287 : *udatum;
1821 alvherre 4288 CBC 1590 : PartitionKey key = RelationGetPartitionKey(parent);
1821 alvherre 4289 ECB : Expr *keyCol;
4290 : Const *lower_val,
4291 : *upper_val;
4292 : List *lower_or_arms,
4293 : *upper_or_arms;
4294 : int num_or_arms,
4295 : current_or_arm;
4296 : ListCell *lower_or_start_datum,
4297 : *upper_or_start_datum;
4298 : bool need_next_lower_arm,
4299 : need_next_upper_arm;
4300 :
1821 alvherre 4301 CBC 1590 : if (spec->is_default)
1821 alvherre 4302 EUB : {
1821 alvherre 4303 GIC 111 : List *or_expr_args = NIL;
717 alvherre 4304 CBC 111 : PartitionDesc pdesc = RelationGetPartitionDesc(parent, false);
1821 alvherre 4305 GIC 111 : Oid *inhoids = pdesc->oids;
4306 111 : int nparts = pdesc->nparts,
4307 : k;
1821 alvherre 4308 ECB :
186 drowley 4309 GNC 425 : for (k = 0; k < nparts; k++)
4310 : {
4311 314 : Oid inhrelid = inhoids[k];
4312 : HeapTuple tuple;
4313 : Datum datum;
1821 alvherre 4314 ECB : PartitionBoundSpec *bspec;
4315 :
1821 alvherre 4316 GIC 314 : tuple = SearchSysCache1(RELOID, inhrelid);
4317 314 : if (!HeapTupleIsValid(tuple))
1821 alvherre 4318 UIC 0 : elog(ERROR, "cache lookup failed for relation %u", inhrelid);
4319 :
15 dgustafsson 4320 GNC 314 : datum = SysCacheGetAttrNotNull(RELOID, tuple,
4321 : Anum_pg_class_relpartbound);
4322 : bspec = (PartitionBoundSpec *)
1821 alvherre 4323 CBC 314 : stringToNode(TextDatumGetCString(datum));
1821 alvherre 4324 GIC 314 : if (!IsA(bspec, PartitionBoundSpec))
1821 alvherre 4325 UIC 0 : elog(ERROR, "expected PartitionBoundSpec");
4326 :
1821 alvherre 4327 GIC 314 : if (!bspec->is_default)
4328 : {
4329 : List *part_qual;
4330 :
4331 203 : part_qual = get_qual_for_range(parent, bspec, true);
4332 :
4333 : /*
1821 alvherre 4334 ECB : * AND the constraints of the partition and add to
4335 : * or_expr_args
4336 : */
1821 alvherre 4337 CBC 406 : or_expr_args = lappend(or_expr_args, list_length(part_qual) > 1
1821 alvherre 4338 GIC 194 : ? makeBoolExpr(AND_EXPR, part_qual, -1)
1821 alvherre 4339 CBC 9 : : linitial(part_qual));
4340 : }
1821 alvherre 4341 GIC 314 : ReleaseSysCache(tuple);
4342 : }
4343 :
4344 111 : if (or_expr_args != NIL)
4345 : {
1821 alvherre 4346 ECB : Expr *other_parts_constr;
4347 :
4348 : /*
4349 : * Combine the constraints obtained for non-default partitions
4350 : * using OR. As requested, each of the OR's args doesn't include
4351 : * the NOT NULL test for partition keys (which is to avoid its
4352 : * useless repetition). Add the same now.
4353 : */
4354 : other_parts_constr =
1821 alvherre 4355 GIC 154 : makeBoolExpr(AND_EXPR,
4356 : lappend(get_range_nulltest(key),
1821 alvherre 4357 CBC 77 : list_length(or_expr_args) > 1
4358 58 : ? makeBoolExpr(OR_EXPR, or_expr_args,
4359 : -1)
1821 alvherre 4360 GIC 19 : : linitial(or_expr_args)),
4361 : -1);
4362 :
4363 : /*
4364 : * Finally, the default partition contains everything *NOT*
4365 : * contained in the non-default partitions.
4366 : */
4367 77 : result = list_make1(makeBoolExpr(NOT_EXPR,
1821 alvherre 4368 ECB : list_make1(other_parts_constr), -1));
4369 : }
4370 :
1821 alvherre 4371 CBC 111 : return result;
4372 : }
4373 :
4374 : /*
4375 : * If it is the recursive call for default, we skip the get_range_nulltest
4376 : * to avoid accumulating the NullTest on the same keys for each partition.
4377 : */
1821 alvherre 4378 GIC 1479 : if (!for_default)
4379 1276 : result = get_range_nulltest(key);
1821 alvherre 4380 ECB :
4381 : /*
4382 : * Iterate over the key columns and check if the corresponding lower and
4383 : * upper datums are equal using the btree equality operator for the
4384 : * column's type. If equal, we emit single keyCol = common_value
4385 : * expression. Starting from the first column for which the corresponding
4386 : * lower and upper bound datums are not equal, we generate OR expressions
4387 : * as shown in the function's header comment.
4388 : */
1821 alvherre 4389 GIC 1479 : i = 0;
1821 alvherre 4390 CBC 1479 : partexprs_item = list_head(key->partexprs);
1821 alvherre 4391 GIC 1479 : partexprs_item_saved = partexprs_item; /* placate compiler */
4392 1749 : forboth(cell1, spec->lowerdatums, cell2, spec->upperdatums)
4393 : {
4394 : EState *estate;
4395 : MemoryContext oldcxt;
4396 : Expr *test_expr;
4397 : ExprState *test_exprstate;
4398 : Datum test_result;
4399 : bool isNull;
4400 :
629 peter 4401 CBC 1749 : ldatum = lfirst_node(PartitionRangeDatum, cell1);
629 peter 4402 GIC 1749 : udatum = lfirst_node(PartitionRangeDatum, cell2);
4403 :
4404 : /*
1821 alvherre 4405 ECB : * Since get_range_key_properties() modifies partexprs_item, and we
4406 : * might need to start over from the previous expression in the later
4407 : * part of this function, save away the current value.
4408 : */
1821 alvherre 4409 GIC 1749 : partexprs_item_saved = partexprs_item;
1821 alvherre 4410 ECB :
1821 alvherre 4411 CBC 1749 : get_range_key_properties(key, i, ldatum, udatum,
1821 alvherre 4412 ECB : &partexprs_item,
4413 : &keyCol,
4414 : &lower_val, &upper_val);
4415 :
4416 : /*
4417 : * If either value is NULL, the corresponding partition bound is
4418 : * either MINVALUE or MAXVALUE, and we treat them as unequal, because
4419 : * even if they're the same, there is no common value to equate the
4420 : * key column with.
4421 : */
1821 alvherre 4422 GIC 1749 : if (!lower_val || !upper_val)
4423 : break;
4424 :
4425 : /* Create the test expression */
4426 1559 : estate = CreateExecutorState();
1821 alvherre 4427 CBC 1559 : oldcxt = MemoryContextSwitchTo(estate->es_query_cxt);
1821 alvherre 4428 GBC 1559 : test_expr = make_partition_op_expr(key, i, BTEqualStrategyNumber,
4429 : (Expr *) lower_val,
4430 : (Expr *) upper_val);
1821 alvherre 4431 CBC 1559 : fix_opfuncids((Node *) test_expr);
4432 1559 : test_exprstate = ExecInitExpr(test_expr, NULL);
1821 alvherre 4433 GIC 1559 : test_result = ExecEvalExprSwitchContext(test_exprstate,
4434 1559 : GetPerTupleExprContext(estate),
1821 alvherre 4435 ECB : &isNull);
1821 alvherre 4436 GIC 1559 : MemoryContextSwitchTo(oldcxt);
4437 1559 : FreeExecutorState(estate);
4438 :
1821 alvherre 4439 ECB : /* If not equal, go generate the OR expressions */
1821 alvherre 4440 CBC 1559 : if (!DatumGetBool(test_result))
1821 alvherre 4441 GIC 1289 : break;
4442 :
1821 alvherre 4443 ECB : /*
4444 : * The bounds for the last key column can't be equal, because such a
4445 : * range partition would never be allowed to be defined (it would have
4446 : * an empty range otherwise).
4447 : */
1821 alvherre 4448 GIC 270 : if (i == key->partnatts - 1)
1821 alvherre 4449 LBC 0 : elog(ERROR, "invalid range bound specification");
1821 alvherre 4450 ECB :
4451 : /* Equal, so generate keyCol = lower_val expression */
1821 alvherre 4452 GIC 270 : result = lappend(result,
1821 alvherre 4453 CBC 270 : make_partition_op_expr(key, i, BTEqualStrategyNumber,
1821 alvherre 4454 ECB : keyCol, (Expr *) lower_val));
4455 :
1821 alvherre 4456 CBC 270 : i++;
4457 : }
4458 :
1821 alvherre 4459 ECB : /* First pair of lower_val and upper_val that are not equal. */
1821 alvherre 4460 CBC 1479 : lower_or_start_datum = cell1;
1821 alvherre 4461 GIC 1479 : upper_or_start_datum = cell2;
1821 alvherre 4462 ECB :
4463 : /* OR will have as many arms as there are key columns left. */
1821 alvherre 4464 CBC 1479 : num_or_arms = key->partnatts - i;
1821 alvherre 4465 GIC 1479 : current_or_arm = 0;
1821 alvherre 4466 CBC 1479 : lower_or_arms = upper_or_arms = NIL;
4467 1479 : need_next_lower_arm = need_next_upper_arm = true;
4468 1625 : while (current_or_arm < num_or_arms)
4469 : {
4470 1625 : List *lower_or_arm_args = NIL,
1821 alvherre 4471 GIC 1625 : *upper_or_arm_args = NIL;
4472 :
4473 : /* Restart scan of columns from the i'th one */
4474 1625 : j = i;
1821 alvherre 4475 CBC 1625 : partexprs_item = partexprs_item_saved;
4476 :
1364 tgl 4477 GIC 1813 : for_both_cell(cell1, spec->lowerdatums, lower_or_start_datum,
4478 : cell2, spec->upperdatums, upper_or_start_datum)
4479 : {
1821 alvherre 4480 1813 : PartitionRangeDatum *ldatum_next = NULL,
4481 1813 : *udatum_next = NULL;
4482 :
629 peter 4483 1813 : ldatum = lfirst_node(PartitionRangeDatum, cell1);
1364 tgl 4484 1813 : if (lnext(spec->lowerdatums, cell1))
1821 alvherre 4485 CBC 373 : ldatum_next = castNode(PartitionRangeDatum,
1364 tgl 4486 ECB : lfirst(lnext(spec->lowerdatums, cell1)));
629 peter 4487 CBC 1813 : udatum = lfirst_node(PartitionRangeDatum, cell2);
1364 tgl 4488 1813 : if (lnext(spec->upperdatums, cell2))
1821 alvherre 4489 373 : udatum_next = castNode(PartitionRangeDatum,
1364 tgl 4490 ECB : lfirst(lnext(spec->upperdatums, cell2)));
1821 alvherre 4491 GIC 1813 : get_range_key_properties(key, j, ldatum, udatum,
1821 alvherre 4492 ECB : &partexprs_item,
4493 : &keyCol,
4494 : &lower_val, &upper_val);
4495 :
1821 alvherre 4496 GIC 1813 : if (need_next_lower_arm && lower_val)
4497 : {
4498 : uint16 strategy;
4499 :
4500 : /*
1821 alvherre 4501 ECB : * For the non-last columns of this arm, use the EQ operator.
4502 : * For the last column of this arm, use GT, unless this is the
4503 : * last column of the whole bound check, or the next bound
4504 : * datum is MINVALUE, in which case use GE.
4505 : */
1821 alvherre 4506 GIC 1673 : if (j - i < current_or_arm)
4507 161 : strategy = BTEqualStrategyNumber;
4508 1512 : else if (j == key->partnatts - 1 ||
4509 155 : (ldatum_next &&
1821 alvherre 4510 CBC 155 : ldatum_next->kind == PARTITION_RANGE_DATUM_MINVALUE))
4511 1378 : strategy = BTGreaterEqualStrategyNumber;
1821 alvherre 4512 ECB : else
1821 alvherre 4513 CBC 134 : strategy = BTGreaterStrategyNumber;
1821 alvherre 4514 ECB :
1821 alvherre 4515 GIC 1673 : lower_or_arm_args = lappend(lower_or_arm_args,
1821 alvherre 4516 CBC 1673 : make_partition_op_expr(key, j,
4517 : strategy,
1821 alvherre 4518 ECB : keyCol,
4519 : (Expr *) lower_val));
4520 : }
4521 :
1821 alvherre 4522 GIC 1813 : if (need_next_upper_arm && upper_val)
4523 : {
4524 : uint16 strategy;
4525 :
4526 : /*
4527 : * For the non-last columns of this arm, use the EQ operator.
4528 : * For the last column of this arm, use LT, unless the next
4529 : * bound datum is MAXVALUE, in which case use LE.
1821 alvherre 4530 ECB : */
1821 alvherre 4531 CBC 1613 : if (j - i < current_or_arm)
1821 alvherre 4532 GIC 128 : strategy = BTEqualStrategyNumber;
4533 1485 : else if (udatum_next &&
4534 137 : udatum_next->kind == PARTITION_RANGE_DATUM_MAXVALUE)
4535 15 : strategy = BTLessEqualStrategyNumber;
4536 : else
1821 alvherre 4537 CBC 1470 : strategy = BTLessStrategyNumber;
1821 alvherre 4538 ECB :
1821 alvherre 4539 CBC 1613 : upper_or_arm_args = lappend(upper_or_arm_args,
4540 1613 : make_partition_op_expr(key, j,
1821 alvherre 4541 ECB : strategy,
4542 : keyCol,
4543 : (Expr *) upper_val));
4544 : }
4545 :
4546 : /*
4547 : * Did we generate enough of OR's arguments? First arm considers
4548 : * the first of the remaining columns, second arm considers first
4549 : * two of the remaining columns, and so on.
4550 : */
1821 alvherre 4551 CBC 1813 : ++j;
1821 alvherre 4552 GIC 1813 : if (j - i > current_or_arm)
1821 alvherre 4553 ECB : {
4554 : /*
4555 : * We must not emit any more arms if the new column that will
4556 : * be considered is unbounded, or this one was.
4557 : */
1821 alvherre 4558 GIC 1625 : if (!lower_val || !ldatum_next ||
4559 155 : ldatum_next->kind != PARTITION_RANGE_DATUM_VALUE)
1821 alvherre 4560 CBC 1497 : need_next_lower_arm = false;
4561 1625 : if (!upper_val || !udatum_next ||
1821 alvherre 4562 GIC 137 : udatum_next->kind != PARTITION_RANGE_DATUM_VALUE)
1821 alvherre 4563 CBC 1521 : need_next_upper_arm = false;
1821 alvherre 4564 GIC 1625 : break;
4565 : }
4566 : }
4567 :
4568 1625 : if (lower_or_arm_args != NIL)
4569 3024 : lower_or_arms = lappend(lower_or_arms,
4570 1512 : list_length(lower_or_arm_args) > 1
1821 alvherre 4571 CBC 128 : ? makeBoolExpr(AND_EXPR, lower_or_arm_args, -1)
4572 1384 : : linitial(lower_or_arm_args));
1821 alvherre 4573 ECB :
1821 alvherre 4574 CBC 1625 : if (upper_or_arm_args != NIL)
4575 2970 : upper_or_arms = lappend(upper_or_arms,
4576 1485 : list_length(upper_or_arm_args) > 1
4577 104 : ? makeBoolExpr(AND_EXPR, upper_or_arm_args, -1)
4578 1381 : : linitial(upper_or_arm_args));
1821 alvherre 4579 ECB :
4580 : /* If no work to do in the next iteration, break away. */
1821 alvherre 4581 GIC 1625 : if (!need_next_lower_arm && !need_next_upper_arm)
4582 1479 : break;
4583 :
4584 146 : ++current_or_arm;
4585 : }
4586 :
4587 : /*
1821 alvherre 4588 ECB : * Generate the OR expressions for each of lower and upper bounds (if
1821 alvherre 4589 EUB : * required), and append to the list of implicitly ANDed list of
4590 : * expressions.
4591 : */
1821 alvherre 4592 GIC 1479 : if (lower_or_arms != NIL)
1821 alvherre 4593 CBC 2768 : result = lappend(result,
1821 alvherre 4594 GIC 1384 : list_length(lower_or_arms) > 1
4595 95 : ? makeBoolExpr(OR_EXPR, lower_or_arms, -1)
4596 1289 : : linitial(lower_or_arms));
4597 1479 : if (upper_or_arms != NIL)
4598 2762 : result = lappend(result,
4599 1381 : list_length(upper_or_arms) > 1
4600 80 : ? makeBoolExpr(OR_EXPR, upper_or_arms, -1)
4601 1301 : : linitial(upper_or_arms));
4602 :
4603 : /*
4604 : * As noted above, for non-default, we return list with constant TRUE. If
4605 : * the result is NIL during the recursive call for default, it implies
4606 : * this is the only other partition which can hold every value of the key
4607 : * except NULL. Hence we return the NullTest result skipped earlier.
4608 : */
4609 1479 : if (result == NIL)
1821 alvherre 4610 UIC 0 : result = for_default
4611 0 : ? get_range_nulltest(key)
1821 alvherre 4612 LBC 0 : : list_make1(makeBoolConst(true, false));
4613 :
1821 alvherre 4614 GIC 1479 : return result;
4615 : }
4616 :
4617 : /*
4618 : * get_range_key_properties
4619 : * Returns range partition key information for a given column
1821 alvherre 4620 ECB : *
4621 : * This is a subroutine for get_qual_for_range, and its API is pretty
4622 : * specialized to that caller.
4623 : *
4624 : * Constructs an Expr for the key column (returned in *keyCol) and Consts
4625 : * for the lower and upper range limits (returned in *lower_val and
4626 : * *upper_val). For MINVALUE/MAXVALUE limits, NULL is returned instead of
4627 : * a Const. All of these structures are freshly palloc'd.
4628 : *
4629 : * *partexprs_item points to the cell containing the next expression in
4630 : * the key->partexprs list, or NULL. It may be advanced upon return.
4631 : */
1821 alvherre 4632 EUB : static void
1821 alvherre 4633 CBC 3562 : get_range_key_properties(PartitionKey key, int keynum,
1821 alvherre 4634 ECB : PartitionRangeDatum *ldatum,
4635 : PartitionRangeDatum *udatum,
4636 : ListCell **partexprs_item,
4637 : Expr **keyCol,
4638 : Const **lower_val, Const **upper_val)
4639 : {
4640 : /* Get partition key expression for this column */
1821 alvherre 4641 CBC 3562 : if (key->partattrs[keynum] != 0)
4642 : {
4643 3198 : *keyCol = (Expr *) makeVar(1,
4644 3198 : key->partattrs[keynum],
1821 alvherre 4645 GIC 3198 : key->parttypid[keynum],
1821 alvherre 4646 CBC 3198 : key->parttypmod[keynum],
4647 3198 : key->parttypcoll[keynum],
4648 : 0);
4649 : }
4650 : else
4651 : {
1821 alvherre 4652 GIC 364 : if (*partexprs_item == NULL)
1821 alvherre 4653 UIC 0 : elog(ERROR, "wrong number of partition key expressions");
1821 alvherre 4654 GIC 364 : *keyCol = copyObject(lfirst(*partexprs_item));
1364 tgl 4655 364 : *partexprs_item = lnext(key->partexprs, *partexprs_item);
1821 alvherre 4656 ECB : }
4657 :
4658 : /* Get appropriate Const nodes for the bounds */
1821 alvherre 4659 GIC 3562 : if (ldatum->kind == PARTITION_RANGE_DATUM_VALUE)
4660 3336 : *lower_val = castNode(Const, copyObject(ldatum->value));
4661 : else
4662 226 : *lower_val = NULL;
1821 alvherre 4663 ECB :
1821 alvherre 4664 CBC 3562 : if (udatum->kind == PARTITION_RANGE_DATUM_VALUE)
1821 alvherre 4665 GIC 3276 : *upper_val = castNode(Const, copyObject(udatum->value));
4666 : else
4667 286 : *upper_val = NULL;
1821 alvherre 4668 CBC 3562 : }
4669 :
1821 alvherre 4670 ECB : /*
4671 : * get_range_nulltest
4672 : *
4673 : * A non-default range partition table does not currently allow partition
4674 : * keys to be null, so emit an IS NOT NULL expression for each key column.
4675 : */
4676 : static List *
1821 alvherre 4677 GIC 1353 : get_range_nulltest(PartitionKey key)
4678 : {
1821 alvherre 4679 CBC 1353 : List *result = NIL;
1821 alvherre 4680 EUB : NullTest *nulltest;
1821 alvherre 4681 ECB : ListCell *partexprs_item;
4682 : int i;
4683 :
1821 alvherre 4684 GIC 1353 : partexprs_item = list_head(key->partexprs);
1821 alvherre 4685 CBC 3092 : for (i = 0; i < key->partnatts; i++)
1821 alvherre 4686 ECB : {
4687 : Expr *keyCol;
4688 :
1821 alvherre 4689 CBC 1739 : if (key->partattrs[i] != 0)
1821 alvherre 4690 ECB : {
1821 alvherre 4691 GIC 1563 : keyCol = (Expr *) makeVar(1,
4692 1563 : key->partattrs[i],
1821 alvherre 4693 CBC 1563 : key->parttypid[i],
1821 alvherre 4694 GIC 1563 : key->parttypmod[i],
4695 1563 : key->parttypcoll[i],
4696 : 0);
4697 : }
4698 : else
4699 : {
4700 176 : if (partexprs_item == NULL)
1821 alvherre 4701 UIC 0 : elog(ERROR, "wrong number of partition key expressions");
1821 alvherre 4702 CBC 176 : keyCol = copyObject(lfirst(partexprs_item));
1364 tgl 4703 GIC 176 : partexprs_item = lnext(key->partexprs, partexprs_item);
4704 : }
4705 :
1821 alvherre 4706 CBC 1739 : nulltest = makeNode(NullTest);
4707 1739 : nulltest->arg = keyCol;
1821 alvherre 4708 GIC 1739 : nulltest->nulltesttype = IS_NOT_NULL;
1821 alvherre 4709 CBC 1739 : nulltest->argisrow = false;
1821 alvherre 4710 GIC 1739 : nulltest->location = -1;
4711 1739 : result = lappend(result, nulltest);
1821 alvherre 4712 ECB : }
4713 :
1821 alvherre 4714 GIC 1353 : return result;
4715 : }
1821 alvherre 4716 ECB :
4717 : /*
4718 : * compute_partition_hash_value
4719 : *
4720 : * Compute the hash value for given partition key values.
4721 : */
4722 : uint64
1479 peter 4723 CBC 106330 : compute_partition_hash_value(int partnatts, FmgrInfo *partsupfunc, Oid *partcollation,
1761 tgl 4724 ECB : Datum *values, bool *isnull)
4725 : {
4726 : int i;
1821 alvherre 4727 CBC 106330 : uint64 rowHash = 0;
1821 alvherre 4728 GIC 106330 : Datum seed = UInt64GetDatum(HASH_PARTITION_SEED);
4729 :
4730 212726 : for (i = 0; i < partnatts; i++)
1821 alvherre 4731 ECB : {
4732 : /* Nulls are just ignored */
1821 alvherre 4733 GIC 106396 : if (!isnull[i])
4734 : {
4735 : Datum hash;
4736 :
4737 106363 : Assert(OidIsValid(partsupfunc[i].fn_oid));
4738 :
4739 : /*
4740 : * Compute hash for each datum value by calling respective
4741 : * datatype-specific hash functions of each partition key
4742 : * attribute.
4743 : */
1455 tgl 4744 106363 : hash = FunctionCall2Coll(&partsupfunc[i], partcollation[i],
4745 106363 : values[i], seed);
4746 :
4747 : /* Form a single 64-bit hash value */
1821 alvherre 4748 106363 : rowHash = hash_combine64(rowHash, DatumGetUInt64(hash));
4749 : }
4750 : }
1821 alvherre 4751 ECB :
1821 alvherre 4752 GIC 106330 : return rowHash;
4753 : }
4754 :
4755 : /*
4756 : * satisfies_hash_partition
4757 : *
4758 : * This is an SQL-callable function for use in hash partition constraints.
4759 : * The first three arguments are the parent table OID, modulus, and remainder.
4760 : * The remaining arguments are the value of the partitioning columns (or
4761 : * expressions); these are hashed and the results are combined into a single
4762 : * hash value by calling hash_combine64.
4763 : *
4764 : * Returns true if remainder produced when this computed single hash value is
4765 : * divided by the given modulus is equal to given remainder, otherwise false.
4766 : * NB: it's important that this never return null, as the constraint machinery
874 tgl 4767 ECB : * would consider that to be a "pass".
4768 : *
1821 alvherre 4769 : * See get_qual_for_hash() for usage.
4770 : */
4771 : Datum
1821 alvherre 4772 CBC 2114 : satisfies_hash_partition(PG_FUNCTION_ARGS)
1821 alvherre 4773 ECB : {
4774 : typedef struct ColumnsHashData
4775 : {
4776 : Oid relid;
4777 : int nkeys;
4778 : Oid variadic_type;
4779 : int16 variadic_typlen;
4780 : bool variadic_typbyval;
4781 : char variadic_typalign;
4782 : Oid partcollid[PARTITION_MAX_KEYS];
1455 tgl 4783 : FmgrInfo partsupfunc[FLEXIBLE_ARRAY_MEMBER];
1821 alvherre 4784 : } ColumnsHashData;
4785 : Oid parentId;
4786 : int modulus;
4787 : int remainder;
1821 alvherre 4788 CBC 2114 : Datum seed = UInt64GetDatum(HASH_PARTITION_SEED);
4789 : ColumnsHashData *my_extra;
1821 alvherre 4790 GIC 2114 : uint64 rowHash = 0;
4791 :
4792 : /* Return false if the parent OID, modulus, or remainder is NULL. */
4793 2114 : if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(2))
874 tgl 4794 6 : PG_RETURN_BOOL(false);
1821 alvherre 4795 CBC 2108 : parentId = PG_GETARG_OID(0);
4796 2108 : modulus = PG_GETARG_INT32(1);
1821 alvherre 4797 GIC 2108 : remainder = PG_GETARG_INT32(2);
4798 :
4799 : /* Sanity check modulus and remainder. */
4800 2108 : if (modulus <= 0)
4801 3 : ereport(ERROR,
4802 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
620 fujii 4803 ECB : errmsg("modulus for hash partition must be an integer value greater than zero")));
1821 alvherre 4804 CBC 2105 : if (remainder < 0)
1821 alvherre 4805 GIC 3 : ereport(ERROR,
4806 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
620 fujii 4807 ECB : errmsg("remainder for hash partition must be an integer value greater than or equal to zero")));
1821 alvherre 4808 CBC 2102 : if (remainder >= modulus)
1821 alvherre 4809 GIC 3 : ereport(ERROR,
4810 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4811 : errmsg("remainder for hash partition must be less than modulus")));
4812 :
1821 alvherre 4813 ECB : /*
4814 : * Cache hash function information.
4815 : */
1821 alvherre 4816 GIC 2099 : my_extra = (ColumnsHashData *) fcinfo->flinfo->fn_extra;
4817 2099 : if (my_extra == NULL || my_extra->relid != parentId)
1821 alvherre 4818 ECB : {
4819 : Relation parent;
4820 : PartitionKey key;
4821 : int j;
4822 :
4823 : /* Open parent relation and fetch partition key info */
874 tgl 4824 GIC 1098 : parent = relation_open(parentId, AccessShareLock);
1821 alvherre 4825 CBC 1095 : key = RelationGetPartitionKey(parent);
1821 alvherre 4826 ECB :
4827 : /* Reject parent table that is not hash-partitioned. */
874 tgl 4828 CBC 1095 : if (key == NULL || key->strategy != PARTITION_STRATEGY_HASH)
1821 alvherre 4829 6 : ereport(ERROR,
1821 alvherre 4830 ECB : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4831 : errmsg("\"%s\" is not a hash partitioned table",
4832 : get_rel_name(parentId))));
4833 :
1821 alvherre 4834 GIC 1089 : if (!get_fn_expr_variadic(fcinfo->flinfo))
4835 : {
1821 alvherre 4836 CBC 1074 : int nargs = PG_NARGS() - 3;
4837 :
1821 alvherre 4838 ECB : /* complain if wrong number of column values */
1821 alvherre 4839 GIC 1074 : if (key->partnatts != nargs)
1821 alvherre 4840 CBC 6 : ereport(ERROR,
1821 alvherre 4841 ECB : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4842 : errmsg("number of partitioning columns (%d) does not match number of partition keys provided (%d)",
4843 : key->partnatts, nargs)));
4844 :
4845 : /* allocate space for our cache */
1821 alvherre 4846 CBC 2136 : fcinfo->flinfo->fn_extra =
4847 1068 : MemoryContextAllocZero(fcinfo->flinfo->fn_mcxt,
1821 alvherre 4848 ECB : offsetof(ColumnsHashData, partsupfunc) +
1821 alvherre 4849 GIC 1068 : sizeof(FmgrInfo) * nargs);
4850 1068 : my_extra = (ColumnsHashData *) fcinfo->flinfo->fn_extra;
4851 1068 : my_extra->relid = parentId;
4852 1068 : my_extra->nkeys = key->partnatts;
1455 tgl 4853 CBC 1068 : memcpy(my_extra->partcollid, key->partcollation,
1455 tgl 4854 GIC 1068 : key->partnatts * sizeof(Oid));
4855 :
1821 alvherre 4856 ECB : /* check argument types and save fmgr_infos */
1821 alvherre 4857 CBC 2157 : for (j = 0; j < key->partnatts; ++j)
4858 : {
1821 alvherre 4859 GIC 1092 : Oid argtype = get_fn_expr_argtype(fcinfo->flinfo, j + 3);
1821 alvherre 4860 ECB :
1821 alvherre 4861 CBC 1092 : if (argtype != key->parttypid[j] && !IsBinaryCoercible(argtype, key->parttypid[j]))
4862 3 : ereport(ERROR,
1821 alvherre 4863 ECB : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
774 peter 4864 : errmsg("column %d of the partition key has type %s, but supplied value is of type %s",
4865 : j + 1, format_type_be(key->parttypid[j]), format_type_be(argtype))));
4866 :
1821 alvherre 4867 GIC 1089 : fmgr_info_copy(&my_extra->partsupfunc[j],
1821 alvherre 4868 CBC 1089 : &key->partsupfunc[j],
1821 alvherre 4869 GIC 1089 : fcinfo->flinfo->fn_mcxt);
4870 : }
1821 alvherre 4871 ECB : }
4872 : else
4873 : {
1821 alvherre 4874 GIC 15 : ArrayType *variadic_array = PG_GETARG_ARRAYTYPE_P(3);
4875 :
4876 : /* allocate space for our cache -- just one FmgrInfo in this case */
4877 30 : fcinfo->flinfo->fn_extra =
4878 15 : MemoryContextAllocZero(fcinfo->flinfo->fn_mcxt,
4879 : offsetof(ColumnsHashData, partsupfunc) +
1821 alvherre 4880 ECB : sizeof(FmgrInfo));
1821 alvherre 4881 GIC 15 : my_extra = (ColumnsHashData *) fcinfo->flinfo->fn_extra;
1821 alvherre 4882 CBC 15 : my_extra->relid = parentId;
1821 alvherre 4883 GIC 15 : my_extra->nkeys = key->partnatts;
4884 15 : my_extra->variadic_type = ARR_ELEMTYPE(variadic_array);
4885 15 : get_typlenbyvalalign(my_extra->variadic_type,
1821 alvherre 4886 ECB : &my_extra->variadic_typlen,
4887 : &my_extra->variadic_typbyval,
4888 : &my_extra->variadic_typalign);
1455 tgl 4889 CBC 15 : my_extra->partcollid[0] = key->partcollation[0];
4890 :
1821 alvherre 4891 ECB : /* check argument types */
1821 alvherre 4892 GIC 36 : for (j = 0; j < key->partnatts; ++j)
4893 27 : if (key->parttypid[j] != my_extra->variadic_type)
4894 6 : ereport(ERROR,
4895 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4896 : errmsg("column %d of the partition key has type \"%s\", but supplied value is of type \"%s\"",
4897 : j + 1,
4898 : format_type_be(key->parttypid[j]),
4899 : format_type_be(my_extra->variadic_type))));
1821 alvherre 4900 ECB :
1821 alvherre 4901 GIC 9 : fmgr_info_copy(&my_extra->partsupfunc[0],
4902 : &key->partsupfunc[0],
4903 9 : fcinfo->flinfo->fn_mcxt);
4904 : }
1821 alvherre 4905 ECB :
4906 : /* Hold lock until commit */
1821 alvherre 4907 CBC 1074 : relation_close(parent, NoLock);
1821 alvherre 4908 EUB : }
4909 :
1821 alvherre 4910 CBC 2075 : if (!OidIsValid(my_extra->variadic_type))
4911 : {
1821 alvherre 4912 GIC 2066 : int nkeys = my_extra->nkeys;
4913 : int i;
4914 :
4915 : /*
1821 alvherre 4916 ECB : * For a non-variadic call, neither the number of arguments nor their
4917 : * types can change across calls, so avoid the expense of rechecking
4918 : * here.
4919 : */
4920 :
1821 alvherre 4921 CBC 4153 : for (i = 0; i < nkeys; i++)
4922 : {
4923 : Datum hash;
4924 :
4925 : /* keys start from fourth argument of function. */
1821 alvherre 4926 GIC 2087 : int argno = i + 3;
1821 alvherre 4927 ECB :
1821 alvherre 4928 GIC 2087 : if (PG_ARGISNULL(argno))
1821 alvherre 4929 LBC 0 : continue;
1821 alvherre 4930 ECB :
1455 tgl 4931 CBC 2087 : hash = FunctionCall2Coll(&my_extra->partsupfunc[i],
4932 : my_extra->partcollid[i],
4933 : PG_GETARG_DATUM(argno),
4934 : seed);
1821 alvherre 4935 ECB :
4936 : /* Form a single 64-bit hash value */
1821 alvherre 4937 GIC 2087 : rowHash = hash_combine64(rowHash, DatumGetUInt64(hash));
4938 : }
4939 : }
4940 : else
1821 alvherre 4941 ECB : {
1821 alvherre 4942 GIC 9 : ArrayType *variadic_array = PG_GETARG_ARRAYTYPE_P(3);
4943 : int i;
4944 : int nelems;
1821 alvherre 4945 ECB : Datum *datum;
1821 alvherre 4946 EUB : bool *isnull;
4947 :
1821 alvherre 4948 CBC 9 : deconstruct_array(variadic_array,
4949 : my_extra->variadic_type,
4950 9 : my_extra->variadic_typlen,
1821 alvherre 4951 GIC 9 : my_extra->variadic_typbyval,
4952 9 : my_extra->variadic_typalign,
4953 : &datum, &isnull, &nelems);
1821 alvherre 4954 ECB :
4955 : /* complain if wrong number of column values */
1821 alvherre 4956 GIC 9 : if (nelems != my_extra->nkeys)
4957 3 : ereport(ERROR,
1821 alvherre 4958 ECB : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4959 : errmsg("number of partitioning columns (%d) does not match number of partition keys provided (%d)",
4960 : my_extra->nkeys, nelems)));
4961 :
1821 alvherre 4962 GIC 18 : for (i = 0; i < nelems; i++)
4963 : {
4964 : Datum hash;
4965 :
4966 12 : if (isnull[i])
1821 alvherre 4967 UIC 0 : continue;
4968 :
1455 tgl 4969 GIC 12 : hash = FunctionCall2Coll(&my_extra->partsupfunc[0],
4970 : my_extra->partcollid[0],
4971 12 : datum[i],
4972 : seed);
4973 :
4974 : /* Form a single 64-bit hash value */
1821 alvherre 4975 12 : rowHash = hash_combine64(rowHash, DatumGetUInt64(hash));
4976 : }
4977 : }
4978 :
4979 2072 : PG_RETURN_BOOL(rowHash % modulus == remainder);
4980 : }
|