Coverage Report

Created: 2026-08-14 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/postgres/src/backend/partitioning/partbounds.c
Line
Count
Source
1
/*-------------------------------------------------------------------------
2
 *
3
 * partbounds.c
4
 *    Support routines for manipulating partition bounds
5
 *
6
 * Portions Copyright (c) 1996-2026, 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/namespace.h"
21
#include "catalog/partition.h"
22
#include "catalog/pg_inherits.h"
23
#include "catalog/pg_type.h"
24
#include "commands/tablecmds.h"
25
#include "common/hashfn.h"
26
#include "executor/executor.h"
27
#include "miscadmin.h"
28
#include "nodes/makefuncs.h"
29
#include "nodes/nodeFuncs.h"
30
#include "nodes/pathnodes.h"
31
#include "parser/parse_coerce.h"
32
#include "partitioning/partbounds.h"
33
#include "partitioning/partdesc.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
0
  (partition_rbound_cmp(partnatts, partsupfunc, partcollations, \
92
0
              (bound1)->datums, (bound1)->kind, (bound1)->lower, \
93
0
              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 *
250
get_qual_from_partbound(Relation parent, PartitionBoundSpec *spec)
251
0
{
252
0
  PartitionKey key = RelationGetPartitionKey(parent);
253
0
  List     *my_qual = NIL;
254
255
0
  Assert(key != NULL);
256
257
0
  switch (key->strategy)
258
0
  {
259
0
    case PARTITION_STRATEGY_HASH:
260
0
      Assert(spec->strategy == PARTITION_STRATEGY_HASH);
261
0
      my_qual = get_qual_for_hash(parent, spec);
262
0
      break;
263
264
0
    case PARTITION_STRATEGY_LIST:
265
0
      Assert(spec->strategy == PARTITION_STRATEGY_LIST);
266
0
      my_qual = get_qual_for_list(parent, spec);
267
0
      break;
268
269
0
    case PARTITION_STRATEGY_RANGE:
270
0
      Assert(spec->strategy == PARTITION_STRATEGY_RANGE);
271
0
      my_qual = get_qual_for_range(parent, spec, false);
272
0
      break;
273
0
  }
274
275
0
  return my_qual;
276
0
}
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
297
 * current memory context.
298
 */
299
PartitionBoundInfo
300
partition_bounds_create(PartitionBoundSpec **boundspecs, int nparts,
301
            PartitionKey key, int **mapping)
302
0
{
303
0
  int     i;
304
305
0
  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
  /*
320
   * Initialize mapping array with invalid values, this is filled within
321
   * each sub-routine below depending on the bound type.
322
   */
323
0
  *mapping = palloc_array(int, nparts);
324
0
  for (i = 0; i < nparts; i++)
325
0
    (*mapping)[i] = -1;
326
327
0
  switch (key->strategy)
328
0
  {
329
0
    case PARTITION_STRATEGY_HASH:
330
0
      return create_hash_bounds(boundspecs, nparts, key, mapping);
331
332
0
    case PARTITION_STRATEGY_LIST:
333
0
      return create_list_bounds(boundspecs, nparts, key, mapping);
334
335
0
    case PARTITION_STRATEGY_RANGE:
336
0
      return create_range_bounds(boundspecs, nparts, key, mapping);
337
0
  }
338
339
0
  Assert(false);
340
0
  return NULL;       /* keep compiler quiet */
341
0
}
342
343
/*
344
 * create_hash_bounds
345
 *    Create a PartitionBoundInfo for a hash partitioned table
346
 */
347
static PartitionBoundInfo
348
create_hash_bounds(PartitionBoundSpec **boundspecs, int nparts,
349
           PartitionKey key, int **mapping)
350
0
{
351
0
  PartitionBoundInfo boundinfo;
352
0
  PartitionHashBound *hbounds;
353
0
  int     i;
354
0
  int     greatest_modulus;
355
0
  Datum    *boundDatums;
356
357
0
  boundinfo = palloc0_object(PartitionBoundInfoData);
358
0
  boundinfo->strategy = key->strategy;
359
  /* No special hash partitions. */
360
0
  boundinfo->null_index = -1;
361
0
  boundinfo->default_index = -1;
362
363
0
  hbounds = palloc_array(PartitionHashBound, nparts);
364
365
  /* Convert from node to the internal representation */
366
0
  for (i = 0; i < nparts; i++)
367
0
  {
368
0
    PartitionBoundSpec *spec = boundspecs[i];
369
370
0
    if (spec->strategy != PARTITION_STRATEGY_HASH)
371
0
      elog(ERROR, "invalid strategy in partition bound spec");
372
373
0
    hbounds[i].modulus = spec->modulus;
374
0
    hbounds[i].remainder = spec->remainder;
375
0
    hbounds[i].index = i;
376
0
  }
377
378
  /* Sort all the bounds in ascending order */
379
0
  qsort(hbounds, nparts, sizeof(PartitionHashBound),
380
0
      qsort_partition_hbound_cmp);
381
382
  /* After sorting, moduli are now stored in ascending order. */
383
0
  greatest_modulus = hbounds[nparts - 1].modulus;
384
385
0
  boundinfo->ndatums = nparts;
386
0
  boundinfo->datums = palloc0_array(Datum *, nparts);
387
0
  boundinfo->kind = NULL;
388
0
  boundinfo->interleaved_parts = NULL;
389
0
  boundinfo->nindexes = greatest_modulus;
390
0
  boundinfo->indexes = (int *) palloc(greatest_modulus * sizeof(int));
391
0
  for (i = 0; i < greatest_modulus; i++)
392
0
    boundinfo->indexes[i] = -1;
393
394
  /*
395
   * In the loop below, to save from allocating a series of small datum
396
   * arrays, here we just allocate a single array and below we'll just
397
   * assign a portion of this array per partition.
398
   */
399
0
  boundDatums = (Datum *) palloc(nparts * 2 * sizeof(Datum));
400
401
  /*
402
   * For hash partitioning, there are as many datums (modulus and remainder
403
   * pairs) as there are partitions.  Indexes are simply values ranging from
404
   * 0 to (nparts - 1).
405
   */
406
0
  for (i = 0; i < nparts; i++)
407
0
  {
408
0
    int     modulus = hbounds[i].modulus;
409
0
    int     remainder = hbounds[i].remainder;
410
411
0
    boundinfo->datums[i] = &boundDatums[i * 2];
412
0
    boundinfo->datums[i][0] = Int32GetDatum(modulus);
413
0
    boundinfo->datums[i][1] = Int32GetDatum(remainder);
414
415
0
    while (remainder < greatest_modulus)
416
0
    {
417
      /* overlap? */
418
0
      Assert(boundinfo->indexes[remainder] == -1);
419
0
      boundinfo->indexes[remainder] = i;
420
0
      remainder += modulus;
421
0
    }
422
423
0
    (*mapping)[hbounds[i].index] = i;
424
0
  }
425
0
  pfree(hbounds);
426
427
0
  return boundinfo;
428
0
}
429
430
/*
431
 * get_non_null_list_datum_count
432
 *    Counts the number of non-null Datums in each partition.
433
 */
434
static int
435
get_non_null_list_datum_count(PartitionBoundSpec **boundspecs, int nparts)
436
0
{
437
0
  int     i;
438
0
  int     count = 0;
439
440
0
  for (i = 0; i < nparts; i++)
441
0
  {
442
0
    ListCell   *lc;
443
444
0
    foreach(lc, boundspecs[i]->listdatums)
445
0
    {
446
0
      Const    *val = lfirst_node(Const, lc);
447
448
0
      if (!val->constisnull)
449
0
        count++;
450
0
    }
451
0
  }
452
453
0
  return count;
454
0
}
455
456
/*
457
 * create_list_bounds
458
 *    Create a PartitionBoundInfo for a list partitioned table
459
 */
460
static PartitionBoundInfo
461
create_list_bounds(PartitionBoundSpec **boundspecs, int nparts,
462
           PartitionKey key, int **mapping)
463
0
{
464
0
  PartitionBoundInfo boundinfo;
465
0
  PartitionListValue *all_values;
466
0
  int     i;
467
0
  int     j;
468
0
  int     ndatums;
469
0
  int     next_index = 0;
470
0
  int     default_index = -1;
471
0
  int     null_index = -1;
472
0
  Datum    *boundDatums;
473
474
0
  boundinfo = palloc0_object(PartitionBoundInfoData);
475
0
  boundinfo->strategy = key->strategy;
476
  /* Will be set correctly below. */
477
0
  boundinfo->null_index = -1;
478
0
  boundinfo->default_index = -1;
479
480
0
  ndatums = get_non_null_list_datum_count(boundspecs, nparts);
481
0
  all_values = (PartitionListValue *)
482
0
    palloc(ndatums * sizeof(PartitionListValue));
483
484
  /* Create a unified list of non-null values across all partitions. */
485
0
  for (j = 0, i = 0; i < nparts; i++)
486
0
  {
487
0
    PartitionBoundSpec *spec = boundspecs[i];
488
0
    ListCell   *c;
489
490
0
    if (spec->strategy != PARTITION_STRATEGY_LIST)
491
0
      elog(ERROR, "invalid strategy in partition bound spec");
492
493
    /*
494
     * Note the index of the partition bound spec for the default
495
     * partition.  There's no datum to add to the list on non-null datums
496
     * for this partition.
497
     */
498
0
    if (spec->is_default)
499
0
    {
500
0
      default_index = i;
501
0
      continue;
502
0
    }
503
504
0
    foreach(c, spec->listdatums)
505
0
    {
506
0
      Const    *val = lfirst_node(Const, c);
507
508
0
      if (!val->constisnull)
509
0
      {
510
0
        all_values[j].index = i;
511
0
        all_values[j].value = val->constvalue;
512
0
        j++;
513
0
      }
514
0
      else
515
0
      {
516
        /*
517
         * Never put a null into the values array; save the index of
518
         * the partition that stores nulls, instead.
519
         */
520
0
        if (null_index != -1)
521
0
          elog(ERROR, "found null more than once");
522
0
        null_index = i;
523
0
      }
524
0
    }
525
0
  }
526
527
  /* ensure we found a Datum for every slot in the all_values array */
528
0
  Assert(j == ndatums);
529
530
0
  qsort_arg(all_values, ndatums, sizeof(PartitionListValue),
531
0
        qsort_partition_list_value_cmp, key);
532
533
0
  boundinfo->ndatums = ndatums;
534
0
  boundinfo->datums = palloc0_array(Datum *, ndatums);
535
0
  boundinfo->kind = NULL;
536
0
  boundinfo->interleaved_parts = NULL;
537
0
  boundinfo->nindexes = ndatums;
538
0
  boundinfo->indexes = (int *) palloc(ndatums * sizeof(int));
539
540
  /*
541
   * In the loop below, to save from allocating a series of small datum
542
   * arrays, here we just allocate a single array and below we'll just
543
   * assign a portion of this array per datum.
544
   */
545
0
  boundDatums = (Datum *) palloc(ndatums * sizeof(Datum));
546
547
  /*
548
   * Copy values.  Canonical indexes are values ranging from 0 to (nparts -
549
   * 1) assigned to each partition such that all datums of a given partition
550
   * receive the same value. The value for a given partition is the index of
551
   * that partition's smallest datum in the all_values[] array.
552
   */
553
0
  for (i = 0; i < ndatums; i++)
554
0
  {
555
0
    int     orig_index = all_values[i].index;
556
557
0
    boundinfo->datums[i] = &boundDatums[i];
558
0
    boundinfo->datums[i][0] = datumCopy(all_values[i].value,
559
0
                      key->parttypbyval[0],
560
0
                      key->parttyplen[0]);
561
562
    /* If the old index has no mapping, assign one */
563
0
    if ((*mapping)[orig_index] == -1)
564
0
      (*mapping)[orig_index] = next_index++;
565
566
0
    boundinfo->indexes[i] = (*mapping)[orig_index];
567
0
  }
568
569
0
  pfree(all_values);
570
571
  /*
572
   * Set the canonical value for null_index, if any.
573
   *
574
   * It is possible that the null-accepting partition has not been assigned
575
   * an index yet, which could happen if such partition accepts only null
576
   * and hence not handled in the above loop which only looked at non-null
577
   * values.
578
   */
579
0
  if (null_index != -1)
580
0
  {
581
0
    Assert(null_index >= 0);
582
0
    if ((*mapping)[null_index] == -1)
583
0
      (*mapping)[null_index] = next_index++;
584
0
    boundinfo->null_index = (*mapping)[null_index];
585
0
  }
586
587
  /* Set the canonical value for default_index, if any. */
588
0
  if (default_index != -1)
589
0
  {
590
    /*
591
     * The default partition accepts any value not specified in the lists
592
     * of other partitions, hence it should not get mapped index while
593
     * assigning those for non-null datums.
594
     */
595
0
    Assert(default_index >= 0);
596
0
    Assert((*mapping)[default_index] == -1);
597
0
    (*mapping)[default_index] = next_index++;
598
0
    boundinfo->default_index = (*mapping)[default_index];
599
0
  }
600
601
  /*
602
   * Calculate interleaved partitions.  Here we look for partitions which
603
   * might be interleaved with other partitions and set a bit in
604
   * interleaved_parts for any partitions which may be interleaved with
605
   * another partition.
606
   */
607
608
  /*
609
   * There must be multiple partitions to have any interleaved partitions,
610
   * otherwise there's nothing to interleave with.
611
   */
612
0
  if (nparts > 1)
613
0
  {
614
    /*
615
     * Short-circuit check to see if only 1 Datum is allowed per
616
     * partition.  When this is true there's no need to do the more
617
     * expensive checks to look for interleaved values.
618
     */
619
0
    if (boundinfo->ndatums +
620
0
      partition_bound_accepts_nulls(boundinfo) +
621
0
      partition_bound_has_default(boundinfo) != nparts)
622
0
    {
623
0
      int     last_index = -1;
624
625
      /*
626
       * Since the indexes array is sorted in Datum order, if any
627
       * partitions are interleaved then it will show up by the
628
       * partition indexes not being in ascending order.  Here we check
629
       * for that and record all partitions that are out of order.
630
       */
631
0
      for (i = 0; i < boundinfo->nindexes; i++)
632
0
      {
633
0
        int     index = boundinfo->indexes[i];
634
635
0
        if (index < last_index)
636
0
          boundinfo->interleaved_parts = bms_add_member(boundinfo->interleaved_parts,
637
0
                                  index);
638
639
        /*
640
         * Otherwise, if the null_index exists in the indexes array,
641
         * then the NULL partition must also allow some other Datum,
642
         * therefore it's "interleaved".
643
         */
644
0
        else if (partition_bound_accepts_nulls(boundinfo) &&
645
0
             index == boundinfo->null_index)
646
0
          boundinfo->interleaved_parts = bms_add_member(boundinfo->interleaved_parts,
647
0
                                  index);
648
649
0
        last_index = index;
650
0
      }
651
0
    }
652
653
    /*
654
     * The DEFAULT partition is the "catch-all" partition that can contain
655
     * anything that does not belong to any other partition.  If there are
656
     * any other partitions then the DEFAULT partition must be marked as
657
     * interleaved.
658
     */
659
0
    if (partition_bound_has_default(boundinfo))
660
0
      boundinfo->interleaved_parts = bms_add_member(boundinfo->interleaved_parts,
661
0
                              boundinfo->default_index);
662
0
  }
663
664
665
  /* All partitions must now have been assigned canonical indexes. */
666
0
  Assert(next_index == nparts);
667
0
  return boundinfo;
668
0
}
669
670
/*
671
 * create_range_bounds
672
 *    Create a PartitionBoundInfo for a range partitioned table
673
 */
674
static PartitionBoundInfo
675
create_range_bounds(PartitionBoundSpec **boundspecs, int nparts,
676
          PartitionKey key, int **mapping)
677
0
{
678
0
  PartitionBoundInfo boundinfo;
679
0
  PartitionRangeBound **rbounds = NULL;
680
0
  PartitionRangeBound **all_bounds,
681
0
         *prev;
682
0
  int     i,
683
0
        k,
684
0
        partnatts;
685
0
  int     ndatums = 0;
686
0
  int     default_index = -1;
687
0
  int     next_index = 0;
688
0
  Datum    *boundDatums;
689
0
  PartitionRangeDatumKind *boundKinds;
690
691
0
  boundinfo = palloc0_object(PartitionBoundInfoData);
692
0
  boundinfo->strategy = key->strategy;
693
  /* There is no special null-accepting range partition. */
694
0
  boundinfo->null_index = -1;
695
  /* Will be set correctly below. */
696
0
  boundinfo->default_index = -1;
697
698
0
  all_bounds = palloc0_array(PartitionRangeBound *, 2 * nparts);
699
700
  /* Create a unified list of range bounds across all the partitions. */
701
0
  ndatums = 0;
702
0
  for (i = 0; i < nparts; i++)
703
0
  {
704
0
    PartitionBoundSpec *spec = boundspecs[i];
705
0
    PartitionRangeBound *lower,
706
0
           *upper;
707
708
0
    if (spec->strategy != PARTITION_STRATEGY_RANGE)
709
0
      elog(ERROR, "invalid strategy in partition bound spec");
710
711
    /*
712
     * Note the index of the partition bound spec for the default
713
     * partition.  There's no datum to add to the all_bounds array for
714
     * this partition.
715
     */
716
0
    if (spec->is_default)
717
0
    {
718
0
      default_index = i;
719
0
      continue;
720
0
    }
721
722
0
    lower = make_one_partition_rbound(key, i, spec->lowerdatums, true);
723
0
    upper = make_one_partition_rbound(key, i, spec->upperdatums, false);
724
0
    all_bounds[ndatums++] = lower;
725
0
    all_bounds[ndatums++] = upper;
726
0
  }
727
728
0
  Assert(ndatums == nparts * 2 ||
729
0
       (default_index != -1 && ndatums == (nparts - 1) * 2));
730
731
  /* Sort all the bounds in ascending order */
732
0
  qsort_arg(all_bounds, ndatums,
733
0
        sizeof(PartitionRangeBound *),
734
0
        qsort_partition_rbound_cmp,
735
0
        key);
736
737
  /* Save distinct bounds from all_bounds into rbounds. */
738
0
  rbounds = (PartitionRangeBound **)
739
0
    palloc(ndatums * sizeof(PartitionRangeBound *));
740
0
  k = 0;
741
0
  prev = NULL;
742
0
  for (i = 0; i < ndatums; i++)
743
0
  {
744
0
    PartitionRangeBound *cur = all_bounds[i];
745
0
    bool    is_distinct = false;
746
0
    int     j;
747
748
    /* Is the current bound distinct from the previous one? */
749
0
    for (j = 0; j < key->partnatts; j++)
750
0
    {
751
0
      Datum   cmpval;
752
753
0
      if (prev == NULL || cur->kind[j] != prev->kind[j])
754
0
      {
755
0
        is_distinct = true;
756
0
        break;
757
0
      }
758
759
      /*
760
       * If the bounds are both MINVALUE or MAXVALUE, stop now and treat
761
       * them as equal, since any values after this point must be
762
       * ignored.
763
       */
764
0
      if (cur->kind[j] != PARTITION_RANGE_DATUM_VALUE)
765
0
        break;
766
767
0
      cmpval = FunctionCall2Coll(&key->partsupfunc[j],
768
0
                     key->partcollation[j],
769
0
                     cur->datums[j],
770
0
                     prev->datums[j]);
771
0
      if (DatumGetInt32(cmpval) != 0)
772
0
      {
773
0
        is_distinct = true;
774
0
        break;
775
0
      }
776
0
    }
777
778
    /*
779
     * Only if the bound is distinct save it into a temporary array, i.e,
780
     * rbounds which is later copied into boundinfo datums array.
781
     */
782
0
    if (is_distinct)
783
0
      rbounds[k++] = all_bounds[i];
784
785
0
    prev = cur;
786
0
  }
787
788
0
  pfree(all_bounds);
789
790
  /* Update ndatums to hold the count of distinct datums. */
791
0
  ndatums = k;
792
793
  /*
794
   * Add datums to boundinfo.  Canonical indexes are values ranging from 0
795
   * to nparts - 1, assigned in that order to each partition's upper bound.
796
   * For 'datums' elements that are lower bounds, there is -1 in the
797
   * 'indexes' array to signify that no partition exists for the values less
798
   * than such a bound and greater than or equal to the previous upper
799
   * bound.
800
   */
801
0
  boundinfo->ndatums = ndatums;
802
0
  boundinfo->datums = palloc0_array(Datum *, ndatums);
803
0
  boundinfo->kind = palloc0_array(PartitionRangeDatumKind *, ndatums);
804
0
  boundinfo->interleaved_parts = NULL;
805
806
  /*
807
   * For range partitioning, an additional value of -1 is stored as the last
808
   * element of the indexes[] array.
809
   */
810
0
  boundinfo->nindexes = ndatums + 1;
811
0
  boundinfo->indexes = palloc_array(int, (ndatums + 1));
812
813
  /*
814
   * In the loop below, to save from allocating a series of small arrays,
815
   * here we just allocate a single array for Datums and another for
816
   * PartitionRangeDatumKinds, below we'll just assign a portion of these
817
   * arrays in each loop.
818
   */
819
0
  partnatts = key->partnatts;
820
0
  boundDatums = (Datum *) palloc(ndatums * partnatts * sizeof(Datum));
821
0
  boundKinds = palloc_array(PartitionRangeDatumKind, ndatums * partnatts);
822
823
0
  for (i = 0; i < ndatums; i++)
824
0
  {
825
0
    int     j;
826
827
0
    boundinfo->datums[i] = &boundDatums[i * partnatts];
828
0
    boundinfo->kind[i] = &boundKinds[i * partnatts];
829
0
    for (j = 0; j < partnatts; j++)
830
0
    {
831
0
      if (rbounds[i]->kind[j] == PARTITION_RANGE_DATUM_VALUE)
832
0
        boundinfo->datums[i][j] =
833
0
          datumCopy(rbounds[i]->datums[j],
834
0
                key->parttypbyval[j],
835
0
                key->parttyplen[j]);
836
0
      boundinfo->kind[i][j] = rbounds[i]->kind[j];
837
0
    }
838
839
    /*
840
     * There is no mapping for invalid indexes.
841
     *
842
     * Any lower bounds in the rbounds array have invalid indexes
843
     * assigned, because the values between the previous bound (if there
844
     * is one) and this (lower) bound are not part of the range of any
845
     * existing partition.
846
     */
847
0
    if (rbounds[i]->lower)
848
0
      boundinfo->indexes[i] = -1;
849
0
    else
850
0
    {
851
0
      int     orig_index = rbounds[i]->index;
852
853
      /* If the old index has no mapping, assign one */
854
0
      if ((*mapping)[orig_index] == -1)
855
0
        (*mapping)[orig_index] = next_index++;
856
857
0
      boundinfo->indexes[i] = (*mapping)[orig_index];
858
0
    }
859
0
  }
860
861
0
  pfree(rbounds);
862
863
  /* Set the canonical value for default_index, if any. */
864
0
  if (default_index != -1)
865
0
  {
866
0
    Assert(default_index >= 0 && (*mapping)[default_index] == -1);
867
0
    (*mapping)[default_index] = next_index++;
868
0
    boundinfo->default_index = (*mapping)[default_index];
869
0
  }
870
871
  /* The extra -1 element. */
872
0
  Assert(i == ndatums);
873
0
  boundinfo->indexes[i] = -1;
874
875
  /* All partitions must now have been assigned canonical indexes. */
876
0
  Assert(next_index == nparts);
877
0
  return boundinfo;
878
0
}
879
880
/*
881
 * Are two partition bound collections logically equal?
882
 *
883
 * Used in the keep logic of relcache.c (ie, in RelationClearRelation()).
884
 * This is also useful when b1 and b2 are bound collections of two separate
885
 * relations, respectively, because PartitionBoundInfo is a canonical
886
 * representation of partition bounds.
887
 */
888
bool
889
partition_bounds_equal(int partnatts, int16 *parttyplen, bool *parttypbyval,
890
             PartitionBoundInfo b1, PartitionBoundInfo b2)
891
0
{
892
0
  int     i;
893
894
0
  if (b1->strategy != b2->strategy)
895
0
    return false;
896
897
0
  if (b1->ndatums != b2->ndatums)
898
0
    return false;
899
900
0
  if (b1->nindexes != b2->nindexes)
901
0
    return false;
902
903
0
  if (b1->null_index != b2->null_index)
904
0
    return false;
905
906
0
  if (b1->default_index != b2->default_index)
907
0
    return false;
908
909
  /* For all partition strategies, the indexes[] arrays have to match */
910
0
  for (i = 0; i < b1->nindexes; i++)
911
0
  {
912
0
    if (b1->indexes[i] != b2->indexes[i])
913
0
      return false;
914
0
  }
915
916
  /* Finally, compare the datums[] arrays */
917
0
  if (b1->strategy == PARTITION_STRATEGY_HASH)
918
0
  {
919
    /*
920
     * We arrange the partitions in the ascending order of their moduli
921
     * and remainders.  Also every modulus is factor of next larger
922
     * modulus.  Therefore we can safely store index of a given partition
923
     * in indexes array at remainder of that partition.  Also entries at
924
     * (remainder + N * modulus) positions in indexes array are all same
925
     * for (modulus, remainder) specification for any partition.  Thus the
926
     * datums arrays from the given bounds are the same, if and only if
927
     * their indexes arrays are the same.  So, it suffices to compare the
928
     * indexes arrays.
929
     *
930
     * Nonetheless make sure that the bounds are indeed the same when the
931
     * indexes match.  Hash partition bound stores modulus and remainder
932
     * at b1->datums[i][0] and b1->datums[i][1] position respectively.
933
     */
934
#ifdef USE_ASSERT_CHECKING
935
    for (i = 0; i < b1->ndatums; i++)
936
      Assert((b1->datums[i][0] == b2->datums[i][0] &&
937
          b1->datums[i][1] == b2->datums[i][1]));
938
#endif
939
0
  }
940
0
  else
941
0
  {
942
0
    for (i = 0; i < b1->ndatums; i++)
943
0
    {
944
0
      int     j;
945
946
0
      for (j = 0; j < partnatts; j++)
947
0
      {
948
        /* For range partitions, the bounds might not be finite. */
949
0
        if (b1->kind != NULL)
950
0
        {
951
          /* The different kinds of bound all differ from each other */
952
0
          if (b1->kind[i][j] != b2->kind[i][j])
953
0
            return false;
954
955
          /*
956
           * Non-finite bounds are equal without further
957
           * examination.
958
           */
959
0
          if (b1->kind[i][j] != PARTITION_RANGE_DATUM_VALUE)
960
0
            continue;
961
0
        }
962
963
        /*
964
         * Compare the actual values. Note that it would be both
965
         * incorrect and unsafe to invoke the comparison operator
966
         * derived from the partitioning specification here.  It would
967
         * be incorrect because we want the relcache entry to be
968
         * updated for ANY change to the partition bounds, not just
969
         * those that the partitioning operator thinks are
970
         * significant.  It would be unsafe because we might reach
971
         * this code in the context of an aborted transaction, and an
972
         * arbitrary partitioning operator might not be safe in that
973
         * context.  datumIsEqual() should be simple enough to be
974
         * safe.
975
         */
976
0
        if (!datumIsEqual(b1->datums[i][j], b2->datums[i][j],
977
0
                  parttypbyval[j], parttyplen[j]))
978
0
          return false;
979
0
      }
980
0
    }
981
0
  }
982
0
  return true;
983
0
}
984
985
/*
986
 * Return a copy of given PartitionBoundInfo structure. The data types of bounds
987
 * are described by given partition key specification.
988
 *
989
 * Note: it's important that this function and its callees not do any catalog
990
 * access, nor anything else that would result in allocating memory other than
991
 * the returned data structure.  Since this is called in a long-lived context,
992
 * that would result in unwanted memory leaks.
993
 */
994
PartitionBoundInfo
995
partition_bounds_copy(PartitionBoundInfo src,
996
            PartitionKey key)
