LCOV - code coverage report
Current view: top level - src/backend/partitioning - partbounds.c (source / functions) Hit Total Coverage
Test: PostgreSQL 12beta2 Lines: 896 930 96.3 %
Date: 2019-06-19 16:07:09 Functions: 32 32 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * partbounds.c
       4             :  *      Support routines for manipulating partition bounds
       5             :  *
       6             :  * Portions Copyright (c) 1996-2019, 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 "executor/executor.h"
      25             : #include "miscadmin.h"
      26             : #include "nodes/makefuncs.h"
      27             : #include "nodes/nodeFuncs.h"
      28             : #include "parser/parse_coerce.h"
      29             : #include "partitioning/partbounds.h"
      30             : #include "partitioning/partdesc.h"
      31             : #include "partitioning/partprune.h"
      32             : #include "utils/builtins.h"
      33             : #include "utils/datum.h"
      34             : #include "utils/fmgroids.h"
      35             : #include "utils/hashutils.h"
      36             : #include "utils/lsyscache.h"
      37             : #include "utils/partcache.h"
      38             : #include "utils/rel.h"
      39             : #include "utils/snapmgr.h"
      40             : #include "utils/ruleutils.h"
      41             : #include "utils/syscache.h"
      42             : 
      43             : /*
      44             :  * When qsort'ing partition bounds after reading from the catalog, each bound
      45             :  * is represented with one of the following structs.
      46             :  */
      47             : 
      48             : /* One bound of a hash partition */
      49             : typedef struct PartitionHashBound
      50             : {
      51             :     int         modulus;
      52             :     int         remainder;
      53             :     int         index;
      54             : } PartitionHashBound;
      55             : 
      56             : /* One value coming from some (index'th) list partition */
      57             : typedef struct PartitionListValue
      58             : {
      59             :     int         index;
      60             :     Datum       value;
      61             : } PartitionListValue;
      62             : 
      63             : /* One bound of a range partition */
      64             : typedef struct PartitionRangeBound
      65             : {
      66             :     int         index;
      67             :     Datum      *datums;         /* range bound datums */
      68             :     PartitionRangeDatumKind *kind;  /* the kind of each datum */
      69             :     bool        lower;          /* this is the lower (vs upper) bound */
      70             : } PartitionRangeBound;
      71             : 
      72             : static int32 qsort_partition_hbound_cmp(const void *a, const void *b);
      73             : static int32 qsort_partition_list_value_cmp(const void *a, const void *b,
      74             :                                             void *arg);
      75             : static int32 qsort_partition_rbound_cmp(const void *a, const void *b,
      76             :                                         void *arg);
      77             : static PartitionBoundInfo create_hash_bounds(PartitionBoundSpec **boundspecs,
      78             :                                              int nparts, PartitionKey key, int **mapping);
      79             : static PartitionBoundInfo create_list_bounds(PartitionBoundSpec **boundspecs,
      80             :                                              int nparts, PartitionKey key, int **mapping);
      81             : static PartitionBoundInfo create_range_bounds(PartitionBoundSpec **boundspecs,
      82             :                                               int nparts, PartitionKey key, int **mapping);
      83             : static PartitionRangeBound *make_one_partition_rbound(PartitionKey key, int index,
      84             :                                                       List *datums, bool lower);
      85             : static int32 partition_hbound_cmp(int modulus1, int remainder1, int modulus2,
      86             :                                   int remainder2);
      87             : static int32 partition_rbound_cmp(int partnatts, FmgrInfo *partsupfunc,
      88             :                                   Oid *partcollation, Datum *datums1,
      89             :                                   PartitionRangeDatumKind *kind1, bool lower1,
      90             :                                   PartitionRangeBound *b2);
      91             : static int  partition_range_bsearch(int partnatts, FmgrInfo *partsupfunc,
      92             :                                     Oid *partcollation,
      93             :                                     PartitionBoundInfo boundinfo,
      94             :                                     PartitionRangeBound *probe, bool *is_equal);
      95             : static int  get_partition_bound_num_indexes(PartitionBoundInfo b);
      96             : static Expr *make_partition_op_expr(PartitionKey key, int keynum,
      97             :                                     uint16 strategy, Expr *arg1, Expr *arg2);
      98             : static Oid  get_partition_operator(PartitionKey key, int col,
      99             :                                    StrategyNumber strategy, bool *need_relabel);
     100             : static List *get_qual_for_hash(Relation parent, PartitionBoundSpec *spec);
     101             : static List *get_qual_for_list(Relation parent, PartitionBoundSpec *spec);
     102             : static List *get_qual_for_range(Relation parent, PartitionBoundSpec *spec,
     103             :                                 bool for_default);
     104             : static void get_range_key_properties(PartitionKey key, int keynum,
     105             :                                      PartitionRangeDatum *ldatum,
     106             :                                      PartitionRangeDatum *udatum,
     107             :                                      ListCell **partexprs_item,
     108             :                                      Expr **keyCol,
     109             :                                      Const **lower_val, Const **upper_val);
     110             : static List *get_range_nulltest(PartitionKey key);
     111             : 
     112             : /*
     113             :  * get_qual_from_partbound
     114             :  *      Given a parser node for partition bound, return the list of executable
     115             :  *      expressions as partition constraint
     116             :  */
     117             : List *
     118        4232 : get_qual_from_partbound(Relation rel, Relation parent,
     119             :                         PartitionBoundSpec *spec)
     120             : {
     121        4232 :     PartitionKey key = RelationGetPartitionKey(parent);
     122        4232 :     List       *my_qual = NIL;
     123             : 
     124             :     Assert(key != NULL);
     125             : 
     126        4232 :     switch (key->strategy)
     127             :     {
     128             :         case PARTITION_STRATEGY_HASH:
     129             :             Assert(spec->strategy == PARTITION_STRATEGY_HASH);
     130         142 :             my_qual = get_qual_for_hash(parent, spec);
     131         142 :             break;
     132             : 
     133             :         case PARTITION_STRATEGY_LIST:
     134             :             Assert(spec->strategy == PARTITION_STRATEGY_LIST);
     135        1774 :             my_qual = get_qual_for_list(parent, spec);
     136        1774 :             break;
     137             : 
     138             :         case PARTITION_STRATEGY_RANGE:
     139             :             Assert(spec->strategy == PARTITION_STRATEGY_RANGE);
     140        2316 :             my_qual = get_qual_for_range(parent, spec, false);
     141        2316 :             break;
     142             : 
     143             :         default:
     144           0 :             elog(ERROR, "unexpected partition strategy: %d",
     145             :                  (int) key->strategy);
     146             :     }
     147             : 
     148        4232 :     return my_qual;
     149             : }
     150             : 
     151             : /*
     152             :  *  partition_bounds_create
     153             :  *      Build a PartitionBoundInfo struct from a list of PartitionBoundSpec
     154             :  *      nodes
     155             :  *
     156             :  * This function creates a PartitionBoundInfo and fills the values of its
     157             :  * various members based on the input list.  Importantly, 'datums' array will
     158             :  * contain Datum representation of individual bounds (possibly after
     159             :  * de-duplication as in case of range bounds), sorted in a canonical order
     160             :  * defined by qsort_partition_* functions of respective partitioning methods.
     161             :  * 'indexes' array will contain as many elements as there are bounds (specific
     162             :  * exceptions to this rule are listed in the function body), which represent
     163             :  * the 0-based canonical positions of partitions.
     164             :  *
     165             :  * Upon return from this function, *mapping is set to an array of
     166             :  * list_length(boundspecs) elements, each of which maps the original index of
     167             :  * a partition to its canonical index.
     168             :  *
     169             :  * Note: The objects returned by this function are wholly allocated in the
     170             :  * current memory context.
     171             :  */
     172             : PartitionBoundInfo
     173       10522 : partition_bounds_create(PartitionBoundSpec **boundspecs, int nparts,
     174             :                         PartitionKey key, int **mapping)
     175             : {
     176             :     int         i;
     177             : 
     178             :     Assert(nparts > 0);
     179             : 
     180             :     /*
     181             :      * For each partitioning method, we first convert the partition bounds
     182             :      * from their parser node representation to the internal representation,
     183             :      * along with any additional preprocessing (such as de-duplicating range
     184             :      * bounds).  Resulting bound datums are then added to the 'datums' array
     185             :      * in PartitionBoundInfo.  For each datum added, an integer indicating the
     186             :      * canonical partition index is added to the 'indexes' array.
     187             :      *
     188             :      * For each bound, we remember its partition's position (0-based) in the
     189             :      * original list to later map it to the canonical index.
     190             :      */
     191             : 
     192             :     /*
     193             :      * Initialize mapping array with invalid values, this is filled within
     194             :      * each sub-routine below depending on the bound type.
     195             :      */
     196       10522 :     *mapping = (int *) palloc(sizeof(int) * nparts);
     197       32022 :     for (i = 0; i < nparts; i++)
     198       21500 :         (*mapping)[i] = -1;
     199             : 
     200       10522 :     switch (key->strategy)
     201             :     {
     202             :         case PARTITION_STRATEGY_HASH:
     203         338 :             return create_hash_bounds(boundspecs, nparts, key, mapping);
     204             : 
     205             :         case PARTITION_STRATEGY_LIST:
     206        4856 :             return create_list_bounds(boundspecs, nparts, key, mapping);
     207             : 
     208             :         case PARTITION_STRATEGY_RANGE:
     209        5328 :             return create_range_bounds(boundspecs, nparts, key, mapping);
     210             : 
     211             :         default:
     212           0 :             elog(ERROR, "unexpected partition strategy: %d",
     213             :                  (int) key->strategy);
     214             :             break;
     215             :     }
     216             : 
     217             :     Assert(false);
     218             :     return NULL;                /* keep compiler quiet */
     219             : }
     220             : 
     221             : /*
     222             :  * create_hash_bounds
     223             :  *      Create a PartitionBoundInfo for a hash partitioned table
     224             :  */
     225             : static PartitionBoundInfo
     226         338 : create_hash_bounds(PartitionBoundSpec **boundspecs, int nparts,
     227             :                    PartitionKey key, int **mapping)
     228             : {
     229             :     PartitionBoundInfo boundinfo;
     230         338 :     PartitionHashBound **hbounds = NULL;
     231             :     int         i;
     232         338 :     int         ndatums = 0;
     233             :     int         greatest_modulus;
     234             : 
     235         338 :     boundinfo = (PartitionBoundInfoData *)
     236             :         palloc0(sizeof(PartitionBoundInfoData));
     237         338 :     boundinfo->strategy = key->strategy;
     238             :     /* No special hash partitions. */
     239         338 :     boundinfo->null_index = -1;
     240         338 :     boundinfo->default_index = -1;
     241             : 
     242         338 :     ndatums = nparts;
     243         338 :     hbounds = (PartitionHashBound **)
     244         338 :         palloc(nparts * sizeof(PartitionHashBound *));
     245             : 
     246             :     /* Convert from node to the internal representation */
     247        1042 :     for (i = 0; i < nparts; i++)
     248             :     {
     249         704 :         PartitionBoundSpec *spec = boundspecs[i];
     250             : 
     251         704 :         if (spec->strategy != PARTITION_STRATEGY_HASH)
     252           0 :             elog(ERROR, "invalid strategy in partition bound spec");
     253             : 
     254         704 :         hbounds[i] = (PartitionHashBound *) palloc(sizeof(PartitionHashBound));
     255         704 :         hbounds[i]->modulus = spec->modulus;
     256         704 :         hbounds[i]->remainder = spec->remainder;
     257         704 :         hbounds[i]->index = i;
     258             :     }
     259             : 
     260             :     /* Sort all the bounds in ascending order */
     261         338 :     qsort(hbounds, nparts, sizeof(PartitionHashBound *),
     262             :           qsort_partition_hbound_cmp);
     263             : 
     264             :     /* After sorting, moduli are now stored in ascending order. */
     265         338 :     greatest_modulus = hbounds[ndatums - 1]->modulus;
     266             : 
     267         338 :     boundinfo->ndatums = ndatums;
     268         338 :     boundinfo->datums = (Datum **) palloc0(ndatums * sizeof(Datum *));
     269         338 :     boundinfo->indexes = (int *) palloc(greatest_modulus * sizeof(int));
     270        2504 :     for (i = 0; i < greatest_modulus; i++)
     271        2166 :         boundinfo->indexes[i] = -1;
     272             : 
     273             :     /*
     274             :      * For hash partitioning, there are as many datums (modulus and remainder
     275             :      * pairs) as there are partitions.  Indexes are simply values ranging from
     276             :      * 0 to (nparts - 1).
     277             :      */
     278        1042 :     for (i = 0; i < nparts; i++)
     279             :     {
     280         704 :         int         modulus = hbounds[i]->modulus;
     281         704 :         int         remainder = hbounds[i]->remainder;
     282             : 
     283         704 :         boundinfo->datums[i] = (Datum *) palloc(2 * sizeof(Datum));
     284         704 :         boundinfo->datums[i][0] = Int32GetDatum(modulus);
     285         704 :         boundinfo->datums[i][1] = Int32GetDatum(remainder);
     286             : 
     287        2264 :         while (remainder < greatest_modulus)
     288             :         {
     289             :             /* overlap? */
     290             :             Assert(boundinfo->indexes[remainder] == -1);
     291         856 :             boundinfo->indexes[remainder] = i;
     292         856 :             remainder += modulus;
     293             :         }
     294             : 
     295         704 :         (*mapping)[hbounds[i]->index] = i;
     296         704 :         pfree(hbounds[i]);
     297             :     }
     298         338 :     pfree(hbounds);
     299             : 
     300         338 :     return boundinfo;
     301             : }
     302             : 
     303             : /*
     304             :  * create_list_bounds
     305             :  *      Create a PartitionBoundInfo for a list partitioned table
     306             :  */
     307             : static PartitionBoundInfo
     308        4856 : create_list_bounds(PartitionBoundSpec **boundspecs, int nparts,
     309             :                    PartitionKey key, int **mapping)
     310             : {
     311             :     PartitionBoundInfo boundinfo;
     312        4856 :     PartitionListValue **all_values = NULL;
     313             :     ListCell   *cell;
     314        4856 :     int         i = 0;
     315        4856 :     int         ndatums = 0;
     316        4856 :     int         next_index = 0;
     317        4856 :     int         default_index = -1;
     318        4856 :     int         null_index = -1;
     319        4856 :     List       *non_null_values = NIL;
     320             : 
     321        4856 :     boundinfo = (PartitionBoundInfoData *)
     322             :         palloc0(sizeof(PartitionBoundInfoData));
     323        4856 :     boundinfo->strategy = key->strategy;
     324             :     /* Will be set correctly below. */
     325        4856 :     boundinfo->null_index = -1;
     326        4856 :     boundinfo->default_index = -1;
     327             : 
     328             :     /* Create a unified list of non-null values across all partitions. */
     329       14724 :     for (i = 0; i < nparts; i++)
     330             :     {
     331        9868 :         PartitionBoundSpec *spec = boundspecs[i];
     332             :         ListCell   *c;
     333             : 
     334        9868 :         if (spec->strategy != PARTITION_STRATEGY_LIST)
     335           0 :             elog(ERROR, "invalid strategy in partition bound spec");
     336             : 
     337             :         /*
     338             :          * Note the index of the partition bound spec for the default
     339             :          * partition.  There's no datum to add to the list on non-null datums
     340             :          * for this partition.
     341             :          */
     342        9868 :         if (spec->is_default)
     343             :         {
     344         596 :             default_index = i;
     345         596 :             continue;
     346             :         }
     347             : 
     348       22608 :         foreach(c, spec->listdatums)
     349             :         {
     350       13336 :             Const      *val = castNode(Const, lfirst(c));
     351       13336 :             PartitionListValue *list_value = NULL;
     352             : 
     353       13336 :             if (!val->constisnull)
     354             :             {
     355       12924 :                 list_value = (PartitionListValue *)
     356             :                     palloc0(sizeof(PartitionListValue));
     357       12924 :                 list_value->index = i;
     358       12924 :                 list_value->value = val->constvalue;
     359             :             }
     360             :             else
     361             :             {
     362             :                 /*
     363             :                  * Never put a null into the values array, flag instead for
     364             :                  * the code further down below where we construct the actual
     365             :                  * relcache struct.
     366             :                  */
     367         412 :                 if (null_index != -1)
     368           0 :                     elog(ERROR, "found null more than once");
     369         412 :                 null_index = i;
     370             :             }
     371             : 
     372       13336 :             if (list_value)
     373       12924 :                 non_null_values = lappend(non_null_values, list_value);
     374             :         }
     375             :     }
     376             : 
     377        4856 :     ndatums = list_length(non_null_values);
     378             : 
     379             :     /*
     380             :      * Collect all list values in one array. Alongside the value, we also save
     381             :      * the index of partition the value comes from.
     382             :      */
     383        4856 :     all_values = (PartitionListValue **)
     384        4856 :         palloc(ndatums * sizeof(PartitionListValue *));
     385        4856 :     i = 0;
     386       17780 :     foreach(cell, non_null_values)
     387             :     {
     388       12924 :         PartitionListValue *src = lfirst(cell);
     389             : 
     390       25848 :         all_values[i] = (PartitionListValue *)
     391       12924 :             palloc(sizeof(PartitionListValue));
     392       12924 :         all_values[i]->value = src->value;
     393       12924 :         all_values[i]->index = src->index;
     394       12924 :         i++;
     395             :     }
     396             : 
     397        4856 :     qsort_arg(all_values, ndatums, sizeof(PartitionListValue *),
     398             :               qsort_partition_list_value_cmp, (void *) key);
     399             : 
     400        4856 :     boundinfo->ndatums = ndatums;
     401        4856 :     boundinfo->datums = (Datum **) palloc0(ndatums * sizeof(Datum *));
     402        4856 :     boundinfo->indexes = (int *) palloc(ndatums * sizeof(int));
     403             : 
     404             :     /*
     405             :      * Copy values.  Canonical indexes are values ranging from 0 to (nparts -
     406             :      * 1) assigned to each partition such that all datums of a given partition
     407             :      * receive the same value. The value for a given partition is the index of
     408             :      * that partition's smallest datum in the all_values[] array.
     409             :      */
     410       17780 :     for (i = 0; i < ndatums; i++)
     411             :     {
     412       12924 :         int         orig_index = all_values[i]->index;
     413             : 
     414       12924 :         boundinfo->datums[i] = (Datum *) palloc(sizeof(Datum));
     415       38772 :         boundinfo->datums[i][0] = datumCopy(all_values[i]->value,
     416       12924 :                                             key->parttypbyval[0],
     417       12924 :                                             key->parttyplen[0]);
     418             : 
     419             :         /* If the old index has no mapping, assign one */
     420       12924 :         if ((*mapping)[orig_index] == -1)
     421        9172 :             (*mapping)[orig_index] = next_index++;
     422             : 
     423       12924 :         boundinfo->indexes[i] = (*mapping)[orig_index];
     424             :     }
     425             : 
     426             :     /*
     427             :      * Set the canonical value for null_index, if any.
     428             :      *
     429             :      * It is possible that the null-accepting partition has not been assigned
     430             :      * an index yet, which could happen if such partition accepts only null
     431             :      * and hence not handled in the above loop which only looked at non-null
     432             :      * values.
     433             :      */
     434        4856 :     if (null_index != -1)
     435             :     {
     436             :         Assert(null_index >= 0);
     437         412 :         if ((*mapping)[null_index] == -1)
     438         100 :             (*mapping)[null_index] = next_index++;
     439         412 :         boundinfo->null_index = (*mapping)[null_index];
     440             :     }
     441             : 
     442             :     /* Set the canonical value for default_index, if any. */
     443        4856 :     if (default_index != -1)
     444             :     {
     445             :         /*
     446             :          * The default partition accepts any value not specified in the lists
     447             :          * of other partitions, hence it should not get mapped index while
     448             :          * assigning those for non-null datums.
     449             :          */
     450             :         Assert(default_index >= 0);
     451             :         Assert((*mapping)[default_index] == -1);
     452         596 :         (*mapping)[default_index] = next_index++;
     453         596 :         boundinfo->default_index = (*mapping)[default_index];
     454             :     }
     455             : 
     456             :     /* All partition must now have been assigned canonical indexes. */
     457             :     Assert(next_index == nparts);
     458        4856 :     return boundinfo;
     459             : }
     460             : 
     461             : /*
     462             :  * create_range_bounds
     463             :  *      Create a PartitionBoundInfo for a range partitioned table
     464             :  */
     465             : static PartitionBoundInfo
     466        5328 : create_range_bounds(PartitionBoundSpec **boundspecs, int nparts,
     467             :                     PartitionKey key, int **mapping)
     468             : {
     469             :     PartitionBoundInfo boundinfo;
     470        5328 :     PartitionRangeBound **rbounds = NULL;
     471             :     PartitionRangeBound **all_bounds,
     472             :                *prev;
     473             :     int         i,
     474             :                 k;
     475        5328 :     int         ndatums = 0;
     476        5328 :     int         default_index = -1;
     477        5328 :     int         next_index = 0;
     478             : 
     479        5328 :     boundinfo = (PartitionBoundInfoData *)
     480             :         palloc0(sizeof(PartitionBoundInfoData));
     481        5328 :     boundinfo->strategy = key->strategy;
     482             :     /* There is no special null-accepting range partition. */
     483        5328 :     boundinfo->null_index = -1;
     484             :     /* Will be set correctly below. */
     485        5328 :     boundinfo->default_index = -1;
     486             : 
     487        5328 :     all_bounds = (PartitionRangeBound **)
     488        5328 :         palloc0(2 * nparts * sizeof(PartitionRangeBound *));
     489             : 
     490             :     /* Create a unified list of range bounds across all the partitions. */
     491        5328 :     ndatums = 0;
     492       16256 :     for (i = 0; i < nparts; i++)
     493             :     {
     494       10928 :         PartitionBoundSpec *spec = boundspecs[i];
     495             :         PartitionRangeBound *lower,
     496             :                    *upper;
     497             : 
     498       10928 :         if (spec->strategy != PARTITION_STRATEGY_RANGE)
     499           0 :             elog(ERROR, "invalid strategy in partition bound spec");
     500             : 
     501             :         /*
     502             :          * Note the index of the partition bound spec for the default
     503             :          * partition.  There's no datum to add to the all_bounds array for
     504             :          * this partition.
     505             :          */
     506       10928 :         if (spec->is_default)
     507             :         {
     508         578 :             default_index = i;
     509         578 :             continue;
     510             :         }
     511             : 
     512       10350 :         lower = make_one_partition_rbound(key, i, spec->lowerdatums, true);
     513       10350 :         upper = make_one_partition_rbound(key, i, spec->upperdatums, false);
     514       10350 :         all_bounds[ndatums++] = lower;
     515       10350 :         all_bounds[ndatums++] = upper;
     516             :     }
     517             : 
     518             :     Assert(ndatums == nparts * 2 ||
     519             :            (default_index != -1 && ndatums == (nparts - 1) * 2));
     520             : 
     521             :     /* Sort all the bounds in ascending order */
     522        5328 :     qsort_arg(all_bounds, ndatums,
     523             :               sizeof(PartitionRangeBound *),
     524             :               qsort_partition_rbound_cmp,
     525             :               (void *) key);
     526             : 
     527             :     /* Save distinct bounds from all_bounds into rbounds. */
     528        5328 :     rbounds = (PartitionRangeBound **)
     529        5328 :         palloc(ndatums * sizeof(PartitionRangeBound *));
     530        5328 :     k = 0;
     531        5328 :     prev = NULL;
     532       26028 :     for (i = 0; i < ndatums; i++)
     533             :     {
     534       20700 :         PartitionRangeBound *cur = all_bounds[i];
     535       20700 :         bool        is_distinct = false;
     536             :         int         j;
     537             : 
     538             :         /* Is the current bound distinct from the previous one? */
     539       29178 :         for (j = 0; j < key->partnatts; j++)
     540             :         {
     541             :             Datum       cmpval;
     542             : 
     543       24628 :             if (prev == NULL || cur->kind[j] != prev->kind[j])
     544             :             {
     545        5844 :                 is_distinct = true;
     546        5844 :                 break;
     547             :             }
     548             : 
     549             :             /*
     550             :              * If the bounds are both MINVALUE or MAXVALUE, stop now and treat
     551             :              * them as equal, since any values after this point must be
     552             :              * ignored.
     553             :              */
     554       18784 :             if (cur->kind[j] != PARTITION_RANGE_DATUM_VALUE)
     555         124 :                 break;
     556             : 
     557       55980 :             cmpval = FunctionCall2Coll(&key->partsupfunc[j],
     558       18660 :                                        key->partcollation[j],
     559       18660 :                                        cur->datums[j],
     560       18660 :                                        prev->datums[j]);
     561       18660 :             if (DatumGetInt32(cmpval) != 0)
     562             :             {
     563       10182 :                 is_distinct = true;
     564       10182 :                 break;
     565             :             }
     566             :         }
     567             : 
     568             :         /*
     569             :          * Only if the bound is distinct save it into a temporary array, i.e,
     570             :          * rbounds which is later copied into boundinfo datums array.
     571             :          */
     572       20700 :         if (is_distinct)
     573       16026 :             rbounds[k++] = all_bounds[i];
     574             : 
     575       20700 :         prev = cur;
     576             :     }
     577             : 
     578             :     /* Update ndatums to hold the count of distinct datums. */
     579        5328 :     ndatums = k;
     580             : 
     581             :     /*
     582             :      * Add datums to boundinfo.  Canonical indexes are values ranging from 0
     583             :      * to nparts - 1, assigned in that order to each partition's upper bound.
     584             :      * For 'datums' elements that are lower bounds, there is -1 in the
     585             :      * 'indexes' array to signify that no partition exists for the values less
     586             :      * than such a bound and greater than or equal to the previous upper
     587             :      * bound.
     588             :      */
     589        5328 :     boundinfo->ndatums = ndatums;
     590        5328 :     boundinfo->datums = (Datum **) palloc0(ndatums * sizeof(Datum *));
     591        5328 :     boundinfo->kind = (PartitionRangeDatumKind **)
     592        5328 :         palloc(ndatums *
     593             :                sizeof(PartitionRangeDatumKind *));
     594             : 
     595             :     /*
     596             :      * For range partitioning, an additional value of -1 is stored as the last
     597             :      * element.
     598             :      */
     599        5328 :     boundinfo->indexes = (int *) palloc((ndatums + 1) * sizeof(int));
     600             : 
     601       21354 :     for (i = 0; i < ndatums; i++)
     602             :     {
     603             :         int         j;
     604             : 
     605       16026 :         boundinfo->datums[i] = (Datum *) palloc(key->partnatts *
     606             :                                                 sizeof(Datum));
     607       32052 :         boundinfo->kind[i] = (PartitionRangeDatumKind *)
     608       16026 :             palloc(key->partnatts *
     609             :                    sizeof(PartitionRangeDatumKind));
     610       37192 :         for (j = 0; j < key->partnatts; j++)
     611             :         {
     612       21166 :             if (rbounds[i]->kind[j] == PARTITION_RANGE_DATUM_VALUE)
     613       39476 :                 boundinfo->datums[i][j] =
     614       39476 :                     datumCopy(rbounds[i]->datums[j],
     615       19738 :                               key->parttypbyval[j],
     616       19738 :                               key->parttyplen[j]);
     617       21166 :             boundinfo->kind[i][j] = rbounds[i]->kind[j];
     618             :         }
     619             : 
     620             :         /*
     621             :          * There is no mapping for invalid indexes.
     622             :          *
     623             :          * Any lower bounds in the rbounds array have invalid indexes
     624             :          * assigned, because the values between the previous bound (if there
     625             :          * is one) and this (lower) bound are not part of the range of any
     626             :          * existing partition.
     627             :          */
     628       16026 :         if (rbounds[i]->lower)
     629        5676 :             boundinfo->indexes[i] = -1;
     630             :         else
     631             :         {
     632       10350 :             int         orig_index = rbounds[i]->index;
     633             : 
     634             :             /* If the old index has no mapping, assign one */
     635       10350 :             if ((*mapping)[orig_index] == -1)
     636       10350 :                 (*mapping)[orig_index] = next_index++;
     637             : 
     638       10350 :             boundinfo->indexes[i] = (*mapping)[orig_index];
     639             :         }
     640             :     }
     641             : 
     642             :     /* Set the canonical value for default_index, if any. */
     643        5328 :     if (default_index != -1)
     644             :     {
     645             :         Assert(default_index >= 0 && (*mapping)[default_index] == -1);
     646         578 :         (*mapping)[default_index] = next_index++;
     647         578 :         boundinfo->default_index = (*mapping)[default_index];
     648             :     }
     649             : 
     650             :     /* The extra -1 element. */
     651             :     Assert(i == ndatums);
     652        5328 :     boundinfo->indexes[i] = -1;
     653             : 
     654             :     /* All partition must now have been assigned canonical indexes. */
     655             :     Assert(next_index == nparts);
     656        5328 :     return boundinfo;
     657             : }
     658             : 
     659             : /*
     660             :  * Are two partition bound collections logically equal?
     661             :  *
     662             :  * Used in the keep logic of relcache.c (ie, in RelationClearRelation()).
     663             :  * This is also useful when b1 and b2 are bound collections of two separate
     664             :  * relations, respectively, because PartitionBoundInfo is a canonical
     665             :  * representation of partition bounds.
     666             :  */
     667             : bool
     668        3030 : partition_bounds_equal(int partnatts, int16 *parttyplen, bool *parttypbyval,
     669             :                        PartitionBoundInfo b1, PartitionBoundInfo b2)
     670             : {
     671             :     int         i;
     672             : 
     673        3030 :     if (b1->strategy != b2->strategy)
     674           0 :         return false;
     675             : 
     676        3030 :     if (b1->ndatums != b2->ndatums)
     677          16 :         return false;
     678             : 
     679        3014 :     if (b1->null_index != b2->null_index)
     680           0 :         return false;
     681             : 
     682        3014 :     if (b1->default_index != b2->default_index)
     683           0 :         return false;
     684             : 
     685        3014 :     if (b1->strategy == PARTITION_STRATEGY_HASH)
     686             :     {
     687         106 :         int         greatest_modulus = get_hash_partition_greatest_modulus(b1);
     688             : 
     689             :         /*
     690             :          * If two hash partitioned tables have different greatest moduli,
     691             :          * their partition schemes don't match.
     692             :          */
     693         106 :         if (greatest_modulus != get_hash_partition_greatest_modulus(b2))
     694           0 :             return false;
     695             : 
     696             :         /*
     697             :          * We arrange the partitions in the ascending order of their moduli
     698             :          * and remainders.  Also every modulus is factor of next larger
     699             :          * modulus.  Therefore we can safely store index of a given partition
     700             :          * in indexes array at remainder of that partition.  Also entries at
     701             :          * (remainder + N * modulus) positions in indexes array are all same
     702             :          * for (modulus, remainder) specification for any partition.  Thus
     703             :          * datums array from both the given bounds are same, if and only if
     704             :          * their indexes array will be same.  So, it suffices to compare
     705             :          * indexes array.
     706             :          */
     707         424 :         for (i = 0; i < greatest_modulus; i++)
     708         318 :             if (b1->indexes[i] != b2->indexes[i])
     709           0 :                 return false;
     710             : 
     711             : #ifdef USE_ASSERT_CHECKING
     712             : 
     713             :         /*
     714             :          * Nonetheless make sure that the bounds are indeed same when the
     715             :          * indexes match.  Hash partition bound stores modulus and remainder
     716             :          * at b1->datums[i][0] and b1->datums[i][1] position respectively.
     717             :          */
     718             :         for (i = 0; i < b1->ndatums; i++)
     719             :             Assert((b1->datums[i][0] == b2->datums[i][0] &&
     720             :                     b1->datums[i][1] == b2->datums[i][1]));
     721             : #endif
     722             :     }
     723             :     else
     724             :     {
     725       11878 :         for (i = 0; i < b1->ndatums; i++)
     726             :         {
     727             :             int         j;
     728             : 
     729       18948 :             for (j = 0; j < partnatts; j++)
     730             :             {
     731             :                 /* For range partitions, the bounds might not be finite. */
     732        9978 :                 if (b1->kind != NULL)
     733             :                 {
     734             :                     /* The different kinds of bound all differ from each other */
     735        6792 :                     if (b1->kind[i][j] != b2->kind[i][j])
     736           0 :                         return false;
     737             : 
     738             :                     /*
     739             :                      * Non-finite bounds are equal without further
     740             :                      * examination.
     741             :                      */
     742        6792 :                     if (b1->kind[i][j] != PARTITION_RANGE_DATUM_VALUE)
     743         124 :                         continue;
     744             :                 }
     745             : 
     746             :                 /*
     747             :                  * Compare the actual values. Note that it would be both
     748             :                  * incorrect and unsafe to invoke the comparison operator
     749             :                  * derived from the partitioning specification here.  It would
     750             :                  * be incorrect because we want the relcache entry to be
     751             :                  * updated for ANY change to the partition bounds, not just
     752             :                  * those that the partitioning operator thinks are
     753             :                  * significant.  It would be unsafe because we might reach
     754             :                  * this code in the context of an aborted transaction, and an
     755             :                  * arbitrary partitioning operator might not be safe in that
     756             :                  * context.  datumIsEqual() should be simple enough to be
     757             :                  * safe.
     758             :                  */
     759       19708 :                 if (!datumIsEqual(b1->datums[i][j], b2->datums[i][j],
     760       19708 :                                   parttypbyval[j], parttyplen[j]))
     761           0 :                     return false;
     762             :             }
     763             : 
     764        8970 :             if (b1->indexes[i] != b2->indexes[i])
     765           0 :                 return false;
     766             :         }
     767             : 
     768             :         /* There are ndatums+1 indexes in case of range partitions */
     769        4768 :         if (b1->strategy == PARTITION_STRATEGY_RANGE &&
     770        1860 :             b1->indexes[i] != b2->indexes[i])
     771           0 :             return false;
     772             :     }
     773        3014 :     return true;
     774             : }
     775             : 
     776             : /*
     777             :  * Return a copy of given PartitionBoundInfo structure. The data types of bounds
     778             :  * are described by given partition key specification.
     779             :  */
     780             : PartitionBoundInfo
     781       10522 : partition_bounds_copy(PartitionBoundInfo src,
     782             :                       PartitionKey key)
     783             : {
     784             :     PartitionBoundInfo dest;
     785             :     int         i;
     786             :     int         ndatums;
     787             :     int         partnatts;
     788             :     int         num_indexes;
     789             : 
     790       10522 :     dest = (PartitionBoundInfo) palloc(sizeof(PartitionBoundInfoData));
     791             : 
     792       10522 :     dest->strategy = src->strategy;
     793       10522 :     ndatums = dest->ndatums = src->ndatums;
     794       10522 :     partnatts = key->partnatts;
     795             : 
     796       10522 :     num_indexes = get_partition_bound_num_indexes(src);
     797             : 
     798             :     /* List partitioned tables have only a single partition key. */
     799             :     Assert(key->strategy != PARTITION_STRATEGY_LIST || partnatts == 1);
     800             : 
     801       10522 :     dest->datums = (Datum **) palloc(sizeof(Datum *) * ndatums);
     802             : 
     803       10522 :     if (src->kind != NULL)
     804             :     {
     805        5328 :         dest->kind = (PartitionRangeDatumKind **) palloc(ndatums *
     806             :                                                          sizeof(PartitionRangeDatumKind *));
     807       21354 :         for (i = 0; i < ndatums; i++)
     808             :         {
     809       16026 :             dest->kind[i] = (PartitionRangeDatumKind *) palloc(partnatts *
     810             :                                                                sizeof(PartitionRangeDatumKind));
     811             : 
     812       16026 :             memcpy(dest->kind[i], src->kind[i],
     813       16026 :                    sizeof(PartitionRangeDatumKind) * key->partnatts);
     814             :         }
     815             :     }
     816             :     else
     817        5194 :         dest->kind = NULL;
     818             : 
     819       40176 :     for (i = 0; i < ndatums; i++)
     820             :     {
     821             :         int         j;
     822             : 
     823             :         /*
     824             :          * For a corresponding to hash partition, datums array will have two
     825             :          * elements - modulus and remainder.
     826             :          */
     827       29654 :         bool        hash_part = (key->strategy == PARTITION_STRATEGY_HASH);
     828       29654 :         int         natts = hash_part ? 2 : partnatts;
     829             : 
     830       29654 :         dest->datums[i] = (Datum *) palloc(sizeof(Datum) * natts);
     831             : 
     832       65152 :         for (j = 0; j < natts; j++)
     833             :         {
     834             :             bool        byval;
     835             :             int         typlen;
     836             : 
     837       35498 :             if (hash_part)
     838             :             {
     839        1408 :                 typlen = sizeof(int32); /* Always int4 */
     840        1408 :                 byval = true;   /* int4 is pass-by-value */
     841             :             }
     842             :             else
     843             :             {
     844       34090 :                 byval = key->parttypbyval[j];
     845       34090 :                 typlen = key->parttyplen[j];
     846             :             }
     847             : 
     848       56664 :             if (dest->kind == NULL ||
     849       21166 :                 dest->kind[i][j] == PARTITION_RANGE_DATUM_VALUE)
     850       34070 :                 dest->datums[i][j] = datumCopy(src->datums[i][j],
     851             :                                                byval, typlen);
     852             :         }
     853             :     }
     854             : 
     855       10522 :     dest->indexes = (int *) palloc(sizeof(int) * num_indexes);
     856       10522 :     memcpy(dest->indexes, src->indexes, sizeof(int) * num_indexes);
     857             : 
     858       10522 :     dest->null_index = src->null_index;
     859       10522 :     dest->default_index = src->default_index;
     860             : 
     861       10522 :     return dest;
     862             : }
     863             : 
     864             : /*
     865             :  * partitions_are_ordered
     866             :  *      Determine whether the partitions described by 'boundinfo' are ordered,
     867             :  *      that is partitions appearing earlier in the PartitionDesc sequence
     868             :  *      contain partition keys strictly less than those appearing later.
     869             :  *      Also, if NULL values are possible, they must come in the last
     870             :  *      partition defined in the PartitionDesc.
     871             :  *
     872             :  * If out of order, or there is insufficient info to know the order,
     873             :  * then we return false.
     874             :  */
     875             : bool
     876        9914 : partitions_are_ordered(PartitionBoundInfo boundinfo, int nparts)
     877             : {
     878             :     Assert(boundinfo != NULL);
     879             : 
     880        9914 :     switch (boundinfo->strategy)
     881             :     {
     882             :         case PARTITION_STRATEGY_RANGE:
     883             : 
     884             :             /*
     885             :              * RANGE-type partitioning guarantees that the partitions can be
     886             :              * scanned in the order that they're defined in the PartitionDesc
     887             :              * to provide sequential, non-overlapping ranges of tuples.
     888             :              * However, if a DEFAULT partition exists then it doesn't work, as
     889             :              * that could contain tuples from either below or above the
     890             :              * defined range, or tuples belonging to gaps between partitions.
     891             :              */
     892        5144 :             if (!partition_bound_has_default(boundinfo))
     893        4084 :                 return true;
     894        1060 :             break;
     895             : 
     896             :         case PARTITION_STRATEGY_LIST:
     897             : 
     898             :             /*
     899             :              * LIST partitioning can also guarantee ordering, but only if the
     900             :              * partitions don't accept interleaved values.  We could likely
     901             :              * check for this by looping over the PartitionBound's indexes
     902             :              * array to check that the indexes are in order.  For now, let's
     903             :              * just keep it simple and just accept LIST partitioning when
     904             :              * there's no DEFAULT partition, exactly one value per partition,
     905             :              * and optionally a NULL partition that does not accept any other
     906             :              * values.  Such a NULL partition will come last in the
     907             :              * PartitionDesc, and the other partitions will be properly
     908             :              * ordered.  This is a cheap test to make as it does not require
     909             :              * any per-partition processing.  Maybe we'd like to handle more
     910             :              * complex cases in the future.
     911             :              */
     912        4546 :             if (partition_bound_has_default(boundinfo))
     913         548 :                 return false;
     914             : 
     915        3998 :             if (boundinfo->ndatums + partition_bound_accepts_nulls(boundinfo)
     916             :                 == nparts)
     917        3264 :                 return true;
     918         734 :             break;
     919             : 
     920             :         default:
     921             :             /* HASH, or some other strategy */
     922         224 :             break;
     923             :     }
     924             : 
     925        2018 :     return false;
     926             : }
     927             : 
     928             : /*
     929             :  * check_new_partition_bound
     930             :  *
     931             :  * Checks if the new partition's bound overlaps any of the existing partitions
     932             :  * of parent.  Also performs additional checks as necessary per strategy.
     933             :  */
     934             : void
     935        4274 : check_new_partition_bound(char *relname, Relation parent,
     936             :                           PartitionBoundSpec *spec)
     937             : {
     938        4274 :     PartitionKey key = RelationGetPartitionKey(parent);
     939        4274 :     PartitionDesc partdesc = RelationGetPartitionDesc(parent);
     940        4274 :     PartitionBoundInfo boundinfo = partdesc->boundinfo;
     941        4274 :     ParseState *pstate = make_parsestate(NULL);
     942        4274 :     int         with = -1;
     943        4274 :     bool        overlap = false;
     944             : 
     945        4274 :     if (spec->is_default)
     946             :     {
     947             :         /*
     948             :          * The default partition bound never conflicts with any other
     949             :          * partition's; if that's what we're attaching, the only possible
     950             :          * problem is that one already exists, so check for that and we're
     951             :          * done.
     952             :          */
     953         238 :         if (boundinfo == NULL || !partition_bound_has_default(boundinfo))
     954         222 :             return;
     955             : 
     956             :         /* Default partition already exists, error out. */
     957          16 :         ereport(ERROR,
     958             :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     959             :                  errmsg("partition \"%s\" conflicts with existing default partition \"%s\"",
     960             :                         relname, get_rel_name(partdesc->oids[boundinfo->default_index])),
     961             :                  parser_errposition(pstate, spec->location)));
     962             :     }
     963             : 
     964        4036 :     switch (key->strategy)
     965             :     {
     966             :         case PARTITION_STRATEGY_HASH:
     967             :             {
     968             :                 Assert(spec->strategy == PARTITION_STRATEGY_HASH);
     969             :                 Assert(spec->remainder >= 0 && spec->remainder < spec->modulus);
     970             : 
     971         218 :                 if (partdesc->nparts > 0)
     972             :                 {
     973         152 :                     Datum     **datums = boundinfo->datums;
     974         152 :                     int         ndatums = boundinfo->ndatums;
     975             :                     int         greatest_modulus;
     976             :                     int         remainder;
     977             :                     int         offset;
     978         152 :                     bool        valid_modulus = true;
     979             :                     int         prev_modulus,   /* Previous largest modulus */
     980             :                                 next_modulus;   /* Next largest modulus */
     981             : 
     982             :                     /*
     983             :                      * Check rule that every modulus must be a factor of the
     984             :                      * next larger modulus.  For example, if you have a bunch
     985             :                      * of partitions that all have modulus 5, you can add a
     986             :                      * new partition with modulus 10 or a new partition with
     987             :                      * modulus 15, but you cannot add both a partition with
     988             :                      * modulus 10 and a partition with modulus 15, because 10
     989             :                      * is not a factor of 15.
     990             :                      *
     991             :                      * Get the greatest (modulus, remainder) pair contained in
     992             :                      * boundinfo->datums that is less than or equal to the
     993             :                      * (spec->modulus, spec->remainder) pair.
     994             :                      */
     995         152 :                     offset = partition_hash_bsearch(boundinfo,
     996             :                                                     spec->modulus,
     997             :                                                     spec->remainder);
     998         152 :                     if (offset < 0)
     999             :                     {
    1000           8 :                         next_modulus = DatumGetInt32(datums[0][0]);
    1001           8 :                         valid_modulus = (next_modulus % spec->modulus) == 0;
    1002             :                     }
    1003             :                     else
    1004             :                     {
    1005         144 :                         prev_modulus = DatumGetInt32(datums[offset][0]);
    1006         144 :                         valid_modulus = (spec->modulus % prev_modulus) == 0;
    1007             : 
    1008         144 :                         if (valid_modulus && (offset + 1) < ndatums)
    1009             :                         {
    1010          12 :                             next_modulus = DatumGetInt32(datums[offset + 1][0]);
    1011          12 :                             valid_modulus = (next_modulus % spec->modulus) == 0;
    1012             :                         }
    1013             :                     }
    1014             : 
    1015         152 :                     if (!valid_modulus)
    1016          12 :                         ereport(ERROR,
    1017             :                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1018             :                                  errmsg("every hash partition modulus must be a factor of the next larger modulus")));
    1019             : 
    1020         140 :                     greatest_modulus = get_hash_partition_greatest_modulus(boundinfo);
    1021         140 :                     remainder = spec->remainder;
    1022             : 
    1023             :                     /*
    1024             :                      * Normally, the lowest remainder that could conflict with
    1025             :                      * the new partition is equal to the remainder specified
    1026             :                      * for the new partition, but when the new partition has a
    1027             :                      * modulus higher than any used so far, we need to adjust.
    1028             :                      */
    1029         140 :                     if (remainder >= greatest_modulus)
    1030           8 :                         remainder = remainder % greatest_modulus;
    1031             : 
    1032             :                     /* Check every potentially-conflicting remainder. */
    1033             :                     do
    1034             :                     {
    1035         148 :                         if (boundinfo->indexes[remainder] != -1)
    1036             :                         {
    1037          12 :                             overlap = true;
    1038          12 :                             with = boundinfo->indexes[remainder];
    1039          12 :                             break;
    1040             :                         }
    1041         136 :                         remainder += spec->modulus;
    1042         136 :                     } while (remainder < greatest_modulus);
    1043             :                 }
    1044             : 
    1045         206 :                 break;
    1046             :             }
    1047             : 
    1048             :         case PARTITION_STRATEGY_LIST:
    1049             :             {
    1050             :                 Assert(spec->strategy == PARTITION_STRATEGY_LIST);
    1051             : 
    1052        1966 :                 if (partdesc->nparts > 0)
    1053             :                 {
    1054             :                     ListCell   *cell;
    1055             : 
    1056             :                     Assert(boundinfo &&
    1057             :                            boundinfo->strategy == PARTITION_STRATEGY_LIST &&
    1058             :                            (boundinfo->ndatums > 0 ||
    1059             :                             partition_bound_accepts_nulls(boundinfo) ||
    1060             :                             partition_bound_has_default(boundinfo)));
    1061             : 
    1062        2366 :                     foreach(cell, spec->listdatums)
    1063             :                     {
    1064        1376 :                         Const      *val = castNode(Const, lfirst(cell));
    1065             : 
    1066        1376 :                         if (!val->constisnull)
    1067             :                         {
    1068             :                             int         offset;
    1069             :                             bool        equal;
    1070             : 
    1071        1344 :                             offset = partition_list_bsearch(&key->partsupfunc[0],
    1072             :                                                             key->partcollation,
    1073             :                                                             boundinfo,
    1074             :                                                             val->constvalue,
    1075             :                                                             &equal);
    1076        1344 :                             if (offset >= 0 && equal)
    1077             :                             {
    1078          12 :                                 overlap = true;
    1079          12 :                                 with = boundinfo->indexes[offset];
    1080          12 :                                 break;
    1081             :                             }
    1082             :                         }
    1083          32 :                         else if (partition_bound_accepts_nulls(boundinfo))
    1084             :                         {
    1085           4 :                             overlap = true;
    1086           4 :                             with = boundinfo->null_index;
    1087           4 :                             break;
    1088             :                         }
    1089             :                     }
    1090             :                 }
    1091             : 
    1092        1966 :                 break;
    1093             :             }
    1094             : 
    1095             :         case PARTITION_STRATEGY_RANGE:
    1096             :             {
    1097             :                 PartitionRangeBound *lower,
    1098             :                            *upper;
    1099             : 
    1100             :                 Assert(spec->strategy == PARTITION_STRATEGY_RANGE);
    1101        1852 :                 lower = make_one_partition_rbound(key, -1, spec->lowerdatums, true);
    1102        1852 :                 upper = make_one_partition_rbound(key, -1, spec->upperdatums, false);
    1103             : 
    1104             :                 /*
    1105             :                  * First check if the resulting range would be empty with
    1106             :                  * specified lower and upper bounds
    1107             :                  */
    1108        1852 :                 if (partition_rbound_cmp(key->partnatts, key->partsupfunc,
    1109             :                                          key->partcollation, lower->datums,
    1110             :                                          lower->kind, true, upper) >= 0)
    1111             :                 {
    1112           8 :                     ereport(ERROR,
    1113             :                             (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1114             :                              errmsg("empty range bound specified for partition \"%s\"",
    1115             :                                     relname),
    1116             :                              errdetail("Specified lower bound %s is greater than or equal to upper bound %s.",
    1117             :                                        get_range_partbound_string(spec->lowerdatums),
    1118             :                                        get_range_partbound_string(spec->upperdatums)),
    1119             :                              parser_errposition(pstate, spec->location)));
    1120             :                 }
    1121             : 
    1122        1844 :                 if (partdesc->nparts > 0)
    1123             :                 {
    1124             :                     int         offset;
    1125             :                     bool        equal;
    1126             : 
    1127             :                     Assert(boundinfo &&
    1128             :                            boundinfo->strategy == PARTITION_STRATEGY_RANGE &&
    1129             :                            (boundinfo->ndatums > 0 ||
    1130             :                             partition_bound_has_default(boundinfo)));
    1131             : 
    1132             :                     /*
    1133             :                      * Test whether the new lower bound (which is treated
    1134             :                      * inclusively as part of the new partition) lies inside
    1135             :                      * an existing partition, or in a gap.
    1136             :                      *
    1137             :                      * If it's inside an existing partition, the bound at
    1138             :                      * offset + 1 will be the upper bound of that partition,
    1139             :                      * and its index will be >= 0.
    1140             :                      *
    1141             :                      * If it's in a gap, the bound at offset + 1 will be the
    1142             :                      * lower bound of the next partition, and its index will
    1143             :                      * be -1. This is also true if there is no next partition,
    1144             :                      * since the index array is initialised with an extra -1
    1145             :                      * at the end.
    1146             :                      */
    1147        1050 :                     offset = partition_range_bsearch(key->partnatts,
    1148             :                                                      key->partsupfunc,
    1149             :                                                      key->partcollation,
    1150             :                                                      boundinfo, lower,
    1151             :                                                      &equal);
    1152             : 
    1153        1050 :                     if (boundinfo->indexes[offset + 1] < 0)
    1154             :                     {
    1155             :                         /*
    1156             :                          * Check that the new partition will fit in the gap.
    1157             :                          * For it to fit, the new upper bound must be less
    1158             :                          * than or equal to the lower bound of the next
    1159             :                          * partition, if there is one.
    1160             :                          */
    1161        1030 :                         if (offset + 1 < boundinfo->ndatums)
    1162             :                         {
    1163             :                             int32       cmpval;
    1164             :                             Datum      *datums;
    1165             :                             PartitionRangeDatumKind *kind;
    1166             :                             bool        is_lower;
    1167             : 
    1168          40 :                             datums = boundinfo->datums[offset + 1];
    1169          40 :                             kind = boundinfo->kind[offset + 1];
    1170          40 :                             is_lower = (boundinfo->indexes[offset + 1] == -1);
    1171             : 
    1172          40 :                             cmpval = partition_rbound_cmp(key->partnatts,
    1173             :                                                           key->partsupfunc,
    1174             :                                                           key->partcollation,
    1175             :                                                           datums, kind,
    1176             :                                                           is_lower, upper);
    1177          40 :                             if (cmpval < 0)
    1178             :                             {
    1179             :                                 /*
    1180             :                                  * The new partition overlaps with the
    1181             :                                  * existing partition between offset + 1 and
    1182             :                                  * offset + 2.
    1183             :                                  */
    1184           8 :                                 overlap = true;
    1185           8 :                                 with = boundinfo->indexes[offset + 2];
    1186             :                             }
    1187             :                         }
    1188             :                     }
    1189             :                     else
    1190             :                     {
    1191             :                         /*
    1192             :                          * The new partition overlaps with the existing
    1193             :                          * partition between offset and offset + 1.
    1194             :                          */
    1195          20 :                         overlap = true;
    1196          20 :                         with = boundinfo->indexes[offset + 1];
    1197             :                     }
    1198             :                 }
    1199             : 
    1200        1844 :                 break;
    1201             :             }
    1202             : 
    1203             :         default:
    1204           0 :             elog(ERROR, "unexpected partition strategy: %d",
    1205             :                  (int) key->strategy);
    1206             :     }
    1207             : 
    1208        4016 :     if (overlap)
    1209             :     {
    1210             :         Assert(with >= 0);
    1211          56 :         ereport(ERROR,
    1212             :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1213             :                  errmsg("partition \"%s\" would overlap partition \"%s\"",
    1214             :                         relname, get_rel_name(partdesc->oids[with])),
    1215             :                  parser_errposition(pstate, spec->location)));
    1216             :     }
    1217             : }
    1218             : 
    1219             : /*
    1220             :  * check_default_partition_contents
    1221             :  *
    1222             :  * This function checks if there exists a row in the default partition that
    1223             :  * would properly belong to the new partition being added.  If it finds one,
    1224             :  * it throws an error.
    1225             :  */
    1226             : void
    1227         200 : check_default_partition_contents(Relation parent, Relation default_rel,
    1228             :                                  PartitionBoundSpec *new_spec)
    1229             : {
    1230             :     List       *new_part_constraints;
    1231             :     List       *def_part_constraints;
    1232             :     List       *all_parts;
    1233             :     ListCell   *lc;
    1234             : 
    1235         400 :     new_part_constraints = (new_spec->strategy == PARTITION_STRATEGY_LIST)
    1236             :         ? get_qual_for_list(parent, new_spec)
    1237         200 :         : get_qual_for_range(parent, new_spec, false);
    1238         200 :     def_part_constraints =
    1239             :         get_proposed_default_constraint(new_part_constraints);
    1240             : 
    1241             :     /*
    1242             :      * If the existing constraints on the default partition imply that it will
    1243             :      * not contain any row that would belong to the new partition, we can
    1244             :      * avoid scanning the default partition.
    1245             :      */
    1246         200 :     if (PartConstraintImpliedByRelConstraint(default_rel, def_part_constraints))
    1247             :     {
    1248           4 :         ereport(INFO,
    1249             :                 (errmsg("updated partition constraint for default partition \"%s\" is implied by existing constraints",
    1250             :                         RelationGetRelationName(default_rel))));
    1251           4 :         return;
    1252             :     }
    1253             : 
    1254             :     /*
    1255             :      * Scan the default partition and its subpartitions, and check for rows
    1256             :      * that do not satisfy the revised partition constraints.
    1257             :      */
    1258         196 :     if (default_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
    1259          32 :         all_parts = find_all_inheritors(RelationGetRelid(default_rel),
    1260             :                                         AccessExclusiveLock, NULL);
    1261             :     else
    1262         164 :         all_parts = list_make1_oid(RelationGetRelid(default_rel));
    1263             : 
    1264         476 :     foreach(lc, all_parts)
    1265             :     {
    1266         288 :         Oid         part_relid = lfirst_oid(lc);
    1267             :         Relation    part_rel;
    1268             :         Expr       *constr;
    1269             :         Expr       *partition_constraint;
    1270             :         EState     *estate;
    1271         288 :         ExprState  *partqualstate = NULL;
    1272             :         Snapshot    snapshot;
    1273             :         ExprContext *econtext;
    1274             :         TableScanDesc scan;
    1275             :         MemoryContext oldCxt;
    1276             :         TupleTableSlot *tupslot;
    1277             : 
    1278             :         /* Lock already taken above. */
    1279         288 :         if (part_relid != RelationGetRelid(default_rel))
    1280             :         {
    1281          92 :             part_rel = table_open(part_relid, NoLock);
    1282             : 
    1283             :             /*
    1284             :              * If the partition constraints on default partition child imply
    1285             :              * that it will not contain any row that would belong to the new
    1286             :              * partition, we can avoid scanning the child table.
    1287             :              */
    1288          92 :             if (PartConstraintImpliedByRelConstraint(part_rel,
    1289             :                                                      def_part_constraints))
    1290             :             {
    1291           4 :                 ereport(INFO,
    1292             :                         (errmsg("updated partition constraint for default partition \"%s\" is implied by existing constraints",
    1293             :                                 RelationGetRelationName(part_rel))));
    1294             : 
    1295           4 :                 table_close(part_rel, NoLock);
    1296           4 :                 continue;
    1297             :             }
    1298             :         }
    1299             :         else
    1300         196 :             part_rel = default_rel;
    1301             : 
    1302             :         /*
    1303             :          * Only RELKIND_RELATION relations (i.e. leaf partitions) need to be
    1304             :          * scanned.
    1305             :          */
    1306         284 :         if (part_rel->rd_rel->relkind != RELKIND_RELATION)
    1307             :         {
    1308          32 :             if (part_rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
    1309           0 :                 ereport(WARNING,
    1310             :                         (errcode(ERRCODE_CHECK_VIOLATION),
    1311             :                          errmsg("skipped scanning foreign table \"%s\" which is a partition of default partition \"%s\"",
    1312             :                                 RelationGetRelationName(part_rel),
    1313             :                                 RelationGetRelationName(default_rel))));
    1314             : 
    1315          32 :             if (RelationGetRelid(default_rel) != RelationGetRelid(part_rel))
    1316           0 :                 table_close(part_rel, NoLock);
    1317             : 
    1318          32 :             continue;
    1319             :         }
    1320             : 
    1321         252 :         constr = linitial(def_part_constraints);
    1322         252 :         partition_constraint = (Expr *)
    1323             :             map_partition_varattnos((List *) constr,
    1324             :                                     1, part_rel, parent, NULL);
    1325         252 :         estate = CreateExecutorState();
    1326             : 
    1327             :         /* Build expression execution states for partition check quals */
    1328         252 :         partqualstate = ExecPrepareExpr(partition_constraint, estate);
    1329             : 
    1330         252 :         econtext = GetPerTupleExprContext(estate);
    1331         252 :         snapshot = RegisterSnapshot(GetLatestSnapshot());
    1332         252 :         tupslot = table_slot_create(part_rel, &estate->es_tupleTable);
    1333         252 :         scan = table_beginscan(part_rel, snapshot, 0, NULL);
    1334             : 
    1335             :         /*
    1336             :          * Switch to per-tuple memory context and reset it for each tuple
    1337             :          * produced, so we don't leak memory.
    1338             :          */
    1339         252 :         oldCxt = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
    1340             : 
    1341         536 :         while (table_scan_getnextslot(scan, ForwardScanDirection, tupslot))
    1342             :         {
    1343          40 :             econtext->ecxt_scantuple = tupslot;
    1344             : 
    1345          40 :             if (!ExecCheck(partqualstate, econtext))
    1346           8 :                 ereport(ERROR,
    1347             :                         (errcode(ERRCODE_CHECK_VIOLATION),
    1348             :                          errmsg("updated partition constraint for default partition \"%s\" would be violated by some row",
    1349             :                                 RelationGetRelationName(default_rel))));
    1350             : 
    1351          32 :             ResetExprContext(econtext);
    1352          32 :             CHECK_FOR_INTERRUPTS();
    1353             :         }
    1354             : 
    1355         244 :         MemoryContextSwitchTo(oldCxt);
    1356         244 :         table_endscan(scan);
    1357         244 :         UnregisterSnapshot(snapshot);
    1358         244 :         ExecDropSingleTupleTableSlot(tupslot);
    1359         244 :         FreeExecutorState(estate);
    1360             : 
    1361         244 :         if (RelationGetRelid(default_rel) != RelationGetRelid(part_rel))
    1362          88 :             table_close(part_rel, NoLock);  /* keep the lock until commit */
    1363             :     }
    1364             : }
    1365             : 
    1366             : /*
    1367             :  * get_hash_partition_greatest_modulus
    1368             :  *
    1369             :  * Returns the greatest modulus of the hash partition bound. The greatest
    1370             :  * modulus will be at the end of the datums array because hash partitions are
    1371             :  * arranged in the ascending order of their moduli and remainders.
    1372             :  */
    1373             : int
    1374        3474 : get_hash_partition_greatest_modulus(PartitionBoundInfo bound)
    1375             : {
    1376             :     Assert(bound && bound->strategy == PARTITION_STRATEGY_HASH);
    1377             :     Assert(bound->datums && bound->ndatums > 0);
    1378             :     Assert(DatumGetInt32(bound->datums[bound->ndatums - 1][0]) > 0);
    1379             : 
    1380        3474 :     return DatumGetInt32(bound->datums[bound->ndatums - 1][0]);
    1381             : }
    1382             : 
    1383             : /*
    1384             :  * make_one_partition_rbound
    1385             :  *
    1386             :  * Return a PartitionRangeBound given a list of PartitionRangeDatum elements
    1387             :  * and a flag telling whether the bound is lower or not.  Made into a function
    1388             :  * because there are multiple sites that want to use this facility.
    1389             :  */
    1390             : static PartitionRangeBound *
    1391       24404 : make_one_partition_rbound(PartitionKey key, int index, List *datums, bool lower)
    1392             : {
    1393             :     PartitionRangeBound *bound;
    1394             :     ListCell   *lc;
    1395             :     int         i;
    1396             : 
    1397             :     Assert(datums != NIL);
    1398             : 
    1399       24404 :     bound = (PartitionRangeBound *) palloc0(sizeof(PartitionRangeBound));
    1400       24404 :     bound->index = index;
    1401       24404 :     bound->datums = (Datum *) palloc0(key->partnatts * sizeof(Datum));
    1402       24404 :     bound->kind = (PartitionRangeDatumKind *) palloc0(key->partnatts *
    1403             :                                                       sizeof(PartitionRangeDatumKind));
    1404       24404 :     bound->lower = lower;
    1405             : 
    1406       24404 :     i = 0;
    1407       57008 :     foreach(lc, datums)
    1408             :     {
    1409       32604 :         PartitionRangeDatum *datum = castNode(PartitionRangeDatum, lfirst(lc));
    1410             : 
    1411             :         /* What's contained in this range datum? */
    1412       32604 :         bound->kind[i] = datum->kind;
    1413             : 
    1414       32604 :         if (datum->kind == PARTITION_RANGE_DATUM_VALUE)
    1415             :         {
    1416       30624 :             Const      *val = castNode(Const, datum->value);
    1417             : 
    1418       30624 :             if (val->constisnull)
    1419           0 :                 elog(ERROR, "invalid range bound datum");
    1420       30624 :             bound->datums[i] = val->constvalue;
    1421             :         }
    1422             : 
    1423       32604 :         i++;
    1424             :     }
    1425             : 
    1426       24404 :     return bound;
    1427             : }
    1428             : 
    1429             : /*
    1430             :  * partition_rbound_cmp
    1431             :  *
    1432             :  * Return for two range bounds whether the 1st one (specified in datums1,
    1433             :  * kind1, and lower1) is <, =, or > the bound specified in *b2.
    1434             :  *
    1435             :  * partnatts, partsupfunc and partcollation give the number of attributes in the
    1436             :  * bounds to be compared, comparison function to be used and the collations of
    1437             :  * attributes, respectively.
    1438             :  *
    1439             :  * Note that if the values of the two range bounds compare equal, then we take
    1440             :  * into account whether they are upper or lower bounds, and an upper bound is
    1441             :  * considered to be smaller than a lower bound. This is important to the way
    1442             :  * that RelationBuildPartitionDesc() builds the PartitionBoundInfoData
    1443             :  * structure, which only stores the upper bound of a common boundary between
    1444             :  * two contiguous partitions.
    1445             :  */
    1446             : static int32
    1447       21462 : partition_rbound_cmp(int partnatts, FmgrInfo *partsupfunc,
    1448             :                      Oid *partcollation,
    1449             :                      Datum *datums1, PartitionRangeDatumKind *kind1,
    1450             :                      bool lower1, PartitionRangeBound *b2)
    1451             : {
    1452       21462 :     int32       cmpval = 0;     /* placate compiler */
    1453             :     int         i;
    1454       21462 :     Datum      *datums2 = b2->datums;
    1455       21462 :     PartitionRangeDatumKind *kind2 = b2->kind;
    1456       21462 :     bool        lower2 = b2->lower;
    1457             : 
    1458       32502 :     for (i = 0; i < partnatts; i++)
    1459             :     {
    1460             :         /*
    1461             :          * First, handle cases where the column is unbounded, which should not
    1462             :          * invoke the comparison procedure, and should not consider any later
    1463             :          * columns. Note that the PartitionRangeDatumKind enum elements
    1464             :          * compare the same way as the values they represent.
    1465             :          */
    1466       27090 :         if (kind1[i] < kind2[i])
    1467         904 :             return -1;
    1468       26186 :         else if (kind1[i] > kind2[i])
    1469           4 :             return 1;
    1470       26182 :         else if (kind1[i] != PARTITION_RANGE_DATUM_VALUE)
    1471             : 
    1472             :             /*
    1473             :              * The column bounds are both MINVALUE or both MAXVALUE. No later
    1474             :              * columns should be considered, but we still need to compare
    1475             :              * whether they are upper or lower bounds.
    1476             :              */
    1477         172 :             break;
    1478             : 
    1479       26010 :         cmpval = DatumGetInt32(FunctionCall2Coll(&partsupfunc[i],
    1480             :                                                  partcollation[i],
    1481             :                                                  datums1[i],
    1482             :                                                  datums2[i]));
    1483       26010 :         if (cmpval != 0)
    1484       14970 :             break;
    1485             :     }
    1486             : 
    1487             :     /*
    1488             :      * If the comparison is anything other than equal, we're done. If they
    1489             :      * compare equal though, we still have to consider whether the boundaries
    1490             :      * are inclusive or exclusive.  Exclusive one is considered smaller of the
    1491             :      * two.
    1492             :      */
    1493       20554 :     if (cmpval == 0 && lower1 != lower2)
    1494        5572 :         cmpval = lower1 ? 1 : -1;
    1495             : 
    1496       20554 :     return cmpval;
    1497             : }
    1498             : 
    1499             : /*
    1500             :  * partition_rbound_datum_cmp
    1501             :  *
    1502             :  * Return whether range bound (specified in rb_datums, rb_kind, and rb_lower)
    1503             :  * is <, =, or > partition key of tuple (tuple_datums)
    1504             :  *
    1505             :  * n_tuple_datums, partsupfunc and partcollation give number of attributes in
    1506             :  * the bounds to be compared, comparison function to be used and the collations
    1507             :  * of attributes resp.
    1508             :  *
    1509             :  */
    1510             : int32
    1511      684104 : partition_rbound_datum_cmp(FmgrInfo *partsupfunc, Oid *partcollation,
    1512             :                            Datum *rb_datums, PartitionRangeDatumKind *rb_kind,
    1513             :                            Datum *tuple_datums, int n_tuple_datums)
    1514             : {
    1515             :     int         i;
    1516      684104 :     int32       cmpval = -1;
    1517             : 
    1518      722268 :     for (i = 0; i < n_tuple_datums; i++)
    1519             :     {
    1520      687656 :         if (rb_kind[i] == PARTITION_RANGE_DATUM_MINVALUE)
    1521         376 :             return -1;
    1522      687280 :         else if (rb_kind[i] == PARTITION_RANGE_DATUM_MAXVALUE)
    1523         280 :             return 1;
    1524             : 
    1525      687000 :         cmpval = DatumGetInt32(FunctionCall2Coll(&partsupfunc[i],
    1526             :                                                  partcollation[i],
    1527             :                                                  rb_datums[i],
    1528             :                                                  tuple_datums[i]));
    1529      687000 :         if (cmpval != 0)
    1530      648836 :             break;
    1531             :     }
    1532             : 
    1533      683448 :     return cmpval;
    1534             : }
    1535             : 
    1536             : /*
    1537             :  * partition_hbound_cmp
    1538             :  *
    1539             :  * Compares modulus first, then remainder if modulus is equal.
    1540             :  */
    1541             : static int32
    1542         608 : partition_hbound_cmp(int modulus1, int remainder1, int modulus2, int remainder2)
    1543             : {
    1544         608 :     if (modulus1 < modulus2)
    1545          96 :         return -1;
    1546         512 :     if (modulus1 > modulus2)
    1547          24 :         return 1;
    1548         488 :     if (modulus1 == modulus2 && remainder1 != remainder2)
    1549         488 :         return (remainder1 > remainder2) ? 1 : -1;
    1550           0 :     return 0;
    1551             : }
    1552             : 
    1553             : /*
    1554             :  * partition_list_bsearch
    1555             :  *      Returns the index of the greatest bound datum that is less than equal
    1556             :  *      to the given value or -1 if all of the bound datums are greater
    1557             :  *
    1558             :  * *is_equal is set to true if the bound datum at the returned index is equal
    1559             :  * to the input value.
    1560             :  */
    1561             : int
    1562       77880 : partition_list_bsearch(FmgrInfo *partsupfunc, Oid *partcollation,
    1563             :                        PartitionBoundInfo boundinfo,
    1564             :                        Datum value, bool *is_equal)
    1565             : {
    1566             :     int         lo,
    1567             :                 hi,
    1568             :                 mid;
    1569             : 
    1570       77880 :     lo = -1;
    1571       77880 :     hi = boundinfo->ndatums - 1;
    1572      243468 :     while (lo < hi)
    1573             :     {
    1574             :         int32       cmpval;
    1575             : 
    1576      161188 :         mid = (lo + hi + 1) / 2;
    1577      161188 :         cmpval = DatumGetInt32(FunctionCall2Coll(&partsupfunc[0],
    1578             :                                                  partcollation[0],
    1579             :                                                  boundinfo->datums[mid][0],
    1580             :                                                  value));
    1581      161188 :         if (cmpval <= 0)
    1582             :         {
    1583      130582 :             lo = mid;
    1584      130582 :             *is_equal = (cmpval == 0);
    1585      130582 :             if (*is_equal)
    1586       73480 :                 break;
    1587             :         }
    1588             :         else
    1589       30606 :             hi = mid - 1;
    1590             :     }
    1591             : 
    1592       77880 :     return lo;
    1593             : }
    1594             : 
    1595             : /*
    1596             :  * partition_range_bsearch
    1597             :  *      Returns the index of the greatest range bound that is less than or
    1598             :  *      equal to the given range bound or -1 if all of the range bounds are
    1599             :  *      greater
    1600             :  *
    1601             :  * *is_equal is set to true if the range bound at the returned index is equal
    1602             :  * to the input range bound
    1603             :  */
    1604             : static int
    1605        1050 : partition_range_bsearch(int partnatts, FmgrInfo *partsupfunc,
    1606             :                         Oid *partcollation,
    1607             :                         PartitionBoundInfo boundinfo,
    1608             :                         PartitionRangeBound *probe, bool *is_equal)
    1609             : {
    1610             :     int         lo,
    1611             :                 hi,
    1612             :                 mid;
    1613             : 
    1614        1050 :     lo = -1;
    1615        1050 :     hi = boundinfo->ndatums - 1;
    1616        4354 :     while (lo < hi)
    1617             :     {
    1618             :         int32       cmpval;
    1619             : 
    1620        2266 :         mid = (lo + hi + 1) / 2;
    1621        6798 :         cmpval = partition_rbound_cmp(partnatts, partsupfunc,
    1622             :                                       partcollation,
    1623        2266 :                                       boundinfo->datums[mid],
    1624        2266 :                                       boundinfo->kind[mid],
    1625        2266 :                                       (boundinfo->indexes[mid] == -1),
    1626             :                                       probe);
    1627        2266 :         if (cmpval <= 0)
    1628             :         {
    1629        2202 :             lo = mid;
    1630        2202 :             *is_equal = (cmpval == 0);
    1631             : 
    1632        2202 :             if (*is_equal)
    1633          12 :                 break;
    1634             :         }
    1635             :         else
    1636          64 :             hi = mid - 1;
    1637             :     }
    1638             : 
    1639        1050 :     return lo;
    1640             : }
    1641             : 
    1642             : /*
    1643             :  * partition_range_bsearch
    1644             :  *      Returns the index of the greatest range bound that is less than or
    1645             :  *      equal to the given tuple or -1 if all of the range bounds are greater
    1646             :  *
    1647             :  * *is_equal is set to true if the range bound at the returned index is equal
    1648             :  * to the input tuple.
    1649             :  */
    1650             : int
    1651      308498 : partition_range_datum_bsearch(FmgrInfo *partsupfunc, Oid *partcollation,
    1652             :                               PartitionBoundInfo boundinfo,
    1653             :                               int nvalues, Datum *values, bool *is_equal)
    1654             : {
    1655             :     int         lo,
    1656             :                 hi,
    1657             :                 mid;
    1658             : 
    1659      308498 :     lo = -1;
    1660      308498 :     hi = boundinfo->ndatums - 1;
    1661     1265920 :     while (lo < hi)
    1662             :     {
    1663             :         int32       cmpval;
    1664             : 
    1665      683192 :         mid = (lo + hi + 1) / 2;
    1666     1366384 :         cmpval = partition_rbound_datum_cmp(partsupfunc,
    1667             :                                             partcollation,
    1668      683192 :                                             boundinfo->datums[mid],
    1669      683192 :                                             boundinfo->kind[mid],
    1670             :                                             values,
    1671             :                                             nvalues);
    1672      683192 :         if (cmpval <= 0)
    1673             :         {
    1674      395618 :             lo = mid;
    1675      395618 :             *is_equal = (cmpval == 0);
    1676             : 
    1677      395618 :             if (*is_equal)
    1678       34268 :                 break;
    1679             :         }
    1680             :         else
    1681      287574 :             hi = mid - 1;
    1682             :     }
    1683             : 
    1684      308498 :     return lo;
    1685             : }
    1686             : 
    1687             : /*
    1688             :  * partition_hash_bsearch
    1689             :  *      Returns the index of the greatest (modulus, remainder) pair that is
    1690             :  *      less than or equal to the given (modulus, remainder) pair or -1 if
    1691             :  *      all of them are greater
    1692             :  */
    1693             : int
    1694         152 : partition_hash_bsearch(PartitionBoundInfo boundinfo,
    1695             :                        int modulus, int remainder)
    1696             : {
    1697             :     int         lo,
    1698             :                 hi,
    1699             :                 mid;
    1700             : 
    1701         152 :     lo = -1;
    1702         152 :     hi = boundinfo->ndatums - 1;
    1703         534 :     while (lo < hi)
    1704             :     {
    1705             :         int32       cmpval,
    1706             :                     bound_modulus,
    1707             :                     bound_remainder;
    1708             : 
    1709         230 :         mid = (lo + hi + 1) / 2;
    1710         230 :         bound_modulus = DatumGetInt32(boundinfo->datums[mid][0]);
    1711         230 :         bound_remainder = DatumGetInt32(boundinfo->datums[mid][1]);
    1712         230 :         cmpval = partition_hbound_cmp(bound_modulus, bound_remainder,
    1713             :                                       modulus, remainder);
    1714         230 :         if (cmpval <= 0)
    1715             :         {
    1716         198 :             lo = mid;
    1717             : 
    1718         198 :             if (cmpval == 0)
    1719           0 :                 break;
    1720             :         }
    1721             :         else
    1722          32 :             hi = mid - 1;
    1723             :     }
    1724             : 
    1725         152 :     return lo;
    1726             : }
    1727             : 
    1728             : /*
    1729             :  * qsort_partition_hbound_cmp
    1730             :  *
    1731             :  * Hash bounds are sorted by modulus, then by remainder.
    1732             :  */
    1733             : static int32
    1734         378 : qsort_partition_hbound_cmp(const void *a, const void *b)
    1735             : {
    1736         378 :     PartitionHashBound *h1 = (*(PartitionHashBound *const *) a);
    1737         378 :     PartitionHashBound *h2 = (*(PartitionHashBound *const *) b);
    1738             : 
    1739         378 :     return partition_hbound_cmp(h1->modulus, h1->remainder,
    1740             :                                 h2->modulus, h2->remainder);
    1741             : }
    1742             : 
    1743             : /*
    1744             :  * qsort_partition_list_value_cmp
    1745             :  *
    1746             :  * Compare two list partition bound datums.
    1747             :  */
    1748             : static int32
    1749       15148 : qsort_partition_list_value_cmp(const void *a, const void *b, void *arg)
    1750             : {
    1751       15148 :     Datum       val1 = (*(PartitionListValue *const *) a)->value,
    1752       15148 :                 val2 = (*(PartitionListValue *const *) b)->value;
    1753       15148 :     PartitionKey key = (PartitionKey) arg;
    1754             : 
    1755       15148 :     return DatumGetInt32(FunctionCall2Coll(&key->partsupfunc[0],
    1756             :                                            key->partcollation[0],
    1757             :                                            val1, val2));
    1758             : }
    1759             : 
    1760             : /*
    1761             :  * qsort_partition_rbound_cmp
    1762             :  *
    1763             :  * Used when sorting range bounds across all range partitions.
    1764             :  */
    1765             : static int32
    1766       17304 : qsort_partition_rbound_cmp(const void *a, const void *b, void *arg)
    1767             : {
    1768       17304 :     PartitionRangeBound *b1 = (*(PartitionRangeBound *const *) a);
    1769       17304 :     PartitionRangeBound *b2 = (*(PartitionRangeBound *const *) b);
    1770       17304 :     PartitionKey key = (PartitionKey) arg;
    1771             : 
    1772       17304 :     return partition_rbound_cmp(key->partnatts, key->partsupfunc,
    1773             :                                 key->partcollation, b1->datums, b1->kind,
    1774       17304 :                                 b1->lower, b2);
    1775             : }
    1776             : 
    1777             : /*
    1778             :  * get_partition_bound_num_indexes
    1779             :  *
    1780             :  * Returns the number of the entries in the partition bound indexes array.
    1781             :  */
    1782             : static int
    1783       10522 : get_partition_bound_num_indexes(PartitionBoundInfo bound)
    1784             : {
    1785             :     int         num_indexes;
    1786             : 
    1787             :     Assert(bound);
    1788             : 
    1789       10522 :     switch (bound->strategy)
    1790             :     {
    1791             :         case PARTITION_STRATEGY_HASH:
    1792             : 
    1793             :             /*
    1794             :              * The number of the entries in the indexes array is same as the
    1795             :              * greatest modulus.
    1796             :              */
    1797         338 :             num_indexes = get_hash_partition_greatest_modulus(bound);
    1798         338 :             break;
    1799             : 
    1800             :         case PARTITION_STRATEGY_LIST:
    1801        4856 :             num_indexes = bound->ndatums;
    1802        4856 :             break;
    1803             : 
    1804             :         case PARTITION_STRATEGY_RANGE:
    1805             :             /* Range partitioned table has an extra index. */
    1806        5328 :             num_indexes = bound->ndatums + 1;
    1807        5328 :             break;
    1808             : 
    1809             :         default:
    1810           0 :             elog(ERROR, "unexpected partition strategy: %d",
    1811             :                  (int) bound->strategy);
    1812             :     }
    1813             : 
    1814       10522 :     return num_indexes;
    1815             : }
    1816             : 
    1817             : /*
    1818             :  * get_partition_operator
    1819             :  *
    1820             :  * Return oid of the operator of the given strategy for the given partition
    1821             :  * key column.  It is assumed that the partitioning key is of the same type as
    1822             :  * the chosen partitioning opclass, or at least binary-compatible.  In the
    1823             :  * latter case, *need_relabel is set to true if the opclass is not of a
    1824             :  * polymorphic type (indicating a RelabelType node needed on top), otherwise
    1825             :  * false.
    1826             :  */
    1827             : static Oid
    1828       11592 : get_partition_operator(PartitionKey key, int col, StrategyNumber strategy,
    1829             :                        bool *need_relabel)
    1830             : {
    1831             :     Oid         operoid;
    1832             : 
    1833             :     /*
    1834             :      * Get the operator in the partitioning opfamily using the opclass'
    1835             :      * declared input type as both left- and righttype.
    1836             :      */
    1837       34776 :     operoid = get_opfamily_member(key->partopfamily[col],
    1838       11592 :                                   key->partopcintype[col],
    1839       11592 :                                   key->partopcintype[col],
    1840             :                                   strategy);
    1841       11592 :     if (!OidIsValid(operoid))
    1842           0 :         elog(ERROR, "missing operator %d(%u,%u) in partition opfamily %u",
    1843             :              strategy, key->partopcintype[col], key->partopcintype[col],
    1844             :              key->partopfamily[col]);
    1845             : 
    1846             :     /*
    1847             :      * If the partition key column is not of the same type as the operator
    1848             :      * class and not polymorphic, tell caller to wrap the non-Const expression
    1849             :      * in a RelabelType.  This matches what parse_coerce.c does.
    1850             :      */
    1851       23272 :     *need_relabel = (key->parttypid[col] != key->partopcintype[col] &&
    1852       11760 :                      key->partopcintype[col] != RECORDOID &&
    1853         176 :                      !IsPolymorphicType(key->partopcintype[col]));
    1854             : 
    1855       11592 :     return operoid;
    1856             : }
    1857             : 
    1858             : /*
    1859             :  * make_partition_op_expr
    1860             :  *      Returns an Expr for the given partition key column with arg1 and
    1861             :  *      arg2 as its leftop and rightop, respectively
    1862             :  */
    1863             : static Expr *
    1864       11592 : make_partition_op_expr(PartitionKey key, int keynum,
    1865             :                        uint16 strategy, Expr *arg1, Expr *arg2)
    1866             : {
    1867             :     Oid         operoid;
    1868       11592 :     bool        need_relabel = false;
    1869       11592 :     Expr       *result = NULL;
    1870             : 
    1871             :     /* Get the correct btree operator for this partitioning column */
    1872       11592 :     operoid = get_partition_operator(key, keynum, strategy, &need_relabel);
    1873             : 
    1874             :     /*
    1875             :      * Chosen operator may be such that the non-Const operand needs to be
    1876             :      * coerced, so apply the same; see the comment in
    1877             :      * get_partition_operator().
    1878             :      */
    1879       20046 :     if (!IsA(arg1, Const) &&
    1880       16840 :         (need_relabel ||
    1881        8386 :          key->partcollation[keynum] != key->parttypcoll[keynum]))
    1882         136 :         arg1 = (Expr *) makeRelabelType(arg1,
    1883          68 :                                         key->partopcintype[keynum],
    1884             :                                         -1,
    1885          68 :                                         key->partcollation[keynum],
    1886             :                                         COERCE_EXPLICIT_CAST);
    1887             : 
    1888             :     /* Generate the actual expression */
    1889       11592 :     switch (key->strategy)
    1890             :     {
    1891             :         case PARTITION_STRATEGY_LIST:
    1892             :             {
    1893        1826 :                 List       *elems = (List *) arg2;
    1894        1826 :                 int         nelems = list_length(elems);
    1895             : 
    1896             :                 Assert(nelems >= 1);
    1897             :                 Assert(keynum == 0);
    1898             : 
    1899        2176 :                 if (nelems > 1 &&
    1900         350 :                     !type_is_array(key->parttypid[keynum]))
    1901         346 :                 {
    1902             :                     ArrayExpr  *arrexpr;
    1903             :                     ScalarArrayOpExpr *saopexpr;
    1904             : 
    1905             :                     /* Construct an ArrayExpr for the right-hand inputs */
    1906         346 :                     arrexpr = makeNode(ArrayExpr);
    1907         346 :                     arrexpr->array_typeid =
    1908         346 :                         get_array_type(key->parttypid[keynum]);
    1909         346 :                     arrexpr->array_collid = key->parttypcoll[keynum];
    1910         346 :                     arrexpr->element_typeid = key->parttypid[keynum];
    1911         346 :                     arrexpr->elements = elems;
    1912         346 :                     arrexpr->multidims = false;
    1913         346 :                     arrexpr->location = -1;
    1914             : 
    1915             :                     /* Build leftop = ANY (rightop) */
    1916         346 :                     saopexpr = makeNode(ScalarArrayOpExpr);
    1917         346 :                     saopexpr->opno = operoid;
    1918         346 :                     saopexpr->opfuncid = get_opcode(operoid);
    1919         346 :                     saopexpr->useOr = true;
    1920         346 :                     saopexpr->inputcollid = key->partcollation[keynum];
    1921         346 :                     saopexpr->args = list_make2(arg1, arrexpr);
    1922         346 :                     saopexpr->location = -1;
    1923             : 
    1924         346 :                     result = (Expr *) saopexpr;
    1925             :                 }
    1926             :                 else
    1927             :                 {
    1928        1480 :                     List       *elemops = NIL;
    1929             :                     ListCell   *lc;
    1930             : 
    1931        2964 :                     foreach(lc, elems)
    1932             :                     {
    1933        1484 :                         Expr       *elem = lfirst(lc),
    1934             :                                    *elemop;
    1935             : 
    1936        1484 :                         elemop = make_opclause(operoid,
    1937             :                                                BOOLOID,
    1938             :                                                false,
    1939             :                                                arg1, elem,
    1940             :                                                InvalidOid,
    1941        1484 :                                                key->partcollation[keynum]);
    1942        1484 :                         elemops = lappend(elemops, elemop);
    1943             :                     }
    1944             : 
    1945        1480 :                     result = nelems > 1 ? makeBoolExpr(OR_EXPR, elemops, -1) : linitial(elemops);
    1946             :                 }
    1947        1826 :                 break;
    1948             :             }
    1949             : 
    1950             :         case PARTITION_STRATEGY_RANGE:
    1951        9766 :             result = make_opclause(operoid,
    1952             :                                    BOOLOID,
    1953             :                                    false,
    1954             :                                    arg1, arg2,
    1955             :                                    InvalidOid,
    1956        9766 :                                    key->partcollation[keynum]);
    1957        9766 :             break;
    1958             : 
    1959             :         default:
    1960           0 :             elog(ERROR, "invalid partitioning strategy");
    1961             :             break;
    1962             :     }
    1963             : 
    1964       11592 :     return result;
    1965             : }
    1966             : 
    1967             : /*
    1968             :  * get_qual_for_hash
    1969             :  *
    1970             :  * Returns a CHECK constraint expression to use as a hash partition's
    1971             :  * constraint, given the parent relation and partition bound structure.
    1972             :  *
    1973             :  * The partition constraint for a hash partition is always a call to the
    1974             :  * built-in function satisfies_hash_partition().
    1975             :  */
    1976             : static List *
    1977         142 : get_qual_for_hash(Relation parent, PartitionBoundSpec *spec)
    1978             : {
    1979         142 :     PartitionKey key = RelationGetPartitionKey(parent);
    1980             :     FuncExpr   *fexpr;
    1981             :     Node       *relidConst;
    1982             :     Node       *modulusConst;
    1983             :     Node       *remainderConst;
    1984             :     List       *args;
    1985             :     ListCell   *partexprs_item;
    1986             :     int         i;
    1987             : 
    1988             :     /* Fixed arguments. */
    1989         142 :     relidConst = (Node *) makeConst(OIDOID,
    1990             :                                     -1,
    1991             :                                     InvalidOid,
    1992             :                                     sizeof(Oid),
    1993         142 :                                     ObjectIdGetDatum(RelationGetRelid(parent)),
    1994             :                                     false,
    1995             :                                     true);
    1996             : 
    1997         142 :     modulusConst = (Node *) makeConst(INT4OID,
    1998             :                                       -1,
    1999             :                                       InvalidOid,
    2000             :                                       sizeof(int32),
    2001         142 :                                       Int32GetDatum(spec->modulus),
    2002             :                                       false,
    2003             :                                       true);
    2004             : 
    2005         142 :     remainderConst = (Node *) makeConst(INT4OID,
    2006             :                                         -1,
    2007             :                                         InvalidOid,
    2008             :                                         sizeof(int32),
    2009         142 :                                         Int32GetDatum(spec->remainder),
    2010             :                                         false,
    2011             :                                         true);
    2012             : 
    2013         142 :     args = list_make3(relidConst, modulusConst, remainderConst);
    2014         142 :     partexprs_item = list_head(key->partexprs);
    2015             : 
    2016             :     /* Add an argument for each key column. */
    2017         316 :     for (i = 0; i < key->partnatts; i++)
    2018             :     {
    2019             :         Node       *keyCol;
    2020             : 
    2021             :         /* Left operand */
    2022         174 :         if (key->partattrs[i] != 0)
    2023             :         {
    2024         624 :             keyCol = (Node *) makeVar(1,
    2025         156 :                                       key->partattrs[i],
    2026         156 :                                       key->parttypid[i],
    2027         156 :                                       key->parttypmod[i],
    2028         156 :                                       key->parttypcoll[i],
    2029             :                                       0);
    2030             :         }
    2031             :         else
    2032             :         {
    2033          18 :             keyCol = (Node *) copyObject(lfirst(partexprs_item));
    2034          18 :             partexprs_item = lnext(partexprs_item);
    2035             :         }
    2036             : 
    2037         174 :         args = lappend(args, keyCol);
    2038             :     }
    2039             : 
    2040         142 :     fexpr = makeFuncExpr(F_SATISFIES_HASH_PARTITION,
    2041             :                          BOOLOID,
    2042             :                          args,
    2043             :                          InvalidOid,
    2044             :                          InvalidOid,
    2045             :                          COERCE_EXPLICIT_CALL);
    2046             : 
    2047         142 :     return list_make1(fexpr);
    2048             : }
    2049             : 
    2050             : /*
    2051             :  * get_qual_for_list
    2052             :  *
    2053             :  * Returns an implicit-AND list of expressions to use as a list partition's
    2054             :  * constraint, given the parent relation and partition bound structure.
    2055             :  *
    2056             :  * The function returns NIL for a default partition when it's the only
    2057             :  * partition since in that case there is no constraint.
    2058             :  */
    2059             : static List *
    2060        1850 : get_qual_for_list(Relation parent, PartitionBoundSpec *spec)
    2061             : {
    2062        1850 :     PartitionKey key = RelationGetPartitionKey(parent);
    2063             :     List       *result;
    2064             :     Expr       *keyCol;
    2065             :     Expr       *opexpr;
    2066             :     NullTest   *nulltest;
    2067             :     ListCell   *cell;
    2068        1850 :     List       *elems = NIL;
    2069        1850 :     bool        list_has_null = false;
    2070             : 
    2071             :     /*
    2072             :      * Only single-column list partitioning is supported, so we are worried
    2073             :      * only about the partition key with index 0.
    2074             :      */
    2075             :     Assert(key->partnatts == 1);
    2076             : 
    2077             :     /* Construct Var or expression representing the partition column */
    2078        1850 :     if (key->partattrs[0] != 0)
    2079        7104 :         keyCol = (Expr *) makeVar(1,
    2080        1776 :                                   key->partattrs[0],
    2081        1776 :                                   key->parttypid[0],
    2082        1776 :                                   key->parttypmod[0],
    2083        1776 :                                   key->parttypcoll[0],
    2084             :                                   0);
    2085             :     else
    2086          74 :         keyCol = (Expr *) copyObject(linitial(key->partexprs));
    2087             : 
    2088             :     /*
    2089             :      * For default list partition, collect datums for all the partitions. The
    2090             :      * default partition constraint should check that the partition key is
    2091             :      * equal to none of those.
    2092             :      */
    2093        1850 :     if (spec->is_default)
    2094             :     {
    2095             :         int         i;
    2096          92 :         int         ndatums = 0;
    2097          92 :         PartitionDesc pdesc = RelationGetPartitionDesc(parent);
    2098          92 :         PartitionBoundInfo boundinfo = pdesc->boundinfo;
    2099             : 
    2100          92 :         if (boundinfo)
    2101             :         {
    2102          92 :             ndatums = boundinfo->ndatums;
    2103             : 
    2104          92 :             if (partition_bound_accepts_nulls(boundinfo))
    2105          24 :                 list_has_null = true;
    2106             :         }
    2107             : 
    2108             :         /*
    2109             :          * If default is the only partition, there need not be any partition
    2110             :          * constraint on it.
    2111             :          */
    2112          92 :         if (ndatums == 0 && !list_has_null)
    2113           8 :             return NIL;
    2114             : 
    2115         384 :         for (i = 0; i < ndatums; i++)
    2116             :         {
    2117             :             Const      *val;
    2118             : 
    2119             :             /*
    2120             :              * Construct Const from known-not-null datum.  We must be careful
    2121             :              * to copy the value, because our result has to be able to outlive
    2122             :              * the relcache entry we're copying from.
    2123             :              */
    2124        2100 :             val = makeConst(key->parttypid[0],
    2125         300 :                             key->parttypmod[0],
    2126         300 :                             key->parttypcoll[0],
    2127         300 :                             key->parttyplen[0],
    2128         300 :                             datumCopy(*boundinfo->datums[i],
    2129         300 :                                       key->parttypbyval[0],
    2130         300 :                                       key->parttyplen[0]),
    2131             :                             false,  /* isnull */
    2132         300 :                             key->parttypbyval[0]);
    2133             : 
    2134         300 :             elems = lappend(elems, val);
    2135             :         }
    2136             :     }
    2137             :     else
    2138             :     {
    2139             :         /*
    2140             :          * Create list of Consts for the allowed values, excluding any nulls.
    2141             :          */
    2142        4134 :         foreach(cell, spec->listdatums)
    2143             :         {
    2144        2376 :             Const      *val = castNode(Const, lfirst(cell));
    2145             : 
    2146        2376 :             if (val->constisnull)
    2147          36 :                 list_has_null = true;
    2148             :             else
    2149        2340 :                 elems = lappend(elems, copyObject(val));
    2150             :         }
    2151             :     }
    2152             : 
    2153        1842 :     if (elems)
    2154             :     {
    2155             :         /*
    2156             :          * Generate the operator expression from the non-null partition
    2157             :          * values.
    2158             :          */
    2159        1826 :         opexpr = make_partition_op_expr(key, 0, BTEqualStrategyNumber,
    2160             :                                         keyCol, (Expr *) elems);
    2161             :     }
    2162             :     else
    2163             :     {
    2164             :         /*
    2165             :          * If there are no partition values, we don't need an operator
    2166             :          * expression.
    2167             :          */
    2168          16 :         opexpr = NULL;
    2169             :     }
    2170             : 
    2171        1842 :     if (!list_has_null)
    2172             :     {
    2173             :         /*
    2174             :          * Gin up a "col IS NOT NULL" test that will be AND'd with the main
    2175             :          * expression.  This might seem redundant, but the partition routing
    2176             :          * machinery needs it.
    2177             :          */
    2178        1782 :         nulltest = makeNode(NullTest);
    2179        1782 :         nulltest->arg = keyCol;
    2180        1782 :         nulltest->nulltesttype = IS_NOT_NULL;
    2181        1782 :         nulltest->argisrow = false;
    2182        1782 :         nulltest->location = -1;
    2183             : 
    2184        1782 :         result = opexpr ? list_make2(nulltest, opexpr) : list_make1(nulltest);
    2185             :     }
    2186             :     else
    2187             :     {
    2188             :         /*
    2189             :          * Gin up a "col IS NULL" test that will be OR'd with the main
    2190             :          * expression.
    2191             :          */
    2192          60 :         nulltest = makeNode(NullTest);
    2193          60 :         nulltest->arg = keyCol;
    2194          60 :         nulltest->nulltesttype = IS_NULL;
    2195          60 :         nulltest->argisrow = false;
    2196          60 :         nulltest->location = -1;
    2197             : 
    2198          60 :         if (opexpr)
    2199             :         {
    2200             :             Expr       *or;
    2201             : 
    2202          44 :             or = makeBoolExpr(OR_EXPR, list_make2(nulltest, opexpr), -1);
    2203          44 :             result = list_make1(or);
    2204             :         }
    2205             :         else
    2206          16 :             result = list_make1(nulltest);
    2207             :     }
    2208             : 
    2209             :     /*
    2210             :      * Note that, in general, applying NOT to a constraint expression doesn't
    2211             :      * necessarily invert the set of rows it accepts, because NOT (NULL) is
    2212             :      * NULL.  However, the partition constraints we construct here never
    2213             :      * evaluate to NULL, so applying NOT works as intended.
    2214             :      */
    2215        1842 :     if (spec->is_default)
    2216             :     {
    2217          84 :         result = list_make1(make_ands_explicit(result));
    2218          84 :         result = list_make1(makeBoolExpr(NOT_EXPR, result, -1));
    2219             :     }
    2220             : 
    2221        1842 :     return result;
    2222             : }
    2223             : 
    2224             : /*
    2225             :  * get_qual_for_range
    2226             :  *
    2227             :  * Returns an implicit-AND list of expressions to use as a range partition's
    2228             :  * constraint, given the parent relation and partition bound structure.
    2229             :  *
    2230             :  * For a multi-column range partition key, say (a, b, c), with (al, bl, cl)
    2231             :  * as the lower bound tuple and (au, bu, cu) as the upper bound tuple, we
    2232             :  * generate an expression tree of the following form:
    2233             :  *
    2234             :  *  (a IS NOT NULL) and (b IS NOT NULL) and (c IS NOT NULL)
    2235             :  *      AND
    2236             :  *  (a > al OR (a = al AND b > bl) OR (a = al AND b = bl AND c >= cl))
    2237             :  *      AND
    2238             :  *  (a < au OR (a = au AND b < bu) OR (a = au AND b = bu AND c < cu))
    2239             :  *
    2240             :  * It is often the case that a prefix of lower and upper bound tuples contains
    2241             :  * the same values, for example, (al = au), in which case, we will emit an
    2242             :  * expression tree of the following form:
    2243             :  *
    2244             :  *  (a IS NOT NULL) and (b IS NOT NULL) and (c IS NOT NULL)
    2245             :  *      AND
    2246             :  *  (a = al)
    2247             :  *      AND
    2248             :  *  (b > bl OR (b = bl AND c >= cl))
    2249             :  *      AND
    2250             :  *  (b < bu) OR (b = bu AND c < cu))
    2251             :  *
    2252             :  * If a bound datum is either MINVALUE or MAXVALUE, these expressions are
    2253             :  * simplified using the fact that any value is greater than MINVALUE and less
    2254             :  * than MAXVALUE. So, for example, if cu = MAXVALUE, c < cu is automatically
    2255             :  * true, and we need not emit any expression for it, and the last line becomes
    2256             :  *
    2257             :  *  (b < bu) OR (b = bu), which is simplified to (b <= bu)
    2258             :  *
    2259             :  * In most common cases with only one partition column, say a, the following
    2260             :  * expression tree will be generated: a IS NOT NULL AND a >= al AND a < au
    2261             :  *
    2262             :  * For default partition, it returns the negation of the constraints of all
    2263             :  * the other partitions.
    2264             :  *
    2265             :  * External callers should pass for_default as false; we set it to true only
    2266             :  * when recursing.
    2267             :  */
    2268             : static List *
    2269        2736 : get_qual_for_range(Relation parent, PartitionBoundSpec *spec,
    2270             :                    bool for_default)
    2271             : {
    2272        2736 :     List       *result = NIL;
    2273             :     ListCell   *cell1,
    2274             :                *cell2,
    2275             :                *partexprs_item,
    2276             :                *partexprs_item_saved;
    2277             :     int         i,
    2278             :                 j;
    2279             :     PartitionRangeDatum *ldatum,
    2280             :                *udatum;
    2281        2736 :     PartitionKey key = RelationGetPartitionKey(parent);
    2282             :     Expr       *keyCol;
    2283             :     Const      *lower_val,
    2284             :                *upper_val;
    2285             :     List       *lower_or_arms,
    2286             :                *upper_or_arms;
    2287             :     int         num_or_arms,
    2288             :                 current_or_arm;
    2289             :     ListCell   *lower_or_start_datum,
    2290             :                *upper_or_start_datum;
    2291             :     bool        need_next_lower_arm,
    2292             :                 need_next_upper_arm;
    2293             : 
    2294        2736 :     if (spec->is_default)
    2295             :     {
    2296         130 :         List       *or_expr_args = NIL;
    2297         130 :         PartitionDesc pdesc = RelationGetPartitionDesc(parent);
    2298         130 :         Oid        *inhoids = pdesc->oids;
    2299         130 :         int         nparts = pdesc->nparts,
    2300             :                     i;
    2301             : 
    2302         556 :         for (i = 0; i < nparts; i++)
    2303             :         {
    2304         426 :             Oid         inhrelid = inhoids[i];
    2305             :             HeapTuple   tuple;
    2306             :             Datum       datum;
    2307             :             bool        isnull;
    2308             :             PartitionBoundSpec *bspec;
    2309             : 
    2310         426 :             tuple = SearchSysCache1(RELOID, inhrelid);
    2311         426 :             if (!HeapTupleIsValid(tuple))
    2312           0 :                 elog(ERROR, "cache lookup failed for relation %u", inhrelid);
    2313             : 
    2314         426 :             datum = SysCacheGetAttr(RELOID, tuple,
    2315             :                                     Anum_pg_class_relpartbound,
    2316             :                                     &isnull);
    2317         426 :             if (isnull)
    2318           0 :                 elog(ERROR, "null relpartbound for relation %u", inhrelid);
    2319             : 
    2320         426 :             bspec = (PartitionBoundSpec *)
    2321         426 :                 stringToNode(TextDatumGetCString(datum));
    2322         426 :             if (!IsA(bspec, PartitionBoundSpec))
    2323           0 :                 elog(ERROR, "expected PartitionBoundSpec");
    2324             : 
    2325         426 :             if (!bspec->is_default)
    2326             :             {
    2327             :                 List       *part_qual;
    2328             : 
    2329         296 :                 part_qual = get_qual_for_range(parent, bspec, true);
    2330             : 
    2331             :                 /*
    2332             :                  * AND the constraints of the partition and add to
    2333             :                  * or_expr_args
    2334             :                  */
    2335         308 :                 or_expr_args = lappend(or_expr_args, list_length(part_qual) > 1
    2336             :                                        ? makeBoolExpr(AND_EXPR, part_qual, -1)
    2337          12 :                                        : linitial(part_qual));
    2338             :             }
    2339         426 :             ReleaseSysCache(tuple);
    2340             :         }
    2341             : 
    2342         130 :         if (or_expr_args != NIL)
    2343             :         {
    2344             :             Expr       *other_parts_constr;
    2345             : 
    2346             :             /*
    2347             :              * Combine the constraints obtained for non-default partitions
    2348             :              * using OR.  As requested, each of the OR's args doesn't include
    2349             :              * the NOT NULL test for partition keys (which is to avoid its
    2350             :              * useless repetition).  Add the same now.
    2351             :              */
    2352         106 :             other_parts_constr =
    2353         130 :                 makeBoolExpr(AND_EXPR,
    2354             :                              lappend(get_range_nulltest(key),
    2355         106 :                                      list_length(or_expr_args) > 1
    2356             :                                      ? makeBoolExpr(OR_EXPR, or_expr_args,
    2357             :                                                     -1)
    2358          24 :                                      : linitial(or_expr_args)),
    2359             :                              -1);
    2360             : 
    2361             :             /*
    2362             :              * Finally, the default partition contains everything *NOT*
    2363             :              * contained in the non-default partitions.
    2364             :              */
    2365         106 :             result = list_make1(makeBoolExpr(NOT_EXPR,
    2366             :                                              list_make1(other_parts_constr), -1));
    2367             :         }
    2368             : 
    2369         130 :         return result;
    2370             :     }
    2371             : 
    2372        2606 :     lower_or_start_datum = list_head(spec->lowerdatums);
    2373        2606 :     upper_or_start_datum = list_head(spec->upperdatums);
    2374        2606 :     num_or_arms = key->partnatts;
    2375             : 
    2376             :     /*
    2377             :      * If it is the recursive call for default, we skip the get_range_nulltest
    2378             :      * to avoid accumulating the NullTest on the same keys for each partition.
    2379             :      */
    2380        2606 :     if (!for_default)
    2381        2310 :         result = get_range_nulltest(key);
    2382             : 
    2383             :     /*
    2384             :      * Iterate over the key columns and check if the corresponding lower and
    2385             :      * upper datums are equal using the btree equality operator for the
    2386             :      * column's type.  If equal, we emit single keyCol = common_value
    2387             :      * expression.  Starting from the first column for which the corresponding
    2388             :      * lower and upper bound datums are not equal, we generate OR expressions
    2389             :      * as shown in the function's header comment.
    2390             :      */
    2391        2606 :     i = 0;
    2392        2606 :     partexprs_item = list_head(key->partexprs);
    2393        2606 :     partexprs_item_saved = partexprs_item;  /* placate compiler */
    2394        3270 :     forboth(cell1, spec->lowerdatums, cell2, spec->upperdatums)
    2395             :     {
    2396             :         EState     *estate;
    2397             :         MemoryContext oldcxt;
    2398             :         Expr       *test_expr;
    2399             :         ExprState  *test_exprstate;
    2400             :         Datum       test_result;
    2401             :         bool        isNull;
    2402             : 
    2403        3270 :         ldatum = castNode(PartitionRangeDatum, lfirst(cell1));
    2404        3270 :         udatum = castNode(PartitionRangeDatum, lfirst(cell2));
    2405             : 
    2406             :         /*
    2407             :          * Since get_range_key_properties() modifies partexprs_item, and we
    2408             :          * might need to start over from the previous expression in the later
    2409             :          * part of this function, save away the current value.
    2410             :          */
    2411        3270 :         partexprs_item_saved = partexprs_item;
    2412             : 
    2413        3270 :         get_range_key_properties(key, i, ldatum, udatum,
    2414             :                                  &partexprs_item,
    2415             :                                  &keyCol,
    2416             :                                  &lower_val, &upper_val);
    2417             : 
    2418             :         /*
    2419             :          * If either value is NULL, the corresponding partition bound is
    2420             :          * either MINVALUE or MAXVALUE, and we treat them as unequal, because
    2421             :          * even if they're the same, there is no common value to equate the
    2422             :          * key column with.
    2423             :          */
    2424        3270 :         if (!lower_val || !upper_val)
    2425             :             break;
    2426             : 
    2427             :         /* Create the test expression */
    2428        3138 :         estate = CreateExecutorState();
    2429        3138 :         oldcxt = MemoryContextSwitchTo(estate->es_query_cxt);
    2430        3138 :         test_expr = make_partition_op_expr(key, i, BTEqualStrategyNumber,
    2431             :                                            (Expr *) lower_val,
    2432             :                                            (Expr *) upper_val);
    2433        3138 :         fix_opfuncids((Node *) test_expr);
    2434        3138 :         test_exprstate = ExecInitExpr(test_expr, NULL);
    2435        3138 :         test_result = ExecEvalExprSwitchContext(test_exprstate,
    2436        3138 :                                                 GetPerTupleExprContext(estate),
    2437             :                                                 &isNull);
    2438        3138 :         MemoryContextSwitchTo(oldcxt);
    2439        3138 :         FreeExecutorState(estate);
    2440             : 
    2441             :         /* If not equal, go generate the OR expressions */
    2442        3138 :         if (!DatumGetBool(test_result))
    2443        2474 :             break;
    2444             : 
    2445             :         /*
    2446             :          * The bounds for the last key column can't be equal, because such a
    2447             :          * range partition would never be allowed to be defined (it would have
    2448             :          * an empty range otherwise).
    2449             :          */
    2450         664 :         if (i == key->partnatts - 1)
    2451           0 :             elog(ERROR, "invalid range bound specification");
    2452             : 
    2453             :         /* Equal, so generate keyCol = lower_val expression */
    2454        1328 :         result = lappend(result,
    2455        1328 :                          make_partition_op_expr(key, i, BTEqualStrategyNumber,
    2456             :                                                 keyCol, (Expr *) lower_val));
    2457             : 
    2458         664 :         i++;
    2459             :     }
    2460             : 
    2461             :     /* First pair of lower_val and upper_val that are not equal. */
    2462        2606 :     lower_or_start_datum = cell1;
    2463        2606 :     upper_or_start_datum = cell2;
    2464             : 
    2465             :     /* OR will have as many arms as there are key columns left. */
    2466        2606 :     num_or_arms = key->partnatts - i;
    2467        2606 :     current_or_arm = 0;
    2468        2606 :     lower_or_arms = upper_or_arms = NIL;
    2469        2606 :     need_next_lower_arm = need_next_upper_arm = true;
    2470        5462 :     while (current_or_arm < num_or_arms)
    2471             :     {
    2472        2856 :         List       *lower_or_arm_args = NIL,
    2473        2856 :                    *upper_or_arm_args = NIL;
    2474             : 
    2475             :         /* Restart scan of columns from the i'th one */
    2476        2856 :         j = i;
    2477        2856 :         partexprs_item = partexprs_item_saved;
    2478             : 
    2479        3166 :         for_both_cell(cell1, lower_or_start_datum, cell2, upper_or_start_datum)
    2480             :         {
    2481        3166 :             PartitionRangeDatum *ldatum_next = NULL,
    2482        3166 :                        *udatum_next = NULL;
    2483             : 
    2484        3166 :             ldatum = castNode(PartitionRangeDatum, lfirst(cell1));
    2485        3166 :             if (lnext(cell1))
    2486         616 :                 ldatum_next = castNode(PartitionRangeDatum,
    2487             :                                        lfirst(lnext(cell1)));
    2488        3166 :             udatum = castNode(PartitionRangeDatum, lfirst(cell2));
    2489        3166 :             if (lnext(cell2))
    2490         616 :                 udatum_next = castNode(PartitionRangeDatum,
    2491             :                                        lfirst(lnext(cell2)));
    2492        3166 :             get_range_key_properties(key, j, ldatum, udatum,
    2493             :                                      &partexprs_item,
    2494             :                                      &keyCol,
    2495             :                                      &lower_val, &upper_val);
    2496             : 
    2497        3166 :             if (need_next_lower_arm && lower_val)
    2498             :             {
    2499             :                 uint16      strategy;
    2500             : 
    2501             :                 /*
    2502             :                  * For the non-last columns of this arm, use the EQ operator.
    2503             :                  * For the last column of this arm, use GT, unless this is the
    2504             :                  * last column of the whole bound check, or the next bound
    2505             :                  * datum is MINVALUE, in which case use GE.
    2506             :                  */
    2507        3042 :                 if (j - i < current_or_arm)
    2508         274 :                     strategy = BTEqualStrategyNumber;
    2509        2768 :                 else if (j == key->partnatts - 1 ||
    2510         266 :                          (ldatum_next &&
    2511         266 :                           ldatum_next->kind == PARTITION_RANGE_DATUM_MINVALUE))
    2512        2534 :                     strategy = BTGreaterEqualStrategyNumber;
    2513             :                 else
    2514         234 :                     strategy = BTGreaterStrategyNumber;
    2515             : 
    2516        6084 :                 lower_or_arm_args = lappend(lower_or_arm_args,
    2517        6084 :                                             make_partition_op_expr(key, j,
    2518             :                                                                    strategy,
    2519             :                                                                    keyCol,
    2520             :                                                                    (Expr *) lower_val));
    2521             :             }
    2522             : 
    2523        3166 :             if (need_next_upper_arm && upper_val)
    2524             :             {
    2525             :                 uint16      strategy;
    2526             : 
    2527             :                 /*
    2528             :                  * For the non-last columns of this arm, use the EQ operator.
    2529             :                  * For the last column of this arm, use LT, unless the next
    2530             :                  * bound datum is MAXVALUE, in which case use LE.
    2531             :                  */
    2532        2922 :                 if (j - i < current_or_arm)
    2533         214 :                     strategy = BTEqualStrategyNumber;
    2534        2942 :                 else if (udatum_next &&
    2535         234 :                          udatum_next->kind == PARTITION_RANGE_DATUM_MAXVALUE)
    2536          24 :                     strategy = BTLessEqualStrategyNumber;
    2537             :                 else
    2538        2684 :                     strategy = BTLessStrategyNumber;
    2539             : 
    2540        5844 :                 upper_or_arm_args = lappend(upper_or_arm_args,
    2541        5844 :                                             make_partition_op_expr(key, j,
    2542             :                                                                    strategy,
    2543             :                                                                    keyCol,
    2544             :                                                                    (Expr *) upper_val));
    2545             :             }
    2546             : 
    2547             :             /*
    2548             :              * Did we generate enough of OR's arguments?  First arm considers
    2549             :              * the first of the remaining columns, second arm considers first
    2550             :              * two of the remaining columns, and so on.
    2551             :              */
    2552        3166 :             ++j;
    2553        3166 :             if (j - i > current_or_arm)
    2554             :             {
    2555             :                 /*
    2556             :                  * We must not emit any more arms if the new column that will
    2557             :                  * be considered is unbounded, or this one was.
    2558             :                  */
    2559        3122 :                 if (!lower_val || !ldatum_next ||
    2560         266 :                     ldatum_next->kind != PARTITION_RANGE_DATUM_VALUE)
    2561        2630 :                     need_next_lower_arm = false;
    2562        3090 :                 if (!upper_val || !udatum_next ||
    2563         234 :                     udatum_next->kind != PARTITION_RANGE_DATUM_VALUE)
    2564        2674 :                     need_next_upper_arm = false;
    2565        2856 :                 break;
    2566             :             }
    2567             :         }
    2568             : 
    2569        2856 :         if (lower_or_arm_args != NIL)
    2570        5310 :             lower_or_arms = lappend(lower_or_arms,
    2571        2768 :                                     list_length(lower_or_arm_args) > 1
    2572             :                                     ? makeBoolExpr(AND_EXPR, lower_or_arm_args, -1)
    2573        2542 :                                     : linitial(lower_or_arm_args));
    2574             : 
    2575        2856 :         if (upper_or_arm_args != NIL)
    2576        5234 :             upper_or_arms = lappend(upper_or_arms,
    2577        2708 :                                     list_length(upper_or_arm_args) > 1
    2578             :                                     ? makeBoolExpr(AND_EXPR, upper_or_arm_args, -1)
    2579        2526 :                                     : linitial(upper_or_arm_args));
    2580             : 
    2581             :         /* If no work to do in the next iteration, break away. */
    2582        2856 :         if (!need_next_lower_arm && !need_next_upper_arm)
    2583        2606 :             break;
    2584             : 
    2585         250 :         ++current_or_arm;
    2586             :     }
    2587             : 
    2588             :     /*
    2589             :      * Generate the OR expressions for each of lower and upper bounds (if
    2590             :      * required), and append to the list of implicitly ANDed list of
    2591             :      * expressions.
    2592             :      */
    2593        2606 :     if (lower_or_arms != NIL)
    2594        4906 :         result = lappend(result,
    2595        2542 :                          list_length(lower_or_arms) > 1
    2596             :                          ? makeBoolExpr(OR_EXPR, lower_or_arms, -1)
    2597        2364 :                          : linitial(lower_or_arms));
    2598        2606 :     if (upper_or_arms != NIL)
    2599        4902 :         result = lappend(result,
    2600        2526 :                          list_length(upper_or_arms) > 1
    2601             :                          ? makeBoolExpr(OR_EXPR, upper_or_arms, -1)
    2602        2376 :                          : linitial(upper_or_arms));
    2603             : 
    2604             :     /*
    2605             :      * As noted above, for non-default, we return list with constant TRUE. If
    2606             :      * the result is NIL during the recursive call for default, it implies
    2607             :      * this is the only other partition which can hold every value of the key
    2608             :      * except NULL. Hence we return the NullTest result skipped earlier.
    2609             :      */
    2610        2606 :     if (result == NIL)
    2611           0 :         result = for_default
    2612             :             ? get_range_nulltest(key)
    2613           0 :             : list_make1(makeBoolConst(true, false));
    2614             : 
    2615        2606 :     return result;
    2616             : }
    2617             : 
    2618             : /*
    2619             :  * get_range_key_properties
    2620             :  *      Returns range partition key information for a given column
    2621             :  *
    2622             :  * This is a subroutine for get_qual_for_range, and its API is pretty
    2623             :  * specialized to that caller.
    2624             :  *
    2625             :  * Constructs an Expr for the key column (returned in *keyCol) and Consts
    2626             :  * for the lower and upper range limits (returned in *lower_val and
    2627             :  * *upper_val).  For MINVALUE/MAXVALUE limits, NULL is returned instead of
    2628             :  * a Const.  All of these structures are freshly palloc'd.
    2629             :  *
    2630             :  * *partexprs_item points to the cell containing the next expression in
    2631             :  * the key->partexprs list, or NULL.  It may be advanced upon return.
    2632             :  */
    2633             : static void
    2634        6436 : get_range_key_properties(PartitionKey key, int keynum,
    2635             :                          PartitionRangeDatum *ldatum,
    2636             :                          PartitionRangeDatum *udatum,
    2637             :                          ListCell **partexprs_item,
    2638             :                          Expr **keyCol,
    2639             :                          Const **lower_val, Const **upper_val)
    2640             : {
    2641             :     /* Get partition key expression for this column */
    2642        6436 :     if (key->partattrs[keynum] != 0)
    2643             :     {
    2644       21928 :         *keyCol = (Expr *) makeVar(1,
    2645        5482 :                                    key->partattrs[keynum],
    2646        5482 :                                    key->parttypid[keynum],
    2647        5482 :                                    key->parttypmod[keynum],
    2648        5482 :                                    key->parttypcoll[keynum],
    2649             :                                    0);
    2650             :     }
    2651             :     else
    2652             :     {
    2653         954 :         if (*partexprs_item == NULL)
    2654           0 :             elog(ERROR, "wrong number of partition key expressions");
    2655         954 :         *keyCol = copyObject(lfirst(*partexprs_item));
    2656         954 :         *partexprs_item = lnext(*partexprs_item);
    2657             :     }
    2658             : 
    2659             :     /* Get appropriate Const nodes for the bounds */
    2660        6436 :     if (ldatum->kind == PARTITION_RANGE_DATUM_VALUE)
    2661        6260 :         *lower_val = castNode(Const, copyObject(ldatum->value));
    2662             :     else
    2663         176 :         *lower_val = NULL;
    2664             : 
    2665        6436 :     if (udatum->kind == PARTITION_RANGE_DATUM_VALUE)
    2666        6136 :         *upper_val = castNode(Const, copyObject(udatum->value));
    2667             :     else
    2668         300 :         *upper_val = NULL;
    2669        6436 : }
    2670             : 
    2671             : /*
    2672             :  * get_range_nulltest
    2673             :  *
    2674             :  * A non-default range partition table does not currently allow partition
    2675             :  * keys to be null, so emit an IS NOT NULL expression for each key column.
    2676             :  */
    2677             : static List *
    2678        2416 : get_range_nulltest(PartitionKey key)
    2679             : {
    2680        2416 :     List       *result = NIL;
    2681             :     NullTest   *nulltest;
    2682             :     ListCell   *partexprs_item;
    2683             :     int         i;
    2684             : 
    2685        2416 :     partexprs_item = list_head(key->partexprs);
    2686        5690 :     for (i = 0; i < key->partnatts; i++)
    2687             :     {
    2688             :         Expr       *keyCol;
    2689             : 
    2690        3274 :         if (key->partattrs[i] != 0)
    2691             :         {
    2692       11184 :             keyCol = (Expr *) makeVar(1,
    2693        2796 :                                       key->partattrs[i],
    2694        2796 :                                       key->parttypid[i],
    2695        2796 :                                       key->parttypmod[i],
    2696        2796 :                                       key->parttypcoll[i],
    2697             :                                       0);
    2698             :         }
    2699             :         else
    2700             :         {
    2701         478 :             if (partexprs_item == NULL)
    2702           0 :                 elog(ERROR, "wrong number of partition key expressions");
    2703         478 :             keyCol = copyObject(lfirst(partexprs_item));
    2704         478 :             partexprs_item = lnext(partexprs_item);
    2705             :         }
    2706             : 
    2707        3274 :         nulltest = makeNode(NullTest);
    2708        3274 :         nulltest->arg = keyCol;
    2709        3274 :         nulltest->nulltesttype = IS_NOT_NULL;
    2710        3274 :         nulltest->argisrow = false;
    2711        3274 :         nulltest->location = -1;
    2712        3274 :         result = lappend(result, nulltest);
    2713             :     }
    2714             : 
    2715        2416 :     return result;
    2716             : }
    2717             : 
    2718             : /*
    2719             :  * compute_partition_hash_value
    2720             :  *
    2721             :  * Compute the hash value for given partition key values.
    2722             :  */
    2723             : uint64
    2724        2784 : compute_partition_hash_value(int partnatts, FmgrInfo *partsupfunc, Oid *partcollation,
    2725             :                              Datum *values, bool *isnull)
    2726             : {
    2727             :     int         i;
    2728        2784 :     uint64      rowHash = 0;
    2729        2784 :     Datum       seed = UInt64GetDatum(HASH_PARTITION_SEED);
    2730             : 
    2731        5632 :     for (i = 0; i < partnatts; i++)
    2732             :     {
    2733             :         /* Nulls are just ignored */
    2734        2848 :         if (!isnull[i])
    2735             :         {
    2736             :             Datum       hash;
    2737             : 
    2738             :             Assert(OidIsValid(partsupfunc[i].fn_oid));
    2739             : 
    2740             :             /*
    2741             :              * Compute hash for each datum value by calling respective
    2742             :              * datatype-specific hash functions of each partition key
    2743             :              * attribute.
    2744             :              */
    2745        2808 :             hash = FunctionCall2Coll(&partsupfunc[i], partcollation[i],
    2746        2808 :                                      values[i], seed);
    2747             : 
    2748             :             /* Form a single 64-bit hash value */
    2749        2808 :             rowHash = hash_combine64(rowHash, DatumGetUInt64(hash));
    2750             :         }
    2751             :     }
    2752             : 
    2753        2784 :     return rowHash;
    2754             : }
    2755             : 
    2756             : /*
    2757             :  * satisfies_hash_partition
    2758             :  *
    2759             :  * This is an SQL-callable function for use in hash partition constraints.
    2760             :  * The first three arguments are the parent table OID, modulus, and remainder.
    2761             :  * The remaining arguments are the value of the partitioning columns (or
    2762             :  * expressions); these are hashed and the results are combined into a single
    2763             :  * hash value by calling hash_combine64.
    2764             :  *
    2765             :  * Returns true if remainder produced when this computed single hash value is
    2766             :  * divided by the given modulus is equal to given remainder, otherwise false.
    2767             :  *
    2768             :  * See get_qual_for_hash() for usage.
    2769             :  */
    2770             : Datum
    2771         132 : satisfies_hash_partition(PG_FUNCTION_ARGS)
    2772             : {
    2773             :     typedef struct ColumnsHashData
    2774             :     {
    2775             :         Oid         relid;
    2776             :         int         nkeys;
    2777             :         Oid         variadic_type;
    2778             :         int16       variadic_typlen;
    2779             :         bool        variadic_typbyval;
    2780             :         char        variadic_typalign;
    2781             :         Oid         partcollid[PARTITION_MAX_KEYS];
    2782             :         FmgrInfo    partsupfunc[FLEXIBLE_ARRAY_MEMBER];
    2783             :     } ColumnsHashData;
    2784             :     Oid         parentId;
    2785             :     int         modulus;
    2786             :     int         remainder;
    2787         132 :     Datum       seed = UInt64GetDatum(HASH_PARTITION_SEED);
    2788             :     ColumnsHashData *my_extra;
    2789         132 :     uint64      rowHash = 0;
    2790             : 
    2791             :     /* Return null if the parent OID, modulus, or remainder is NULL. */
    2792         132 :     if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(2))
    2793           8 :         PG_RETURN_NULL();
    2794         124 :     parentId = PG_GETARG_OID(0);
    2795         124 :     modulus = PG_GETARG_INT32(1);
    2796         124 :     remainder = PG_GETARG_INT32(2);
    2797             : 
    2798             :     /* Sanity check modulus and remainder. */
    2799         124 :     if (modulus <= 0)
    2800           4 :         ereport(ERROR,
    2801             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    2802             :                  errmsg("modulus for hash partition must be a positive integer")));
    2803         120 :     if (remainder < 0)
    2804           4 :         ereport(ERROR,
    2805             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    2806             :                  errmsg("remainder for hash partition must be a non-negative integer")));
    2807         116 :     if (remainder >= modulus)
    2808           4 :         ereport(ERROR,
    2809             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    2810             :                  errmsg("remainder for hash partition must be less than modulus")));
    2811             : 
    2812             :     /*
    2813             :      * Cache hash function information.
    2814             :      */
    2815         112 :     my_extra = (ColumnsHashData *) fcinfo->flinfo->fn_extra;
    2816         112 :     if (my_extra == NULL || my_extra->relid != parentId)
    2817             :     {
    2818             :         Relation    parent;
    2819             :         PartitionKey key;
    2820             :         int         j;
    2821             : 
    2822             :         /* Open parent relation and fetch partition keyinfo */
    2823         108 :         parent = try_relation_open(parentId, AccessShareLock);
    2824         108 :         if (parent == NULL)
    2825           4 :             PG_RETURN_NULL();
    2826         104 :         key = RelationGetPartitionKey(parent);
    2827             : 
    2828             :         /* Reject parent table that is not hash-partitioned. */
    2829         200 :         if (parent->rd_rel->relkind != RELKIND_PARTITIONED_TABLE ||
    2830          96 :             key->strategy != PARTITION_STRATEGY_HASH)
    2831           8 :             ereport(ERROR,
    2832             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    2833             :                      errmsg("\"%s\" is not a hash partitioned table",
    2834             :                             get_rel_name(parentId))));
    2835             : 
    2836          96 :         if (!get_fn_expr_variadic(fcinfo->flinfo))
    2837             :         {
    2838          76 :             int         nargs = PG_NARGS() - 3;
    2839             : 
    2840             :             /* complain if wrong number of column values */
    2841          76 :             if (key->partnatts != nargs)
    2842           8 :                 ereport(ERROR,
    2843             :                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    2844             :                          errmsg("number of partitioning columns (%d) does not match number of partition keys provided (%d)",
    2845             :                                 key->partnatts, nargs)));
    2846             : 
    2847             :             /* allocate space for our cache */
    2848         136 :             fcinfo->flinfo->fn_extra =
    2849          68 :                 MemoryContextAllocZero(fcinfo->flinfo->fn_mcxt,
    2850             :                                        offsetof(ColumnsHashData, partsupfunc) +
    2851          68 :                                        sizeof(FmgrInfo) * nargs);
    2852          68 :             my_extra = (ColumnsHashData *) fcinfo->flinfo->fn_extra;
    2853          68 :             my_extra->relid = parentId;
    2854          68 :             my_extra->nkeys = key->partnatts;
    2855          68 :             memcpy(my_extra->partcollid, key->partcollation,
    2856          68 :                    key->partnatts * sizeof(Oid));
    2857             : 
    2858             :             /* check argument types and save fmgr_infos */
    2859         164 :             for (j = 0; j < key->partnatts; ++j)
    2860             :             {
    2861         100 :                 Oid         argtype = get_fn_expr_argtype(fcinfo->flinfo, j + 3);
    2862             : 
    2863         100 :                 if (argtype != key->parttypid[j] && !IsBinaryCoercible(argtype, key->parttypid[j]))
    2864           4 :                     ereport(ERROR,
    2865             :                             (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    2866             :                              errmsg("column %d of the partition key has type \"%s\", but supplied value is of type \"%s\"",
    2867             :                                     j + 1, format_type_be(key->parttypid[j]), format_type_be(argtype))));
    2868             : 
    2869         192 :                 fmgr_info_copy(&my_extra->partsupfunc[j],
    2870          96 :                                &key->partsupfunc[j],
    2871          96 :                                fcinfo->flinfo->fn_mcxt);
    2872             :             }
    2873             :         }
    2874             :         else
    2875             :         {
    2876          20 :             ArrayType  *variadic_array = PG_GETARG_ARRAYTYPE_P(3);
    2877             : 
    2878             :             /* allocate space for our cache -- just one FmgrInfo in this case */
    2879          40 :             fcinfo->flinfo->fn_extra =
    2880          20 :                 MemoryContextAllocZero(fcinfo->flinfo->fn_mcxt,
    2881             :                                        offsetof(ColumnsHashData, partsupfunc) +
    2882             :                                        sizeof(FmgrInfo));
    2883          20 :             my_extra = (ColumnsHashData *) fcinfo->flinfo->fn_extra;
    2884          20 :             my_extra->relid = parentId;
    2885          20 :             my_extra->nkeys = key->partnatts;
    2886          20 :             my_extra->variadic_type = ARR_ELEMTYPE(variadic_array);
    2887          20 :             get_typlenbyvalalign(my_extra->variadic_type,
    2888             :                                  &my_extra->variadic_typlen,
    2889             :                                  &my_extra->variadic_typbyval,
    2890             :                                  &my_extra->variadic_typalign);
    2891          20 :             my_extra->partcollid[0] = key->partcollation[0];
    2892             : 
    2893             :             /* check argument types */
    2894          48 :             for (j = 0; j < key->partnatts; ++j)
    2895          36 :                 if (key->parttypid[j] != my_extra->variadic_type)
    2896           8 :                     ereport(ERROR,
    2897             :                             (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    2898             :                              errmsg("column %d of the partition key has type \"%s\", but supplied value is of type \"%s\"",
    2899             :                                     j + 1,
    2900             :                                     format_type_be(key->parttypid[j]),
    2901             :                                     format_type_be(my_extra->variadic_type))));
    2902             : 
    2903          12 :             fmgr_info_copy(&my_extra->partsupfunc[0],
    2904             :                            &key->partsupfunc[0],
    2905          12 :                            fcinfo->flinfo->fn_mcxt);
    2906             :         }
    2907             : 
    2908             :         /* Hold lock until commit */
    2909          76 :         relation_close(parent, NoLock);
    2910             :     }
    2911             : 
    2912          80 :     if (!OidIsValid(my_extra->variadic_type))
    2913             :     {
    2914          68 :         int         nkeys = my_extra->nkeys;
    2915             :         int         i;
    2916             : 
    2917             :         /*
    2918             :          * For a non-variadic call, neither the number of arguments nor their
    2919             :          * types can change across calls, so avoid the expense of rechecking
    2920             :          * here.
    2921             :          */
    2922             : 
    2923         164 :         for (i = 0; i < nkeys; i++)
    2924             :         {
    2925             :             Datum       hash;
    2926             : 
    2927             :             /* keys start from fourth argument of function. */
    2928          96 :             int         argno = i + 3;
    2929             : 
    2930          96 :             if (PG_ARGISNULL(argno))
    2931           0 :                 continue;
    2932             : 
    2933          96 :             hash = FunctionCall2Coll(&my_extra->partsupfunc[i],
    2934             :                                      my_extra->partcollid[i],
    2935             :                                      PG_GETARG_DATUM(argno),
    2936             :                                      seed);
    2937             : 
    2938             :             /* Form a single 64-bit hash value */
    2939          96 :             rowHash = hash_combine64(rowHash, DatumGetUInt64(hash));
    2940             :         }
    2941             :     }
    2942             :     else
    2943             :     {
    2944          12 :         ArrayType  *variadic_array = PG_GETARG_ARRAYTYPE_P(3);
    2945             :         int         i;
    2946             :         int         nelems;
    2947             :         Datum      *datum;
    2948             :         bool       *isnull;
    2949             : 
    2950          36 :         deconstruct_array(variadic_array,
    2951             :                           my_extra->variadic_type,
    2952          12 :                           my_extra->variadic_typlen,
    2953          12 :                           my_extra->variadic_typbyval,
    2954          12 :                           my_extra->variadic_typalign,
    2955             :                           &datum, &isnull, &nelems);
    2956             : 
    2957             :         /* complain if wrong number of column values */
    2958          12 :         if (nelems != my_extra->nkeys)
    2959           4 :             ereport(ERROR,
    2960             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    2961             :                      errmsg("number of partitioning columns (%d) does not match number of partition keys provided (%d)",
    2962             :                             my_extra->nkeys, nelems)));
    2963             : 
    2964          24 :         for (i = 0; i < nelems; i++)
    2965             :         {
    2966             :             Datum       hash;
    2967             : 
    2968          16 :             if (isnull[i])
    2969           0 :                 continue;
    2970             : 
    2971          16 :             hash = FunctionCall2Coll(&my_extra->partsupfunc[0],
    2972             :                                      my_extra->partcollid[0],
    2973          16 :                                      datum[i],
    2974             :                                      seed);
    2975             : 
    2976             :             /* Form a single 64-bit hash value */
    2977          16 :             rowHash = hash_combine64(rowHash, DatumGetUInt64(hash));
    2978             :         }
    2979             :     }
    2980             : 
    2981          76 :     PG_RETURN_BOOL(rowHash % modulus == remainder);
    2982             : }

Generated by: LCOV version 1.13