LCOV - differential code coverage report
Current view: top level - src/backend/partitioning - partbounds.c (source / functions) Coverage Total Hit UNC LBC UIC UBC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 95.5 % 1572 1501 3 13 54 1 17 962 6 516 52 964 1 8
Current Date: 2023-04-08 15:15:32 Functions: 98.1 % 52 51 1 51 1 51
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

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

Generated by: LCOV version v1.16-55-g56c0a2a