997
0
{
998
0
  PartitionBoundInfo dest;
999
0
  int     i;
1000
0
  int     ndatums;
1001
0
  int     nindexes;
1002
0
  int     partnatts;
1003
1004
0
  dest = (PartitionBoundInfo) palloc_object(PartitionBoundInfoData);
1005
1006
0
  dest->strategy = src->strategy;
1007
0
  ndatums = dest->ndatums = src->ndatums;
1008
0
  nindexes = dest->nindexes = src->nindexes;
1009
0
  partnatts = key->partnatts;
1010
1011
  /* List partitioned tables have only a single partition key. */
1012
0
  Assert(key->strategy != PARTITION_STRATEGY_LIST || partnatts == 1);
1013
1014
0
  dest->datums = palloc_array(Datum *, ndatums);
1015
1016
0
  if (src->kind != NULL && ndatums > 0)
1017
0
  {
1018
0
    PartitionRangeDatumKind *boundKinds;
1019
1020
    /* only RANGE partition should have a non-NULL kind */
1021
0
    Assert(key->strategy == PARTITION_STRATEGY_RANGE);
1022
1023
0
    dest->kind = (PartitionRangeDatumKind **) palloc(ndatums *
1024
0
                             sizeof(PartitionRangeDatumKind *));
1025
1026
    /*
1027
     * In the loop below, to save from allocating a series of small arrays
1028
     * for storing the PartitionRangeDatumKind, we allocate a single chunk
1029
     * here and use a smaller portion of it for each datum.
1030
     */
1031
0
    boundKinds = (PartitionRangeDatumKind *) palloc(ndatums * partnatts *
1032
0
                            sizeof(PartitionRangeDatumKind));
1033
1034
0
    for (i = 0; i < ndatums; i++)
1035
0
    {
1036
0
      dest->kind[i] = &boundKinds[i * partnatts];
1037
0
      memcpy(dest->kind[i], src->kind[i],
1038
0
           sizeof(PartitionRangeDatumKind) * partnatts);
1039
0
    }
1040
0
  }
1041
0
  else
1042
0
    dest->kind = NULL;
1043
1044
  /* copy interleaved partitions for LIST partitioned tables */
1045
0
  dest->interleaved_parts = bms_copy(src->interleaved_parts);
1046
1047
  /*
1048
   * For hash partitioning, datums array will have two elements - modulus
1049
   * and remainder.
1050
   */
1051
0
  if (ndatums > 0)
1052
0
  {
1053
0
    bool    hash_part = (key->strategy == PARTITION_STRATEGY_HASH);
1054
0
    int     natts = hash_part ? 2 : partnatts;
1055
0
    Datum    *boundDatums = palloc(ndatums * natts * sizeof(Datum));
1056
1057
0
    for (i = 0; i < ndatums; i++)
1058
0
    {
1059
0
      int     j;
1060
1061
0
      dest->datums[i] = &boundDatums[i * natts];
1062
1063
0
      for (j = 0; j < natts; j++)
1064
0
      {
1065
0
        if (dest->kind == NULL ||
1066
0
          dest->kind[i][j] == PARTITION_RANGE_DATUM_VALUE)
1067
0
        {
1068
0
          bool    byval;
1069
0
          int     typlen;
1070
1071
0
          if (hash_part)
1072
0
          {
1073
0
            typlen = sizeof(int32); /* Always int4 */
1074
0
            byval = true; /* int4 is pass-by-value */
1075
0
          }
1076
0
          else
1077
0
          {
1078
0
            byval = key->parttypbyval[j];
1079
0
            typlen = key->parttyplen[j];
1080
0
          }
1081
0
          dest->datums[i][j] = datumCopy(src->datums[i][j],
1082
0
                           byval, typlen);
1083
0
        }
1084
0
      }
1085
0
    }
1086
0
  }
1087
1088
0
  dest->indexes = palloc_array(int, nindexes);
1089
0
  memcpy(dest->indexes, src->indexes, sizeof(int) * nindexes);
1090
1091
0
  dest->null_index = src->null_index;
1092
0
  dest->default_index = src->default_index;
1093
1094
0
  return dest;
1095
0
}
1096
1097
/*
1098
 * partition_bounds_merge
1099
 *    Check to see whether every partition of 'outer_rel' matches/overlaps
1100
 *    one partition of 'inner_rel' at most, and vice versa; and if so, build
1101
 *    and return the partition bounds for a join relation between the rels,
1102
 *    generating two lists of the matching/overlapping partitions, which are
1103
 *    returned to *outer_parts and *inner_parts respectively.
1104
 *
1105
 * The lists contain the same number of partitions, and the partitions at the
1106
 * same positions in the lists indicate join pairs used for partitioned join.
1107
 * If a partition on one side matches/overlaps multiple partitions on the other
1108
 * side, this function returns NULL, setting *outer_parts and *inner_parts to
1109
 * NIL.
1110
 */
1111
PartitionBoundInfo
1112
partition_bounds_merge(int partnatts,
1113
             FmgrInfo *partsupfunc, Oid *partcollation,
1114
             RelOptInfo *outer_rel, RelOptInfo *inner_rel,
1115
             JoinType jointype,
1116
             List **outer_parts, List **inner_parts)
1117
0
{
1118
  /*
1119
   * Currently, this function is called only from try_partitionwise_join(),
1120
   * so the join type should be INNER, LEFT, FULL, SEMI, or ANTI.
1121
   */
1122
0
  Assert(jointype == JOIN_INNER || jointype == JOIN_LEFT ||
1123
0
       jointype == JOIN_FULL || jointype == JOIN_SEMI ||
1124
0
       jointype == JOIN_ANTI);
1125
1126
  /* The partitioning strategies should be the same. */
1127
0
  Assert(outer_rel->boundinfo->strategy == inner_rel->boundinfo->strategy);
1128
1129
0
  *outer_parts = *inner_parts = NIL;
1130
0
  switch (outer_rel->boundinfo->strategy)
1131
0
  {
1132
0
    case PARTITION_STRATEGY_HASH:
1133
1134
      /*
1135
       * For hash partitioned tables, we currently support partitioned
1136
       * join only when they have exactly the same partition bounds.
1137
       *
1138
       * XXX: it might be possible to relax the restriction to support
1139
       * cases where hash partitioned tables have missing partitions
1140
       * and/or different moduli, but it's not clear if it would be
1141
       * useful to support the former case since it's unusual to have
1142
       * missing partitions.  On the other hand, it would be useful to
1143
       * support the latter case, but in that case, there is a high
1144
       * probability that a partition on one side will match multiple
1145
       * partitions on the other side, which is the scenario the current
1146
       * implementation of partitioned join can't handle.
1147
       */
1148
0
      return NULL;
1149
1150
0
    case PARTITION_STRATEGY_LIST:
1151
0
      return merge_list_bounds(partsupfunc,
1152
0
                   partcollation,
1153
0
                   outer_rel,
1154
0
                   inner_rel,
1155
0
                   jointype,
1156
0
                   outer_parts,
1157
0
                   inner_parts);
1158
1159
0
    case PARTITION_STRATEGY_RANGE:
1160
0
      return merge_range_bounds(partnatts,
1161
0
                    partsupfunc,
1162
0
                    partcollation,
1163
0
                    outer_rel,
1164
0
                    inner_rel,
1165
0
                    jointype,
1166
0
                    outer_parts,
1167
0
                    inner_parts);
1168
0
  }
1169
1170
0
  return NULL;
1171
0
}
1172
1173
/*
1174
 * merge_list_bounds
1175
 *    Create the partition bounds for a join relation between list
1176
 *    partitioned tables, if possible
1177
 *
1178
 * In this function we try to find sets of matching partitions from both sides
1179
 * by comparing list values stored in their partition bounds.  Since the list
1180
 * values appear in the ascending order, an algorithm similar to merge join is
1181
 * used for that.  If a partition on one side doesn't have a matching
1182
 * partition on the other side, the algorithm tries to match it with the
1183
 * default partition on the other side if any; if not, the algorithm tries to
1184
 * match it with a dummy partition on the other side if it's on the
1185
 * non-nullable side of an outer join.  Also, if both sides have the default
1186
 * partitions, the algorithm tries to match them with each other.  We give up
1187
 * if the algorithm finds a partition matching multiple partitions on the
1188
 * other side, which is the scenario the current implementation of partitioned
1189
 * join can't handle.
1190
 */
1191
static PartitionBoundInfo
1192
merge_list_bounds(FmgrInfo *partsupfunc, Oid *partcollation,
1193
          RelOptInfo *outer_rel, RelOptInfo *inner_rel,
1194
          JoinType jointype,
1195
          List **outer_parts, List **inner_parts)
1196
0
{
1197
0
  PartitionBoundInfo merged_bounds = NULL;
1198
0
  PartitionBoundInfo outer_bi = outer_rel->boundinfo;
1199
0
  PartitionBoundInfo inner_bi = inner_rel->boundinfo;
1200
0
  bool    outer_has_default = partition_bound_has_default(outer_bi);
1201
0
  bool    inner_has_default = partition_bound_has_default(inner_bi);
1202
0
  int     outer_default = outer_bi->default_index;
1203
0
  int     inner_default = inner_bi->default_index;
1204
0
  bool    outer_has_null = partition_bound_accepts_nulls(outer_bi);
1205
0
  bool    inner_has_null = partition_bound_accepts_nulls(inner_bi);
1206
0
  PartitionMap outer_map;
1207
0
  PartitionMap inner_map;
1208
0
  int     outer_pos;
1209
0
  int     inner_pos;
1210
0
  int     next_index = 0;
1211
0
  int     null_index = -1;
1212
0
  int     default_index = -1;
1213
0
  List     *merged_datums = NIL;
1214
0
  List     *merged_indexes = NIL;
1215
1216
0
  Assert(*outer_parts == NIL);
1217
0
  Assert(*inner_parts == NIL);
1218
0
  Assert(outer_bi->strategy == inner_bi->strategy &&
1219
0
       outer_bi->strategy == PARTITION_STRATEGY_LIST);
1220
  /* List partitioning doesn't require kinds. */
1221
0
  Assert(!outer_bi->kind && !inner_bi->kind);
1222
1223
0
  init_partition_map(outer_rel, &outer_map);
1224
0
  init_partition_map(inner_rel, &inner_map);
1225
1226
  /*
1227
   * If the default partitions (if any) have been proven empty, deem them
1228
   * non-existent.
1229
   */
1230
0
  if (outer_has_default && is_dummy_partition(outer_rel, outer_default))
1231
0
    outer_has_default = false;
1232
0
  if (inner_has_default && is_dummy_partition(inner_rel, inner_default))
1233
0
    inner_has_default = false;
1234
1235
  /*
1236
   * Merge partitions from both sides.  In each iteration we compare a pair
1237
   * of list values, one from each side, and decide whether the
1238
   * corresponding partitions match or not.  If the two values match
1239
   * exactly, move to the next pair of list values, otherwise move to the
1240
   * next list value on the side with a smaller list value.
1241
   */
1242
0
  outer_pos = inner_pos = 0;
1243
0
  while (outer_pos < outer_bi->ndatums || inner_pos < inner_bi->ndatums)
1244
0
  {
1245
0
    int     outer_index = -1;
1246
0
    int     inner_index = -1;
1247
0
    Datum    *outer_datums;
1248
0
    Datum    *inner_datums;
1249
0
    int     cmpval;
1250
0
    Datum    *merged_datum = NULL;
1251
0
    int     merged_index = -1;
1252
1253
0
    if (outer_pos < outer_bi->ndatums)
1254
0
    {
1255
      /*
1256
       * If the partition on the outer side has been proven empty,
1257
       * ignore it and move to the next datum on the outer side.
1258
       */
1259
0
      outer_index = outer_bi->indexes[outer_pos];
1260
0
      if (is_dummy_partition(outer_rel, outer_index))
1261
0
      {
1262
0
        outer_pos++;
1263
0
        continue;
1264
0
      }
1265
0
    }
1266
0
    if (inner_pos < inner_bi->ndatums)
1267
0
    {
1268
      /*
1269
       * If the partition on the inner side has been proven empty,
1270
       * ignore it and move to the next datum on the inner side.
1271
       */
1272
0
      inner_index = inner_bi->indexes[inner_pos];
1273
0
      if (is_dummy_partition(inner_rel, inner_index))
1274
0
      {
1275
0
        inner_pos++;
1276
0
        continue;
1277
0
      }
1278
0
    }
1279
1280
    /* Get the list values. */
1281
0
    outer_datums = outer_pos < outer_bi->ndatums ?
1282
0
      outer_bi->datums[outer_pos] : NULL;
1283
0
    inner_datums = inner_pos < inner_bi->ndatums ?
1284
0
      inner_bi->datums[inner_pos] : NULL;
1285
1286
    /*
1287
     * We run this loop till both sides finish.  This allows us to avoid
1288
     * duplicating code to handle the remaining values on the side which
1289
     * finishes later.  For that we set the comparison parameter cmpval in
1290
     * such a way that it appears as if the side which finishes earlier
1291
     * has an extra value higher than any other value on the unfinished
1292
     * side. That way we advance the values on the unfinished side till
1293
     * all of its values are exhausted.
1294
     */
1295
0
    if (outer_pos >= outer_bi->ndatums)
1296
0
      cmpval = 1;
1297
0
    else if (inner_pos >= inner_bi->ndatums)
1298
0
      cmpval = -1;
1299
0
    else
1300
0
    {
1301
0
      Assert(outer_datums != NULL && inner_datums != NULL);
1302
0
      cmpval = DatumGetInt32(FunctionCall2Coll(&partsupfunc[0],
1303
0
                           partcollation[0],
1304
0
                           outer_datums[0],
1305
0
                           inner_datums[0]));
1306
0
    }
1307
1308
0
    if (cmpval == 0)
1309
0
    {
1310
      /* Two list values match exactly. */
1311
0
      Assert(outer_pos < outer_bi->ndatums);
1312
0
      Assert(inner_pos < inner_bi->ndatums);
1313
0
      Assert(outer_index >= 0);
1314
0
      Assert(inner_index >= 0);
1315
1316
      /*
1317
       * Try merging both partitions.  If successful, add the list value
1318
       * and index of the merged partition below.
1319
       */
1320
0
      merged_index = merge_matching_partitions(&outer_map, &inner_map,
1321
0
                           outer_index, inner_index,
1322
0
                           &next_index);
1323
0
      if (merged_index == -1)
1324
0
        goto cleanup;
1325
1326
0
      merged_datum = outer_datums;
1327
1328
      /* Move to the next pair of list values. */
1329
0
      outer_pos++;
1330
0
      inner_pos++;
1331
0
    }
1332
0
    else if (cmpval < 0)
1333
0
    {
1334
      /* A list value missing from the inner side. */
1335
0
      Assert(outer_pos < outer_bi->ndatums);
1336
1337
      /*
1338
       * If the inner side has the default partition, or this is an
1339
       * outer join, try to assign a merged partition to the outer
1340
       * partition (see process_outer_partition()).  Otherwise, the
1341
       * outer partition will not contribute to the result.
1342
       */
1343
0
      if (inner_has_default || IS_OUTER_JOIN(jointype))
1344
0
      {
1345
        /* Get the outer partition. */
1346
0
        outer_index = outer_bi->indexes[outer_pos];
1347
0
        Assert(outer_index >= 0);
1348
0
        merged_index = process_outer_partition(&outer_map,
1349
0
                             &inner_map,
1350
0
                             outer_has_default,
1351
0
                             inner_has_default,
1352
0
                             outer_index,
1353
0
                             inner_default,
1354
0
                             jointype,
1355
0
                             &next_index,
1356
0
                             &default_index);
1357
0
        if (merged_index == -1)
1358
0
          goto cleanup;
1359
0
        merged_datum = outer_datums;
1360
0
      }
1361
1362
      /* Move to the next list value on the outer side. */
1363
0
      outer_pos++;
1364
0
    }
1365
0
    else
1366
0
    {
1367
      /* A list value missing from the outer side. */
1368
0
      Assert(cmpval > 0);
1369
0
      Assert(inner_pos < inner_bi->ndatums);
1370
1371
      /*
1372
       * If the outer side has the default partition, or this is a FULL
1373
       * join, try to assign a merged partition to the inner partition
1374
       * (see process_inner_partition()).  Otherwise, the inner
1375
       * partition will not contribute to the result.
1376
       */
1377
0
      if (outer_has_default || jointype == JOIN_FULL)
1378
0
      {
1379
        /* Get the inner partition. */
1380
0
        inner_index = inner_bi->indexes[inner_pos];
1381
0
        Assert(inner_index >= 0);
1382
0
        merged_index = process_inner_partition(&outer_map,
1383
0
                             &inner_map,
1384
0
                             outer_has_default,
1385
0
                             inner_has_default,
1386
0
                             inner_index,
1387
0
                             outer_default,
1388
0
                             jointype,
1389
0
                             &next_index,
1390
0
                             &default_index);
1391
0
        if (merged_index == -1)
1392
0
          goto cleanup;
1393
0
        merged_datum = inner_datums;
1394
0
      }
1395
1396
      /* Move to the next list value on the inner side. */
1397
0
      inner_pos++;
1398
0
    }
1399
1400
    /*
1401
     * If we assigned a merged partition, add the list value and index of
1402
     * the merged partition if appropriate.
1403
     */
1404
0
    if (merged_index >= 0 && merged_index != default_index)
1405
0
    {
1406
0
      merged_datums = lappend(merged_datums, merged_datum);
1407
0
      merged_indexes = lappend_int(merged_indexes, merged_index);
1408
0
    }
1409
0
  }
1410
1411
  /*
1412
   * If the NULL partitions (if any) have been proven empty, deem them
1413
   * non-existent.
1414
   */
1415
0
  if (outer_has_null &&
1416
0
    is_dummy_partition(outer_rel, outer_bi->null_index))
1417
0
    outer_has_null = false;
1418
0
  if (inner_has_null &&
1419
0
    is_dummy_partition(inner_rel, inner_bi->null_index))
1420
0
    inner_has_null = false;
1421
1422
  /* Merge the NULL partitions if any. */
1423
0
  if (outer_has_null || inner_has_null)
1424
0
    merge_null_partitions(&outer_map, &inner_map,
1425
0
                outer_has_null, inner_has_null,
1426
0
                outer_bi->null_index, inner_bi->null_index,
1427
0
                jointype, &next_index, &null_index);
1428
0
  else
1429
0
    Assert(null_index == -1);
1430
1431
  /* Merge the default partitions if any. */
1432
0
  if (outer_has_default || inner_has_default)
1433
0
    merge_default_partitions(&outer_map, &inner_map,
1434
0
                 outer_has_default, inner_has_default,
1435
0
                 outer_default, inner_default,
1436
0
                 jointype, &next_index, &default_index);
1437
0
  else
1438
0
    Assert(default_index == -1);
1439
1440
  /* If we have merged partitions, create the partition bounds. */
1441
0
  if (next_index > 0)
1442
0
  {
1443
    /* Fix the merged_indexes list if necessary. */
1444
0
    if (outer_map.did_remapping || inner_map.did_remapping)
1445
0
    {
1446
0
      Assert(jointype == JOIN_FULL);
1447
0
      fix_merged_indexes(&outer_map, &inner_map,
1448
0
                 next_index, merged_indexes);
1449
0
    }
1450
1451
    /* Use maps to match partitions from inputs. */
1452
0
    generate_matching_part_pairs(outer_rel, inner_rel,
1453
0
                   &outer_map, &inner_map,
1454
0
                   next_index,
1455
0
                   outer_parts, inner_parts);
1456
0
    Assert(*outer_parts != NIL);
1457
0
    Assert(*inner_parts != NIL);
1458
0
    Assert(list_length(*outer_parts) == list_length(*inner_parts));
1459
0
    Assert(list_length(*outer_parts) <= next_index);
1460
1461
    /* Make a PartitionBoundInfo struct to return. */
1462
0
    merged_bounds = build_merged_partition_bounds(outer_bi->strategy,
1463
0
                            merged_datums,
1464
0
                            NIL,
1465
0
                            merged_indexes,
1466
0
                            null_index,
1467
0
                            default_index);
1468
0
    Assert(merged_bounds);
1469
0
  }
1470
1471
0
cleanup:
1472
  /* Free local memory before returning. */
1473
0
  list_free(merged_datums);
1474
0
  list_free(merged_indexes);
1475
0
  free_partition_map(&outer_map);
1476
0
  free_partition_map(&inner_map);
1477
1478
0
  return merged_bounds;
1479
0
}
1480
1481
/*
1482
 * merge_range_bounds
1483
 *    Create the partition bounds for a join relation between range
1484
 *    partitioned tables, if possible
1485
 *
1486
 * In this function we try to find sets of overlapping partitions from both
1487
 * sides by comparing ranges stored in their partition bounds.  Since the
1488
 * ranges appear in the ascending order, an algorithm similar to merge join is
1489
 * used for that.  If a partition on one side doesn't have an overlapping
1490
 * partition on the other side, the algorithm tries to match it with the
1491
 * default partition on the other side if any; if not, the algorithm tries to
1492
 * match it with a dummy partition on the other side if it's on the
1493
 * non-nullable side of an outer join.  Also, if both sides have the default
1494
 * partitions, the algorithm tries to match them with each other.  We give up
1495
 * if the algorithm finds a partition overlapping multiple partitions on the
1496
 * other side, which is the scenario the current implementation of partitioned
1497
 * join can't handle.
1498
 */
1499
static PartitionBoundInfo
1500
merge_range_bounds(int partnatts, FmgrInfo *partsupfuncs,
1501
           Oid *partcollations,
1502
           RelOptInfo *outer_rel, RelOptInfo *inner_rel,
1503
           JoinType jointype,
1504
           List **outer_parts, List **inner_parts)
1505
0
{
1506
0
  PartitionBoundInfo merged_bounds = NULL;
1507
0
  PartitionBoundInfo outer_bi = outer_rel->boundinfo;
1508
0
  PartitionBoundInfo inner_bi = inner_rel->boundinfo;
1509
0
  bool    outer_has_default = partition_bound_has_default(outer_bi);
1510
0
  bool    inner_has_default = partition_bound_has_default(inner_bi);
1511
0
  int     outer_default = outer_bi->default_index;
1512
0
  int     inner_default = inner_bi->default_index;
1513
0
  PartitionMap outer_map;
1514
0
  PartitionMap inner_map;
1515
0
  int     outer_index;
1516
0
  int     inner_index;
1517
0
  int     outer_lb_pos;
1518
0
  int     inner_lb_pos;
1519
0
  PartitionRangeBound outer_lb;
1520
0
  PartitionRangeBound outer_ub;
1521
0
  PartitionRangeBound inner_lb;
1522
0
  PartitionRangeBound inner_ub;
1523
0
  int     next_index = 0;
1524
0
  int     default_index = -1;
1525
0
  List     *merged_datums = NIL;
1526
0
  List     *merged_kinds = NIL;
1527
0
  List     *merged_indexes = NIL;
1528
1529
0
  Assert(*outer_parts == NIL);
1530
0
  Assert(*inner_parts == NIL);
1531
0
  Assert(outer_bi->strategy == inner_bi->strategy &&
1532
0
       outer_bi->strategy == PARTITION_STRATEGY_RANGE);
1533
1534
0
  init_partition_map(outer_rel, &outer_map);
1535
0
  init_partition_map(inner_rel, &inner_map);
1536
1537
  /*
1538
   * If the default partitions (if any) have been proven empty, deem them
1539
   * non-existent.
1540
   */
1541
0
  if (outer_has_default && is_dummy_partition(outer_rel, outer_default))
1542
0
    outer_has_default = false;
1543
0
  if (inner_has_default && is_dummy_partition(inner_rel, inner_default))
1544
0
    inner_has_default = false;
1545
1546
  /*
1547
   * Merge partitions from both sides.  In each iteration we compare a pair
1548
   * of ranges, one from each side, and decide whether the corresponding
1549
   * partitions match or not.  If the two ranges overlap, move to the next
1550
   * pair of ranges, otherwise move to the next range on the side with a
1551
   * lower range.  outer_lb_pos/inner_lb_pos keep track of the positions of
1552
   * lower bounds in the datums arrays in the outer/inner
1553
   * PartitionBoundInfos respectively.
1554
   */
1555
0
  outer_lb_pos = inner_lb_pos = 0;
1556
0
  outer_index = get_range_partition(outer_rel, outer_bi, &outer_lb_pos,
1557
0
                    &outer_lb, &outer_ub);
1558
0
  inner_index = get_range_partition(inner_rel, inner_bi, &inner_lb_pos,
1559
0
                    &inner_lb, &inner_ub);
1560
0
  while (outer_index >= 0 || inner_index >= 0)
1561
0
  {
1562
0
    bool    overlap;
1563
0
    int     ub_cmpval;
1564
0
    int     lb_cmpval;
1565
0
    PartitionRangeBound merged_lb = {-1, NULL, NULL, true};
1566
0
    PartitionRangeBound merged_ub = {-1, NULL, NULL, false};
1567
0
    int     merged_index = -1;
1568
1569
    /*
1570
     * We run this loop till both sides finish.  This allows us to avoid
1571
     * duplicating code to handle the remaining ranges on the side which
1572
     * finishes later.  For that we set the comparison parameter cmpval in
1573
     * such a way that it appears as if the side which finishes earlier
1574
     * has an extra range higher than any other range on the unfinished
1575
     * side. That way we advance the ranges on the unfinished side till
1576
     * all of its ranges are exhausted.
1577
     */
1578
0
    if (outer_index == -1)
1579
0
    {
1580
0
      overlap = false;
1581
0
      lb_cmpval = 1;
1582
0
      ub_cmpval = 1;
1583
0
    }
1584
0
    else if (inner_index == -1)
1585
0
    {
1586
0
      overlap = false;
1587
0
      lb_cmpval = -1;
1588
0
      ub_cmpval = -1;
1589
0
    }
1590
0
    else
1591
0
      overlap = compare_range_partitions(partnatts, partsupfuncs,
1592
0
                         partcollations,
1593
0
                         &outer_lb, &outer_ub,
1594
0
                         &inner_lb, &inner_ub,
1595
0
                         &lb_cmpval, &ub_cmpval);
1596
1597
0
    if (overlap)
1598
0
    {
1599
      /* Two ranges overlap; form a join pair. */
1600
1601
0
      PartitionRangeBound save_outer_ub;
1602
0
      PartitionRangeBound save_inner_ub;
1603
1604
      /* Both partitions should not have been merged yet. */
1605
0
      Assert(outer_index >= 0);
1606
0
      Assert(outer_map.merged_indexes[outer_index] == -1 &&
1607
0
           outer_map.merged[outer_index] == false);
1608
0
      Assert(inner_index >= 0);
1609
0
      Assert(inner_map.merged_indexes[inner_index] == -1 &&
1610
0
           inner_map.merged[inner_index] == false);
1611
1612
      /*
1613
       * Get the index of the merged partition.  Both partitions aren't
1614
       * merged yet, so the partitions should be merged successfully.
1615
       */
1616
0
      merged_index = merge_matching_partitions(&outer_map, &inner_map,
1617
0
                           outer_index, inner_index,
1618
0
                           &next_index);
1619
0
      Assert(merged_index >= 0);
1620
1621
      /* Get the range bounds of the merged partition. */
1622
0
      get_merged_range_bounds(partnatts, partsupfuncs,
1623
0
                  partcollations, jointype,
1624
0
                  &outer_lb, &outer_ub,
1625
0
                  &inner_lb, &inner_ub,
1626
0
                  lb_cmpval, ub_cmpval,
1627
0
                  &merged_lb, &merged_ub);
1628
1629
      /* Save the upper bounds of both partitions for use below. */
1630
0
      save_outer_ub = outer_ub;
1631
0
      save_inner_ub = inner_ub;
1632
1633
      /* Move to the next pair of ranges. */
1634
0
      outer_index = get_range_partition(outer_rel, outer_bi, &outer_lb_pos,
1635
0
                        &outer_lb, &outer_ub);
1636
0
      inner_index = get_range_partition(inner_rel, inner_bi, &inner_lb_pos,
1637
0
                        &inner_lb, &inner_ub);
1638
1639
      /*
1640
       * If the range of a partition on one side overlaps the range of
1641
       * the next partition on the other side, that will cause the
1642
       * partition on one side to match at least two partitions on the
1643
       * other side, which is the case that we currently don't support
1644
       * partitioned join for; give up.
1645
       */
1646
0
      if (ub_cmpval > 0 && inner_index >= 0 &&
1647
0
        compare_range_bounds(partnatts, partsupfuncs, partcollations,
1648
0
                   &save_outer_ub, &inner_lb) > 0)
1649
0
        goto cleanup;
1650
0
      if (ub_cmpval < 0 && outer_index >= 0 &&
1651
0
        compare_range_bounds(partnatts, partsupfuncs, partcollations,
1652
0
                   &outer_lb, &save_inner_ub) < 0)
1653
0
        goto cleanup;
1654
1655
      /*
1656
       * A row from a non-overlapping portion (if any) of a partition on
1657
       * one side might find its join partner in the default partition
1658
       * (if any) on the other side, causing the same situation as
1659
       * above; give up in that case.
1660
       */
1661
0
      if ((outer_has_default && (lb_cmpval > 0 || ub_cmpval < 0)) ||
1662
0
        (inner_has_default && (lb_cmpval < 0 || ub_cmpval > 0)))
1663
0
        goto cleanup;
1664
0
    }
1665
0
    else if (ub_cmpval < 0)
1666
0
    {
1667
      /* A non-overlapping outer range. */
1668
1669
      /* The outer partition should not have been merged yet. */
1670
0
      Assert(outer_index >= 0);
1671
0
      Assert(outer_map.merged_indexes[outer_index] == -1 &&
1672
0
           outer_map.merged[outer_index] == false);
1673
1674
      /*
1675
       * If the inner side has the default partition, or this is an
1676
       * outer join, try to assign a merged partition to the outer
1677
       * partition (see process_outer_partition()).  Otherwise, the
1678
       * outer partition will not contribute to the result.
1679
       */
1680
0
      if (inner_has_default || IS_OUTER_JOIN(jointype))
1681
0
      {
1682
0
        merged_index = process_outer_partition(&outer_map,
1683
0
                             &inner_map,
1684
0
                             outer_has_default,
1685
0
                             inner_has_default,
1686
0
                             outer_index,
1687
0
                             inner_default,
1688
0
                             jointype,
1689
0
                             &next_index,
1690
0
                             &default_index);
1691
0
        if (merged_index == -1)
1692
0
          goto cleanup;
1693
0
        merged_lb = outer_lb;
1694
0
        merged_ub = outer_ub;
1695
0
      }
1696
1697
      /* Move to the next range on the outer side. */
1698
0
      outer_index = get_range_partition(outer_rel, outer_bi, &outer_lb_pos,
1699
0
                        &outer_lb, &outer_ub);
1700
0
    }
1701
0
    else
1702
0
    {
1703
      /* A non-overlapping inner range. */
1704
0
      Assert(ub_cmpval > 0);
1705
1706
      /* The inner partition should not have been merged yet. */
1707
0
      Assert(inner_index >= 0);
1708
0
      Assert(inner_map.merged_indexes[inner_index] == -1 &&
1709
0
           inner_map.merged[inner_index] == false);
1710
1711
      /*
1712
       * If the outer side has the default partition, or this is a FULL
1713
       * join, try to assign a merged partition to the inner partition
1714
       * (see process_inner_partition()).  Otherwise, the inner
1715
       * partition will not contribute to the result.
1716
       */
1717
0
      if (outer_has_default || jointype == JOIN_FULL)
1718
0
      {
1719
0
        merged_index = process_inner_partition(&outer_map,
1720
0
                             &inner_map,
1721
0
                             outer_has_default,
1722
0
                             inner_has_default,
1723
0
                             inner_index,
1724
0
                             outer_default,
1725
0
                             jointype,
1726
0
                             &next_index,
1727
0
                             &default_index);
1728
0
        if (merged_index == -1)
1729
0
          goto cleanup;
1730
0
        merged_lb = inner_lb;
1731
0
        merged_ub = inner_ub;
1732
0
      }
1733
1734
      /* Move to the next range on the inner side. */
1735
0
      inner_index = get_range_partition(inner_rel, inner_bi, &inner_lb_pos,
1736
0
                        &inner_lb, &inner_ub);
1737
0
    }
1738
1739
    /*
1740
     * If we assigned a merged partition, add the range bounds and index
1741
     * of the merged partition if appropriate.
1742
     */
1743
0
    if (merged_index >= 0 && merged_index != default_index)
1744
0
      add_merged_range_bounds(partnatts, partsupfuncs, partcollations,
1745
0
                  &merged_lb, &merged_ub, merged_index,
1746
0
                  &merged_datums, &merged_kinds,
1747
0
                  &merged_indexes);
1748
0
  }
1749
1750
  /* Merge the default partitions if any. */
1751
0
  if (outer_has_default || inner_has_default)
1752
0
    merge_default_partitions(&outer_map, &inner_map,
1753
0
                 outer_has_default, inner_has_default,
1754
0
                 outer_default, inner_default,
1755
0
                 jointype, &next_index, &default_index);
1756
0
  else
1757
0
    Assert(default_index == -1);
1758
1759
  /* If we have merged partitions, create the partition bounds. */
1760
0
  if (next_index > 0)
1761
0
  {
1762
    /*
1763
     * Unlike the case of list partitioning, we wouldn't have re-merged
1764
     * partitions, so did_remapping should be left alone.
1765
     */
1766
0
    Assert(!outer_map.did_remapping);
1767
0
    Assert(!inner_map.did_remapping);
1768
1769
    /* Use maps to match partitions from inputs. */
1770
0
    generate_matching_part_pairs(outer_rel, inner_rel,
1771
0
                   &outer_map, &inner_map,
1772
0
                   next_index,
1773
0
                   outer_parts, inner_parts);
1774
0
    Assert(*outer_parts != NIL);
1775
0
    Assert(*inner_parts != NIL);
1776
0
    Assert(list_length(*outer_parts) == list_length(*inner_parts));
1777
0
    Assert(list_length(*outer_parts) == next_index);
1778
1779
    /* Make a PartitionBoundInfo struct to return. */
1780
0
    merged_bounds = build_merged_partition_bounds(outer_bi->strategy,
1781
0
                            merged_datums,
1782
0
                            merged_kinds,
1783
0
                            merged_indexes,
1784
0
                            -1,
1785
0
                            default_index);
1786
0
    Assert(merged_bounds);
1787
0
  }
1788
1789
0
cleanup:
1790
  /* Free local memory before returning. */
1791
0
  list_free(merged_datums);
1792
0
  list_free(merged_kinds);
1793
0
  list_free(merged_indexes);
1794
0
  free_partition_map(&outer_map);
1795
0
  free_partition_map(&inner_map);
1796
1797
0
  return merged_bounds;
1798
0
}
1799
1800
/*
1801
 * init_partition_map
1802
 *    Initialize a PartitionMap struct for given relation
1803
 */
1804
static void
1805
init_partition_map(RelOptInfo *rel, PartitionMap *map)
1806
0
{
1807
0
  int     nparts = rel->nparts;
1808
0
  int     i;
1809
1810
0
  map->nparts = nparts;
1811
0
  map->merged_indexes = palloc_array(int, nparts);
1812
0
  map->merged = palloc_array(bool, nparts);
1813
0
  map->did_remapping = false;
1814
0
  map->old_indexes = palloc_array(int, nparts);
1815
0
  for (i = 0; i < nparts; i++)
1816
0
  {
1817
0
    map->merged_indexes[i] = map->old_indexes[i] = -1;
1818
0
    map->merged[i] = false;
1819
0
  }
1820
0
}
1821
1822
/*
1823
 * free_partition_map
1824
 */
1825
static void
1826
free_partition_map(PartitionMap *map)
1827
0
{
1828
0
  pfree(map->merged_indexes);
1829
0
  pfree(map->merged);
1830
0
  pfree(map->old_indexes);
1831
0
}
1832
1833
/*
1834
 * is_dummy_partition --- has partition been proven empty?
1835
 */
1836
static bool
1837
is_dummy_partition(RelOptInfo *rel, int part_index)
1838
0
{
1839
0
  RelOptInfo *part_rel;
1840
1841
0
  Assert(part_index >= 0);
1842
0
  part_rel = rel->part_rels[part_index];
1843
0
  if (part_rel == NULL || IS_DUMMY_REL(part_rel))
1844
0
    return true;
1845
0
  return false;
1846
0
}
1847
1848
/*
1849
 * merge_matching_partitions
1850
 *    Try to merge given outer/inner partitions, and return the index of a
1851
 *    merged partition produced from them if successful, -1 otherwise
1852
 *
1853
 * If the merged partition is newly created, *next_index is incremented.
1854
 */
1855
static int
1856
merge_matching_partitions(PartitionMap *outer_map, PartitionMap *inner_map,
1857
              int outer_index, int inner_index, int *next_index)
1858
0
{
1859
0
  int     outer_merged_index;
1860
0
  int     inner_merged_index;
1861
0
  bool    outer_merged;
1862
0
  bool    inner_merged;
1863
1864
0
  Assert(outer_index >= 0 && outer_index < outer_map->nparts);
1865
0
  outer_merged_index = outer_map->merged_indexes[outer_index];
1866
0
  outer_merged = outer_map->merged[outer_index];
1867
0
  Assert(inner_index >= 0 && inner_index < inner_map->nparts);
1868
0
  inner_merged_index = inner_map->merged_indexes[inner_index];
1869
0
  inner_merged = inner_map->merged[inner_index];
1870
1871
  /*
1872
   * Handle cases where we have already assigned a merged partition to each
1873
   * of the given partitions.
1874
   */
1875
0
  if (outer_merged_index >= 0 && inner_merged_index >= 0)
1876
0
  {
1877
    /*
1878
     * If the merged partitions are the same, no need to do anything;
1879
     * return the index of the merged partitions.  Otherwise, if each of
1880
     * the given partitions has been merged with a dummy partition on the
1881
     * other side, re-map them to either of the two merged partitions.
1882
     * Otherwise, they can't be merged, so return -1.
1883
     */
1884
0
    if (outer_merged_index == inner_merged_index)
1885
0
    {
1886
0
      Assert(outer_merged);
1887
0
      Assert(inner_merged);
1888
0
      return outer_merged_index;
1889
0
    }
1890
0
    if (!outer_merged && !inner_merged)
1891
0
    {
1892
      /*
1893
       * This can only happen for a list-partitioning case.  We re-map
1894
       * them to the merged partition with the smaller of the two merged
1895
       * indexes to preserve the property that the canonical order of
1896
       * list partitions is determined by the indexes assigned to the
1897
       * smallest list value of each partition.
1898
       */
1899
0
      if (outer_merged_index < inner_merged_index)
1900
0
      {
1901
0
        outer_map->merged[outer_index] = true;
1902
0
        inner_map->merged_indexes[inner_index] = outer_merged_index;
1903
0
        inner_map->merged[inner_index] = true;
1904
0
        inner_map->did_remapping = true;
1905
0
        inner_map->old_indexes[inner_index] = inner_merged_index;
1906
0
        return outer_merged_index;
1907
0
      }
1908
0
      else
1909
0
      {
1910
0
        inner_map->merged[inner_index] = true;
1911
0
        outer_map->merged_indexes[outer_index] = inner_merged_index;
1912
0
        outer_map->merged[outer_index] = true;
1913
0
        outer_map->did_remapping = true;
1914
0
        outer_map->old_indexes[outer_index] = outer_merged_index;
1915
0
        return inner_merged_index;
1916
0
      }
1917
0
    }
1918
0
    return -1;
1919
0
  }
1920
1921
  /* At least one of the given partitions should not have yet been merged. */
1922
0
  Assert(outer_merged_index == -1 || inner_merged_index == -1);
1923
1924
  /*
1925
   * If neither of them has been merged, merge them.  Otherwise, if one has
1926
   * been merged with a dummy partition on the other side (and the other
1927
   * hasn't yet been merged with anything), re-merge them.  Otherwise, they
1928
   * can't be merged, so return -1.
1929
   */
1930
0
  if (outer_merged_index == -1 && inner_merged_index == -1)
1931
0
  {
1932
0
    int     merged_index = *next_index;
1933
1934
0
    Assert(!outer_merged);
1935
0
    Assert(!inner_merged);
1936
0
    outer_map->merged_indexes[outer_index] = merged_index;
1937
0
    outer_map->merged[outer_index] = true;
1938
0
    inner_map->merged_indexes[inner_index] = merged_index;
1939
0
    inner_map->merged[inner_index] = true;
1940
0
    *next_index = *next_index + 1;
1941
0
    return merged_index;
1942
0
  }
1943
0
  if (outer_merged_index >= 0 && !outer_map->merged[outer_index])
1944
0
  {
1945
0
    Assert(inner_merged_index == -1);
1946
0
    Assert(!inner_merged);
1947
0
    inner_map->merged_indexes[inner_index] = outer_merged_index;
1948
0
    inner_map->merged[inner_index] = true;
1949
0
    outer_map->merged[outer_index] = true;
1950
0
    return outer_merged_index;
1951
0
  }
1952
0
  if (inner_merged_index >= 0 && !inner_map->merged[inner_index])
1953
0
  {
1954
0
    Assert(outer_merged_index == -1);
1955
0
    Assert(!outer_merged);
1956
0
    outer_map->merged_indexes[outer_index] = inner_merged_index;
1957
0
    outer_map->merged[outer_index] = true;
1958
0
    inner_map->merged[inner_index] = true;
1959
0
    return inner_merged_index;
1960
0
  }
1961
0
  return -1;
1962
0
}
1963
1964
/*
1965
 * process_outer_partition
1966
 *    Try to assign given outer partition a merged partition, and return the
1967
 *    index of the merged partition if successful, -1 otherwise
1968
 *
1969
 * If the partition is newly created, *next_index is incremented.  Also, if it
1970
 * is the default partition of the join relation, *default_index is set to the
1971
 * index if not already done.
1972
 */
1973
static int
1974
process_outer_partition(PartitionMap *outer_map,
1975
            PartitionMap *inner_map,
1976
            bool outer_has_default,
1977
            bool inner_has_default,
1978
            int outer_index,
1979
            int inner_default,
1980
            JoinType jointype,
1981
            int *next_index,
1982
            int *default_index)
1983
0
{
1984
0
  int     merged_index = -1;
1985
1986
0
  Assert(outer_index >= 0);
1987
1988
  /*
1989
   * If the inner side has the default partition, a row from the outer
1990
   * partition might find its join partner in the default partition; try
1991
   * merging the outer partition with the default partition.  Otherwise,
1992
   * this should be an outer join, in which case the outer partition has to
1993
   * be scanned all the way anyway; merge the outer partition with a dummy
1994
   * partition on the other side.
1995
   */
1996
0
  if (inner_has_default)
1997
0
  {
1998
0
    Assert(inner_default >= 0);
1999
2000
    /*
2001
     * If the outer side has the default partition as well, the default
2002
     * partition on the inner side will have two matching partitions on
2003
     * the other side: the outer partition and the default partition on
2004
     * the outer side.  Partitionwise join doesn't handle this scenario
2005
     * yet.
2006
     */
2007
0
    if (outer_has_default)
2008
0
      return -1;
2009
2010
0
    merged_index = merge_matching_partitions(outer_map, inner_map,
2011
0
                         outer_index, inner_default,
2012
0
                         next_index);
2013
0
    if (merged_index == -1)
2014
0
      return -1;
2015
2016
    /*
2017
     * If this is a FULL join, the default partition on the inner side has
2018
     * to be scanned all the way anyway, so the resulting partition will
2019
     * contain all key values from the default partition, which any other
2020
     * partition of the join relation will not contain.  Thus the
2021
     * resulting partition will act as the default partition of the join
2022
     * relation; record the index in *default_index if not already done.
2023
     */
2024
0
    if (jointype == JOIN_FULL)
2025
0
    {
2026
0
      if (*default_index == -1)
2027
0
        *default_index = merged_index;
2028
0
      else
2029
0
        Assert(*default_index == merged_index);
2030
0
    }
2031
0
  }
2032
0
  else
2033
0
  {
2034
0
    Assert(IS_OUTER_JOIN(jointype));
2035
0
    Assert(jointype != JOIN_RIGHT);
2036
2037
    /* If we have already assigned a partition, no need to do anything. */
2038
0
    merged_index = outer_map->merged_indexes[outer_index];
2039
0
    if (merged_index == -1)
2040
0
      merged_index = merge_partition_with_dummy(outer_map, outer_index,
2041
0
                            next_index);
2042
0
  }
2043
0
  return merged_index;
2044
0
}
2045
2046
/*
2047
 * process_inner_partition
2048
 *    Try to assign given inner partition a merged partition, and return the
2049
 *    index of the merged partition if successful, -1 otherwise
2050
 *
2051
 * If the partition is newly created, *next_index is incremented.  Also, if it
2052
 * is the default partition of the join relation, *default_index is set to the
2053
 * index if not already done.
2054
 */
2055
static int
2056
process_inner_partition(PartitionMap *outer_map,
2057
            PartitionMap *inner_map,
2058
            bool outer_has_default,
2059
            bool inner_has_default,
2060
            int inner_index,
2061
            int outer_default,
2062
            JoinType jointype,
2063
            int *next_index,
2064
            int *default_index)
2065
0
{
2066
0
  int     merged_index = -1;
2067
2068
0
  Assert(inner_index >= 0);
2069
2070
  /*
2071
   * If the outer side has the default partition, a row from the inner
2072
   * partition might find its join partner in the default partition; try
2073
   * merging the inner partition with the default partition.  Otherwise,
2074
   * this should be a FULL join, in which case the inner partition has to be
2075
   * scanned all the way anyway; merge the inner partition with a dummy
2076
   * partition on the other side.
2077
   */
2078
0
  if (outer_has_default)
2079
0
  {
2080
0
    Assert(outer_default >= 0);
2081
2082
    /*
2083
     * If the inner side has the default partition as well, the default
2084
     * partition on the outer side will have two matching partitions on
2085
     * the other side: the inner partition and the default partition on
2086
     * the inner side.  Partitionwise join doesn't handle this scenario
2087
     * yet.
2088
     */
2089
0
    if (inner_has_default)
2090
0
      return -1;
2091
2092
0
    merged_index = merge_matching_partitions(outer_map, inner_map,
2093
0
                         outer_default, inner_index,
2094
0
                         next_index);
2095
0
    if (merged_index == -1)
2096
0
      return -1;
2097
2098
    /*
2099
     * If this is an outer join, the default partition on the outer side
2100
     * has to be scanned all the way anyway, so the resulting partition
2101
     * will contain all key values from the default partition, which any
2102
     * other partition of the join relation will not contain.  Thus the
2103
     * resulting partition will act as the default partition of the join
2104
     * relation; record the index in *default_index if not already done.
2105
     */
2106
0
    if (IS_OUTER_JOIN(jointype))
2107
0
    {
2108
0
      Assert(jointype != JOIN_RIGHT);
2109
0
      if (*default_index == -1)
2110
0
        *default_index = merged_index;
2111
0
      else
2112
0
        Assert(*default_index == merged_index);
2113
0
    }
2114
0
  }
2115
0
  else
2116
0
  {
2117
0
    Assert(jointype == JOIN_FULL);
2118
2119
    /* If we have already assigned a partition, no need to do anything. */
2120
0
    merged_index = inner_map->merged_indexes[inner_index];
2121
0
    if (merged_index == -1)
2122
0
      merged_index = merge_partition_with_dummy(inner_map, inner_index,
2123
0
                            next_index);
2124
0
  }
2125
0
  return merged_index;
2126
0
}
2127
2128
/*
2129
 * merge_null_partitions
2130
 *    Merge the NULL partitions from a join's outer and inner sides.
2131
 *
2132
 * If the merged partition produced from them is the NULL partition of the join
2133
 * relation, *null_index is set to the index of the merged partition.
2134
 *
2135
 * Note: We assume here that the join clause for a partitioned join is strict
2136
 * because have_partkey_equi_join() requires that the corresponding operator
2137
 * be mergejoinable, and we currently assume that mergejoinable operators are
2138
 * strict (see MJEvalOuterValues()/MJEvalInnerValues()).
2139
 */
2140
static void
2141
merge_null_partitions(PartitionMap *outer_map,
2142
            PartitionMap *inner_map,
2143
            bool outer_has_null,
2144
            bool inner_has_null,
2145
            int outer_null,
2146
            int inner_null,
2147
            JoinType jointype,
2148
            int *next_index,
2149
            int *null_index)
2150
0
{
2151
0
  bool    consider_outer_null = false;
2152
0
  bool    consider_inner_null = false;
2153
2154
0
  Assert(outer_has_null || inner_has_null);
2155
0
  Assert(*null_index == -1);
2156
2157
  /*
2158
   * Check whether the NULL partitions have already been merged and if so,
2159
   * set the consider_outer_null/consider_inner_null flags.
2160
   */
2161
0
  if (outer_has_null)
2162
0
  {
2163
0
    Assert(outer_null >= 0 && outer_null < outer_map->nparts);
2164
0
    if (outer_map->merged_indexes[outer_null] == -1)
2165
0
      consider_outer_null = true;
2166
0
  }
2167
0
  if (inner_has_null)
2168
0
  {
2169
0
    Assert(inner_null >= 0 && inner_null < inner_map->nparts);
2170
0
    if (inner_map->merged_indexes[inner_null] == -1)
2171
0
      consider_inner_null = true;
2172
0
  }
2173
2174
  /* If both flags are set false, we don't need to do anything. */
2175
0
  if (!consider_outer_null && !consider_inner_null)
2176
0
    return;
2177
2178
0
  if (consider_outer_null && !consider_inner_null)
2179
0
  {
2180
0
    Assert(outer_has_null);
2181
2182
    /*
2183
     * If this is an outer join, the NULL partition on the outer side has
2184
     * to be scanned all the way anyway; merge the NULL partition with a
2185
     * dummy partition on the other side.  In that case
2186
     * consider_outer_null means that the NULL partition only contains
2187
     * NULL values as the key values, so the merged partition will do so;
2188
     * treat it as the NULL partition of the join relation.
2189
     */
2190
0
    if (IS_OUTER_JOIN(jointype))
2191
0
    {
2192
0
      Assert(jointype != JOIN_RIGHT);
2193
0
      *null_index = merge_partition_with_dummy(outer_map, outer_null,
2194
0
                           next_index);
2195
0
    }
2196
0
  }
2197
0
  else if (!consider_outer_null && consider_inner_null)
2198
0
  {
2199
0
    Assert(inner_has_null);
2200
2201
    /*
2202
     * If this is a FULL join, the NULL partition on the inner side has to
2203
     * be scanned all the way anyway; merge the NULL partition with a
2204
     * dummy partition on the other side.  In that case
2205
     * consider_inner_null means that the NULL partition only contains
2206
     * NULL values as the key values, so the merged partition will do so;
2207
     * treat it as the NULL partition of the join relation.
2208
     */
2209
0
    if (jointype == JOIN_FULL)
2210
0
      *null_index = merge_partition_with_dummy(inner_map, inner_null,
2211
0
                           next_index);
2212
0
  }
2213
0
  else
2214
0
  {
2215
0
    Assert(consider_outer_null && consider_inner_null);
2216
0
    Assert(outer_has_null);
2217
0
    Assert(inner_has_null);
2218
2219
    /*
2220
     * If this is an outer join, the NULL partition on the outer side (and
2221
     * that on the inner side if this is a FULL join) have to be scanned
2222
     * all the way anyway, so merge them.  Note that each of the NULL
2223
     * partitions isn't merged yet, so they should be merged successfully.
2224
     * Like the above, each of the NULL partitions only contains NULL
2225
     * values as the key values, so the merged partition will do so; treat
2226
     * it as the NULL partition of the join relation.
2227
     *
2228
     * Note: if this an INNER/SEMI join, the join clause will never be
2229
     * satisfied by two NULL values (see comments above), so both the NULL
2230
     * partitions can be eliminated.
2231
     */
2232
0
    if (IS_OUTER_JOIN(jointype))
2233
0
    {
2234
0
      Assert(jointype != JOIN_RIGHT);
2235
0
      *null_index = merge_matching_partitions(outer_map, inner_map,
2236
0
                          outer_null, inner_null,
2237
0
                          next_index);
2238
0
      Assert(*null_index >= 0);
2239
0
    }
2240
0
  }
2241
0
}
2242
2243
/*
2244
 * merge_default_partitions
2245
 *    Merge the default partitions from a join's outer and inner sides.
2246
 *
2247
 * If the merged partition produced from them is the default partition of the
2248
 * join relation, *default_index is set to the index of the merged partition.
2249
 */
2250
static void
2251
merge_default_partitions(PartitionMap *outer_map,
2252
             PartitionMap *inner_map,
2253
             bool outer_has_default,
2254
             bool inner_has_default,
2255
             int outer_default,
2256
             int inner_default,
2257
             JoinType jointype,
2258
             int *next_index,
2259
             int *default_index)
2260
0
{
2261
0
  int     outer_merged_index = -1;
2262
0
  int     inner_merged_index = -1;
2263
2264
0
  Assert(outer_has_default || inner_has_default);
2265
2266
  /* Get the merged partition indexes for the default partitions. */
2267
0
  if (outer_has_default)
2268
0
  {
2269
0
    Assert(outer_default >= 0 && outer_default < outer_map->nparts);
2270
0
    outer_merged_index = outer_map->merged_indexes[outer_default];
2271
0
  }
2272
0
  if (inner_has_default)
2273
0
  {
2274
0
    Assert(inner_default >= 0 && inner_default < inner_map->nparts);
2275
0
    inner_merged_index = inner_map->merged_indexes[inner_default];
2276
0
  }
2277
2278
0
  if (outer_has_default && !inner_has_default)
2279
0
  {
2280
    /*
2281
     * If this is an outer join, the default partition on the outer side
2282
     * has to be scanned all the way anyway; if we have not yet assigned a
2283
     * partition, merge the default partition with a dummy partition on
2284
     * the other side.  The merged partition will act as the default
2285
     * partition of the join relation (see comments in
2286
     * process_inner_partition()).
2287
     */
2288
0
    if (IS_OUTER_JOIN(jointype))
2289
0
    {
2290
0
      Assert(jointype != JOIN_RIGHT);
2291
0
      if (outer_merged_index == -1)
2292
0
      {
2293
0
        Assert(*default_index == -1);
2294
0
        *default_index = merge_partition_with_dummy(outer_map,
2295
0
                              outer_default,
2296
0
                              next_index);
2297
0
      }
2298
0
      else
2299
0
        Assert(*default_index == outer_merged_index);
2300
0
    }
2301
0
    else
2302
0
      Assert(*default_index == -1);
2303
0
  }
2304
0
  else if (!outer_has_default && inner_has_default)
2305
0
  {
2306
    /*
2307
     * If this is a FULL join, the default partition on the inner side has
2308
     * to be scanned all the way anyway; if we have not yet assigned a
2309
     * partition, merge the default partition with a dummy partition on
2310
     * the other side.  The merged partition will act as the default
2311
     * partition of the join relation (see comments in
2312
     * process_outer_partition()).
2313
     */
2314
0
    if (jointype == JOIN_FULL)
2315
0
    {
2316
0
      if (inner_merged_index == -1)
2317
0
      {
2318
0
        Assert(*default_index == -1);
2319
0
        *default_index = merge_partition_with_dummy(inner_map,
2320
0
                              inner_default,
2321
0
                              next_index);
2322
0
      }
2323
0
      else
2324
0
        Assert(*default_index == inner_merged_index);
2325
0
    }
2326
0
    else
2327
0
      Assert(*default_index == -1);
2328
0
  }
2329
0
  else
2330
0
  {
2331
0
    Assert(outer_has_default && inner_has_default);
2332
2333
    /*
2334
     * The default partitions have to be joined with each other, so merge
2335
     * them.  Note that each of the default partitions isn't merged yet
2336
     * (see, process_outer_partition()/process_inner_partition()), so they
2337
     * should be merged successfully.  The merged partition will act as
2338
     * the default partition of the join relation.
2339
     */
2340
0
    Assert(outer_merged_index == -1);
2341
0
    Assert(inner_merged_index == -1);
2342
0
    Assert(*default_index == -1);
2343
0
    *default_index = merge_matching_partitions(outer_map,
2344
0
                           inner_map,
2345
0
                           outer_default,
2346
0
                           inner_default,
2347
0
                           next_index);
2348
0
    Assert(*default_index >= 0);
2349
0
  }
2350
0
}
2351
2352
/*
2353
 * merge_partition_with_dummy
2354
 *    Assign given partition a new partition of a join relation
2355
 *
2356
 * Note: The caller assumes that the given partition doesn't have a non-dummy
2357
 * matching partition on the other side, but if the given partition finds the
2358
 * matching partition later, we will adjust the assignment.
2359
 */
2360
static int
2361
merge_partition_with_dummy(PartitionMap *map, int index, int *next_index)
2362
0
{
2363
0
  int     merged_index = *next_index;
2364
2365
0
  Assert(index >= 0 && index < map->nparts);
2366
0
  Assert(map->merged_indexes[index] == -1);
2367
0
  Assert(!map->merged[index]);
2368
0
  map->merged_indexes[index] = merged_index;
2369
  /* Leave the merged flag alone! */
2370
0
  *next_index = *next_index + 1;
2371
0
  return merged_index;
2372
0
}
2373
2374
/*
2375
 * fix_merged_indexes
2376
 *    Adjust merged indexes of re-merged partitions
2377
 */
2378
static void
2379
fix_merged_indexes(PartitionMap *outer_map, PartitionMap *inner_map,
2380
           int nmerged, List *merged_indexes)
2381
0
{
2382
0
  int      *new_indexes;
2383
0
  int     merged_index;
2384
0
  int     i;
2385
0
  ListCell   *lc;
2386
2387
0
  Assert(nmerged > 0);
2388
2389
0
  new_indexes = palloc_array(int, nmerged);
2390
0
  for (i = 0; i < nmerged; i++)
2391
0
    new_indexes[i] = -1;
2392
2393
  /* Build the mapping of old merged indexes to new merged indexes. */
2394
0
  if (outer_map->did_remapping)
2395
0
  {
2396
0
    for (i = 0; i < outer_map->nparts; i++)
2397
0
    {
2398
0
      merged_index = outer_map->old_indexes[i];
2399
0
      if (merged_index >= 0)
2400
0
        new_indexes[merged_index] = outer_map->merged_indexes[i];
2401
0
    }
2402
0
  }
2403
0
  if (inner_map->did_remapping)
2404
0
  {
2405
0
    for (i = 0; i < inner_map->nparts; i++)
2406
0
    {
2407
0
      merged_index = inner_map->old_indexes[i];
2408
0
      if (merged_index >= 0)
2409
0
        new_indexes[merged_index] = inner_map->merged_indexes[i];
2410
0
    }
2411
0
  }
2412
2413
  /* Fix the merged_indexes list using the mapping. */
2414
0
  foreach(lc, merged_indexes)
2415
0
  {
2416
0
    merged_index = lfirst_int(lc);
2417
0
    Assert(merged_index >= 0);
2418
0
    if (new_indexes[merged_index] >= 0)
2419
0
      lfirst_int(lc) = new_indexes[merged_index];
2420
0
  }
2421
2422
0
  pfree(new_indexes);
2423
0
}
2424
2425
/*
2426
 * generate_matching_part_pairs
2427
 *    Generate a pair of lists of partitions that produce merged partitions
2428
 *
2429
 * The lists of partitions are built in the order of merged partition indexes,
2430
 * and returned in *outer_parts and *inner_parts.
2431
 */
2432
static void
2433
generate_matching_part_pairs(RelOptInfo *outer_rel, RelOptInfo *inner_rel,
2434
               PartitionMap *outer_map, PartitionMap *inner_map,
2435
               int nmerged,
2436
               List **outer_parts, List **inner_parts)
2437
0
{
2438
0
  int     outer_nparts = outer_map->nparts;
2439
0
  int     inner_nparts = inner_map->nparts;
2440
0
  int      *outer_indexes;
2441
0
  int      *inner_indexes;
2442
0
  int     max_nparts;
2443
0
  int     i;
2444
2445
0
  Assert(nmerged > 0);
2446
0
  Assert(*outer_parts == NIL);
2447
0
  Assert(*inner_parts == NIL);
2448
2449
0
  outer_indexes = palloc_array(int, nmerged);
2450
0
  inner_indexes = palloc_array(int, nmerged);
2451
0
  for (i = 0; i < nmerged; i++)
2452
0
    outer_indexes[i] = inner_indexes[i] = -1;
2453
2454
  /* Set pairs of matching partitions. */
2455
0
  Assert(outer_nparts == outer_rel->nparts);
2456
0
  Assert(inner_nparts == inner_rel->nparts);
2457
0
  max_nparts = Max(outer_nparts, inner_nparts);
2458
0
  for (i = 0; i < max_nparts; i++)
2459
0
  {
2460
0
    if (i < outer_nparts)
2461
0
    {
2462
0
      int     merged_index = outer_map->merged_indexes[i];
2463
2464
0
      if (merged_index >= 0)
2465
0
      {
2466
0
        Assert(merged_index < nmerged);
2467
0
        outer_indexes[merged_index] = i;
2468
0
      }
2469
0
    }
2470
0
    if (i < inner_nparts)
2471
0
    {
2472
0
      int     merged_index = inner_map->merged_indexes[i];
2473
2474
0
      if (merged_index >= 0)
2475
0
      {
2476
0
        Assert(merged_index < nmerged);
2477
0
        inner_indexes[merged_index] = i;
2478
0
      }
2479
0
    }
2480
0
  }
2481
2482
  /* Build the list pairs. */
2483
0
  for (i = 0; i < nmerged; i++)
2484
0
  {
2485
0
    int     outer_index = outer_indexes[i];
2486
0
    int     inner_index = inner_indexes[i];
2487
2488
    /*
2489
     * If both partitions are dummy, it means the merged partition that
2490
     * had been assigned to the outer/inner partition was removed when
2491
     * re-merging the outer/inner partition in
2492
     * merge_matching_partitions(); ignore the merged partition.
2493
     */
2494
0
    if (outer_index == -1 && inner_index == -1)
2495
0
      continue;
2496
2497
0
    *outer_parts = lappend(*outer_parts, outer_index >= 0 ?
2498
0
                 outer_rel->part_rels[outer_index] : NULL);
2499
0
    *inner_parts = lappend(*inner_parts, inner_index >= 0 ?
2500
0
                 inner_rel->part_rels[inner_index] : NULL);
2501
0
  }
2502
2503
0
  pfree(outer_indexes);
2504
0
  pfree(inner_indexes);
2505
0
}
2506
2507
/*
2508
 * build_merged_partition_bounds
2509
 *    Create a PartitionBoundInfo struct from merged partition bounds
2510
 */
2511
static PartitionBoundInfo
2512
build_merged_partition_bounds(char strategy, List *merged_datums,
2513
                List *merged_kinds, List *merged_indexes,
2514
                int null_index, int default_index)
2515
0
{
2516
0
  PartitionBoundInfo merged_bounds;
2517
0
  int     ndatums = list_length(merged_datums);
2518
0
  int     pos;
2519
0
  ListCell   *lc;
2520
2521
0
  merged_bounds = palloc_object(PartitionBoundInfoData);
2522
0
  merged_bounds->strategy = strategy;
2523
0
  merged_bounds->ndatums = ndatums;
2524
2525
0
  merged_bounds->datums = palloc_array(Datum *, ndatums);
2526
0
  pos = 0;
2527
0
  foreach(lc, merged_datums)
2528
0
    merged_bounds->datums[pos++] = (Datum *) lfirst(lc);
2529
2530
0
  if (strategy == PARTITION_STRATEGY_RANGE)
2531
0
  {
2532
0
    Assert(list_length(merged_kinds) == ndatums);
2533
0
    merged_bounds->kind = palloc_array(PartitionRangeDatumKind *, ndatums);
2534
0
    pos = 0;
2535
0
    foreach(lc, merged_kinds)
2536
0
      merged_bounds->kind[pos++] = (PartitionRangeDatumKind *) lfirst(lc);
2537
2538
    /* There are ndatums+1 indexes in the case of range partitioning. */
2539
0
    merged_indexes = lappend_int(merged_indexes, -1);
2540
0
    ndatums++;
2541
0
  }
2542
0
  else
2543
0
  {
2544
0
    Assert(strategy == PARTITION_STRATEGY_LIST);
2545
0
    Assert(merged_kinds == NIL);
2546
0
    merged_bounds->kind = NULL;
2547
0
  }
2548
2549
  /* interleaved_parts is always NULL for join relations. */
2550
0
  merged_bounds->interleaved_parts = NULL;
2551
2552
0
  Assert(list_length(merged_indexes) == ndatums);
2553
0
  merged_bounds->nindexes = ndatums;
2554
0
  merged_bounds->indexes = palloc_array(int, ndatums);
2555
0
  pos = 0;
2556
0
  foreach(lc, merged_indexes)
2557
0
    merged_bounds->indexes[pos++] = lfirst_int(lc);
2558
2559
0
  merged_bounds->null_index = null_index;
2560
0
  merged_bounds->default_index = default_index;
2561
2562
0
  return merged_bounds;
2563
0
}
2564
2565
/*
2566
 * get_range_partition
2567
 *    Get the next non-dummy partition of a range-partitioned relation,
2568
 *    returning the index of that partition
2569
 *
2570
 * *lb and *ub are set to the lower and upper bounds of that partition
2571
 * respectively, and *lb_pos is advanced to the next lower bound, if any.
2572
 */
2573
static int
2574
get_range_partition(RelOptInfo *rel,
2575
          PartitionBoundInfo bi,
2576
          int *lb_pos,
2577
          PartitionRangeBound *lb,
2578
          PartitionRangeBound *ub)
2579
0
{
2580
0
  int     part_index;
2581
2582
0
  Assert(bi->strategy == PARTITION_STRATEGY_RANGE);
2583
2584
0
  do
2585
0
  {
2586
0
    part_index = get_range_partition_internal(bi, lb_pos, lb, ub);
2587
0
    if (part_index == -1)
2588
0
      return -1;
2589
0
  } while (is_dummy_partition(rel, part_index));
2590
2591
0
  return part_index;
2592
0
}
2593
2594
static int
2595
get_range_partition_internal(PartitionBoundInfo bi,
2596
               int *lb_pos,
2597
               PartitionRangeBound *lb,
2598
               PartitionRangeBound *ub)
2599
0
{
2600
  /* Return the index as -1 if we've exhausted all lower bounds. */
2601
0
  if (*lb_pos >= bi->ndatums)
2602
0
    return -1;
2603
2604
  /* A lower bound should have at least one more bound after it. */
2605
0
  Assert(*lb_pos + 1 < bi->ndatums);
2606
2607
  /* Set the lower bound. */
2608
0
  lb->index = bi->indexes[*lb_pos];
2609
0
  lb->datums = bi->datums[*lb_pos];
2610
0
  lb->kind = bi->kind[*lb_pos];
2611
0
  lb->lower = true;
2612
  /* Set the upper bound. */
2613
0
  ub->index = bi->indexes[*lb_pos + 1];
2614
0
  ub->datums = bi->datums[*lb_pos + 1];
2615
0
  ub->kind = bi->kind[*lb_pos + 1];
2616
0
  ub->lower = false;
2617
2618
  /* The index assigned to an upper bound should be valid. */
2619
0
  Assert(ub->index >= 0);
2620
2621
  /*
2622
   * Advance the position to the next lower bound.  If there are no bounds
2623
   * left beyond the upper bound, we have reached the last lower bound.
2624
   */
2625
0
  if (*lb_pos + 2 >= bi->ndatums)
2626
0
    *lb_pos = bi->ndatums;
2627
0
  else
2628
0
  {
2629
    /*
2630
     * If the index assigned to the bound next to the upper bound isn't
2631
     * valid, that is the next lower bound; else, the upper bound is also
2632
     * the lower bound of the next range partition.
2633
     */
2634
0
    if (bi->indexes[*lb_pos + 2] < 0)
2635
0
      *lb_pos = *lb_pos + 2;
2636
0
    else
2637
0
      *lb_pos = *lb_pos + 1;
2638
0
  }
2639
2640
0
  return ub->index;
2641
0
}
2642
2643
/*
2644
 * compare_range_partitions
2645
 *    Compare the bounds of two range partitions, and return true if the
2646
 *    two partitions overlap, false otherwise
2647
 *
2648
 * *lb_cmpval is set to -1, 0, or 1 if the outer partition's lower bound is
2649
 * lower than, equal to, or higher than the inner partition's lower bound
2650
 * respectively.  Likewise, *ub_cmpval is set to -1, 0, or 1 if the outer
2651
 * partition's upper bound is lower than, equal to, or higher than the inner
2652
 * partition's upper bound respectively.
2653
 */
2654
static bool
2655
compare_range_partitions(int partnatts, FmgrInfo *partsupfuncs,
2656
             Oid *partcollations,
2657
             PartitionRangeBound *outer_lb,
2658
             PartitionRangeBound *outer_ub,
2659
             PartitionRangeBound *inner_lb,
2660
             PartitionRangeBound *inner_ub,
2661
             int *lb_cmpval, int *ub_cmpval)
2662
0
{
2663
  /*
2664
   * Check if the outer partition's upper bound is lower than the inner
2665
   * partition's lower bound; if so the partitions aren't overlapping.
2666
   */
2667
0
  if (compare_range_bounds(partnatts, partsupfuncs, partcollations,
2668
0
               outer_ub, inner_lb) < 0)
2669
0
  {
2670
0
    *lb_cmpval = -1;
2671
0
    *ub_cmpval = -1;
2672
0
    return false;
2673
0
  }
2674
2675
  /*
2676
   * Check if the outer partition's lower bound is higher than the inner
2677
   * partition's upper bound; if so the partitions aren't overlapping.
2678
   */
2679
0
  if (compare_range_bounds(partnatts, partsupfuncs, partcollations,
2680
0
               outer_lb, inner_ub) > 0)
2681
0
  {
2682
0
    *lb_cmpval = 1;
2683
0
    *ub_cmpval = 1;
2684
0
    return false;
2685
0
  }
2686
2687
  /* All other cases indicate overlapping partitions. */
2688
0
  *lb_cmpval = compare_range_bounds(partnatts, partsupfuncs, partcollations,
2689
0
                    outer_lb, inner_lb);
2690
0
  *ub_cmpval = compare_range_bounds(partnatts, partsupfuncs, partcollations,
2691
0
                    outer_ub, inner_ub);
2692
0
  return true;
2693
0
}
2694
2695
/*
2696
 * get_merged_range_bounds
2697
 *    Given the bounds of range partitions to be joined, determine the bounds
2698
 *    of a merged partition produced from the range partitions
2699
 *
2700
 * *merged_lb and *merged_ub are set to the lower and upper bounds of the
2701
 * merged partition.
2702
 */
2703
static void
2704
get_merged_range_bounds(int partnatts, FmgrInfo *partsupfuncs,
2705
            Oid *partcollations, JoinType jointype,
2706
            PartitionRangeBound *outer_lb,
2707
            PartitionRangeBound *outer_ub,
2708
            PartitionRangeBound *inner_lb,
2709
            PartitionRangeBound *inner_ub,
2710
            int lb_cmpval, int ub_cmpval,
2711
            PartitionRangeBound *merged_lb,
2712
            PartitionRangeBound *merged_ub)
2713
0
{
2714
0
  Assert(compare_range_bounds(partnatts, partsupfuncs, partcollations,
2715
0
                outer_lb, inner_lb) == lb_cmpval);
2716
0
  Assert(compare_range_bounds(partnatts, partsupfuncs, partcollations,
2717
0
                outer_ub, inner_ub) == ub_cmpval);
2718
2719
0
  switch (jointype)
2720
0
  {
2721
0
    case JOIN_INNER:
2722
0
    case JOIN_SEMI:
2723
2724
      /*
2725
       * An INNER/SEMI join will have the rows that fit both sides, so
2726
       * the lower bound of the merged partition will be the higher of
2727
       * the two lower bounds, and the upper bound of the merged
2728
       * partition will be the lower of the two upper bounds.
2729
       */
2730
0
      *merged_lb = (lb_cmpval > 0) ? *outer_lb : *inner_lb;
2731
0
      *merged_ub = (ub_cmpval < 0) ? *outer_ub : *inner_ub;
2732
0
      break;
2733
2734
0
    case JOIN_LEFT:
2735
0
    case JOIN_ANTI:
2736
2737
      /*
2738
       * A LEFT/ANTI join will have all the rows from the outer side, so
2739
       * the bounds of the merged partition will be the same as the
2740
       * outer bounds.
2741
       */
2742
0
      *merged_lb = *outer_lb;
2743
0
      *merged_ub = *outer_ub;
2744
0
      break;
2745
2746
0
    case JOIN_FULL:
2747
2748
      /*
2749
       * A FULL join will have all the rows from both sides, so the
2750
       * lower bound of the merged partition will be the lower of the
2751
       * two lower bounds, and the upper bound of the merged partition
2752
       * will be the higher of the two upper bounds.
2753
       */
2754
0
      *merged_lb = (lb_cmpval < 0) ? *outer_lb : *inner_lb;
2755
0
      *merged_ub = (ub_cmpval > 0) ? *outer_ub : *inner_ub;
2756
0
      break;
2757
2758
0
    default:
2759
0
      elog(ERROR, "unrecognized join type: %d", (int) jointype);
2760
0
  }
2761
0
}
2762
2763
/*
2764
 * add_merged_range_bounds
2765
 *    Add the bounds of a merged partition to the lists of range bounds
2766
 */
2767
static void
2768
add_merged_range_bounds(int partnatts, FmgrInfo *partsupfuncs,
2769
            Oid *partcollations,
2770
            PartitionRangeBound *merged_lb,
2771
            PartitionRangeBound *merged_ub,
2772
            int merged_index,
2773
            List **merged_datums,
2774
            List **merged_kinds,
2775
            List **merged_indexes)
2776
0
{
2777
0
  int     cmpval;
2778
2779
0
  if (!*merged_datums)
2780
0
  {
2781
    /* First merged partition */
2782
0
    Assert(!*merged_kinds);
2783
0
    Assert(!*merged_indexes);
2784
0
    cmpval = 1;
2785
0
  }
2786
0
  else
2787
0
  {
2788
0
    PartitionRangeBound prev_ub;
2789
2790
0
    Assert(*merged_datums);
2791
0
    Assert(*merged_kinds);
2792
0
    Assert(*merged_indexes);
2793
2794
    /* Get the last upper bound. */
2795
0
    prev_ub.index = llast_int(*merged_indexes);
2796
0
    prev_ub.datums = (Datum *) llast(*merged_datums);
2797
0
    prev_ub.kind = (PartitionRangeDatumKind *) llast(*merged_kinds);
2798
0
    prev_ub.lower = false;
2799
2800
    /*
2801
     * We pass lower1 = false to partition_rbound_cmp() to prevent it from
2802
     * considering the last upper bound to be smaller than the lower bound
2803
     * of the merged partition when the values of the two range bounds
2804
     * compare equal.
2805
     */
2806
0
    cmpval = partition_rbound_cmp(partnatts, partsupfuncs, partcollations,
2807
0
                    merged_lb->datums, merged_lb->kind,
2808
0
                    false, &prev_ub);
2809
0
    Assert(cmpval >= 0);
2810
0
  }
2811
2812
  /*
2813
   * If the lower bound is higher than the last upper bound, add the lower
2814
   * bound with the index as -1 indicating that that is a lower bound; else,
2815
   * the last upper bound will be reused as the lower bound of the merged
2816
   * partition, so skip this.
2817
   */
2818
0
  if (cmpval > 0)
2819
0
  {
2820
0
    *merged_datums = lappend(*merged_datums, merged_lb->datums);
2821
0
    *merged_kinds = lappend(*merged_kinds, merged_lb->kind);
2822
0
    *merged_indexes = lappend_int(*merged_indexes, -1);
2823
0
  }
2824
2825
  /* Add the upper bound and index of the merged partition. */
2826
0
  *merged_datums = lappend(*merged_datums, merged_ub->datums);
2827
0
  *merged_kinds = lappend(*merged_kinds, merged_ub->kind);
2828
0
  *merged_indexes = lappend_int(*merged_indexes, merged_index);
2829
0
}
2830
2831
/*
2832
 * partitions_are_ordered
2833
 *    Determine whether the partitions described by 'boundinfo' are ordered,
2834
 *    that is partitions appearing earlier in the PartitionDesc sequence
2835
 *    contain partition keys strictly less than those appearing later.
2836
 *    Also, if NULL values are possible, they must come in the last
2837
 *    partition defined in the PartitionDesc.  'live_parts' marks which
2838
 *    partitions we should include when checking the ordering.  Partitions
2839
 *    that do not appear in 'live_parts' are ignored.
2840
 *
2841
 * If out of order, or there is insufficient info to know the order,
2842
 * then we return false.
2843
 */
2844
bool
2845
partitions_are_ordered(PartitionBoundInfo boundinfo, Bitmapset *live_parts)
2846
0
{
2847
0
  Assert(boundinfo != NULL);
2848
2849
0
  switch (boundinfo->strategy)
2850
0
  {
2851
0
    case PARTITION_STRATEGY_RANGE:
2852
2853
      /*
2854
       * RANGE-type partitioning guarantees that the partitions can be
2855
       * scanned in the order that they're defined in the PartitionDesc
2856
       * to provide sequential, non-overlapping ranges of tuples.
2857
       * However, if a DEFAULT partition exists and it's contained
2858
       * within live_parts, then the partitions are not ordered.
2859
       */
2860
0
      if (!partition_bound_has_default(boundinfo) ||
2861
0
        !bms_is_member(boundinfo->default_index, live_parts))
2862
0
        return true;
2863
0
      break;
2864
2865
0
    case PARTITION_STRATEGY_LIST:
2866
2867
      /*
2868
       * LIST partitioned are ordered providing none of live_parts
2869
       * overlap with the partitioned table's interleaved partitions.
2870
       */
2871
0
      if (!bms_overlap(live_parts, boundinfo->interleaved_parts))
2872
0
        return true;
2873
2874
0
      break;
2875
0
    case PARTITION_STRATEGY_HASH:
2876
0
      break;
2877
0
  }
2878
2879
0
  return false;
2880
0
}
2881
2882
/*
2883
 * check_new_partition_bound
2884
 *
2885
 * Checks if the new partition's bound overlaps any of the existing partitions
2886
 * of parent.  Also performs additional checks as necessary per strategy.
2887
 */
2888
void
2889
check_new_partition_bound(char *relname, Relation parent,
2890
              PartitionBoundSpec *spec, ParseState *pstate)
2891
0
{
2892
0
  PartitionKey key = RelationGetPartitionKey(parent);
2893
0
  PartitionDesc partdesc = RelationGetPartitionDesc(parent, false);
2894
0
  PartitionBoundInfo boundinfo = partdesc->boundinfo;
2895
0
  int     with = -1;
2896
0
  bool    overlap = false;
2897
0
  int     overlap_location = -1;
2898
2899
0
  if (spec->is_default)
2900
0
  {
2901
    /*
2902
     * The default partition bound never conflicts with any other
2903
     * partition's; if that's what we're attaching, the only possible
2904
     * problem is that one already exists, so check for that and we're
2905
     * done.
2906
     */
2907
0
    if (boundinfo == NULL || !partition_bound_has_default(boundinfo))
2908
0
      return;
2909
2910
    /* Default partition already exists, error out. */
2911
0
    ereport(ERROR,
2912
0
        (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2913
0
         errmsg("partition \"%s\" conflicts with existing default partition \"%s\"",
2914
0
            relname, get_rel_name(partdesc->oids[boundinfo->default_index])),
2915
0
         parser_errposition(pstate, spec->location)));
2916
0
  }
2917
2918
0
  switch (key->strategy)
2919
0
  {
2920
0
    case PARTITION_STRATEGY_HASH:
2921
0
      {
2922
0
        Assert(spec->strategy == PARTITION_STRATEGY_HASH);
2923
0
        Assert(spec->remainder >= 0 && spec->remainder < spec->modulus);
2924
2925
0
        if (partdesc->nparts > 0)
2926
0
        {
2927
0
          int     greatest_modulus;
2928
0
          int     remainder;
2929
0
          int     offset;
2930
2931
          /*
2932
           * Check rule that every modulus must be a factor of the
2933
           * next larger modulus.  (For example, if you have a bunch
2934
           * of partitions that all have modulus 5, you can add a
2935
           * new partition with modulus 10 or a new partition with
2936
           * modulus 15, but you cannot add both a partition with
2937
           * modulus 10 and a partition with modulus 15, because 10
2938
           * is not a factor of 15.)  We need only check the next
2939
           * smaller and next larger existing moduli, relying on
2940
           * previous enforcement of this rule to be sure that the
2941
           * rest are in line.
2942
           */
2943
2944
          /*
2945
           * Get the greatest (modulus, remainder) pair contained in
2946
           * boundinfo->datums that is less than or equal to the
2947
           * (spec->modulus, spec->remainder) pair.
2948
           */
2949
0
          offset = partition_hash_bsearch(boundinfo,
2950
0
                          spec->modulus,
2951
0
                          spec->remainder);
2952
0
          if (offset < 0)
2953
0
          {
2954
0
            int     next_modulus;
2955
2956
            /*
2957
             * All existing moduli are greater or equal, so the
2958
             * new one must be a factor of the smallest one, which
2959
             * is first in the boundinfo.
2960
             */
2961
0
            next_modulus = DatumGetInt32(boundinfo->datums[0][0]);
2962
0
            if (next_modulus % spec->modulus != 0)
2963
0
              ereport(ERROR,
2964
0
                  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2965
0
                   errmsg("every hash partition modulus must be a factor of the next larger modulus"),
2966
0
                   errdetail("The new modulus %d is not a factor of %d, the modulus of existing partition \"%s\".",
2967
0
                         spec->modulus, next_modulus,
2968
0
                         get_rel_name(partdesc->oids[0]))));
2969
0
          }
2970
0
          else
2971
0
          {
2972
0
            int     prev_modulus;
2973
2974
            /*
2975
             * We found the largest (modulus, remainder) pair less
2976
             * than or equal to the new one.  That modulus must be
2977
             * a divisor of, or equal to, the new modulus.
2978
             */
2979
0
            prev_modulus = DatumGetInt32(boundinfo->datums[offset][0]);
2980
2981
0
            if (spec->modulus % prev_modulus != 0)
2982
0
              ereport(ERROR,
2983
0
                  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2984
0
                   errmsg("every hash partition modulus must be a factor of the next larger modulus"),
2985
0
                   errdetail("The new modulus %d is not divisible by %d, the modulus of existing partition \"%s\".",
2986
0
                         spec->modulus,
2987
0
                         prev_modulus,
2988
0
                         get_rel_name(partdesc->oids[offset]))));
2989
2990
0
            if (offset + 1 < boundinfo->ndatums)
2991
0
            {
2992
0
              int     next_modulus;
2993
2994
              /*
2995
               * Look at the next higher (modulus, remainder)
2996
               * pair.  That could have the same modulus and a
2997
               * larger remainder than the new pair, in which
2998
               * case we're good.  If it has a larger modulus,
2999
               * the new modulus must divide that one.
3000
               */
3001
0
              next_modulus = DatumGetInt32(boundinfo->datums[offset + 1][0]);
3002
3003
0
              if (next_modulus % spec->modulus != 0)
3004
0
                ereport(ERROR,
3005
0
                    (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3006
0
                     errmsg("every hash partition modulus must be a factor of the next larger modulus"),
3007
0
                     errdetail("The new modulus %d is not a factor of %d, the modulus of existing partition \"%s\".",
3008
0
                           spec->modulus, next_modulus,
3009
0
                           get_rel_name(partdesc->oids[offset + 1]))));
3010
0
            }
3011
0
          }
3012
3013
0
          greatest_modulus = boundinfo->nindexes;
3014
0
          remainder = spec->remainder;
3015
3016
          /*
3017
           * Normally, the lowest remainder that could conflict with
3018
           * the new partition is equal to the remainder specified
3019
           * for the new partition, but when the new partition has a
3020
           * modulus higher than any used so far, we need to adjust.
3021
           */
3022
0
          if (remainder >= greatest_modulus)
3023
0
            remainder = remainder % greatest_modulus;
3024
3025
          /* Check every potentially-conflicting remainder. */
3026
0
          do
3027
0
          {
3028
0
            if (boundinfo->indexes[remainder] != -1)
3029
0
            {
3030
0
              overlap = true;
3031
0
              overlap_location = spec->location;
3032
0
              with = boundinfo->indexes[remainder];
3033
0
              break;
3034
0
            }
3035
0
            remainder += spec->modulus;
3036
0
          } while (remainder < greatest_modulus);
3037
0
        }
3038
3039
0
        break;
3040
0
      }
3041
3042
0
    case PARTITION_STRATEGY_LIST:
3043
0
      {
3044
0
        Assert(spec->strategy == PARTITION_STRATEGY_LIST);
3045
3046
0
        if (partdesc->nparts > 0)
3047
0
        {
3048
0
          ListCell   *cell;
3049
3050
0
          Assert(boundinfo &&
3051
0
               boundinfo->strategy == PARTITION_STRATEGY_LIST &&
3052
0
               (boundinfo->ndatums > 0 ||
3053
0
              partition_bound_accepts_nulls(boundinfo) ||
3054
0
              partition_bound_has_default(boundinfo)));
3055
3056
0
          foreach(cell, spec->listdatums)
3057
0
          {
3058
0
            Const    *val = lfirst_node(Const, cell);
3059
3060
0
            overlap_location = val->location;
3061
0
            if (!val->constisnull)
3062
0
            {
3063
0
              int     offset;
3064
0
              bool    equal;
3065
3066
0
              offset = partition_list_bsearch(&key->partsupfunc[0],
3067
0
                              key->partcollation,
3068
0
                              boundinfo,
3069
0
                              val->constvalue,
3070
0
                              &equal);
3071
0
              if (offset >= 0 && equal)
3072
0
              {
3073
0
                overlap = true;
3074
0
                with = boundinfo->indexes[offset];
3075
0
                break;
3076
0
              }
3077
0
            }
3078
0
            else if (partition_bound_accepts_nulls(boundinfo))
3079
0
            {
3080
0
              overlap = true;
3081
0
              with = boundinfo->null_index;
3082
0
              break;
3083
0
            }
3084
0
          }
3085
0
        }
3086
3087
0
        break;
3088
0
      }
3089
3090
0
    case PARTITION_STRATEGY_RANGE:
3091
0
      {
3092
0
        PartitionRangeBound *lower,
3093
0
               *upper;
3094
0
        int     cmpval;
3095
3096
0
        Assert(spec->strategy == PARTITION_STRATEGY_RANGE);
3097
0
        lower = make_one_partition_rbound(key, -1, spec->lowerdatums, true);
3098
0
        upper = make_one_partition_rbound(key, -1, spec->upperdatums, false);
3099
3100
        /*
3101
         * First check if the resulting range would be empty with
3102
         * specified lower and upper bounds.  partition_rbound_cmp
3103
         * cannot return zero here, since the lower-bound flags are
3104
         * different.
3105
         */
3106
0
        cmpval = partition_rbound_cmp(key->partnatts,
3107
0
                        key->partsupfunc,
3108
0
                        key->partcollation,
3109
0
                        lower->datums, lower->kind,
3110
0
                        true, upper);
3111
0
        Assert(cmpval != 0);
3112
0
        if (cmpval > 0)
3113
0
        {
3114
          /* Point to problematic key in the lower datums list. */
3115
0
          PartitionRangeDatum *datum = list_nth(spec->lowerdatums,
3116
0
                              cmpval - 1);
3117
3118
0
          ereport(ERROR,
3119
0
              (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3120
0
               errmsg("empty range bound specified for partition \"%s\"",
3121
0
                  relname),
3122
0
               errdetail("Specified lower bound %s is greater than or equal to upper bound %s.",
3123
0
                     get_range_partbound_string(spec->lowerdatums),
3124
0
                     get_range_partbound_string(spec->upperdatums)),
3125
0
               parser_errposition(pstate, datum->location)));
3126
0
        }
3127
3128
0
        if (partdesc->nparts > 0)
3129
0
        {
3130
0
          int     offset;
3131
3132
0
          Assert(boundinfo &&
3133
0
               boundinfo->strategy == PARTITION_STRATEGY_RANGE &&
3134
0
               (boundinfo->ndatums > 0 ||
3135
0
              partition_bound_has_default(boundinfo)));
3136
3137
          /*
3138
           * Test whether the new lower bound (which is treated
3139
           * inclusively as part of the new partition) lies inside
3140
           * an existing partition, or in a gap.
3141
           *
3142
           * If it's inside an existing partition, the bound at
3143
           * offset + 1 will be the upper bound of that partition,
3144
           * and its index will be >= 0.
3145
           *
3146
           * If it's in a gap, the bound at offset + 1 will be the
3147
           * lower bound of the next partition, and its index will
3148
           * be -1. This is also true if there is no next partition,
3149
           * since the index array is initialised with an extra -1
3150
           * at the end.
3151
           */
3152
0
          offset = partition_range_bsearch(key->partnatts,
3153
0
                           key->partsupfunc,
3154
0
                           key->partcollation,
3155
0
                           boundinfo, lower,
3156
0
                           &cmpval);
3157
3158
0
          if (boundinfo->indexes[offset + 1] < 0)
3159
0
          {
3160
            /*
3161
             * Check that the new partition will fit in the gap.
3162
             * For it to fit, the new upper bound must be less
3163
             * than or equal to the lower bound of the next
3164
             * partition, if there is one.
3165
             */
3166
0
            if (offset + 1 < boundinfo->ndatums)
3167
0
            {
3168
0
              Datum    *datums;
3169
0
              PartitionRangeDatumKind *kind;
3170
0
              bool    is_lower;
3171
3172
0
              datums = boundinfo->datums[offset + 1];
3173
0
              kind = boundinfo->kind[offset + 1];
3174
0
              is_lower = (boundinfo->indexes[offset + 1] == -1);
3175
3176
0
              cmpval = partition_rbound_cmp(key->partnatts,
3177
0
                              key->partsupfunc,
3178
0
                              key->partcollation,
3179
0
                              datums, kind,
3180
0
                              is_lower, upper);
3181
0
              if (cmpval < 0)
3182
0
              {
3183
                /*
3184
                 * Point to problematic key in the upper
3185
                 * datums list.
3186
                 */
3187
0
                PartitionRangeDatum *datum =
3188
0
                  list_nth(spec->upperdatums, abs(cmpval) - 1);
3189
3190
                /*
3191
                 * The new partition overlaps with the
3192
                 * existing partition between offset + 1 and
3193
                 * offset + 2.
3194
                 */
3195
0
                overlap = true;
3196
0
                overlap_location = datum->location;
3197
0
                with = boundinfo->indexes[offset + 2];
3198
0
              }
3199
0
            }
3200
0
          }
3201
0
          else
3202
0
          {
3203
            /*
3204
             * The new partition overlaps with the existing
3205
             * partition between offset and offset + 1.
3206
             */
3207
0
            PartitionRangeDatum *datum;
3208
3209
            /*
3210
             * Point to problematic key in the lower datums list;
3211
             * if we have equality, point to the first one.
3212
             */
3213
0
            datum = cmpval == 0 ? linitial(spec->lowerdatums) :
3214
0
              list_nth(spec->lowerdatums, abs(cmpval) - 1);
3215
0
            overlap = true;
3216
0
            overlap_location = datum->location;
3217
0
            with = boundinfo->indexes[offset + 1];
3218
0
          }
3219
0
        }
3220
3221
0
        break;
3222
0
      }
3223
0
  }
3224
3225
0
  if (overlap)
3226
0
  {
3227
0
    Assert(with >= 0);
3228
0
    ereport(ERROR,
3229
0
        (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3230
0
         errmsg("partition \"%s\" would overlap partition \"%s\"",
3231
0
            relname, get_rel_name(partdesc->oids[with])),
3232
0
         parser_errposition(pstate, overlap_location)));
3233
0
  }
3234
0
}
3235
3236
/*
3237
 * check_default_partition_contents
3238
 *
3239
 * This function checks if there exists a row in the default partition that
3240
 * would properly belong to the new partition being added.  If it finds one,
3241
 * it throws an error.
3242
 */
3243
void
3244
check_default_partition_contents(Relation parent, Relation default_rel,
3245
                 PartitionBoundSpec *new_spec)
3246
0
{
3247
0
  List     *new_part_constraints;
3248
0
  List     *def_part_constraints;
3249
0
  List     *all_parts;
3250
0
  ListCell   *lc;
3251
3252
0
  new_part_constraints = (new_spec->strategy == PARTITION_STRATEGY_LIST)
3253
0
    ? get_qual_for_list(parent, new_spec)
3254
0
    : get_qual_for_range(parent, new_spec, false);
3255
0
  def_part_constraints =
3256
0
    get_proposed_default_constraint(new_part_constraints);
3257
3258
  /*
3259
   * Map the Vars in the constraint expression from parent's attnos to
3260
   * default_rel's.
3261
   */
3262
0
  def_part_constraints =
3263
0
    map_partition_varattnos(def_part_constraints, 1, default_rel,
3264
0
                parent);
3265
3266
  /*
3267
   * If the existing constraints on the default partition imply that it will
3268
   * not contain any row that would belong to the new partition, we can
3269
   * avoid scanning the default partition.
3270
   */
3271
0
  if (PartConstraintImpliedByRelConstraint(default_rel, def_part_constraints))
3272
0
  {
3273
0
    ereport(DEBUG1,
3274
0
        (errmsg_internal("updated partition constraint for default partition \"%s\" is implied by existing constraints",
3275
0
                 RelationGetRelationName(default_rel))));
3276
0
    return;
3277
0
  }
3278
3279
  /*
3280
   * Scan the default partition and its subpartitions, and check for rows
3281
   * that do not satisfy the revised partition constraints.
3282
   */
3283
0
  if (default_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
3284
0
    all_parts = find_all_inheritors(RelationGetRelid(default_rel),
3285
0
                    AccessExclusiveLock, NULL);
3286
0
  else
3287
0
    all_parts = list_make1_oid(RelationGetRelid(default_rel));
3288
3289
0
  foreach(lc, all_parts)
3290
0
  {
3291
0
    Oid     part_relid = lfirst_oid(lc);
3292
0
    Relation  part_rel;
3293
0
    Expr     *partition_constraint;
3294
0
    EState     *estate;
3295
0
    ExprState  *partqualstate = NULL;
3296
0
    Snapshot  snapshot;
3297
0
    ExprContext *econtext;
3298
0
    TableScanDesc scan;
3299
0
    MemoryContext oldCxt;
3300
0
    TupleTableSlot *tupslot;
3301
3302
    /* Lock already taken above. */
3303
0
    if (part_relid != RelationGetRelid(default_rel))
3304
0
    {
3305
0
      part_rel = table_open(part_relid, NoLock);
3306
3307
      /*
3308
       * Map the Vars in the constraint expression from default_rel's
3309
       * the sub-partition's.
3310
       */
3311
0
      partition_constraint = make_ands_explicit(def_part_constraints);
3312
0
      partition_constraint = (Expr *)
3313
0
        map_partition_varattnos((List *) partition_constraint, 1,
3314
0
                    part_rel, default_rel);
3315
3316
      /*
3317
       * If the partition constraints on default partition child imply
3318
       * that it will not contain any row that would belong to the new
3319
       * partition, we can avoid scanning the child table.
3320
       */
3321
0
      if (PartConstraintImpliedByRelConstraint(part_rel,
3322
0
                           def_part_constraints))
3323
0
      {
3324
0
        ereport(DEBUG1,
3325
0
            (errmsg_internal("updated partition constraint for default partition \"%s\" is implied by existing constraints",
3326
0
                     RelationGetRelationName(part_rel))));
3327
3328
0
        table_close(part_rel, NoLock);
3329
0
        continue;
3330
0
      }
3331
0
    }
3332
0
    else
3333
0
    {
3334
0
      part_rel = default_rel;
3335
0
      partition_constraint = make_ands_explicit(def_part_constraints);
3336
0
    }
3337
3338
    /*
3339
     * Only RELKIND_RELATION relations (i.e. leaf partitions) need to be
3340
     * scanned.
3341
     */
3342
0
    if (part_rel->rd_rel->relkind != RELKIND_RELATION)
3343
0
    {
3344
0
      if (part_rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
3345
0
        ereport(WARNING,
3346
0
            (errcode(ERRCODE_CHECK_VIOLATION),
3347
0
             errmsg("skipped scanning foreign table \"%s\" which is a partition of default partition \"%s\"",
3348
0
                RelationGetRelationName(part_rel),
3349
0
                RelationGetRelationName(default_rel))));
3350
3351
0
      if (RelationGetRelid(default_rel) != RelationGetRelid(part_rel))
3352
0
        table_close(part_rel, NoLock);
3353
3354
0
      continue;
3355
0
    }
3356
3357
0
    estate = CreateExecutorState();
3358
3359
    /* Build expression execution states for partition check quals */
3360
0
    partqualstate = ExecPrepareExpr(partition_constraint, estate);
3361
3362
0
    econtext = GetPerTupleExprContext(estate);
3363
0
    snapshot = RegisterSnapshot(GetLatestSnapshot());
3364
0
    tupslot = table_slot_create(part_rel, &estate->es_tupleTable);
3365
0
    scan = table_beginscan(part_rel, snapshot, 0, NULL,
3366
0
                 SO_NONE);
3367
3368
    /*
3369
     * Switch to per-tuple memory context and reset it for each tuple
3370
     * produced, so we don't leak memory.
3371
     */
3372
0
    oldCxt = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
3373
3374
0
    while (table_scan_getnextslot(scan, ForwardScanDirection, tupslot))
3375
0
    {
3376
0
      econtext->ecxt_scantuple = tupslot;
3377
3378
0
      if (!ExecCheck(partqualstate, econtext))
3379
0
        ereport(ERROR,
3380
0
            (errcode(ERRCODE_CHECK_VIOLATION),
3381
0
             errmsg("updated partition constraint for default partition \"%s\" would be violated by some row",
3382
0
                RelationGetRelationName(default_rel)),
3383
0
             errtable(default_rel)));
3384
3385
0
      ResetExprContext(econtext);
3386
0
      CHECK_FOR_INTERRUPTS();
3387
0
    }
3388
3389
0
    MemoryContextSwitchTo(oldCxt);
3390
0
    table_endscan(scan);
3391
0
    UnregisterSnapshot(snapshot);
3392
0
    ExecDropSingleTupleTableSlot(tupslot);
3393
0
    FreeExecutorState(estate);
3394
3395
0
    if (RelationGetRelid(default_rel) != RelationGetRelid(part_rel))
3396
0
      table_close(part_rel, NoLock);  /* keep the lock until commit */
3397
0
  }
3398
0
}
3399
3400
/*
3401
 * get_hash_partition_greatest_modulus
3402
 *
3403
 * Returns the greatest modulus of the hash partition bound.
3404
 * This is no longer used in the core code, but we keep it around
3405
 * in case external modules are using it.
3406
 */
3407
int
3408
get_hash_partition_greatest_modulus(PartitionBoundInfo bound)
3409
0
{
3410
0
  Assert(bound && bound->strategy == PARTITION_STRATEGY_HASH);
3411
0
  return bound->nindexes;
3412
0
}
3413
3414
/*
3415
 * make_one_partition_rbound
3416
 *
3417
 * Return a PartitionRangeBound given a list of PartitionRangeDatum elements
3418
 * and a flag telling whether the bound is lower or not.  Made into a function
3419
 * because there are multiple sites that want to use this facility.
3420
 */
3421
static PartitionRangeBound *
3422
make_one_partition_rbound(PartitionKey key, int index, List *datums, bool lower)
3423
0
{
3424
0
  PartitionRangeBound *bound;
3425
0
  ListCell   *lc;
3426
0
  int     i;
3427
3428
0
  Assert(datums != NIL);
3429
3430
0
  bound = palloc0_object(PartitionRangeBound);
3431
0
  bound->index = index;
3432
0
  bound->datums = palloc0_array(Datum, key->partnatts);
3433
0
  bound->kind = palloc0_array(PartitionRangeDatumKind, key->partnatts);
3434
0
  bound->lower = lower;
3435
3436
0
  i = 0;
3437
0
  foreach(lc, datums)
3438
0
  {
3439
0
    PartitionRangeDatum *datum = lfirst_node(PartitionRangeDatum, lc);
3440
3441
    /* What's contained in this range datum? */
3442
0
    bound->kind[i] = datum->kind;
3443
3444
0
    if (datum->kind == PARTITION_RANGE_DATUM_VALUE)
3445
0
    {
3446
0
      Const    *val = castNode(Const, datum->value);
3447
3448
0
      if (val->constisnull)
3449
0
        elog(ERROR, "invalid range bound datum");
3450
0
      bound->datums[i] = val->constvalue;
3451
0
    }
3452
3453
0
    i++;
3454
0
  }
3455
3456
0
  return bound;
3457
0
}
3458
3459
/*
3460
 * partition_rbound_cmp
3461
 *
3462
 * For two range bounds this decides whether the 1st one (specified by
3463
 * datums1, kind1, and lower1) is <, =, or > the bound specified in *b2.
3464
 *
3465
 * 0 is returned if they are equal, otherwise a non-zero integer whose sign
3466
 * indicates the ordering, and whose absolute value gives the 1-based
3467
 * partition key number of the first mismatching column.
3468
 *
3469
 * partnatts, partsupfunc and partcollation give the number of attributes in the
3470
 * bounds to be compared, comparison function to be used and the collations of
3471
 * attributes, respectively.
3472
 *
3473
 * Note that if the values of the two range bounds compare equal, then we take
3474
 * into account whether they are upper or lower bounds, and an upper bound is
3475
 * considered to be smaller than a lower bound. This is important to the way
3476
 * that RelationBuildPartitionDesc() builds the PartitionBoundInfoData
3477
 * structure, which only stores the upper bound of a common boundary between
3478
 * two contiguous partitions.
3479
 */
3480
static int32
3481
partition_rbound_cmp(int partnatts, FmgrInfo *partsupfunc,
3482
           Oid *partcollation,
3483
           Datum *datums1, PartitionRangeDatumKind *kind1,
3484
           bool lower1, PartitionRangeBound *b2)
3485
0
{
3486
0
  int32   colnum = 0;
3487
0
  int32   cmpval = 0;   /* placate compiler */
3488
0
  int     i;
3489
0
  Datum    *datums2 = b2->datums;
3490
0
  PartitionRangeDatumKind *kind2 = b2->kind;
3491
0
  bool    lower2 = b2->lower;
3492
3493
0
  for (i = 0; i < partnatts; i++)
3494
0
  {
3495
    /* Track column number in case we need it for result */
3496
0
    colnum++;
3497
3498
    /*
3499
     * First, handle cases where the column is unbounded, which should not
3500
     * invoke the comparison procedure, and should not consider any later
3501
     * columns. Note that the PartitionRangeDatumKind enum elements
3502
     * compare the same way as the values they represent.
3503
     */
3504
0
    if (kind1[i] < kind2[i])
3505
0
      return -colnum;
3506
0
    else if (kind1[i] > kind2[i])
3507
0
      return colnum;
3508
0
    else if (kind1[i] != PARTITION_RANGE_DATUM_VALUE)
3509
0
    {
3510
      /*
3511
       * The column bounds are both MINVALUE or both MAXVALUE. No later
3512
       * columns should be considered, but we still need to compare
3513
       * whether they are upper or lower bounds.
3514
       */
3515
0
      break;
3516
0
    }
3517
3518
0
    cmpval = DatumGetInt32(FunctionCall2Coll(&partsupfunc[i],
3519
0
                         partcollation[i],
3520
0
                         datums1[i],
3521
0
                         datums2[i]));
3522
0
    if (cmpval != 0)
3523
0
      break;
3524
0
  }
3525
3526
  /*
3527
   * If the comparison is anything other than equal, we're done. If they
3528
   * compare equal though, we still have to consider whether the boundaries
3529
   * are inclusive or exclusive.  Exclusive one is considered smaller of the
3530
   * two.
3531
   */
3532
0
  if (cmpval == 0 && lower1 != lower2)
3533
0
    cmpval = lower1 ? 1 : -1;
3534
3535
0
  return cmpval == 0 ? 0 : (cmpval < 0 ? -colnum : colnum);
3536
0
}
3537
3538
/*
3539
 * partition_rbound_datum_cmp
3540
 *
3541
 * Return whether range bound (specified in rb_datums and rb_kind)
3542
 * is <, =, or > partition key of tuple (tuple_datums)
3543
 *
3544
 * n_tuple_datums, partsupfunc and partcollation give number of attributes in
3545
 * the bounds to be compared, comparison function to be used and the collations
3546
 * of attributes resp.
3547
 */
3548
int32
3549
partition_rbound_datum_cmp(FmgrInfo *partsupfunc, Oid *partcollation,
3550
               const Datum *rb_datums, PartitionRangeDatumKind *rb_kind,
3551
               const Datum *tuple_datums, int n_tuple_datums)
3552
0
{
3553
0
  int     i;
3554
0
  int32   cmpval = -1;
3555
3556
0
  for (i = 0; i < n_tuple_datums; i++)
3557
0
  {
3558
0
    if (rb_kind[i] == PARTITION_RANGE_DATUM_MINVALUE)
3559
0
      return -1;
3560
0
    else if (rb_kind[i] == PARTITION_RANGE_DATUM_MAXVALUE)
3561
0
      return 1;
3562
3563
0
    cmpval = DatumGetInt32(FunctionCall2Coll(&partsupfunc[i],
3564
0
                         partcollation[i],
3565
0
                         rb_datums[i],
3566
0
                         tuple_datums[i]));
3567
0
    if (cmpval != 0)
3568
0
      break;
3569
0
  }
3570
3571
0
  return cmpval;
3572
0
}
3573
3574
/*
3575
 * partition_hbound_cmp
3576
 *
3577
 * Compares modulus first, then remainder if modulus is equal.
3578
 */
3579
static int32
3580
partition_hbound_cmp(int modulus1, int remainder1, int modulus2, int remainder2)
3581
0
{
3582
0
  if (modulus1 < modulus2)
3583
0
    return -1;
3584
0
  if (modulus1 > modulus2)
3585
0
    return 1;
3586
0
  if (modulus1 == modulus2 && remainder1 != remainder2)
3587
0
    return (remainder1 > remainder2) ? 1 : -1;
3588
0
  return 0;
3589
0
}
3590
3591
/*
3592
 * partition_list_bsearch
3593
 *    Returns the index of the greatest bound datum that is less than equal
3594
 *    to the given value or -1 if all of the bound datums are greater
3595
 *
3596
 * *is_equal is set to true if the bound datum at the returned index is equal
3597
 * to the input value.
3598
 */
3599
int
3600
partition_list_bsearch(FmgrInfo *partsupfunc, Oid *partcollation,
3601
             PartitionBoundInfo boundinfo,
3602
             Datum value, bool *is_equal)
3603
0
{
3604
0
  int     lo,
3605
0
        hi,
3606
0
        mid;
3607
3608
0
  lo = -1;
3609
0
  hi = boundinfo->ndatums - 1;
3610
0
  while (lo < hi)
3611
0
  {
3612
0
    int32   cmpval;
3613
3614
0
    mid = (lo + hi + 1) / 2;
3615
0
    cmpval = DatumGetInt32(FunctionCall2Coll(&partsupfunc[0],
3616
0
                         partcollation[0],
3617
0
                         boundinfo->datums[mid][0],
3618
0
                         value));
3619
0
    if (cmpval <= 0)
3620
0
    {
3621
0
      lo = mid;
3622
0
      *is_equal = (cmpval == 0);
3623
0
      if (*is_equal)
3624
0
        break;
3625
0
    }
3626
0
    else
3627
0
      hi = mid - 1;
3628
0
  }
3629
3630
0
  return lo;
3631
0
}
3632
3633
/*
3634
 * partition_range_bsearch
3635
 *    Returns the index of the greatest range bound that is less than or
3636
 *    equal to the given range bound or -1 if all of the range bounds are
3637
 *    greater
3638
 *
3639
 * Upon return from this function, *cmpval is set to 0 if the bound at the
3640
 * returned index matches the input range bound exactly, otherwise a
3641
 * non-zero integer whose sign indicates the ordering, and whose absolute
3642
 * value gives the 1-based partition key number of the first mismatching
3643
 * column.
3644
 */
3645
static int
3646
partition_range_bsearch(int partnatts, FmgrInfo *partsupfunc,
3647
            Oid *partcollation,
3648
            PartitionBoundInfo boundinfo,
3649
            PartitionRangeBound *probe, int32 *cmpval)
3650
0
{
3651
0
  int     lo,
3652
0
        hi,
3653
0
        mid;
3654
3655
0
  lo = -1;
3656
0
  hi = boundinfo->ndatums - 1;
3657
0
  while (lo < hi)
3658
0
  {
3659
0
    mid = (lo + hi + 1) / 2;
3660
0
    *cmpval = partition_rbound_cmp(partnatts, partsupfunc,
3661
0
                     partcollation,
3662
0
                     boundinfo->datums[mid],
3663
0
                     boundinfo->kind[mid],
3664
0
                     (boundinfo->indexes[mid] == -1),
3665
0
                     probe);
3666
0
    if (*cmpval <= 0)
3667
0
    {
3668
0
      lo = mid;
3669
0
      if (*cmpval == 0)
3670
0
        break;
3671
0
    }
3672
0
    else
3673
0
      hi = mid - 1;
3674
0
  }
3675
3676
0
  return lo;
3677
0
}
3678
3679
/*
3680
 * partition_range_datum_bsearch
3681
 *    Returns the index of the greatest range bound that is less than or
3682
 *    equal to the given tuple or -1 if all of the range bounds are greater
3683
 *
3684
 * *is_equal is set to true if the range bound at the returned index is equal
3685
 * to the input tuple.
3686
 */
3687
int
3688
partition_range_datum_bsearch(FmgrInfo *partsupfunc, Oid *partcollation,
3689
                PartitionBoundInfo boundinfo,
3690
                int nvalues, const Datum *values, bool *is_equal)
3691
0
{
3692
0
  int     lo,
3693
0
        hi,
3694
0
        mid;
3695
3696
0
  lo = -1;
3697
0
  hi = boundinfo->ndatums - 1;
3698
0
  while (lo < hi)
3699
0
  {
3700
0
    int32   cmpval;
3701
3702
0
    mid = (lo + hi + 1) / 2;
3703
0
    cmpval = partition_rbound_datum_cmp(partsupfunc,
3704
0
                      partcollation,
3705
0
                      boundinfo->datums[mid],
3706
0
                      boundinfo->kind[mid],
3707
0
                      values,
3708
0
                      nvalues);
3709
0
    if (cmpval <= 0)
3710
0
    {
3711
0
      lo = mid;
3712
0
      *is_equal = (cmpval == 0);
3713
3714
0
      if (*is_equal)
3715
0
        break;
3716
0
    }
3717
0
    else
3718
0
      hi = mid - 1;
3719
0
  }
3720
3721
0
  return lo;
3722
0
}
3723
3724
/*
3725
 * partition_hash_bsearch
3726
 *    Returns the index of the greatest (modulus, remainder) pair that is
3727
 *    less than or equal to the given (modulus, remainder) pair or -1 if
3728
 *    all of them are greater
3729
 */
3730
int
3731
partition_hash_bsearch(PartitionBoundInfo boundinfo,
3732
             int modulus, int remainder)
3733
0
{
3734
0
  int     lo,
3735
0
        hi,
3736
0
        mid;
3737
3738
0
  lo = -1;
3739
0
  hi = boundinfo->ndatums - 1;
3740
0
  while (lo < hi)
3741
0
  {
3742
0
    int32   cmpval,
3743
0
          bound_modulus,
3744
0
          bound_remainder;
3745
3746
0
    mid = (lo + hi + 1) / 2;
3747
0
    bound_modulus = DatumGetInt32(boundinfo->datums[mid][0]);
3748
0
    bound_remainder = DatumGetInt32(boundinfo->datums[mid][1]);
3749
0
    cmpval = partition_hbound_cmp(bound_modulus, bound_remainder,
3750
0
                    modulus, remainder);
3751
0
    if (cmpval <= 0)
3752
0
    {
3753
0
      lo = mid;
3754
3755
0
      if (cmpval == 0)
3756
0
        break;
3757
0
    }
3758
0
    else
3759
0
      hi = mid - 1;
3760
0
  }
3761
3762
0
  return lo;
3763
0
}
3764
3765
/*
3766
 * qsort_partition_hbound_cmp
3767
 *
3768
 * Hash bounds are sorted by modulus, then by remainder.
3769
 */
3770
static int32
3771
qsort_partition_hbound_cmp(const void *a, const void *b)
3772
0
{
3773
0
  const PartitionHashBound *h1 = (const PartitionHashBound *) a;
3774
0
  const PartitionHashBound *h2 = (const PartitionHashBound *) b;
3775
3776
0
  return partition_hbound_cmp(h1->modulus, h1->remainder,
3777
0
                h2->modulus, h2->remainder);
3778
0
}
3779
3780
/*
3781
 * qsort_partition_list_value_cmp
3782
 *
3783
 * Compare two list partition bound datums.
3784
 */
3785
static int32
3786
qsort_partition_list_value_cmp(const void *a, const void *b, void *arg)
3787
0
{
3788
0
  Datum   val1 = ((const PartitionListValue *) a)->value,
3789
0
        val2 = ((const PartitionListValue *) b)->value;
3790
0
  PartitionKey key = (PartitionKey) arg;
3791
3792
0
  return DatumGetInt32(FunctionCall2Coll(&key->partsupfunc[0],
3793
0
                       key->partcollation[0],
3794
0
                       val1, val2));
3795
0
}
3796
3797
/*
3798
 * qsort_partition_rbound_cmp
3799
 *
3800
 * Used when sorting range bounds across all range partitions.
3801
 */
3802
static int32
3803
qsort_partition_rbound_cmp(const void *a, const void *b, void *arg)
3804
0
{
3805
0
  PartitionRangeBound *b1 = (*(PartitionRangeBound *const *) a);
3806
0
  PartitionRangeBound *b2 = (*(PartitionRangeBound *const *) b);
3807
0
  PartitionKey key = (PartitionKey) arg;
3808
3809
0
  return compare_range_bounds(key->partnatts, key->partsupfunc,
3810
0
                key->partcollation,
3811
0
                b1, b2);
3812
0
}
3813
3814
/*
3815
 * get_partition_operator
3816
 *
3817
 * Return oid of the operator of the given strategy for the given partition
3818
 * key column.  It is assumed that the partitioning key is of the same type as
3819
 * the chosen partitioning opclass, or at least binary-compatible.  In the
3820
 * latter case, *need_relabel is set to true if the opclass is not of a
3821
 * polymorphic type (indicating a RelabelType node needed on top), otherwise
3822
 * false.
3823
 */
3824
static Oid
3825
get_partition_operator(PartitionKey key, int col, StrategyNumber strategy,
3826
             bool *need_relabel)
3827
0
{
3828
0
  Oid     operoid;
3829
3830
  /*
3831
   * Get the operator in the partitioning opfamily using the opclass'
3832
   * declared input type as both left- and righttype.
3833
   */
3834
0
  operoid = get_opfamily_member(key->partopfamily[col],
3835
0
                  key->partopcintype[col],
3836
0
                  key->partopcintype[col],
3837
0
                  strategy);
3838
0
  if (!OidIsValid(operoid))
3839
0
    elog(ERROR, "missing operator %d(%u,%u) in partition opfamily %u",
3840
0
       strategy, key->partopcintype[col], key->partopcintype[col],
3841
0
       key->partopfamily[col]);
3842
3843
  /*
3844
   * If the partition key column is not of the same type as the operator
3845
   * class and not polymorphic, tell caller to wrap the non-Const expression
3846
   * in a RelabelType.  This matches what parse_coerce.c does.
3847
   */
3848
0
  *need_relabel = (key->parttypid[col] != key->partopcintype[col] &&
3849
0
           key->partopcintype[col] != RECORDOID &&
3850
0
           !IsPolymorphicType(key->partopcintype[col]));
3851
3852
0
  return operoid;
3853
0
}
3854
3855
/*
3856
 * make_partition_op_expr
3857
 *    Returns an Expr for the given partition key column with arg1 and
3858
 *    arg2 as its leftop and rightop, respectively
3859
 */
3860
static Expr *
3861
make_partition_op_expr(PartitionKey key, int keynum,
3862
             uint16 strategy, Expr *arg1, Expr *arg2)
3863
0
{
3864
0
  Oid     operoid;
3865
0
  bool    need_relabel = false;
3866
0
  Expr     *result = NULL;
3867
3868
  /* Get the correct btree operator for this partitioning column */
3869
0
  operoid = get_partition_operator(key, keynum, strategy, &need_relabel);
3870
3871
  /*
3872
   * Chosen operator may be such that the non-Const operand needs to be
3873
   * coerced, so apply the same; see the comment in
3874
   * get_partition_operator().
3875
   */
3876
0
  if (!IsA(arg1, Const) &&
3877
0
    (need_relabel ||
3878
0
     key->partcollation[keynum] != key->parttypcoll[keynum]))
3879
0
    arg1 = (Expr *) makeRelabelType(arg1,
3880
0
                    key->partopcintype[keynum],
3881
0
                    -1,
3882
0
                    key->partcollation[keynum],
3883
0
                    COERCE_EXPLICIT_CAST);
3884
3885
  /* Generate the actual expression */
3886
0
  switch (key->strategy)
3887
0
  {
3888
0
    case PARTITION_STRATEGY_LIST:
3889
0
      {
3890
0
        List     *elems = (List *) arg2;
3891
0
        int     nelems = list_length(elems);
3892
3893
0
        Assert(nelems >= 1);
3894
0
        Assert(keynum == 0);
3895
3896
0
        if (nelems > 1 &&
3897
0
          !type_is_array(key->parttypid[keynum]))
3898
0
        {
3899
0
          ArrayExpr  *arrexpr;
3900
0
          ScalarArrayOpExpr *saopexpr;
3901
3902
          /* Construct an ArrayExpr for the right-hand inputs */
3903
0
          arrexpr = makeNode(ArrayExpr);
3904
0
          arrexpr->array_typeid =
3905
0
            get_array_type(key->parttypid[keynum]);
3906
0
          arrexpr->array_collid = key->parttypcoll[keynum];
3907
0
          arrexpr->element_typeid = key->parttypid[keynum];
3908
0
          arrexpr->elements = elems;
3909
0
          arrexpr->multidims = false;
3910
0
          arrexpr->location = -1;
3911
3912
          /* Build leftop = ANY (rightop) */
3913
0
          saopexpr = makeNode(ScalarArrayOpExpr);
3914
0
          saopexpr->opno = operoid;
3915
0
          saopexpr->opfuncid = get_opcode(operoid);
3916
0
          saopexpr->hashfuncid = InvalidOid;
3917
0
          saopexpr->negfuncid = InvalidOid;
3918
0
          saopexpr->useOr = true;
3919
0
          saopexpr->inputcollid = key->partcollation[keynum];
3920
0
          saopexpr->args = list_make2(arg1, arrexpr);
3921
0
          saopexpr->location = -1;
3922
3923
0
          result = (Expr *) saopexpr;
3924
0
        }
3925
0
        else
3926
0
        {
3927
0
          List     *elemops = NIL;
3928
0
          ListCell   *lc;
3929
3930
0
          foreach(lc, elems)
3931
0
          {
3932
0
            Expr     *elem = lfirst(lc),
3933
0
                   *elemop;
3934
3935
0
            elemop = make_opclause(operoid,
3936
0
                         BOOLOID,
3937
0
                         false,
3938
0
                         arg1, elem,
3939
0
                         InvalidOid,
3940
0
                         key->partcollation[keynum]);
3941
0
            elemops = lappend(elemops, elemop);
3942
0
          }
3943
3944
0
          result = nelems > 1 ? makeBoolExpr(OR_EXPR, elemops, -1) : linitial(elemops);
3945
0
        }
3946
0
        break;
3947
0
      }
3948
3949
0
    case PARTITION_STRATEGY_RANGE:
3950
0
      result = make_opclause(operoid,
3951
0
                   BOOLOID,
3952
0
                   false,
3953
0
                   arg1, arg2,
3954
0
                   InvalidOid,
3955
0
                   key->partcollation[keynum]);
3956
0
      break;
3957
3958
0
    case PARTITION_STRATEGY_HASH:
3959
0
      Assert(false);
3960
0
      break;
3961
0
  }
3962
3963
0
  return result;
3964
0
}
3965
3966
/*
3967
 * get_qual_for_hash
3968
 *
3969
 * Returns a CHECK constraint expression to use as a hash partition's
3970
 * constraint, given the parent relation and partition bound structure.
3971
 *
3972
 * The partition constraint for a hash partition is always a call to the
3973
 * built-in function satisfies_hash_partition().
3974
 */
3975
static List *
3976
get_qual_for_hash(Relation parent, PartitionBoundSpec *spec)
3977
0
{
3978
0
  PartitionKey key = RelationGetPartitionKey(parent);
3979
0
  FuncExpr   *fexpr;
3980
0
  Node     *relidConst;
3981
0
  Node     *modulusConst;
3982
0
  Node     *remainderConst;
3983
0
  List     *args;
3984
0
  ListCell   *partexprs_item;
3985
0
  int     i;
3986
3987
  /* Fixed arguments. */
3988
0
  relidConst = (Node *) makeConst(OIDOID,
3989
0
                  -1,
3990
0
                  InvalidOid,
3991
0
                  sizeof(Oid),
3992
0
                  ObjectIdGetDatum(RelationGetRelid(parent)),
3993
0
                  false,
3994
0
                  true);
3995
3996
0
  modulusConst = (Node *) makeConst(INT4OID,
3997
0
                    -1,
3998
0
                    InvalidOid,
3999
0
                    sizeof(int32),
4000
0
                    Int32GetDatum(spec->modulus),
4001
0
                    false,
4002
0
                    true);
4003
4004
0
  remainderConst = (Node *) makeConst(INT4OID,
4005
0
                    -1,
4006
0
                    InvalidOid,
4007
0
                    sizeof(int32),
4008
0
                    Int32GetDatum(spec->remainder),
4009
0
                    false,
4010
0
                    true);
4011
4012
0
  args = list_make3(relidConst, modulusConst, remainderConst);
4013
0
  partexprs_item = list_head(key->partexprs);
4014
4015
  /* Add an argument for each key column. */
4016
0
  for (i = 0; i < key->partnatts; i++)
4017
0
  {
4018
0
    Node     *keyCol;
4019
4020
    /* Left operand */
4021
0
    if (key->partattrs[i] != 0)
4022
0
    {
4023
0
      keyCol = (Node *) makeVar(1,
4024
0
                    key->partattrs[i],
4025
0
                    key->parttypid[i],
4026
0
                    key->parttypmod[i],
4027
0
                    key->parttypcoll[i],
4028
0
                    0);
4029
0
    }
4030
0
    else
4031
0
    {
4032
0
      keyCol = (Node *) copyObject(lfirst(partexprs_item));
4033
0
      partexprs_item = lnext(key->partexprs, partexprs_item);
4034
0
    }
4035
4036
0
    args = lappend(args, keyCol);
4037
0
  }
4038
4039
0
  fexpr = makeFuncExpr(F_SATISFIES_HASH_PARTITION,
4040
0
             BOOLOID,
4041
0
             args,
4042
0
             InvalidOid,
4043
0
             InvalidOid,
4044
0
             COERCE_EXPLICIT_CALL);
4045
4046
0
  return list_make1(fexpr);
4047
0
}
4048
4049
/*
4050
 * get_qual_for_list
4051
 *
4052
 * Returns an implicit-AND list of expressions to use as a list partition's
4053
 * constraint, given the parent relation and partition bound structure.
4054
 *
4055
 * The function returns NIL for a default partition when it's the only
4056
 * partition since in that case there is no constraint.
4057
 */
4058
static List *
4059
get_qual_for_list(Relation parent, PartitionBoundSpec *spec)
4060
0
{
4061
0
  PartitionKey key = RelationGetPartitionKey(parent);
4062
0
  List     *result;
4063
0
  Expr     *keyCol;
4064
0
  Expr     *opexpr;
4065
0
  NullTest   *nulltest;
4066
0
  ListCell   *cell;
4067
0
  List     *elems = NIL;
4068
0
  bool    list_has_null = false;
4069
4070
  /*
4071
   * Only single-column list partitioning is supported, so we are worried
4072
   * only about the partition key with index 0.
4073
   */
4074
0
  Assert(key->partnatts == 1);
4075
4076
  /* Construct Var or expression representing the partition column */
4077
0
  if (key->partattrs[0] != 0)
4078
0
    keyCol = (Expr *) makeVar(1,
4079
0
                  key->partattrs[0],
4080
0
                  key->parttypid[0],
4081
0
                  key->parttypmod[0],
4082
0
                  key->parttypcoll[0],
4083
0
                  0);
4084
0
  else
4085
0
    keyCol = (Expr *) copyObject(linitial(key->partexprs));
4086
4087
  /*
4088
   * For default list partition, collect datums for all the partitions. The
4089
   * default partition constraint should check that the partition key is
4090
   * equal to none of those.
4091
   */
4092
0
  if (spec->is_default)
4093
0
  {
4094
0
    int     i;
4095
0
    int     ndatums = 0;
4096
0
    PartitionDesc pdesc = RelationGetPartitionDesc(parent, false);
4097
0
    PartitionBoundInfo boundinfo = pdesc->boundinfo;
4098
4099
0
    if (boundinfo)
4100
0
    {
4101
0
      ndatums = boundinfo->ndatums;
4102
4103
0
      if (partition_bound_accepts_nulls(boundinfo))
4104
0
        list_has_null = true;
4105
0
    }
4106
4107
    /*
4108
     * If default is the only partition, there need not be any partition
4109
     * constraint on it.
4110
     */
4111
0
    if (ndatums == 0 && !list_has_null)
4112
0
      return NIL;
4113
4114
0
    for (i = 0; i < ndatums; i++)
4115
0
    {
4116
0
      Const    *val;
4117
4118
      /*
4119
       * Construct Const from known-not-null datum.  We must be careful
4120
       * to copy the value, because our result has to be able to outlive
4121
       * the relcache entry we're copying from.
4122
       */
4123
0
      val = makeConst(key->parttypid[0],
4124
0
              key->parttypmod[0],
4125
0
              key->parttypcoll[0],
4126
0
              key->parttyplen[0],
4127
0
              datumCopy(*boundinfo->datums[i],
4128
0
                    key->parttypbyval[0],
4129
0
                    key->parttyplen[0]),
4130
0
              false,  /* isnull */
4131
0
              key->parttypbyval[0]);
4132
4133
0
      elems = lappend(elems, val);
4134
0
    }
4135
0
  }
4136
0
  else
4137
0
  {
4138
    /*
4139
     * Create list of Consts for the allowed values, excluding any nulls.
4140
     */
4141
0
    foreach(cell, spec->listdatums)
4142
0
    {
4143
0
      Const    *val = lfirst_node(Const, cell);
4144
4145
0
      if (val->constisnull)
4146
0
        list_has_null = true;
4147
0
      else
4148
0
        elems = lappend(elems, copyObject(val));
4149
0
    }
4150
0
  }
4151
4152
0
  if (elems)
4153
0
  {
4154
    /*
4155
     * Generate the operator expression from the non-null partition
4156
     * values.
4157
     */
4158
0
    opexpr = make_partition_op_expr(key, 0, BTEqualStrategyNumber,
4159
0
                    keyCol, (Expr *) elems);
4160
0
  }
4161
0
  else
4162
0
  {
4163
    /*
4164
     * If there are no partition values, we don't need an operator
4165
     * expression.
4166
     */
4167
0
    opexpr = NULL;
4168
0
  }
4169
4170
0
  if (!list_has_null)
4171
0
  {
4172
    /*
4173
     * Gin up a "col IS NOT NULL" test that will be ANDed with the main
4174
     * expression.  This might seem redundant, but the partition routing
4175
     * machinery needs it.
4176
     */
4177
0
    nulltest = makeNode(NullTest);
4178
0
    nulltest->arg = keyCol;
4179
0
    nulltest->nulltesttype = IS_NOT_NULL;
4180
0
    nulltest->argisrow = false;
4181
0
    nulltest->location = -1;
4182
4183
0
    result = opexpr ? list_make2(nulltest, opexpr) : list_make1(nulltest);
4184
0
  }
4185
0
  else
4186
0
  {
4187
    /*
4188
     * Gin up a "col IS NULL" test that will be OR'd with the main
4189
     * expression.
4190
     */
4191
0
    nulltest = makeNode(NullTest);
4192
0
    nulltest->arg = keyCol;
4193
0
    nulltest->nulltesttype = IS_NULL;
4194
0
    nulltest->argisrow = false;
4195
0
    nulltest->location = -1;
4196
4197
0
    if (opexpr)
4198
0
    {
4199
0
      Expr     *or;
4200
4201
0
      or = makeBoolExpr(OR_EXPR, list_make2(nulltest, opexpr), -1);
4202
0
      result = list_make1(or);
4203
0
    }
4204
0
    else
4205
0
      result = list_make1(nulltest);
4206
0
  }
4207
4208
  /*
4209
   * Note that, in general, applying NOT to a constraint expression doesn't
4210
   * necessarily invert the set of rows it accepts, because NOT (NULL) is
4211
   * NULL.  However, the partition constraints we construct here never
4212
   * evaluate to NULL, so applying NOT works as intended.
4213
   */
4214
0
  if (spec->is_default)
4215
0
  {
4216
0
    result = list_make1(make_ands_explicit(result));
4217
0
    result = list_make1(makeBoolExpr(NOT_EXPR, result, -1));
4218
0
  }
4219
4220
0
  return result;
4221
0
}
4222
4223
/*
4224
 * get_qual_for_range
4225
 *
4226
 * Returns an implicit-AND list of expressions to use as a range partition's
4227
 * constraint, given the parent relation and partition bound structure.
4228
 *
4229
 * For a multi-column range partition key, say (a, b, c), with (al, bl, cl)
4230
 * as the lower bound tuple and (au, bu, cu) as the upper bound tuple, we
4231
 * generate an expression tree of the following form:
4232
 *
4233
 *  (a IS NOT NULL) and (b IS NOT NULL) and (c IS NOT NULL)
4234
 *    AND
4235
 *  (a > al OR (a = al AND b > bl) OR (a = al AND b = bl AND c >= cl))
4236
 *    AND
4237
 *  (a < au OR (a = au AND b < bu) OR (a = au AND b = bu AND c < cu))
4238
 *
4239
 * It is often the case that a prefix of lower and upper bound tuples contains
4240
 * the same values, for example, (al = au), in which case, we will emit an
4241
 * expression tree of the following form:
4242
 *
4243
 *  (a IS NOT NULL) and (b IS NOT NULL) and (c IS NOT NULL)
4244
 *    AND
4245
 *  (a = al)
4246
 *    AND
4247
 *  (b > bl OR (b = bl AND c >= cl))
4248
 *    AND
4249
 *  (b < bu OR (b = bu AND c < cu))
4250
 *
4251
 * If a bound datum is either MINVALUE or MAXVALUE, these expressions are
4252
 * simplified using the fact that any value is greater than MINVALUE and less
4253
 * than MAXVALUE. So, for example, if cu = MAXVALUE, c < cu is automatically
4254
 * true, and we need not emit any expression for it, and the last line becomes
4255
 *
4256
 *  (b < bu) OR (b = bu), which is simplified to (b <= bu)
4257
 *
4258
 * In most common cases with only one partition column, say a, the following
4259
 * expression tree will be generated: a IS NOT NULL AND a >= al AND a < au
4260
 *
4261
 * For default partition, it returns the negation of the constraints of all
4262
 * the other partitions.
4263
 *
4264
 * External callers should pass for_default as false; we set it to true only
4265
 * when recursing.
4266
 */
4267
static List *
4268
get_qual_for_range(Relation parent, PartitionBoundSpec *spec,
4269
           bool for_default)
4270
0
{
4271
0
  List     *result = NIL;
4272
0
  ListCell   *cell1,
4273
0
         *cell2,
4274
0
         *partexprs_item,
4275
0
         *partexprs_item_saved;
4276
0
  int     i,
4277
0
        j;
4278
0
  PartitionRangeDatum *ldatum,
4279
0
         *udatum;
4280
0
  PartitionKey key = RelationGetPartitionKey(parent);
4281
0
  Expr     *keyCol;
4282
0
  Const    *lower_val,
4283
0
         *upper_val;
4284
0
  List     *lower_or_arms,
4285
0
         *upper_or_arms;
4286
0
  int     num_or_arms,
4287
0
        current_or_arm;
4288
0
  ListCell   *lower_or_start_datum,
4289
0
         *upper_or_start_datum;
4290
0
  bool    need_next_lower_arm,
4291
0
        need_next_upper_arm;
4292
4293
0
  if (spec->is_default)
4294
0
  {
4295
0
    List     *or_expr_args = NIL;
4296
0
    PartitionDesc pdesc = RelationGetPartitionDesc(parent, false);
4297
0
    Oid      *inhoids = pdesc->oids;
4298
0
    int     nparts = pdesc->nparts,
4299
0
          k;
4300
4301
0
    for (k = 0; k < nparts; k++)
4302
0
    {
4303
0
      Oid     inhrelid = inhoids[k];
4304
0
      HeapTuple tuple;
4305
0
      Datum   datum;
4306
0
      PartitionBoundSpec *bspec;
4307
4308
0
      tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(inhrelid));
4309
0
      if (!HeapTupleIsValid(tuple))
4310
0
        elog(ERROR, "cache lookup failed for relation %u", inhrelid);
4311
4312
0
      datum = SysCacheGetAttrNotNull(RELOID, tuple,
4313
0
                       Anum_pg_class_relpartbound);
4314
0
      bspec = (PartitionBoundSpec *)
4315
0
        stringToNode(TextDatumGetCString(datum));
4316
0
      if (!IsA(bspec, PartitionBoundSpec))
4317
0
        elog(ERROR, "expected PartitionBoundSpec");
4318
4319
0
      if (!bspec->is_default)
4320
0
      {
4321
0
        List     *part_qual;
4322
4323
0
        part_qual = get_qual_for_range(parent, bspec, true);
4324
4325
        /*
4326
         * AND the constraints of the partition and add to
4327
         * or_expr_args
4328
         */
4329
0
        or_expr_args = lappend(or_expr_args, list_length(part_qual) > 1
4330
0
                     ? makeBoolExpr(AND_EXPR, part_qual, -1)
4331
0
                     : linitial(part_qual));
4332
0
      }
4333
0
      ReleaseSysCache(tuple);
4334
0
    }
4335
4336
0
    if (or_expr_args != NIL)
4337
0
    {
4338
0
      Expr     *other_parts_constr;
4339
4340
      /*
4341
       * Combine the constraints obtained for non-default partitions
4342
       * using OR.  As requested, each of the OR's args doesn't include
4343
       * the NOT NULL test for partition keys (which is to avoid its
4344
       * useless repetition).  Add the same now.
4345
       */
4346
0
      other_parts_constr =
4347
0
        makeBoolExpr(AND_EXPR,
4348
0
               lappend(get_range_nulltest(key),
4349
0
                   list_length(or_expr_args) > 1
4350
0
                   ? makeBoolExpr(OR_EXPR, or_expr_args,
4351
0
                          -1)
4352
0
                   : linitial(or_expr_args)),
4353
0
               -1);
4354
4355
      /*
4356
       * Finally, the default partition contains everything *NOT*
4357
       * contained in the non-default partitions.
4358
       */
4359
0
      result = list_make1(makeBoolExpr(NOT_EXPR,
4360
0
                       list_make1(other_parts_constr), -1));
4361
0
    }
4362
4363
0
    return result;
4364
0
  }
4365
4366
  /*
4367
   * If it is the recursive call for default, we skip the get_range_nulltest
4368
   * to avoid accumulating the NullTest on the same keys for each partition.
4369
   */
4370
0
  if (!for_default)
4371
0
    result = get_range_nulltest(key);
4372
4373
  /*
4374
   * Iterate over the key columns and check if the corresponding lower and
4375
   * upper datums are equal using the btree equality operator for the
4376
   * column's type.  If equal, we emit single keyCol = common_value
4377
   * expression.  Starting from the first column for which the corresponding
4378
   * lower and upper bound datums are not equal, we generate OR expressions
4379
   * as shown in the function's header comment.
4380
   */
4381
0
  i = 0;
4382
0
  partexprs_item = list_head(key->partexprs);
4383
0
  partexprs_item_saved = partexprs_item;  /* placate compiler */
4384
0
  forboth(cell1, spec->lowerdatums, cell2, spec->upperdatums)
4385
0
  {
4386
0
    EState     *estate;
4387
0
    MemoryContext oldcxt;
4388
0
    Expr     *test_expr;
4389
0
    ExprState  *test_exprstate;
4390
0
    Datum   test_result;
4391
0
    bool    isNull;
4392
4393
0
    ldatum = lfirst_node(PartitionRangeDatum, cell1);
4394
0
    udatum = lfirst_node(PartitionRangeDatum, cell2);
4395
4396
    /*
4397
     * Since get_range_key_properties() modifies partexprs_item, and we
4398
     * might need to start over from the previous expression in the later
4399
     * part of this function, save away the current value.
4400
     */
4401
0
    partexprs_item_saved = partexprs_item;
4402
4403
0
    get_range_key_properties(key, i, ldatum, udatum,
4404
0
                 &partexprs_item,
4405
0
                 &keyCol,
4406
0
                 &lower_val, &upper_val);
4407
4408
    /*
4409
     * If either value is NULL, the corresponding partition bound is
4410
     * either MINVALUE or MAXVALUE, and we treat them as unequal, because
4411
     * even if they're the same, there is no common value to equate the
4412
     * key column with.
4413
     */
4414
0
    if (!lower_val || !upper_val)
4415
0
      break;
4416
4417
    /* Create the test expression */
4418
0
    estate = CreateExecutorState();
4419
0
    oldcxt = MemoryContextSwitchTo(estate->es_query_cxt);
4420
0
    test_expr = make_partition_op_expr(key, i, BTEqualStrategyNumber,
4421
0
                       (Expr *) lower_val,
4422
0
                       (Expr *) upper_val);
4423
0
    fix_opfuncids((Node *) test_expr);
4424
0
    test_exprstate = ExecInitExpr(test_expr, NULL);
4425
0
    test_result = ExecEvalExprSwitchContext(test_exprstate,
4426
0
                        GetPerTupleExprContext(estate),
4427
0
                        &isNull);
4428
0
    MemoryContextSwitchTo(oldcxt);
4429
0
    FreeExecutorState(estate);
4430
4431
    /* If not equal, go generate the OR expressions */
4432
0
    if (!DatumGetBool(test_result))
4433
0
      break;
4434
4435
    /*
4436
     * The bounds for the last key column can't be equal, because such a
4437
     * range partition would never be allowed to be defined (it would have
4438
     * an empty range otherwise).
4439
     */
4440
0
    if (i == key->partnatts - 1)
4441
0
      elog(ERROR, "invalid range bound specification");
4442
4443
    /* Equal, so generate keyCol = lower_val expression */
4444
0
    result = lappend(result,
4445
0
             make_partition_op_expr(key, i, BTEqualStrategyNumber,
4446
0
                        keyCol, (Expr *) lower_val));
4447
4448
0
    i++;
4449
0
  }
4450
4451
  /* First pair of lower_val and upper_val that are not equal. */
4452
0
  lower_or_start_datum = cell1;
4453
0
  upper_or_start_datum = cell2;
4454
4455
  /* OR will have as many arms as there are key columns left. */
4456
0
  num_or_arms = key->partnatts - i;
4457
0
  current_or_arm = 0;
4458
0
  lower_or_arms = upper_or_arms = NIL;
4459
0
  need_next_lower_arm = need_next_upper_arm = true;
4460
0
  while (current_or_arm < num_or_arms)
4461
0
  {
4462
0
    List     *lower_or_arm_args = NIL,
4463
0
           *upper_or_arm_args = NIL;
4464
4465
    /* Restart scan of columns from the i'th one */
4466
0
    j = i;
4467
0
    partexprs_item = partexprs_item_saved;
4468
4469
0
    for_both_cell(cell1, spec->lowerdatums, lower_or_start_datum,
4470
0
            cell2, spec->upperdatums, upper_or_start_datum)
4471
0
    {
4472
0
      PartitionRangeDatum *ldatum_next = NULL,
4473
0
             *udatum_next = NULL;
4474
4475
0
      ldatum = lfirst_node(PartitionRangeDatum, cell1);
4476
0
      if (lnext(spec->lowerdatums, cell1))
4477
0
        ldatum_next = castNode(PartitionRangeDatum,
4478
0
                     lfirst(lnext(spec->lowerdatums, cell1)));
4479
0
      udatum = lfirst_node(PartitionRangeDatum, cell2);
4480
0
      if (lnext(spec->upperdatums, cell2))
4481
0
        udatum_next = castNode(PartitionRangeDatum,
4482
0
                     lfirst(lnext(spec->upperdatums, cell2)));
4483
0
      get_range_key_properties(key, j, ldatum, udatum,
4484
0
                   &partexprs_item,
4485
0
                   &keyCol,
4486
0
                   &lower_val, &upper_val);
4487
4488
0
      if (need_next_lower_arm && lower_val)
4489
0
      {
4490
0
        uint16    strategy;
4491
4492
        /*
4493
         * For the non-last columns of this arm, use the EQ operator.
4494
         * For the last column of this arm, use GT, unless this is the
4495
         * last column of the whole bound check, or the next bound
4496
         * datum is MINVALUE, in which case use GE.
4497
         */
4498
0
        if (j - i < current_or_arm)
4499
0
          strategy = BTEqualStrategyNumber;
4500
0
        else if (j == key->partnatts - 1 ||
4501
0
             (ldatum_next &&
4502
0
              ldatum_next->kind == PARTITION_RANGE_DATUM_MINVALUE))
4503
0
          strategy = BTGreaterEqualStrategyNumber;
4504
0
        else
4505
0
          strategy = BTGreaterStrategyNumber;
4506
4507
0
        lower_or_arm_args = lappend(lower_or_arm_args,
4508
0
                      make_partition_op_expr(key, j,
4509
0
                                   strategy,
4510
0
                                   keyCol,
4511
0
                                   (Expr *) lower_val));
4512
0
      }
4513
4514
0
      if (need_next_upper_arm && upper_val)
4515
0
      {
4516
0
        uint16    strategy;
4517
4518
        /*
4519
         * For the non-last columns of this arm, use the EQ operator.
4520
         * For the last column of this arm, use LT, unless the next
4521
         * bound datum is MAXVALUE, in which case use LE.
4522
         */
4523
0
        if (j - i < current_or_arm)
4524
0
          strategy = BTEqualStrategyNumber;
4525
0
        else if (udatum_next &&
4526
0
             udatum_next->kind == PARTITION_RANGE_DATUM_MAXVALUE)
4527
0
          strategy = BTLessEqualStrategyNumber;
4528
0
        else
4529
0
          strategy = BTLessStrategyNumber;
4530
4531
0
        upper_or_arm_args = lappend(upper_or_arm_args,
4532
0
                      make_partition_op_expr(key, j,
4533
0
                                   strategy,
4534
0
                                   keyCol,
4535
0
                                   (Expr *) upper_val));
4536
0
      }
4537
4538
      /*
4539
       * Did we generate enough of OR's arguments?  First arm considers
4540
       * the first of the remaining columns, second arm considers first
4541
       * two of the remaining columns, and so on.
4542
       */
4543
0
      ++j;
4544
0
      if (j - i > current_or_arm)
4545
0
      {
4546
        /*
4547
         * We must not emit any more arms if the new column that will
4548
         * be considered is unbounded, or this one was.
4549
         */
4550
0
        if (!lower_val || !ldatum_next ||
4551
0
          ldatum_next->kind != PARTITION_RANGE_DATUM_VALUE)
4552
0
          need_next_lower_arm = false;
4553
0
        if (!upper_val || !udatum_next ||
4554
0
          udatum_next->kind != PARTITION_RANGE_DATUM_VALUE)
4555
0
          need_next_upper_arm = false;
4556
0
        break;
4557
0
      }
4558
0
    }
4559
4560
0
    if (lower_or_arm_args != NIL)
4561
0
      lower_or_arms = lappend(lower_or_arms,
4562
0
                  list_length(lower_or_arm_args) > 1
4563
0
                  ? makeBoolExpr(AND_EXPR, lower_or_arm_args, -1)
4564
0
                  : linitial(lower_or_arm_args));
4565
4566
0
    if (upper_or_arm_args != NIL)
4567
0
      upper_or_arms = lappend(upper_or_arms,
4568
0
                  list_length(upper_or_arm_args) > 1
4569
0
                  ? makeBoolExpr(AND_EXPR, upper_or_arm_args, -1)
4570
0
                  : linitial(upper_or_arm_args));
4571
4572
    /* If no work to do in the next iteration, break away. */
4573
0
    if (!need_next_lower_arm && !need_next_upper_arm)
4574
0
      break;
4575
4576
0
    ++current_or_arm;
4577
0
  }
4578
4579
  /*
4580
   * Generate the OR expressions for each of lower and upper bounds (if
4581
   * required), and append to the list of implicitly ANDed list of
4582
   * expressions.
4583
   */
4584
0
  if (lower_or_arms != NIL)
4585
0
    result = lappend(result,
4586
0
             list_length(lower_or_arms) > 1
4587
0
             ? makeBoolExpr(OR_EXPR, lower_or_arms, -1)
4588
0
             : linitial(lower_or_arms));
4589
0
  if (upper_or_arms != NIL)
4590
0
    result = lappend(result,
4591
0
             list_length(upper_or_arms) > 1
4592
0
             ? makeBoolExpr(OR_EXPR, upper_or_arms, -1)
4593
0
             : linitial(upper_or_arms));
4594
4595
  /*
4596
   * As noted above, for non-default, we return list with constant TRUE. If
4597
   * the result is NIL during the recursive call for default, it implies
4598
   * this is the only other partition which can hold every value of the key
4599
   * except NULL. Hence we return the NullTest result skipped earlier.
4600
   */
4601
0
  if (result == NIL)
4602
0
    result = for_default
4603
0
      ? get_range_nulltest(key)
4604
0
      : list_make1(makeBoolConst(true, false));
4605
4606
0
  return result;
4607
0
}
4608
4609
/*
4610
 * get_range_key_properties
4611
 *    Returns range partition key information for a given column
4612
 *
4613
 * This is a subroutine for get_qual_for_range, and its API is pretty
4614
 * specialized to that caller.
4615
 *
4616
 * Constructs an Expr for the key column (returned in *keyCol) and Consts
4617
 * for the lower and upper range limits (returned in *lower_val and
4618
 * *upper_val).  For MINVALUE/MAXVALUE limits, NULL is returned instead of
4619
 * a Const.  All of these structures are freshly palloc'd.
4620
 *
4621
 * *partexprs_item points to the cell containing the next expression in
4622
 * the key->partexprs list, or NULL.  It may be advanced upon return.
4623
 */
4624
static void
4625
get_range_key_properties(PartitionKey key, int keynum,
4626
             PartitionRangeDatum *ldatum,
4627
             PartitionRangeDatum *udatum,
4628
             ListCell **partexprs_item,
4629
             Expr **keyCol,
4630
             Const **lower_val, Const **upper_val)
4631
0
{
4632
  /* Get partition key expression for this column */
4633
0
  if (key->partattrs[keynum] != 0)
4634
0
  {
4635
0
    *keyCol = (Expr *) makeVar(1,
4636
0
                   key->partattrs[keynum],
4637
0
                   key->parttypid[keynum],
4638
0
                   key->parttypmod[keynum],
4639
0
                   key->parttypcoll[keynum],
4640
0
                   0);
4641
0
  }
4642
0
  else
4643
0
  {
4644
0
    if (*partexprs_item == NULL)
4645
0
      elog(ERROR, "wrong number of partition key expressions");
4646
0
    *keyCol = copyObject(lfirst(*partexprs_item));
4647
0
    *partexprs_item = lnext(key->partexprs, *partexprs_item);
4648
0
  }
4649
4650
  /* Get appropriate Const nodes for the bounds */
4651
0
  if (ldatum->kind == PARTITION_RANGE_DATUM_VALUE)
4652
0
    *lower_val = castNode(Const, copyObject(ldatum->value));
4653
0
  else
4654
0
    *lower_val = NULL;
4655
4656
0
  if (udatum->kind == PARTITION_RANGE_DATUM_VALUE)
4657
0
    *upper_val = castNode(Const, copyObject(udatum->value));
4658
0
  else
4659
0
    *upper_val = NULL;
4660
0
}
4661
4662
/*
4663
 * get_range_nulltest
4664
 *
4665
 * A non-default range partition table does not currently allow partition
4666
 * keys to be null, so emit an IS NOT NULL expression for each key column.
4667
 */
4668
static List *
4669
get_range_nulltest(PartitionKey key)
4670
0
{
4671
0
  List     *result = NIL;
4672
0
  NullTest   *nulltest;
4673
0
  ListCell   *partexprs_item;
4674
0
  int     i;
4675
4676
0
  partexprs_item = list_head(key->partexprs);
4677
0
  for (i = 0; i < key->partnatts; i++)
4678
0
  {
4679
0
    Expr     *keyCol;
4680
4681
0
    if (key->partattrs[i] != 0)
4682
0
    {
4683
0
      keyCol = (Expr *) makeVar(1,
4684
0
                    key->partattrs[i],
4685
0
                    key->parttypid[i],
4686
0
                    key->parttypmod[i],
4687
0
                    key->parttypcoll[i],
4688
0
                    0);
4689
0
    }
4690
0
    else
4691
0
    {
4692
0
      if (partexprs_item == NULL)
4693
0
        elog(ERROR, "wrong number of partition key expressions");
4694
0
      keyCol = copyObject(lfirst(partexprs_item));
4695
0
      partexprs_item = lnext(key->partexprs, partexprs_item);
4696
0
    }
4697
4698
0
    nulltest = makeNode(NullTest);
4699
0
    nulltest->arg = keyCol;
4700
0
    nulltest->nulltesttype = IS_NOT_NULL;
4701
0
    nulltest->argisrow = false;
4702
0
    nulltest->location = -1;
4703
0
    result = lappend(result, nulltest);
4704
0
  }
4705
4706
0
  return result;
4707
0
}
4708
4709
/*
4710
 * compute_partition_hash_value
4711
 *
4712
 * Compute the hash value for given partition key values.
4713
 */
4714
uint64
4715
compute_partition_hash_value(int partnatts, FmgrInfo *partsupfunc, const Oid *partcollation,
4716
               const Datum *values, const bool *isnull)
4717
0
{
4718
0
  int     i;
4719
0
  uint64    rowHash = 0;
4720
0
  Datum   seed = UInt64GetDatum(HASH_PARTITION_SEED);
4721
4722
0
  for (i = 0; i < partnatts; i++)
4723
0
  {
4724
    /* Nulls are just ignored */
4725
0
    if (!isnull[i])
4726
0
    {
4727
0
      Datum   hash;
4728
4729
0
      Assert(OidIsValid(partsupfunc[i].fn_oid));
4730
4731
      /*
4732
       * Compute hash for each datum value by calling respective
4733
       * datatype-specific hash functions of each partition key
4734
       * attribute.
4735
       */
4736
0
      hash = FunctionCall2Coll(&partsupfunc[i], partcollation[i],
4737
0
                   values[i], seed);
4738
4739
      /* Form a single 64-bit hash value */
4740
0
      rowHash = hash_combine64(rowHash, DatumGetUInt64(hash));
4741
0
    }
4742
0
  }
4743
4744
0
  return rowHash;
4745
0
}
4746
4747
/*
4748
 * satisfies_hash_partition
4749
 *
4750
 * This is an SQL-callable function for use in hash partition constraints.
4751
 * The first three arguments are the parent table OID, modulus, and remainder.
4752
 * The remaining arguments are the value of the partitioning columns (or
4753
 * expressions); these are hashed and the results are combined into a single
4754
 * hash value by calling hash_combine64.
4755
 *
4756
 * Returns true if remainder produced when this computed single hash value is
4757
 * divided by the given modulus is equal to given remainder, otherwise false.
4758
 * NB: it's important that this never return null, as the constraint machinery
4759
 * would consider that to be a "pass".
4760
 *
4761
 * See get_qual_for_hash() for usage.
4762
 */
4763
Datum
4764
satisfies_hash_partition(PG_FUNCTION_ARGS)
4765
0
{
4766
0
  typedef struct ColumnsHashData
4767
0
  {
4768
0
    Oid     relid;
4769
0
    int     nkeys;
4770
0
    Oid     variadic_type;
4771
0
    int16   variadic_typlen;
4772
0
    bool    variadic_typbyval;
4773
0
    char    variadic_typalign;
4774
0
    Oid     partcollid[PARTITION_MAX_KEYS];
4775
0
    FmgrInfo  partsupfunc[FLEXIBLE_ARRAY_MEMBER];
4776
0
  } ColumnsHashData;
4777
0
  Oid     parentId;
4778
0
  int     modulus;
4779
0
  int     remainder;
4780
0
  Datum   seed = UInt64GetDatum(HASH_PARTITION_SEED);
4781
0
  ColumnsHashData *my_extra;
4782
0
  uint64    rowHash = 0;
4783
4784
  /* Return false if the parent OID, modulus, or remainder is NULL. */
4785
0
  if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(2))
4786
0
    PG_RETURN_BOOL(false);
4787
0
  parentId = PG_GETARG_OID(0);
4788
0
  modulus = PG_GETARG_INT32(1);
4789
0
  remainder = PG_GETARG_INT32(2);
4790
4791
  /* Sanity check modulus and remainder. */
4792
0
  if (modulus <= 0)
4793
0
    ereport(ERROR,
4794
0
        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4795
0
         errmsg("modulus for hash partition must be an integer value greater than zero")));
4796
0
  if (remainder < 0)
4797
0
    ereport(ERROR,
4798
0
        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4799
0
         errmsg("remainder for hash partition must be an integer value greater than or equal to zero")));
4800
0
  if (remainder >= modulus)
4801
0
    ereport(ERROR,
4802
0
        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4803
0
         errmsg("remainder for hash partition must be less than modulus")));
4804
4805
  /*
4806
   * Cache hash function information.
4807
   */
4808
0
  my_extra = (ColumnsHashData *) fcinfo->flinfo->fn_extra;
4809
0
  if (my_extra == NULL || my_extra->relid != parentId)
4810
0
  {
4811
0
    Relation  parent;
4812
0
    PartitionKey key;
4813
0
    int     j;
4814
4815
    /* Open parent relation and fetch partition key info */
4816
0
    parent = relation_open(parentId, AccessShareLock);
4817
0
    key = RelationGetPartitionKey(parent);
4818
4819
    /* Reject parent table that is not hash-partitioned. */
4820
0
    if (key == NULL || key->strategy != PARTITION_STRATEGY_HASH)
4821
0
      ereport(ERROR,
4822
0
          (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4823
0
           errmsg("\"%s\" is not a hash partitioned table",
4824
0
              get_rel_name(parentId))));
4825
4826
0
    if (!get_fn_expr_variadic(fcinfo->flinfo))
4827
0
    {
4828
0
      int     nargs = PG_NARGS() - 3;
4829
4830
      /* complain if wrong number of column values */
4831
0
      if (key->partnatts != nargs)
4832
0
        ereport(ERROR,
4833
0
            (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4834
0
             errmsg("number of partitioning columns (%d) does not match number of partition keys provided (%d)",
4835
0
                key->partnatts, nargs)));
4836
4837
      /* allocate space for our cache */
4838
0
      fcinfo->flinfo->fn_extra =
4839
0
        MemoryContextAllocZero(fcinfo->flinfo->fn_mcxt,
4840
0
                     offsetof(ColumnsHashData, partsupfunc) +
4841
0
                     sizeof(FmgrInfo) * nargs);
4842
0
      my_extra = (ColumnsHashData *) fcinfo->flinfo->fn_extra;
4843
0
      my_extra->relid = parentId;
4844
0
      my_extra->nkeys = key->partnatts;
4845
0
      memcpy(my_extra->partcollid, key->partcollation,
4846
0
           key->partnatts * sizeof(Oid));
4847
4848
      /* check argument types and save fmgr_infos */
4849
0
      for (j = 0; j < key->partnatts; ++j)
4850
0
      {
4851
0
        Oid     argtype = get_fn_expr_argtype(fcinfo->flinfo, j + 3);
4852
4853
0
        if (argtype != key->parttypid[j] && !IsBinaryCoercible(argtype, key->parttypid[j]))
4854
0
          ereport(ERROR,
4855
0
              (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4856
0
               errmsg("column %d of the partition key has type %s, but supplied value is of type %s",
4857
0
                  j + 1, format_type_be(key->parttypid[j]), format_type_be(argtype))));
4858
4859
0
        fmgr_info_copy(&my_extra->partsupfunc[j],
4860
0
                 &key->partsupfunc[j],
4861
0
                 fcinfo->flinfo->fn_mcxt);
4862
0
      }
4863
0
    }
4864
0
    else if (PG_ARGISNULL(3))
4865
0
    {
4866
      /* Special case for VARIADIC NULL::sometype[] */
4867
0
      relation_close(parent, NoLock);
4868
0
      PG_RETURN_BOOL(false);
4869
0
    }
4870
0
    else
4871
0
    {
4872
0
      ArrayType  *variadic_array = PG_GETARG_ARRAYTYPE_P(3);
4873
4874
      /* allocate space for our cache -- just one FmgrInfo in this case */
4875
0
      fcinfo->flinfo->fn_extra =
4876
0
        MemoryContextAllocZero(fcinfo->flinfo->fn_mcxt,
4877
0
                     offsetof(ColumnsHashData, partsupfunc) +
4878
0
                     sizeof(FmgrInfo));
4879
0
      my_extra = (ColumnsHashData *) fcinfo->flinfo->fn_extra;
4880
0
      my_extra->relid = parentId;
4881
0
      my_extra->nkeys = key->partnatts;
4882
0
      my_extra->variadic_type = ARR_ELEMTYPE(variadic_array);
4883
0
      get_typlenbyvalalign(my_extra->variadic_type,
4884
0
                 &my_extra->variadic_typlen,
4885
0
                 &my_extra->variadic_typbyval,
4886
0
                 &my_extra->variadic_typalign);
4887
0
      my_extra->partcollid[0] = key->partcollation[0];
4888
4889
      /* check argument types */
4890
0
      for (j = 0; j < key->partnatts; ++j)
4891
0
        if (key->parttypid[j] != my_extra->variadic_type)
4892
0
          ereport(ERROR,
4893
0
              (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4894
0
               errmsg("column %d of the partition key has type \"%s\", but supplied value is of type \"%s\"",
4895
0
                  j + 1,
4896
0
                  format_type_be(key->parttypid[j]),
4897
0
                  format_type_be(my_extra->variadic_type))));
4898
4899
0
      fmgr_info_copy(&my_extra->partsupfunc[0],
4900
0
               &key->partsupfunc[0],
4901
0
               fcinfo->flinfo->fn_mcxt);
4902
0
    }
4903
4904
    /* Hold lock until commit */
4905
0
    relation_close(parent, NoLock);
4906
0
  }
4907
4908
0
  if (!OidIsValid(my_extra->variadic_type))
4909
0
  {
4910
0
    int     nkeys = my_extra->nkeys;
4911
0
    int     i;
4912
4913
    /*
4914
     * For a non-variadic call, neither the number of arguments nor their
4915
     * types can change across calls, so avoid the expense of rechecking
4916
     * here.
4917
     */
4918
4919
0
    for (i = 0; i < nkeys; i++)
4920
0
    {
4921
0
      Datum   hash;
4922
4923
      /* keys start from fourth argument of function. */
4924
0
      int     argno = i + 3;
4925
4926
0
      if (PG_ARGISNULL(argno))
4927
0
        continue;
4928
4929
0
      hash = FunctionCall2Coll(&my_extra->partsupfunc[i],
4930
0
                   my_extra->partcollid[i],
4931
0
                   PG_GETARG_DATUM(argno),
4932
0
                   seed);
4933
4934
      /* Form a single 64-bit hash value */
4935
0
      rowHash = hash_combine64(rowHash, DatumGetUInt64(hash));
4936
0
    }
4937
0
  }
4938
0
  else
4939
0
  {
4940
0
    ArrayType  *variadic_array;
4941
0
    int     i;
4942
0
    int     nelems;
4943
0
    Datum    *datum;
4944
0
    bool     *isnull;
4945
4946
    /* Special case for VARIADIC NULL::sometype[] */
4947
0
    if (PG_ARGISNULL(3))
4948
0
      PG_RETURN_BOOL(false);
4949
4950
0
    variadic_array = PG_GETARG_ARRAYTYPE_P(3);
4951
4952
0
    deconstruct_array(variadic_array,
4953
0
              my_extra->variadic_type,
4954
0
              my_extra->variadic_typlen,
4955
0
              my_extra->variadic_typbyval,
4956
0
              my_extra->variadic_typalign,
4957
0
              &datum, &isnull, &nelems);
4958
4959
    /* complain if wrong number of column values */
4960
0
    if (nelems != my_extra->nkeys)
4961
0
      ereport(ERROR,
4962
0
          (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4963
0
           errmsg("number of partitioning columns (%d) does not match number of partition keys provided (%d)",
4964
0
              my_extra->nkeys, nelems)));
4965
4966
0
    for (i = 0; i < nelems; i++)
4967
0
    {
4968
0
      Datum   hash;
4969
4970
0
      if (isnull[i])
4971
0
        continue;
4972
4973
0
      hash = FunctionCall2Coll(&my_extra->partsupfunc[0],
4974
0
                   my_extra->partcollid[0],
4975
0
                   datum[i],
4976
0
                   seed);
4977
4978
      /* Form a single 64-bit hash value */
4979
0
      rowHash = hash_combine64(rowHash, DatumGetUInt64(hash));
4980
0
    }
4981
0
  }
4982
4983
0
  PG_RETURN_BOOL(rowHash % modulus == remainder);
4984
0
}
4985
4986
/*
4987
 * check_two_partitions_bounds_range
4988
 *
4989
 * (function for BY RANGE partitioning)
4990
 *
4991
 * This is a helper function for check_partitions_for_split() and
4992
 * calculate_partition_bound_for_merge().  This function compares the upper
4993
 * bound of first_bound and the lower bound of second_bound.  These bounds
4994
 * should be equal except when "defaultPart == true" (this means that one of
4995
 * the split partitions is DEFAULT).  In this case, the upper bound of
4996
 * first_bound can be less than the lower bound of second_bound because
4997
 * the space between these bounds will be included in the DEFAULT partition.
4998
 *
4999
 * parent:      partitioned table
5000
 * first_name:    name of the first partition
5001
 * first_bound:   bound of the first partition
5002
 * second_name:   name of the second partition
5003
 * second_bound:  bound of the second partition
5004
 * defaultPart:   true if one of the new partitions is DEFAULT
5005
 * is_merge:    true indicates the operation is MERGE PARTITIONS;
5006
 *          false indicates the operation is SPLIT PARTITION.
5007
 * pstate:      pointer to ParseState struct for determining error position
5008
 */
5009
static void
5010
check_two_partitions_bounds_range(Relation parent,
5011
                  RangeVar *first_name,
5012
                  PartitionBoundSpec *first_bound,
5013
                  RangeVar *second_name,
5014
                  PartitionBoundSpec *second_bound,
5015
                  bool defaultPart,
5016
                  bool is_merge,
5017
                  ParseState *pstate)
5018
0
{
5019
0
  PartitionKey key = RelationGetPartitionKey(parent);
5020
0
  PartitionRangeBound *first_upper;
5021
0
  PartitionRangeBound *second_lower;
5022
0
  int     cmpval;
5023
5024
0
  Assert(key->strategy == PARTITION_STRATEGY_RANGE);
5025
5026
0
  first_upper = make_one_partition_rbound(key, -1, first_bound->upperdatums, false);
5027
0
  second_lower = make_one_partition_rbound(key, -1, second_bound->lowerdatums, true);
5028
5029
  /*
5030
   * lower1 argument of partition_rbound_cmp() is set to false for the
5031
   * correct comparison result of the lower and upper bounds.
5032
   */
5033
0
  cmpval = partition_rbound_cmp(key->partnatts,
5034
0
                  key->partsupfunc,
5035
0
                  key->partcollation,
5036
0
                  second_lower->datums, second_lower->kind,
5037
0
                  false, first_upper);
5038
0
  if ((!defaultPart && cmpval) || (defaultPart && cmpval < 0))
5039
0
  {
5040
0
    PartitionRangeDatum *datum = linitial(second_bound->lowerdatums);
5041
5042
0
    if (is_merge)
5043
0
      ereport(ERROR,
5044
0
          errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
5045
0
          errmsg("cannot merge partition \"%s\" together with partition \"%s\"",
5046
0
               second_name->relname, first_name->relname),
5047
0
          errdetail("The lower bound of partition \"%s\" is not equal to the upper bound of partition \"%s\".",
5048
0
                second_name->relname, first_name->relname),
5049
0
          errhint("ALTER TABLE ... MERGE PARTITIONS requires the partition bounds to be adjacent."),
5050
0
          parser_errposition(pstate, datum->location));
5051
0
    else
5052
0
      ereport(ERROR,
5053
0
          errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
5054
0
          errmsg("cannot split to partition \"%s\" together with partition \"%s\"",
5055
0
               second_name->relname, first_name->relname),
5056
0
          errdetail("The lower bound of partition \"%s\" is not equal to the upper bound of partition \"%s\".",
5057
0
                second_name->relname, first_name->relname),
5058
0
          errhint("ALTER TABLE ... SPLIT PARTITION requires the partition bounds to be adjacent."),
5059
0
          parser_errposition(pstate, datum->location));
5060
0
  }
5061
0
}
5062
5063
/*
5064
 * get_partition_bound_spec
5065
 *
5066
 * Returns the PartitionBoundSpec for the partition with the given OID partOid.
5067
 */
5068
static PartitionBoundSpec *
5069
get_partition_bound_spec(Oid partOid)
5070
0
{
5071
0
  HeapTuple tuple;
5072
0
  Datum   datum;
5073
0
  bool    isnull;
5074
0
  PartitionBoundSpec *boundspec = NULL;
5075
5076
  /* Try fetching the tuple from the catcache, for speed. */
5077
0
  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(partOid));
5078
0
  if (!HeapTupleIsValid(tuple))
5079
0
    elog(ERROR, "cache lookup failed for relation %u", partOid);
5080
5081
0
  datum = SysCacheGetAttr(RELOID, tuple,
5082
0
              Anum_pg_class_relpartbound,
5083
0
              &isnull);
5084
0
  if (isnull)
5085
0
    elog(ERROR, "partition bound for relation %u is null",
5086
0
       partOid);
5087
5088
0
  boundspec = stringToNode(TextDatumGetCString(datum));
5089
5090
0
  if (!IsA(boundspec, PartitionBoundSpec))
5091
0
    elog(ERROR, "expected PartitionBoundSpec for relation %u",
5092
0
       partOid);
5093
5094
0
  ReleaseSysCache(tuple);
5095
0
  return boundspec;
5096
0
}
5097
5098
/*
5099
 * calculate_partition_bound_for_merge
5100
 *
5101
 * Calculates the bound of the merged partition "spec" by using the bounds of
5102
 * the partitions to be merged.
5103
 *
5104
 * parent:      partitioned table
5105
 * partNames:   names of partitions to be merged
5106
 * partOids:    Oids of partitions to be merged
5107
 * spec (out):    bounds specification of the merged partition
5108
 * pstate:      pointer to ParseState struct to determine error position
5109
 */
5110
void
5111
calculate_partition_bound_for_merge(Relation parent,
5112
                  List *partNames,
5113
                  List *partOids,
5114
                  PartitionBoundSpec *spec,
5115
                  ParseState *pstate)
5116
0
{
5117
0
  PartitionKey key = RelationGetPartitionKey(parent);
5118
0
  PartitionBoundSpec *bound;
5119
5120
0
  Assert(!spec->is_default);
5121
5122
0
  switch (key->strategy)
5123
0
  {
5124
0
    case PARTITION_STRATEGY_RANGE:
5125
0
      {
5126
0
        int     i;
5127
0
        PartitionRangeBound **lower_bounds;
5128
0
        int     nparts = list_length(partOids);
5129
0
        List     *bounds = NIL;
5130
5131
0
        lower_bounds = palloc0_array(PartitionRangeBound *, nparts);
5132
5133
        /*
5134
         * Create an array of lower bounds and a list of
5135
         * PartitionBoundSpec.
5136
         */
5137
0
        foreach_oid(partoid, partOids)
5138
0
        {
5139
0
          bound = get_partition_bound_spec(partoid);
5140
0
          i = foreach_current_index(partoid);
5141
5142
0
          lower_bounds[i] = make_one_partition_rbound(key, i, bound->lowerdatums, true);
5143
0
          bounds = lappend(bounds, bound);
5144
0
        }
5145
5146
        /* Sort the array of lower bounds. */
5147
0
        qsort_arg(lower_bounds, nparts, sizeof(PartitionRangeBound *),
5148
0
              qsort_partition_rbound_cmp, key);
5149
5150
        /* Ranges of partitions should be adjacent. */
5151
0
        for (i = 1; i < nparts; i++)
5152
0
        {
5153
0
          int     index = lower_bounds[i]->index;
5154
0
          int     prev_index = lower_bounds[i - 1]->index;
5155
5156
0
          check_two_partitions_bounds_range(parent,
5157
0
                            (RangeVar *) list_nth(partNames, prev_index),
5158
0
                            (PartitionBoundSpec *) list_nth(bounds, prev_index),
5159
0
                            (RangeVar *) list_nth(partNames, index),
5160
0
                            (PartitionBoundSpec *) list_nth(bounds, index),
5161
0
                            false,
5162
0
                            true,
5163
0
                            pstate);
5164
0
        }
5165
5166
        /*
5167
         * The lower bound of the first partition is the lower bound
5168
         * of the merged partition.
5169
         */
5170
0
        spec->lowerdatums =
5171
0
          ((PartitionBoundSpec *) list_nth(bounds, lower_bounds[0]->index))->lowerdatums;
5172
5173
        /*
5174
         * The upper bound of the last partition is the upper bound of
5175
         * the merged partition.
5176
         */
5177
0
        spec->upperdatums =
5178
0
          ((PartitionBoundSpec *) list_nth(bounds, lower_bounds[nparts - 1]->index))->upperdatums;
5179
5180
0
        pfree(lower_bounds);
5181
0
        list_free(bounds);
5182
0
        break;
5183
0
      }
5184
5185
0
    case PARTITION_STRATEGY_LIST:
5186
0
      {
5187
        /* Consolidate bounds for all partitions in the list. */
5188
0
        foreach_oid(partoid, partOids)
5189
0
        {
5190
0
          bound = get_partition_bound_spec(partoid);
5191
0
          spec->listdatums = list_concat(spec->listdatums, bound->listdatums);
5192
0
        }
5193
0
        break;
5194
0
      }
5195
5196
0
    default:
5197
0
      elog(ERROR, "unexpected partition strategy: %d",
5198
0
         (int) key->strategy);
5199
0
  }
5200
0
}
5201
5202
/*
5203
 * partitions_listdatum_intersection
5204
 *
5205
 * (function for BY LIST partitioning)
5206
 *
5207
 * Function compares lists of values for different partitions.
5208
 * Return a list that contains *one* cell that is present in both list1 and
5209
 * list2.  The returned list is freshly allocated via palloc(), but the
5210
 * cells themselves point to the same objects as the cells of the
5211
 * input lists.
5212
 *
5213
 * Currently, there is no need to collect all common partition datums from the
5214
 * two lists.
5215
 */
5216
static List *
5217
partitions_listdatum_intersection(FmgrInfo *partsupfunc, Oid *partcollation,
5218
                  const List *list1, const List *list2)
5219
0
{
5220
0
  List     *result = NIL;
5221
5222
0
  if (list1 == NIL || list2 == NIL)
5223
0
    return result;
5224
5225
0
  foreach_node(Const, val1, list1)
5226
0
  {
5227
0
    bool    isnull1 = val1->constisnull;
5228
5229
0
    foreach_node(Const, val2, list2)
5230
0
    {
5231
0
      if (val2->constisnull)
5232
0
      {
5233
0
        if (isnull1)
5234
0
        {
5235
0
          result = lappend(result, val1);
5236
0
          return result;
5237
0
        }
5238
0
        continue;
5239
0
      }
5240
0
      else if (isnull1)
5241
0
        continue;
5242
5243
      /* Compare two datum values. */
5244
0
      if (DatumGetInt32(FunctionCall2Coll(&partsupfunc[0],
5245
0
                        partcollation[0],
5246
0
                        val1->constvalue,
5247
0
                        val2->constvalue)) == 0)
5248
0
      {
5249
0
        result = lappend(result, val1);
5250
0
        return result;
5251
0
      }
5252
0
    }
5253
0
  }
5254
5255
0
  return result;
5256
0
}
5257
5258
/*
5259
 * check_partitions_not_overlap_list
5260
 *
5261
 * (function for BY LIST partitioning)
5262
 *
5263
 * This is a helper function for check_partitions_for_split().
5264
 * Checks that the values of the new partitions do not overlap.
5265
 *
5266
 * parent:  partitioned table
5267
 * parts: array of SinglePartitionSpec structs with info about split partitions
5268
 * nparts:  size of array "parts"
5269
 */
5270
static void
5271
check_partitions_not_overlap_list(Relation parent,
5272
                  SinglePartitionSpec **parts,
5273
                  int nparts,
5274
                  ParseState *pstate)
5275
0
{
5276
0
  PartitionKey key PG_USED_FOR_ASSERTS_ONLY = RelationGetPartitionKey(parent);
5277
0
  int     i,
5278
0
        j;
5279
0
  SinglePartitionSpec *sps1,
5280
0
         *sps2;
5281
0
  List     *overlap;
5282
5283
0
  Assert(key->strategy == PARTITION_STRATEGY_LIST);
5284
5285
0
  for (i = 0; i < nparts; i++)
5286
0
  {
5287
0
    sps1 = parts[i];
5288
5289
0
    for (j = i + 1; j < nparts; j++)
5290
0
    {
5291
0
      sps2 = parts[j];
5292
5293
0
      overlap = partitions_listdatum_intersection(&key->partsupfunc[0],
5294
0
                            key->partcollation,
5295
0
                            sps1->bound->listdatums,
5296
0
                            sps2->bound->listdatums);
5297
0
      if (list_length(overlap) > 0)
5298
0
      {
5299
0
        Const    *val = (Const *) linitial_node(Const, overlap);
5300
5301
0
        ereport(ERROR,
5302
0
            errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
5303
0
            errmsg("new partition \"%s\" would overlap with another new partition \"%s\"",
5304
0
                 sps1->name->relname, sps2->name->relname),
5305
0
            parser_errposition(pstate, exprLocation((Node *) val)));
5306
0
      }
5307
0
    }
5308
0
  }
5309
0
}
5310
5311
/*
5312
 * check_partition_bounds_for_split_range
5313
 *
5314
 * (function for BY RANGE partitioning)
5315
 *
5316
 * Checks that bounds of new partition "spec" are inside bounds of split
5317
 * partition (with Oid splitPartOid). If first=true (this means that "spec" is
5318
 * the first of the new partitions), then the lower bound of "spec" should be
5319
 * equal (or greater than or equal in case defaultPart=true) to the lower
5320
 * bound of the split partition. If last=true (this means that "spec" is the
5321
 * last of the new partitions), then the upper bound of "spec" should be
5322
 * equal (or less than or equal in case defaultPart=true) to the upper bound
5323
 * of the split partition.
5324
 *
5325
 * parent:      partitioned table
5326
 * relname:     name of the new partition
5327
 * spec:      bounds specification of the new partition
5328
 * splitPartOid:  split partition Oid
5329
 * first:     true iff the new partition "spec" is the first of the
5330
 *          new partitions
5331
 * last:      true iff the new partition "spec" is the last of the
5332
 *          new partitions
5333
 * defaultPart:   true iff new partitions contain the DEFAULT partition
5334
 * pstate:      pointer to ParseState struct to determine error position
5335
 */
5336
static void
5337
check_partition_bounds_for_split_range(Relation parent,
5338
                     char *relname,
5339
                     PartitionBoundSpec *spec,
5340
                     Oid splitPartOid,
5341
                     bool first,
5342
                     bool last,
5343
                     bool defaultPart,
5344
                     ParseState *pstate)
5345
0
{
5346
0
  PartitionKey key = RelationGetPartitionKey(parent);
5347
0
  PartitionRangeBound *lower,
5348
0
         *upper;
5349
0
  int     cmpval;
5350
5351
0
  Assert(key->strategy == PARTITION_STRATEGY_RANGE);
5352
0
  Assert(spec->strategy == PARTITION_STRATEGY_RANGE);
5353
5354
0
  lower = make_one_partition_rbound(key, -1, spec->lowerdatums, true);
5355
0
  upper = make_one_partition_rbound(key, -1, spec->upperdatums, false);
5356
5357
  /*
5358
   * First, check if the resulting range would be empty with the specified
5359
   * lower and upper bounds.  partition_rbound_cmp cannot return zero here,
5360
   * since the lower-bound flags are different.
5361
   */
5362
0
  cmpval = partition_rbound_cmp(key->partnatts,
5363
0
                  key->partsupfunc,
5364
0
                  key->partcollation,
5365
0
                  lower->datums, lower->kind,
5366
0
                  true, upper);
5367
0
  Assert(cmpval != 0);
5368
0
  if (cmpval > 0)
5369
0
  {
5370
    /* Point to the problematic key in the lower datums list. */
5371
0
    PartitionRangeDatum *datum = list_nth(spec->lowerdatums, cmpval - 1);
5372
5373
0
    ereport(ERROR,
5374
0
        errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
5375
0
        errmsg("empty range bound specified for partition \"%s\"",
5376
0
             relname),
5377
0
        errdetail("Specified lower bound %s is greater than or equal to upper bound %s.",
5378
0
              get_range_partbound_string(spec->lowerdatums),
5379
0
              get_range_partbound_string(spec->upperdatums)),
5380
0
        parser_errposition(pstate, exprLocation((Node *) datum)));
5381
0
  }
5382
5383
  /*
5384
   * Need to check first and last partitions (from the set of new
5385
   * partitions)
5386
   */
5387
0
  if (first || last)
5388
0
  {
5389
0
    PartitionBoundSpec *split_spec = get_partition_bound_spec(splitPartOid);
5390
0
    PartitionRangeDatum *datum;
5391
5392
0
    if (first)
5393
0
    {
5394
0
      PartitionRangeBound *split_lower;
5395
5396
0
      split_lower = make_one_partition_rbound(key, -1, split_spec->lowerdatums, true);
5397
5398
0
      cmpval = partition_rbound_cmp(key->partnatts,
5399
0
                      key->partsupfunc,
5400
0
                      key->partcollation,
5401
0
                      lower->datums, lower->kind,
5402
0
                      true, split_lower);
5403
0
      if (cmpval != 0)
5404
0
        datum = list_nth(spec->lowerdatums, abs(cmpval) - 1);
5405
5406
      /*
5407
       * The lower bound of "spec" must equal the lower bound of the
5408
       * split partition.  However, if one of the new partitions is
5409
       * DEFAULT, then it is ok for the new partition's lower bound to
5410
       * be greater than that of the split partition.
5411
       */
5412
0
      if (!defaultPart)
5413
0
      {
5414
0
        if (cmpval != 0)
5415
0
          ereport(ERROR,
5416
0
              errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
5417
0
              errmsg("lower bound of partition \"%s\" is not equal to lower bound of split partition \"%s\"",
5418
0
                   relname,
5419
0
                   get_rel_name(splitPartOid)),
5420
0
              errhint("%s requires the combined bounds of the new partitions to exactly match the bound of the split partition.",
5421
0
                  "ALTER TABLE ... SPLIT PARTITION"),
5422
0
              parser_errposition(pstate, exprLocation((Node *) datum)));
5423
0
      }
5424
0
      else if (cmpval < 0)
5425
0
        ereport(ERROR,
5426
0
            errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
5427
0
            errmsg("lower bound of partition \"%s\" is less than lower bound of split partition \"%s\"",
5428
0
                 relname,
5429
0
                 get_rel_name(splitPartOid)),
5430
0
            errhint("Explicit partition bounds must be contained within the bounds of the split partition when a DEFAULT partition is specified."),
5431
0
            parser_errposition(pstate, exprLocation((Node *) datum)));
5432
0
    }
5433
5434
0
    if (last)
5435
0
    {
5436
0
      PartitionRangeBound *split_upper;
5437
5438
0
      split_upper = make_one_partition_rbound(key, -1, split_spec->upperdatums, false);
5439
5440
0
      cmpval = partition_rbound_cmp(key->partnatts,
5441
0
                      key->partsupfunc,
5442
0
                      key->partcollation,
5443
0
                      upper->datums, upper->kind,
5444
0
                      false, split_upper);
5445
0
      if (cmpval != 0)
5446
0
        datum = list_nth(spec->upperdatums, abs(cmpval) - 1);
5447
5448
      /*
5449
       * The upper bound of "spec" must equal the upper bound of the
5450
       * split partition.  However, if one of the new partitions is
5451
       * DEFAULT, then it is ok for the new partition's upper bound to
5452
       * be less than that of the split partition.
5453
       */
5454
0
      if (!defaultPart)
5455
0
      {
5456
0
        if (cmpval != 0)
5457
0
          ereport(ERROR,
5458
0
              errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
5459
0
              errmsg("upper bound of partition \"%s\" is not equal to upper bound of split partition \"%s\"",
5460
0
                   relname,
5461
0
                   get_rel_name(splitPartOid)),
5462
0
              errhint("%s requires the combined bounds of the new partitions to exactly match the bound of the split partition.",
5463
0
                  "ALTER TABLE ... SPLIT PARTITION"),
5464
0
              parser_errposition(pstate, exprLocation((Node *) datum)));
5465
0
      }
5466
0
      else if (cmpval > 0)
5467
0
        ereport(ERROR,
5468
0
            errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
5469
0
            errmsg("upper bound of partition \"%s\" is greater than upper bound of split partition \"%s\"",
5470
0
                 relname,
5471
0
                 get_rel_name(splitPartOid)),
5472
0
            errhint("Explicit partition bounds must be contained within the bounds of the split partition when a DEFAULT partition is specified."),
5473
0
            parser_errposition(pstate, exprLocation((Node *) datum)));
5474
0
    }
5475
0
  }
5476
0
}
5477
5478
/*
5479
 * check_partition_bounds_for_split_list
5480
 *
5481
 * (function for BY LIST partitioning)
5482
 *
5483
 * Checks that the bounds of the new partition are inside the bounds of the
5484
 * split partition (with Oid splitPartOid).
5485
 *
5486
 * parent:      partitioned table
5487
 * relname:     name of the new partition
5488
 * spec:      bounds specification of the new partition
5489
 * splitPartOid:  split partition Oid
5490
 * pstate:      pointer to ParseState struct to determine error position
5491
 */
5492
static void
5493
check_partition_bounds_for_split_list(Relation parent, char *relname,
5494
                    PartitionBoundSpec *spec,
5495
                    Oid splitPartOid,
5496
                    ParseState *pstate)
5497
0
{
5498
0
  PartitionKey key = RelationGetPartitionKey(parent);
5499
0
  PartitionDesc partdesc = RelationGetPartitionDesc(parent, false);
5500
0
  PartitionBoundInfo boundinfo = partdesc->boundinfo;
5501
0
  int     with = -1;
5502
0
  bool    overlap = false;
5503
0
  int     overlap_location = -1;
5504
5505
0
  Assert(key->strategy == PARTITION_STRATEGY_LIST);
5506
0
  Assert(spec->strategy == PARTITION_STRATEGY_LIST);
5507
0
  Assert(boundinfo && boundinfo->strategy == PARTITION_STRATEGY_LIST);
5508
5509
  /*
5510
   * Search each value of the new partition "spec" in the existing
5511
   * partitions.  All of them should be in the split partition (with Oid
5512
   * splitPartOid).
5513
   */
5514
0
  foreach_node(Const, val, spec->listdatums)
5515
0
  {
5516
0
    overlap_location = exprLocation((Node *) val);
5517
0
    if (!val->constisnull)
5518
0
    {
5519
0
      int     offset;
5520
0
      bool    equal;
5521
5522
0
      offset = partition_list_bsearch(&key->partsupfunc[0],
5523
0
                      key->partcollation,
5524
0
                      boundinfo,
5525
0
                      val->constvalue,
5526
0
                      &equal);
5527
0
      if (offset >= 0 && equal)
5528
0
      {
5529
0
        with = boundinfo->indexes[offset];
5530
0
        if (partdesc->oids[with] != splitPartOid)
5531
0
        {
5532
0
          overlap = true;
5533
0
          break;
5534
0
        }
5535
0
      }
5536
0
      else
5537
0
        ereport(ERROR,
5538
0
            errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
5539
0
            errmsg("new partition \"%s\" cannot have this value because split partition \"%s\" does not have it",
5540
0
                 relname,
5541
0
                 get_rel_name(splitPartOid)),
5542
0
            parser_errposition(pstate, overlap_location));
5543
0
    }
5544
0
    else if (partition_bound_accepts_nulls(boundinfo))
5545
0
    {
5546
0
      with = boundinfo->null_index;
5547
0
      if (partdesc->oids[with] != splitPartOid)
5548
0
      {
5549
0
        overlap = true;
5550
0
        break;
5551
0
      }
5552
0
    }
5553
0
    else
5554
0
      ereport(ERROR,
5555
0
          errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
5556
0
          errmsg("new partition \"%s\" cannot have NULL value because split partition \"%s\" does not have it",
5557
0
               relname,
5558
0
               get_rel_name(splitPartOid)),
5559
0
          parser_errposition(pstate, overlap_location));
5560
0
  }
5561
5562
0
  if (overlap)
5563
0
  {
5564
0
    Assert(with >= 0);
5565
0
    ereport(ERROR,
5566
0
        errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
5567
0
        errmsg("new partition \"%s\" would overlap with another (not split) partition \"%s\"",
5568
0
             relname, get_rel_name(partdesc->oids[with])),
5569
0
        parser_errposition(pstate, overlap_location));
5570
0
  }
5571
0
}
5572
5573
/*
5574
 * find_value_in_new_partitions_list
5575
 *
5576
 * (function for BY LIST partitioning)
5577
 *
5578
 * Function returns true iff any of the new partitions contains the value
5579
 * "value".
5580
 *
5581
 * partsupfunc:   information about the comparison function associated with
5582
 *          the partition key
5583
 * partcollation: partitioning collation
5584
 * parts:     pointer to an array with new partition descriptions
5585
 * nparts:      number of new partitions
5586
 * value:     the value that we are looking for
5587
 * isnull:      true if the value that we are looking for is NULL
5588
 */
5589
static bool
5590
find_value_in_new_partitions_list(FmgrInfo *partsupfunc,
5591
                  Oid *partcollation,
5592
                  SinglePartitionSpec **parts,
5593
                  int nparts,
5594
                  Datum value,
5595
                  bool isnull)
5596
0
{
5597
0
  for (int i = 0; i < nparts; i++)
5598
0
  {
5599
0
    SinglePartitionSpec *sps = parts[i];
5600
5601
0
    foreach_node(Const, val, sps->bound->listdatums)
5602
0
    {
5603
0
      if (isnull && val->constisnull)
5604
0
        return true;
5605
5606
0
      if (!isnull && !val->constisnull)
5607
0
      {
5608
0
        if (DatumGetInt32(FunctionCall2Coll(&partsupfunc[0],
5609
0
                          partcollation[0],
5610
0
                          val->constvalue,
5611
0
                          value)) == 0)
5612
0
          return true;
5613
0
      }
5614
0
    }
5615
0
  }
5616
0
  return false;
5617
0
}
5618
5619
/*
5620
 * check_parent_values_in_new_partitions
5621
 *
5622
 * (function for BY LIST partitioning)
5623
 *
5624
 * Checks that all values of split partition (with Oid partOid) are contained
5625
 * in new partitions.
5626
 *
5627
 * parent:  partitioned table
5628
 * partOid: split partition Oid
5629
 * parts: pointer to an array with new partition descriptions
5630
 * nparts:  number of new partitions
5631
 * pstate:  pointer to ParseState struct to determine error position
5632
 */
5633
static void
5634
check_parent_values_in_new_partitions(Relation parent,
5635
                    Oid partOid,
5636
                    SinglePartitionSpec **parts,
5637
                    int nparts,
5638
                    ParseState *pstate)
5639
0
{
5640
0
  PartitionKey key = RelationGetPartitionKey(parent);
5641
0
  PartitionDesc partdesc = RelationGetPartitionDesc(parent, false);
5642
0
  PartitionBoundInfo boundinfo = partdesc->boundinfo;
5643
0
  int     i;
5644
0
  bool    found = true;
5645
0
  Datum   datum = PointerGetDatum(NULL);
5646
5647
0
  Assert(key->strategy == PARTITION_STRATEGY_LIST);
5648
5649
  /*
5650
   * Special processing for NULL value. Search for a NULL value if the split
5651
   * partition (partOid) contains it.
5652
   */
5653
0
  if (partition_bound_accepts_nulls(boundinfo) &&
5654
0
    partdesc->oids[boundinfo->null_index] == partOid)
5655
0
  {
5656
0
    if (!find_value_in_new_partitions_list(&key->partsupfunc[0],
5657
0
                         key->partcollation, parts, nparts, datum, true))
5658
0
      found = false;
5659
0
  }
5660
5661
0
  if (!found)
5662
0
    ereport(ERROR,
5663
0
        errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
5664
0
        errmsg("new partitions' combined partition bounds do not contain value (%s) but split partition \"%s\" does",
5665
0
             "NULL",
5666
0
             get_rel_name(partOid)),
5667
0
        errhint("%s requires the combined bounds of the new partitions to exactly match the bound of the split partition.",
5668
0
            "ALTER TABLE ... SPLIT PARTITION"));
5669
5670
  /*
5671
   * Search all values of split partition with partOid in the PartitionDesc
5672
   * of partitioned table.
5673
   */
5674
0
  for (i = 0; i < boundinfo->ndatums; i++)
5675
0
  {
5676
0
    if (partdesc->oids[boundinfo->indexes[i]] == partOid)
5677
0
    {
5678
      /* We found the value that the split partition contains. */
5679
0
      datum = boundinfo->datums[i][0];
5680
0
      if (!find_value_in_new_partitions_list(&key->partsupfunc[0],
5681
0
                           key->partcollation, parts, nparts, datum, false))
5682
0
      {
5683
0
        found = false;
5684
0
        break;
5685
0
      }
5686
0
    }
5687
0
  }
5688
5689
0
  if (!found)
5690
0
  {
5691
0
    Const    *notFoundVal;
5692
5693
    /*
5694
     * Make a Const for getting the string representation of the missing
5695
     * value.
5696
     */
5697
0
    notFoundVal = makeConst(key->parttypid[0],
5698
0
                key->parttypmod[0],
5699
0
                key->parttypcoll[0],
5700
0
                key->parttyplen[0],
5701
0
                datum,
5702
0
                false,  /* isnull */
5703
0
                key->parttypbyval[0]);
5704
5705
0
    ereport(ERROR,
5706
0
        errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
5707
0
        errmsg("new partitions' combined partition bounds do not contain value (%s) but split partition \"%s\" does",
5708
0
             deparse_expression((Node *) notFoundVal, NIL, false, false),
5709
0
             get_rel_name(partOid)),
5710
0
        errhint("%s requires the combined bounds of the new partitions to exactly match the bound of the split partition.",
5711
0
            "ALTER TABLE ... SPLIT PARTITION"));
5712
0
  }
5713
0
}
5714
5715
/*
5716
 * split_partition_values_contained_in_new_part
5717
 *
5718
 * (function for BY LIST partitioning)
5719
 *
5720
 * Returns true if all values in the LIST bound of the partition being split
5721
 * are contained in the specified non-DEFAULT replacement partition's bound.
5722
 *
5723
 * The caller must already have verified containment in the other direction,
5724
 * so this check is sufficient to prove that the two LIST bounds are equal.
5725
 */
5726
static bool
5727
split_partition_values_contained_in_new_part(Relation parent,
5728
                       Oid splitPartOid,
5729
                       SinglePartitionSpec *part)
5730
0
{
5731
0
  PartitionKey key = RelationGetPartitionKey(parent);
5732
0
  PartitionDesc partdesc = RelationGetPartitionDesc(parent, false);
5733
0
  PartitionBoundInfo boundinfo = partdesc->boundinfo;
5734
0
  SinglePartitionSpec *parts[1];
5735
0
  Datum   datum = PointerGetDatum(NULL);
5736
5737
0
  Assert(key->strategy == PARTITION_STRATEGY_LIST);
5738
5739
0
  parts[0] = part;
5740
5741
  /*
5742
   * Special processing for NULL value.  Search for a NULL value if the
5743
   * split partition contains it.
5744
   */
5745
0
  if (partition_bound_accepts_nulls(boundinfo) &&
5746
0
    partdesc->oids[boundinfo->null_index] == splitPartOid)
5747
0
  {
5748
0
    if (!find_value_in_new_partitions_list(&key->partsupfunc[0],
5749
0
                         key->partcollation, parts, 1,
5750
0
                         datum, true))
5751
0
      return false;
5752
0
  }
5753
5754
  /*
5755
   * Search all values of the split partition in the single non-DEFAULT
5756
   * replacement partition.
5757
   */
5758
0
  for (int i = 0; i < boundinfo->ndatums; i++)
5759
0
  {
5760
0
    if (partdesc->oids[boundinfo->indexes[i]] == splitPartOid)
5761
0
    {
5762
0
      datum = boundinfo->datums[i][0];
5763
5764
0
      if (!find_value_in_new_partitions_list(&key->partsupfunc[0],
5765
0
                           key->partcollation, parts, 1,
5766
0
                           datum, false))
5767
0
        return false;
5768
0
    }
5769
0
  }
5770
5771
0
  return true;
5772
0
}
5773
5774
/*
5775
 * check_split_partition_not_same_bound
5776
 *
5777
 * Reject splitting a non-DEFAULT partition into one non-DEFAULT partition
5778
 * with the original bound plus a DEFAULT partition.  That form does not
5779
 * perform a real split; it merely adds a DEFAULT partition to the parent
5780
 * table through the split-partition path.  Users should use
5781
 * CREATE TABLE ... PARTITION OF ... DEFAULT or ALTER TABLE ... ATTACH
5782
 * PARTITION ... DEFAULT for that.
5783
 *
5784
 * Must be called after the per-partition bound validation in
5785
 * check_partitions_for_split() so that containment of new bounds within the
5786
 * split partition is already established.  Given containment, RANGE bounds
5787
 * are equal iff their lower and upper rbounds match; LIST bound sets are
5788
 * equal iff the split partition's values are also contained in the new
5789
 * partition (the containment is then bidirectional).  Both checks go
5790
 * through the partition operator family (partition_rbound_cmp /
5791
 * find_value_in_new_partitions_list) rather than byte equality, so e.g.
5792
 * -0.0 and 0.0 -- which have different bit patterns but compare equal
5793
 * under float8 -- are correctly recognised as the same bound.
5794
 */
5795
static void
5796
check_split_partition_not_same_bound(Relation parent,
5797
                   Oid splitPartOid,
5798
                   SinglePartitionSpec **parts,
5799
                   int nparts,
5800
                   ParseState *pstate)
5801
0
{
5802
0
  PartitionKey key = RelationGetPartitionKey(parent);
5803
0
  PartitionBoundSpec *new_spec;
5804
0
  PartitionBoundSpec *split_spec;
5805
5806
0
  if (nparts != 1)
5807
0
    return;
5808
5809
0
  new_spec = parts[0]->bound;
5810
0
  split_spec = get_partition_bound_spec(splitPartOid);
5811
5812
0
  Assert(new_spec->strategy == split_spec->strategy);
5813
5814
0
  if (key->strategy == PARTITION_STRATEGY_RANGE)
5815
0
  {
5816
0
    PartitionRangeBound *new_lower;
5817
0
    PartitionRangeBound *new_upper;
5818
0
    PartitionRangeBound *split_lower;
5819
0
    PartitionRangeBound *split_upper;
5820
5821
0
    new_lower = make_one_partition_rbound(key, -1, new_spec->lowerdatums, true);
5822
0
    new_upper = make_one_partition_rbound(key, -1, new_spec->upperdatums, false);
5823
0
    split_lower = make_one_partition_rbound(key, -1, split_spec->lowerdatums, true);
5824
0
    split_upper = make_one_partition_rbound(key, -1, split_spec->upperdatums, false);
5825
5826
0
    if (partition_rbound_cmp(key->partnatts, key->partsupfunc,
5827
0
                 key->partcollation,
5828
0
                 new_lower->datums, new_lower->kind, true,
5829
0
                 split_lower) != 0)
5830
0
      return;
5831
0
    if (partition_rbound_cmp(key->partnatts, key->partsupfunc,
5832
0
                 key->partcollation,
5833
0
                 new_upper->datums, new_upper->kind, false,
5834
0
                 split_upper) != 0)
5835
0
      return;
5836
0
  }
5837
0
  else
5838
0
  {
5839
0
    Assert(key->strategy == PARTITION_STRATEGY_LIST);
5840
5841
0
    if (!split_partition_values_contained_in_new_part(parent, splitPartOid,
5842
0
                              parts[0]))
5843
0
      return;
5844
0
  }
5845
5846
0
  ereport(ERROR,
5847
0
      errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
5848
0
      errmsg("cannot split partition \"%s\" only to add a DEFAULT partition",
5849
0
           get_rel_name(splitPartOid)),
5850
0
      errdetail("The non-DEFAULT partition would keep the same partition bound."),
5851
0
      errhint("Use CREATE TABLE ... PARTITION OF ... DEFAULT to add a DEFAULT partition."),
5852
0
      parser_errposition(pstate, parts[0]->name->location));
5853
0
}
5854
5855
/*
5856
 * check_partitions_for_split
5857
 *
5858
 * Checks new partitions for the SPLIT PARTITION command:
5859
 * 1. Bounds of new partitions should not overlap with new and existing
5860
 *    partitions.
5861
 * 2. In the case when new or existing partitions contain the DEFAULT
5862
 *    partition, new partitions can have any bounds inside the split partition
5863
 *    bound (can be spaces between partition bounds).
5864
 * 3. In case new partitions don't contain the DEFAULT partition and the
5865
 *    partitioned table does not have the DEFAULT partition, the following
5866
 *    should be true: the sum of the bounds of new partitions should be equal
5867
 *    to the bound of the split partition.
5868
 *
5869
 * parent:      partitioned table
5870
 * splitPartOid:  split partition Oid
5871
 * partlist:    list of new partitions after partition split
5872
 * pstate:      pointer to ParseState struct for determine error position
5873
 */
5874
void
5875
check_partitions_for_split(Relation parent,
5876
               Oid splitPartOid,
5877
               List *partlist,
5878
               ParseState *pstate)
5879
0
{
5880
0
  PartitionKey key;
5881
0
  char    strategy;
5882
0
  Oid     defaultPartOid;
5883
0
  bool    isSplitPartDefault;
5884
0
  bool    createDefaultPart = false;
5885
0
  int     default_index = -1;
5886
0
  int     i;
5887
0
  SinglePartitionSpec **new_parts;
5888
0
  SinglePartitionSpec *spsPrev = NULL;
5889
5890
  /*
5891
   * nparts counts the number of split partitions, but it exclude the
5892
   * default partition.
5893
   */
5894
0
  int     nparts = 0;
5895
5896
0
  key = RelationGetPartitionKey(parent);
5897
0
  strategy = get_partition_strategy(key);
5898
5899
0
  defaultPartOid =
5900
0
    get_default_oid_from_partdesc(RelationGetPartitionDesc(parent, true));
5901
5902
0
  Assert(strategy == PARTITION_STRATEGY_RANGE ||
5903
0
       strategy == PARTITION_STRATEGY_LIST);
5904
5905
  /*
5906
   * Make an array new_parts with new partitions except the DEFAULT
5907
   * partition.
5908
   */
5909
0
  new_parts = palloc0_array(SinglePartitionSpec *, list_length(partlist));
5910
5911
  /* isSplitPartDefault flag: is split partition a DEFAULT partition? */
5912
0
  isSplitPartDefault = (defaultPartOid == splitPartOid);
5913
5914
0
  foreach_node(SinglePartitionSpec, sps, partlist)
5915
0
  {
5916
0
    if (sps->bound->is_default)
5917
0
      default_index = foreach_current_index(sps);
5918
0
    else
5919
0
      new_parts[nparts++] = sps;
5920
0
  }
5921
5922
  /* An indicator that the DEFAULT partition will be created. */
5923
0
  if (default_index != -1)
5924
0
  {
5925
0
    createDefaultPart = true;
5926
0
    Assert(nparts == list_length(partlist) - 1);
5927
0
  }
5928
5929
0
  if (strategy == PARTITION_STRATEGY_RANGE)
5930
0
  {
5931
0
    PartitionRangeBound **lower_bounds;
5932
0
    SinglePartitionSpec **tmp_new_parts;
5933
5934
    /*
5935
     * To simplify the check for ranges of new partitions, we need to sort
5936
     * all partitions in ascending order of their bounds (we compare the
5937
     * lower bound only).
5938
     */
5939
0
    lower_bounds = palloc0_array(PartitionRangeBound *, nparts);
5940
5941
    /* Create an array of lower bounds. */
5942
0
    for (i = 0; i < nparts; i++)
5943
0
    {
5944
0
      lower_bounds[i] = make_one_partition_rbound(key, i,
5945
0
                            new_parts[i]->bound->lowerdatums, true);
5946
0
    }
5947
5948
    /* Sort the array of lower bounds. */
5949
0
    qsort_arg(lower_bounds, nparts, sizeof(PartitionRangeBound *),
5950
0
          qsort_partition_rbound_cmp, (void *) key);
5951
5952
    /* Reorder the array of partitions. */
5953
0
    tmp_new_parts = new_parts;
5954
0
    new_parts = palloc0_array(SinglePartitionSpec *, nparts);
5955
0
    for (i = 0; i < nparts; i++)
5956
0
      new_parts[i] = tmp_new_parts[lower_bounds[i]->index];
5957
5958
0
    pfree(tmp_new_parts);
5959
0
    pfree(lower_bounds);
5960
0
  }
5961
5962
0
  for (i = 0; i < nparts; i++)
5963
0
  {
5964
0
    SinglePartitionSpec *sps = new_parts[i];
5965
5966
0
    if (isSplitPartDefault)
5967
0
    {
5968
      /*
5969
       * When the split partition is the DEFAULT partition, we can use
5970
       * any free ranges - as when creating a new partition.
5971
       */
5972
0
      check_new_partition_bound(sps->name->relname, parent, sps->bound,
5973
0
                    pstate);
5974
0
    }
5975
0
    else
5976
0
    {
5977
      /*
5978
       * Checks that the bounds of the current partition are inside the
5979
       * bounds of the split partition. For range partitioning: checks
5980
       * that the upper bound of the previous partition is equal to the
5981
       * lower bound of the current partition. For list partitioning:
5982
       * checks that the split partition contains all values of the
5983
       * current partition.
5984
       */
5985
0
      if (strategy == PARTITION_STRATEGY_RANGE)
5986
0
      {
5987
0
        bool    first = (i == 0);
5988
0
        bool    last = (i == (nparts - 1));
5989
5990
0
        check_partition_bounds_for_split_range(parent, sps->name->relname, sps->bound,
5991
0
                             splitPartOid, first, last,
5992
0
                             createDefaultPart, pstate);
5993
0
      }
5994
0
      else
5995
0
        check_partition_bounds_for_split_list(parent, sps->name->relname,
5996
0
                            sps->bound, splitPartOid, pstate);
5997
0
    }
5998
5999
    /* Ranges of new partitions should not overlap. */
6000
0
    if (strategy == PARTITION_STRATEGY_RANGE && spsPrev)
6001
0
      check_two_partitions_bounds_range(parent, spsPrev->name, spsPrev->bound,
6002
0
                        sps->name, sps->bound,
6003
0
                        createDefaultPart,
6004
0
                        false,
6005
0
                        pstate);
6006
6007
0
    spsPrev = sps;
6008
0
  }
6009
6010
0
  if (strategy == PARTITION_STRATEGY_LIST)
6011
0
  {
6012
    /* Values of new partitions should not overlap. */
6013
0
    check_partitions_not_overlap_list(parent, new_parts, nparts,
6014
0
                      pstate);
6015
6016
    /*
6017
     * Need to check that all values of the split partition are contained
6018
     * in the new partitions. Skip this check if the DEFAULT partition
6019
     * exists.
6020
     */
6021
0
    if (!createDefaultPart)
6022
0
      check_parent_values_in_new_partitions(parent, splitPartOid,
6023
0
                          new_parts, nparts, pstate);
6024
0
  }
6025
6026
  /*
6027
   * Reject the degenerate form where the single non-DEFAULT replacement
6028
   * partition keeps the bound of the split partition; the command then does
6029
   * nothing beyond adding a DEFAULT partition.  Containment was established
6030
   * by the per-partition validation above, so an equality check is enough.
6031
   */
6032
0
  if (!isSplitPartDefault && createDefaultPart)
6033
0
    check_split_partition_not_same_bound(parent, splitPartOid, new_parts,
6034
0
                       nparts, pstate);
6035
6036
0
  pfree(new_parts);
6037
0
}