LCOV - code coverage report
Current view: top level - src/backend/partitioning - partbounds.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 898 932 96.4 %
Date: 2019-09-22 08:06:49 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        4334 : get_qual_from_partbound(Relation rel, Relation parent,
     119             :                         PartitionBoundSpec *spec)
     120             : {
     121        4334 :     PartitionKey key = RelationGetPartitionKey(parent);
     122        4334 :     List       *my_qual = NIL;
     123             : 
     124             :     Assert(key != NULL);
     125             : 
     126        4334 :     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        1860 :             my_qual = get_qual_for_list(parent, spec);
     136        1860 :             break;
     137             : 
     138             :         case PARTITION_STRATEGY_RANGE:
     139             :             Assert(spec->strategy == PARTITION_STRATEGY_RANGE);
     140        2332 :             my_qual = get_qual_for_range(parent, spec, false);
     141        2332 :             break;
     142             : 
     143             :         default:
     144           0 :             elog(ERROR, "unexpected partition strategy: %d",
     145             :                  (int) key->strategy);
     146             :     }
     147             : 
     148        4334 :     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       10944 : 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       10944 :     *mapping = (int *) palloc(sizeof(int) * nparts);
     197       33158 :     for (i = 0; i < nparts; i++)
     198       22214 :         (*mapping)[i] = -1;
     199             : 
     200       10944 :     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        5112 :             return create_list_bounds(boundspecs, nparts, key, mapping);
     207             : 
     208             :         case PARTITION_STRATEGY_RANGE:
     209        5494 :             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        5112 : create_list_bounds(PartitionBoundSpec **boundspecs, int nparts,
     309             :                    PartitionKey key, int **mapping)
     310             : {
     311             :     PartitionBoundInfo boundinfo;
     312        5112 :     PartitionListValue **all_values = NULL;
     313             :     ListCell   *cell;
     314        5112 :     int         i = 0;
     315        5112 :     int         ndatums = 0;
     316        5112 :     int         next_index = 0;
     317        5112 :     int         default_index = -1;
     318        5112 :     int         null_index = -1;
     319        5112 :     List       *non_null_values = NIL;
     320             : 
     321        5112 :     boundinfo = (PartitionBoundInfoData *)
     322             :         palloc0(sizeof(PartitionBoundInfoData));
     323        5112 :     boundinfo->strategy = key->strategy;
     324             :     /* Will be set correctly below. */
     325        5112 :     boundinfo->null_index = -1;
     326        5112 :     boundinfo->default_index = -1;
     327             : 
     328             :     /* Create a unified list of non-null values across all partitions. */
     329       15474 :     for (i = 0; i < nparts; i++)
     330             :     {
     331       10362 :         PartitionBoundSpec *spec = boundspecs[i];
     332             :         ListCell   *c;
     333             : 
     334       10362 :         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       10362 :         if (spec->is_default)
     343             :         {
     344         682 :             default_index = i;
     345         682 :             continue;
     346             :         }
     347             : 
     348       23520 :         foreach(c, spec->listdatums)
     349             :         {
     350       13840 :             Const      *val = castNode(Const, lfirst(c));
     351       13840 :             PartitionListValue *list_value = NULL;
     352             : 
     353       13840 :             if (!val->constisnull)
     354             :             {
     355       13416 :                 list_value = (PartitionListValue *)
     356             :                     palloc0(sizeof(PartitionListValue));
     357       13416 :                 list_value->index = i;
     358       13416 :                 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         424 :                 if (null_index != -1)
     368           0 :                     elog(ERROR, "found null more than once");
     369         424 :                 null_index = i;
     370             :             }
     371             : 
     372       13840 :             if (list_value)
     373       13416 :                 non_null_values = lappend(non_null_values, list_value);
     374             :         }
     375             :     }
     376             : 
     377        5112 :     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        5112 :     all_values = (PartitionListValue **)
     384        5112 :         palloc(ndatums * sizeof(PartitionListValue *));
     385        5112 :     i = 0;
     386       18528 :     foreach(cell, non_null_values)
     387             :     {
     388       13416 :         PartitionListValue *src = lfirst(cell);
     389             : 
     390       26832 :         all_values[i] = (PartitionListValue *)
     391       13416 :             palloc(sizeof(PartitionListValue));
     392       13416 :         all_values[i]->value = src->value;
     393       13416 :         all_values[i]->index = src->index;
     394       13416 :         i++;
     395             :     }
     396             : 
     397        5112 :     qsort_arg(all_values, ndatums, sizeof(PartitionListValue *),
     398             :               qsort_partition_list_value_cmp, (void *) key);
     399             : 
     400        5112 :     boundinfo->ndatums = ndatums;
     401        5112 :     boundinfo->datums = (Datum **) palloc0(ndatums * sizeof(Datum *));
     402        5112 :     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       18528 :     for (i = 0; i < ndatums; i++)
     411             :     {
     412       13416 :         int         orig_index = all_values[i]->index;
     413             : 
     414       13416 :         boundinfo->datums[i] = (Datum *) palloc(sizeof(Datum));
     415       40248 :         boundinfo->datums[i][0] = datumCopy(all_values[i]->value,
     416       13416 :                                             key->parttypbyval[0],
     417       13416 :                                             key->parttyplen[0]);
     418             : 
     419             :         /* If the old index has no mapping, assign one */
     420       13416 :         if ((*mapping)[orig_index] == -1)
     421        9580 :             (*mapping)[orig_index] = next_index++;
     422             : 
     423       13416 :         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        5112 :     if (null_index != -1)
     435             :     {
     436             :         Assert(null_index >= 0);
     437         424 :         if ((*mapping)[null_index] == -1)
     438         100 :             (*mapping)[null_index] = next_index++;
     439         424 :         boundinfo->null_index = (*mapping)[null_index];
     440             :     }
     441             : 
     442             :     /* Set the canonical value for default_index, if any. */
     443        5112 :     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         682 :         (*mapping)[default_index] = next_index++;
     453         682 :         boundinfo->default_index = (*mapping)[default_index];
     454             :     }
     455             : 
     456             :     /* All partitions must now have been assigned canonical indexes. */
     457             :     Assert(next_index == nparts);
     458        5112 :     return boundinfo;
     459             : }
     460             : 
     461             : /*
     462             :  * create_range_bounds
     463             :  *      Create a PartitionBoundInfo for a range partitioned table
     464             :  */
     465             : static PartitionBoundInfo
     466        5494 : create_range_bounds(PartitionBoundSpec **boundspecs, int nparts,
     467             :                     PartitionKey key, int **mapping)
     468             : {
     469             :     PartitionBoundInfo boundinfo;
     470        5494 :     PartitionRangeBound **rbounds = NULL;
     471             :     PartitionRangeBound **all_bounds,
     472             :                *prev;
     473             :     int         i,
     474             :                 k;
     475        5494 :     int         ndatums = 0;
     476        5494 :     int         default_index = -1;
     477        5494 :     int         next_index = 0;
     478             : 
     479        5494 :     boundinfo = (PartitionBoundInfoData *)
     480             :         palloc0(sizeof(PartitionBoundInfoData));
     481        5494 :     boundinfo->strategy = key->strategy;
     482             :     /* There is no special null-accepting range partition. */
     483        5494 :     boundinfo->null_index = -1;
     484             :     /* Will be set correctly below. */
     485        5494 :     boundinfo->default_index = -1;
     486             : 
     487        5494 :     all_bounds = (PartitionRangeBound **)
     488        5494 :         palloc0(2 * nparts * sizeof(PartitionRangeBound *));
     489             : 
     490             :     /* Create a unified list of range bounds across all the partitions. */
     491        5494 :     ndatums = 0;
     492       16642 :     for (i = 0; i < nparts; i++)
     493             :     {
     494       11148 :         PartitionBoundSpec *spec = boundspecs[i];
     495             :         PartitionRangeBound *lower,
     496             :                    *upper;
     497             : 
     498       11148 :         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       11148 :         if (spec->is_default)
     507             :         {
     508         578 :             default_index = i;
     509         578 :             continue;
     510             :         }
     511             : 
     512       10570 :         lower = make_one_partition_rbound(key, i, spec->lowerdatums, true);
     513       10570 :         upper = make_one_partition_rbound(key, i, spec->upperdatums, false);
     514       10570 :         all_bounds[ndatums++] = lower;
     515       10570 :         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        5494 :     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        5494 :     rbounds = (PartitionRangeBound **)
     529        5494 :         palloc(ndatums * sizeof(PartitionRangeBound *));
     530        5494 :     k = 0;
     531        5494 :     prev = NULL;
     532       26634 :     for (i = 0; i < ndatums; i++)
     533             :     {
     534       21140 :         PartitionRangeBound *cur = all_bounds[i];
     535       21140 :         bool        is_distinct = false;
     536             :         int         j;
     537             : 
     538             :         /* Is the current bound distinct from the previous one? */
     539       29766 :         for (j = 0; j < key->partnatts; j++)
     540             :         {
     541             :             Datum       cmpval;
     542             : 
     543       25182 :             if (prev == NULL || cur->kind[j] != prev->kind[j])
     544             :             {
     545        6018 :                 is_distinct = true;
     546        6018 :                 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       19164 :             if (cur->kind[j] != PARTITION_RANGE_DATUM_VALUE)
     555         124 :                 break;
     556             : 
     557       57120 :             cmpval = FunctionCall2Coll(&key->partsupfunc[j],
     558       19040 :                                        key->partcollation[j],
     559       19040 :                                        cur->datums[j],
     560       19040 :                                        prev->datums[j]);
     561       19040 :             if (DatumGetInt32(cmpval) != 0)
     562             :             {
     563       10414 :                 is_distinct = true;
     564       10414 :                 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       21140 :         if (is_distinct)
     573       16432 :             rbounds[k++] = all_bounds[i];
     574             : 
     575       21140 :         prev = cur;
     576             :     }
     577             : 
     578             :     /* Update ndatums to hold the count of distinct datums. */
     579        5494 :     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        5494 :     boundinfo->ndatums = ndatums;
     590        5494 :     boundinfo->datums = (Datum **) palloc0(ndatums * sizeof(Datum *));
     591        5494 :     boundinfo->kind = (PartitionRangeDatumKind **)
     592        5494 :         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        5494 :     boundinfo->indexes = (int *) palloc((ndatums + 1) * sizeof(int));
     600             : 
     601       21926 :     for (i = 0; i < ndatums; i++)
     602             :     {
     603             :         int         j;
     604             : 
     605       16432 :         boundinfo->datums[i] = (Datum *) palloc(key->partnatts *
     606             :                                                 sizeof(Datum));
     607       32864 :         boundinfo->kind[i] = (PartitionRangeDatumKind *)
     608       16432 :             palloc(key->partnatts *
     609             :                    sizeof(PartitionRangeDatumKind));
     610       38180 :         for (j = 0; j < key->partnatts; j++)
     611             :         {
     612       21748 :             if (rbounds[i]->kind[j] == PARTITION_RANGE_DATUM_VALUE)
     613       40608 :                 boundinfo->datums[i][j] =
     614       40608 :                     datumCopy(rbounds[i]->datums[j],
     615       20304 :                               key->parttypbyval[j],
     616       20304 :                               key->parttyplen[j]);
     617       21748 :             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       16432 :         if (rbounds[i]->lower)
     629        5862 :             boundinfo->indexes[i] = -1;
     630             :         else
     631             :         {
     632       10570 :             int         orig_index = rbounds[i]->index;
     633             : 
     634             :             /* If the old index has no mapping, assign one */
     635       10570 :             if ((*mapping)[orig_index] == -1)
     636       10570 :                 (*mapping)[orig_index] = next_index++;
     637             : 
     638       10570 :             boundinfo->indexes[i] = (*mapping)[orig_index];
     639             :         }
     640             :     }
     641             : 
     642             :     /* Set the canonical value for default_index, if any. */
     643        5494 :     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        5494 :     boundinfo->indexes[i] = -1;
     653             : 
     654             :     /* All partitions must now have been assigned canonical indexes. */
     655             :     Assert(next_index == nparts);
     656        5494 :     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        3158 : partition_bounds_equal(int partnatts, int16 *parttyplen, bool *parttypbyval,
     669             :                        PartitionBoundInfo b1, PartitionBoundInfo b2)
     670             : {
     671             :     int         i;
     672             : 
     673        3158 :     if (b1->strategy != b2->strategy)
     674           0 :         return false;
     675             : 
     676        3158 :     if (b1->ndatums != b2->ndatums)
     677          16 :         return false;
     678             : 
     679        3142 :     if (b1->null_index != b2->null_index)
     680           0 :         return false;
     681             : 
     682        3142 :     if (b1->default_index != b2->default_index)
     683           0 :         return false;
     684             : 
     685        3142 :     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       12286 :         for (i = 0; i < b1->ndatums; i++)
     726             :         {
     727             :             int         j;
     728             : 
     729       19518 :             for (j = 0; j < partnatts; j++)
     730             :             {
     731             :                 /* For range partitions, the bounds might not be finite. */
     732       10268 :                 if (b1->kind != NULL)
     733             :                 {
     734             :                     /* The different kinds of bound all differ from each other */
     735        6976 :                     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        6976 :                     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       20288 :                 if (!datumIsEqual(b1->datums[i][j], b2->datums[i][j],
     760       20288 :                                   parttypbyval[j], parttyplen[j]))
     761           0 :                     return false;
     762             :             }
     763             : 
     764        9250 :             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        4972 :         if (b1->strategy == PARTITION_STRATEGY_RANGE &&
     770        1936 :             b1->indexes[i] != b2->indexes[i])
     771           0 :             return false;
     772             :     }
     773        3142 :     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       10944 : 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       10944 :     dest = (PartitionBoundInfo) palloc(sizeof(PartitionBoundInfoData));
     791             : 
     792       10944 :     dest->strategy = src->strategy;
     793       10944 :     ndatums = dest->ndatums = src->ndatums;
     794       10944 :     partnatts = key->partnatts;
     795             : 
     796       10944 :     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       10944 :     dest->datums = (Datum **) palloc(sizeof(Datum *) * ndatums);
     802             : 
     803       10944 :     if (src->kind != NULL)
     804             :     {
     805        5494 :         dest->kind = (PartitionRangeDatumKind **) palloc(ndatums *
     806             :                                                          sizeof(PartitionRangeDatumKind *));
     807       21926 :         for (i = 0; i < ndatums; i++)
     808             :         {
     809       16432 :             dest->kind[i] = (PartitionRangeDatumKind *) palloc(partnatts *
     810             :                                                                sizeof(PartitionRangeDatumKind));
     811             : 
     812       16432 :             memcpy(dest->kind[i], src->kind[i],
     813       16432 :                    sizeof(PartitionRangeDatumKind) * key->partnatts);
     814             :         }
     815             :     }
     816             :     else
     817        5450 :         dest->kind = NULL;
     818             : 
     819       41496 :     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       30552 :         bool        hash_part = (key->strategy == PARTITION_STRATEGY_HASH);
     828       30552 :         int         natts = hash_part ? 2 : partnatts;
     829             : 
     830       30552 :         dest->datums[i] = (Datum *) palloc(sizeof(Datum) * natts);
     831             : 
     832       67124 :         for (j = 0; j < natts; j++)
     833             :         {
     834             :             bool        byval;
     835             :             int         typlen;
     836             : 
     837       36572 :             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       35164 :                 byval = key->parttypbyval[j];
     845       35164 :                 typlen = key->parttyplen[j];
     846             :             }
     847             : 
     848       58320 :             if (dest->kind == NULL ||
     849       21748 :                 dest->kind[i][j] == PARTITION_RANGE_DATUM_VALUE)
     850       35128 :                 dest->datums[i][j] = datumCopy(src->datums[i][j],
     851             :                                                byval, typlen);
     852             :         }
     853             :     }
     854             : 
     855       10944 :     dest->indexes = (int *) palloc(sizeof(int) * num_indexes);
     856       10944 :     memcpy(dest->indexes, src->indexes, sizeof(int) * num_indexes);
     857             : 
     858       10944 :     dest->null_index = src->null_index;
     859       10944 :     dest->default_index = src->default_index;
     860             : 
     861       10944 :     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        9994 : partitions_are_ordered(PartitionBoundInfo boundinfo, int nparts)
     877             : {
     878             :     Assert(boundinfo != NULL);
     879             : 
     880        9994 :     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        5200 :             if (!partition_bound_has_default(boundinfo))
     893        4100 :                 return true;
     894        1100 :             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        4570 :             if (partition_bound_has_default(boundinfo))
     913         540 :                 return false;
     914             : 
     915        4030 :             if (boundinfo->ndatums + partition_bound_accepts_nulls(boundinfo)
     916             :                 == nparts)
     917        3296 :                 return true;
     918         734 :             break;
     919             : 
     920             :         default:
     921             :             /* HASH, or some other strategy */
     922         224 :             break;
     923             :     }
     924             : 
     925        2058 :     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        4458 : check_new_partition_bound(char *relname, Relation parent,
     936             :                           PartitionBoundSpec *spec)
     937             : {
     938        4458 :     PartitionKey key = RelationGetPartitionKey(parent);
     939        4458 :     PartitionDesc partdesc = RelationGetPartitionDesc(parent);
     940        4458 :     PartitionBoundInfo boundinfo = partdesc->boundinfo;
     941        4458 :     ParseState *pstate = make_parsestate(NULL);
     942        4458 :     int         with = -1;
     943        4458 :     bool        overlap = false;
     944             : 
     945        4458 :     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         246 :         if (boundinfo == NULL || !partition_bound_has_default(boundinfo))
     954         230 :             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        4212 :     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        2082 :                 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        2512 :                     foreach(cell, spec->listdatums)
    1063             :                     {
    1064        1452 :                         Const      *val = castNode(Const, lfirst(cell));
    1065             : 
    1066        1452 :                         if (!val->constisnull)
    1067             :                         {
    1068             :                             int         offset;
    1069             :                             bool        equal;
    1070             : 
    1071        1416 :                             offset = partition_list_bsearch(&key->partsupfunc[0],
    1072             :                                                             key->partcollation,
    1073             :                                                             boundinfo,
    1074             :                                                             val->constvalue,
    1075             :                                                             &equal);
    1076        1416 :                             if (offset >= 0 && equal)
    1077             :                             {
    1078          12 :                                 overlap = true;
    1079          12 :                                 with = boundinfo->indexes[offset];
    1080          12 :                                 break;
    1081             :                             }
    1082             :                         }
    1083          36 :                         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        2082 :                 break;
    1093             :             }
    1094             : 
    1095             :         case PARTITION_STRATEGY_RANGE:
    1096             :             {
    1097             :                 PartitionRangeBound *lower,
    1098             :                            *upper;
    1099             : 
    1100             :                 Assert(spec->strategy == PARTITION_STRATEGY_RANGE);
    1101        1912 :                 lower = make_one_partition_rbound(key, -1, spec->lowerdatums, true);
    1102        1912 :                 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        1912 :                 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        1904 :                 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        1072 :                     offset = partition_range_bsearch(key->partnatts,
    1148             :                                                      key->partsupfunc,
    1149             :                                                      key->partcollation,
    1150             :                                                      boundinfo, lower,
    1151             :                                                      &equal);
    1152             : 
    1153        1072 :                     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        1052 :                         if (offset + 1 < boundinfo->ndatums)
    1162             :                         {
    1163             :                             int32       cmpval;
    1164             :                             Datum      *datums;
    1165             :                             PartitionRangeDatumKind *kind;
    1166             :                             bool        is_lower;
    1167             : 
    1168          52 :                             datums = boundinfo->datums[offset + 1];
    1169          52 :                             kind = boundinfo->kind[offset + 1];
    1170          52 :                             is_lower = (boundinfo->indexes[offset + 1] == -1);
    1171             : 
    1172          52 :                             cmpval = partition_rbound_cmp(key->partnatts,
    1173             :                                                           key->partsupfunc,
    1174             :                                                           key->partcollation,
    1175             :                                                           datums, kind,
    1176             :                                                           is_lower, upper);
    1177          52 :                             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        1904 :                 break;
    1201             :             }
    1202             : 
    1203             :         default:
    1204           0 :             elog(ERROR, "unexpected partition strategy: %d",
    1205             :                  (int) key->strategy);
    1206             :     }
    1207             : 
    1208        4192 :     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         214 : 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         428 :     new_part_constraints = (new_spec->strategy == PARTITION_STRATEGY_LIST)
    1236             :         ? get_qual_for_list(parent, new_spec)
    1237         214 :         : get_qual_for_range(parent, new_spec, false);
    1238         214 :     def_part_constraints =
    1239             :         get_proposed_default_constraint(new_part_constraints);
    1240             : 
    1241             :     /*
    1242             :      * Map the Vars in the constraint expression from parent's attnos to
    1243             :      * default_rel's.
    1244             :      */
    1245         214 :     def_part_constraints =
    1246             :         map_partition_varattnos(def_part_constraints, 1, default_rel,
    1247             :                                 parent, NULL);
    1248             : 
    1249             :     /*
    1250             :      * If the existing constraints on the default partition imply that it will
    1251             :      * not contain any row that would belong to the new partition, we can
    1252             :      * avoid scanning the default partition.
    1253             :      */
    1254         214 :     if (PartConstraintImpliedByRelConstraint(default_rel, def_part_constraints))
    1255             :     {
    1256          10 :         ereport(DEBUG1,
    1257             :                 (errmsg("updated partition constraint for default partition \"%s\" is implied by existing constraints",
    1258             :                         RelationGetRelationName(default_rel))));
    1259          10 :         return;
    1260             :     }
    1261             : 
    1262             :     /*
    1263             :      * Scan the default partition and its subpartitions, and check for rows
    1264             :      * that do not satisfy the revised partition constraints.
    1265             :      */
    1266         204 :     if (default_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
    1267          36 :         all_parts = find_all_inheritors(RelationGetRelid(default_rel),
    1268             :                                         AccessExclusiveLock, NULL);
    1269             :     else
    1270         168 :         all_parts = list_make1_oid(RelationGetRelid(default_rel));
    1271             : 
    1272         492 :     foreach(lc, all_parts)
    1273             :     {
    1274         300 :         Oid         part_relid = lfirst_oid(lc);
    1275             :         Relation    part_rel;
    1276             :         Expr       *partition_constraint;
    1277             :         EState     *estate;
    1278         300 :         ExprState  *partqualstate = NULL;
    1279             :         Snapshot    snapshot;
    1280             :         ExprContext *econtext;
    1281             :         TableScanDesc scan;
    1282             :         MemoryContext oldCxt;
    1283             :         TupleTableSlot *tupslot;
    1284             : 
    1285             :         /* Lock already taken above. */
    1286         300 :         if (part_relid != RelationGetRelid(default_rel))
    1287             :         {
    1288          96 :             part_rel = table_open(part_relid, NoLock);
    1289             : 
    1290             :             /*
    1291             :              * Map the Vars in the constraint expression from default_rel's
    1292             :              * the sub-partition's.
    1293             :              */
    1294          96 :             partition_constraint = make_ands_explicit(def_part_constraints);
    1295          96 :             partition_constraint = (Expr *)
    1296             :                 map_partition_varattnos((List *) partition_constraint, 1,
    1297             :                                         part_rel, default_rel, NULL);
    1298             : 
    1299             :             /*
    1300             :              * If the partition constraints on default partition child imply
    1301             :              * that it will not contain any row that would belong to the new
    1302             :              * partition, we can avoid scanning the child table.
    1303             :              */
    1304          96 :             if (PartConstraintImpliedByRelConstraint(part_rel,
    1305             :                                                      def_part_constraints))
    1306             :             {
    1307           6 :                 ereport(DEBUG1,
    1308             :                         (errmsg("updated partition constraint for default partition \"%s\" is implied by existing constraints",
    1309             :                                 RelationGetRelationName(part_rel))));
    1310             : 
    1311           6 :                 table_close(part_rel, NoLock);
    1312           6 :                 continue;
    1313             :             }
    1314             :         }
    1315             :         else
    1316             :         {
    1317         204 :             part_rel = default_rel;
    1318         204 :             partition_constraint = make_ands_explicit(def_part_constraints);
    1319             :         }
    1320             : 
    1321             :         /*
    1322             :          * Only RELKIND_RELATION relations (i.e. leaf partitions) need to be
    1323             :          * scanned.
    1324             :          */
    1325         294 :         if (part_rel->rd_rel->relkind != RELKIND_RELATION)
    1326             :         {
    1327          36 :             if (part_rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
    1328           0 :                 ereport(WARNING,
    1329             :                         (errcode(ERRCODE_CHECK_VIOLATION),
    1330             :                          errmsg("skipped scanning foreign table \"%s\" which is a partition of default partition \"%s\"",
    1331             :                                 RelationGetRelationName(part_rel),
    1332             :                                 RelationGetRelationName(default_rel))));
    1333             : 
    1334          36 :             if (RelationGetRelid(default_rel) != RelationGetRelid(part_rel))
    1335           0 :                 table_close(part_rel, NoLock);
    1336             : 
    1337          36 :             continue;
    1338             :         }
    1339             : 
    1340         258 :         estate = CreateExecutorState();
    1341             : 
    1342             :         /* Build expression execution states for partition check quals */
    1343         258 :         partqualstate = ExecPrepareExpr(partition_constraint, estate);
    1344             : 
    1345         258 :         econtext = GetPerTupleExprContext(estate);
    1346         258 :         snapshot = RegisterSnapshot(GetLatestSnapshot());
    1347         258 :         tupslot = table_slot_create(part_rel, &estate->es_tupleTable);
    1348         258 :         scan = table_beginscan(part_rel, snapshot, 0, NULL);
    1349             : 
    1350             :         /*
    1351             :          * Switch to per-tuple memory context and reset it for each tuple
    1352             :          * produced, so we don't leak memory.
    1353             :          */
    1354         258 :         oldCxt = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
    1355             : 
    1356         548 :         while (table_scan_getnextslot(scan, ForwardScanDirection, tupslot))
    1357             :         {
    1358          44 :             econtext->ecxt_scantuple = tupslot;
    1359             : 
    1360          44 :             if (!ExecCheck(partqualstate, econtext))
    1361          12 :                 ereport(ERROR,
    1362             :                         (errcode(ERRCODE_CHECK_VIOLATION),
    1363             :                          errmsg("updated partition constraint for default partition \"%s\" would be violated by some row",
    1364             :                                 RelationGetRelationName(default_rel))));
    1365             : 
    1366          32 :             ResetExprContext(econtext);
    1367          32 :             CHECK_FOR_INTERRUPTS();
    1368             :         }
    1369             : 
    1370         246 :         MemoryContextSwitchTo(oldCxt);
    1371         246 :         table_endscan(scan);
    1372         246 :         UnregisterSnapshot(snapshot);
    1373         246 :         ExecDropSingleTupleTableSlot(tupslot);
    1374         246 :         FreeExecutorState(estate);
    1375             : 
    1376         246 :         if (RelationGetRelid(default_rel) != RelationGetRelid(part_rel))
    1377          90 :             table_close(part_rel, NoLock);  /* keep the lock until commit */
    1378             :     }
    1379             : }
    1380             : 
    1381             : /*
    1382             :  * get_hash_partition_greatest_modulus
    1383             :  *
    1384             :  * Returns the greatest modulus of the hash partition bound. The greatest
    1385             :  * modulus will be at the end of the datums array because hash partitions are
    1386             :  * arranged in the ascending order of their moduli and remainders.
    1387             :  */
    1388             : int
    1389        3474 : get_hash_partition_greatest_modulus(PartitionBoundInfo bound)
    1390             : {
    1391             :     Assert(bound && bound->strategy == PARTITION_STRATEGY_HASH);
    1392             :     Assert(bound->datums && bound->ndatums > 0);
    1393             :     Assert(DatumGetInt32(bound->datums[bound->ndatums - 1][0]) > 0);
    1394             : 
    1395        3474 :     return DatumGetInt32(bound->datums[bound->ndatums - 1][0]);
    1396             : }
    1397             : 
    1398             : /*
    1399             :  * make_one_partition_rbound
    1400             :  *
    1401             :  * Return a PartitionRangeBound given a list of PartitionRangeDatum elements
    1402             :  * and a flag telling whether the bound is lower or not.  Made into a function
    1403             :  * because there are multiple sites that want to use this facility.
    1404             :  */
    1405             : static PartitionRangeBound *
    1406       24964 : make_one_partition_rbound(PartitionKey key, int index, List *datums, bool lower)
    1407             : {
    1408             :     PartitionRangeBound *bound;
    1409             :     ListCell   *lc;
    1410             :     int         i;
    1411             : 
    1412             :     Assert(datums != NIL);
    1413             : 
    1414       24964 :     bound = (PartitionRangeBound *) palloc0(sizeof(PartitionRangeBound));
    1415       24964 :     bound->index = index;
    1416       24964 :     bound->datums = (Datum *) palloc0(key->partnatts * sizeof(Datum));
    1417       24964 :     bound->kind = (PartitionRangeDatumKind *) palloc0(key->partnatts *
    1418             :                                                       sizeof(PartitionRangeDatumKind));
    1419       24964 :     bound->lower = lower;
    1420             : 
    1421       24964 :     i = 0;
    1422       58388 :     foreach(lc, datums)
    1423             :     {
    1424       33424 :         PartitionRangeDatum *datum = castNode(PartitionRangeDatum, lfirst(lc));
    1425             : 
    1426             :         /* What's contained in this range datum? */
    1427       33424 :         bound->kind[i] = datum->kind;
    1428             : 
    1429       33424 :         if (datum->kind == PARTITION_RANGE_DATUM_VALUE)
    1430             :         {
    1431       31420 :             Const      *val = castNode(Const, datum->value);
    1432             : 
    1433       31420 :             if (val->constisnull)
    1434           0 :                 elog(ERROR, "invalid range bound datum");
    1435       31420 :             bound->datums[i] = val->constvalue;
    1436             :         }
    1437             : 
    1438       33424 :         i++;
    1439             :     }
    1440             : 
    1441       24964 :     return bound;
    1442             : }
    1443             : 
    1444             : /*
    1445             :  * partition_rbound_cmp
    1446             :  *
    1447             :  * Return for two range bounds whether the 1st one (specified in datums1,
    1448             :  * kind1, and lower1) is <, =, or > the bound specified in *b2.
    1449             :  *
    1450             :  * partnatts, partsupfunc and partcollation give the number of attributes in the
    1451             :  * bounds to be compared, comparison function to be used and the collations of
    1452             :  * attributes, respectively.
    1453             :  *
    1454             :  * Note that if the values of the two range bounds compare equal, then we take
    1455             :  * into account whether they are upper or lower bounds, and an upper bound is
    1456             :  * considered to be smaller than a lower bound. This is important to the way
    1457             :  * that RelationBuildPartitionDesc() builds the PartitionBoundInfoData
    1458             :  * structure, which only stores the upper bound of a common boundary between
    1459             :  * two contiguous partitions.
    1460             :  */
    1461             : static int32
    1462       21952 : partition_rbound_cmp(int partnatts, FmgrInfo *partsupfunc,
    1463             :                      Oid *partcollation,
    1464             :                      Datum *datums1, PartitionRangeDatumKind *kind1,
    1465             :                      bool lower1, PartitionRangeBound *b2)
    1466             : {
    1467       21952 :     int32       cmpval = 0;     /* placate compiler */
    1468             :     int         i;
    1469       21952 :     Datum      *datums2 = b2->datums;
    1470       21952 :     PartitionRangeDatumKind *kind2 = b2->kind;
    1471       21952 :     bool        lower2 = b2->lower;
    1472             : 
    1473       33286 :     for (i = 0; i < partnatts; i++)
    1474             :     {
    1475             :         /*
    1476             :          * First, handle cases where the column is unbounded, which should not
    1477             :          * invoke the comparison procedure, and should not consider any later
    1478             :          * columns. Note that the PartitionRangeDatumKind enum elements
    1479             :          * compare the same way as the values they represent.
    1480             :          */
    1481       27826 :         if (kind1[i] < kind2[i])
    1482         916 :             return -1;
    1483       26910 :         else if (kind1[i] > kind2[i])
    1484           4 :             return 1;
    1485       26906 :         else if (kind1[i] != PARTITION_RANGE_DATUM_VALUE)
    1486             : 
    1487             :             /*
    1488             :              * The column bounds are both MINVALUE or both MAXVALUE. No later
    1489             :              * columns should be considered, but we still need to compare
    1490             :              * whether they are upper or lower bounds.
    1491             :              */
    1492         172 :             break;
    1493             : 
    1494       26734 :         cmpval = DatumGetInt32(FunctionCall2Coll(&partsupfunc[i],
    1495             :                                                  partcollation[i],
    1496             :                                                  datums1[i],
    1497             :                                                  datums2[i]));
    1498       26734 :         if (cmpval != 0)
    1499       15400 :             break;
    1500             :     }
    1501             : 
    1502             :     /*
    1503             :      * If the comparison is anything other than equal, we're done. If they
    1504             :      * compare equal though, we still have to consider whether the boundaries
    1505             :      * are inclusive or exclusive.  Exclusive one is considered smaller of the
    1506             :      * two.
    1507             :      */
    1508       21032 :     if (cmpval == 0 && lower1 != lower2)
    1509        5620 :         cmpval = lower1 ? 1 : -1;
    1510             : 
    1511       21032 :     return cmpval;
    1512             : }
    1513             : 
    1514             : /*
    1515             :  * partition_rbound_datum_cmp
    1516             :  *
    1517             :  * Return whether range bound (specified in rb_datums and rb_kind)
    1518             :  * is <, =, or > partition key of tuple (tuple_datums)
    1519             :  *
    1520             :  * n_tuple_datums, partsupfunc and partcollation give number of attributes in
    1521             :  * the bounds to be compared, comparison function to be used and the collations
    1522             :  * of attributes resp.
    1523             :  *
    1524             :  */
    1525             : int32
    1526      684280 : partition_rbound_datum_cmp(FmgrInfo *partsupfunc, Oid *partcollation,
    1527             :                            Datum *rb_datums, PartitionRangeDatumKind *rb_kind,
    1528             :                            Datum *tuple_datums, int n_tuple_datums)
    1529             : {
    1530             :     int         i;
    1531      684280 :     int32       cmpval = -1;
    1532             : 
    1533      722556 :     for (i = 0; i < n_tuple_datums; i++)
    1534             :     {
    1535      687872 :         if (rb_kind[i] == PARTITION_RANGE_DATUM_MINVALUE)
    1536         380 :             return -1;
    1537      687492 :         else if (rb_kind[i] == PARTITION_RANGE_DATUM_MAXVALUE)
    1538         288 :             return 1;
    1539             : 
    1540      687204 :         cmpval = DatumGetInt32(FunctionCall2Coll(&partsupfunc[i],
    1541             :                                                  partcollation[i],
    1542             :                                                  rb_datums[i],
    1543             :                                                  tuple_datums[i]));
    1544      687204 :         if (cmpval != 0)
    1545      648928 :             break;
    1546             :     }
    1547             : 
    1548      683612 :     return cmpval;
    1549             : }
    1550             : 
    1551             : /*
    1552             :  * partition_hbound_cmp
    1553             :  *
    1554             :  * Compares modulus first, then remainder if modulus is equal.
    1555             :  */
    1556             : static int32
    1557         608 : partition_hbound_cmp(int modulus1, int remainder1, int modulus2, int remainder2)
    1558             : {
    1559         608 :     if (modulus1 < modulus2)
    1560          96 :         return -1;
    1561         512 :     if (modulus1 > modulus2)
    1562          24 :         return 1;
    1563         488 :     if (modulus1 == modulus2 && remainder1 != remainder2)
    1564         488 :         return (remainder1 > remainder2) ? 1 : -1;
    1565           0 :     return 0;
    1566             : }
    1567             : 
    1568             : /*
    1569             :  * partition_list_bsearch
    1570             :  *      Returns the index of the greatest bound datum that is less than equal
    1571             :  *      to the given value or -1 if all of the bound datums are greater
    1572             :  *
    1573             :  * *is_equal is set to true if the bound datum at the returned index is equal
    1574             :  * to the input value.
    1575             :  */
    1576             : int
    1577       77912 : partition_list_bsearch(FmgrInfo *partsupfunc, Oid *partcollation,
    1578             :                        PartitionBoundInfo boundinfo,
    1579             :                        Datum value, bool *is_equal)
    1580             : {
    1581             :     int         lo,
    1582             :                 hi,
    1583             :                 mid;
    1584             : 
    1585       77912 :     lo = -1;
    1586       77912 :     hi = boundinfo->ndatums - 1;
    1587      243514 :     while (lo < hi)
    1588             :     {
    1589             :         int32       cmpval;
    1590             : 
    1591      161226 :         mid = (lo + hi + 1) / 2;
    1592      161226 :         cmpval = DatumGetInt32(FunctionCall2Coll(&partsupfunc[0],
    1593             :                                                  partcollation[0],
    1594             :                                                  boundinfo->datums[mid][0],
    1595             :                                                  value));
    1596      161226 :         if (cmpval <= 0)
    1597             :         {
    1598      130680 :             lo = mid;
    1599      130680 :             *is_equal = (cmpval == 0);
    1600      130680 :             if (*is_equal)
    1601       73536 :                 break;
    1602             :         }
    1603             :         else
    1604       30546 :             hi = mid - 1;
    1605             :     }
    1606             : 
    1607       77912 :     return lo;
    1608             : }
    1609             : 
    1610             : /*
    1611             :  * partition_range_bsearch
    1612             :  *      Returns the index of the greatest range bound that is less than or
    1613             :  *      equal to the given range bound or -1 if all of the range bounds are
    1614             :  *      greater
    1615             :  *
    1616             :  * *is_equal is set to true if the range bound at the returned index is equal
    1617             :  * to the input range bound
    1618             :  */
    1619             : static int
    1620        1072 : partition_range_bsearch(int partnatts, FmgrInfo *partsupfunc,
    1621             :                         Oid *partcollation,
    1622             :                         PartitionBoundInfo boundinfo,
    1623             :                         PartitionRangeBound *probe, bool *is_equal)
    1624             : {
    1625             :     int         lo,
    1626             :                 hi,
    1627             :                 mid;
    1628             : 
    1629        1072 :     lo = -1;
    1630        1072 :     hi = boundinfo->ndatums - 1;
    1631        4442 :     while (lo < hi)
    1632             :     {
    1633             :         int32       cmpval;
    1634             : 
    1635        2310 :         mid = (lo + hi + 1) / 2;
    1636        6930 :         cmpval = partition_rbound_cmp(partnatts, partsupfunc,
    1637             :                                       partcollation,
    1638        2310 :                                       boundinfo->datums[mid],
    1639        2310 :                                       boundinfo->kind[mid],
    1640        2310 :                                       (boundinfo->indexes[mid] == -1),
    1641             :                                       probe);
    1642        2310 :         if (cmpval <= 0)
    1643             :         {
    1644        2230 :             lo = mid;
    1645        2230 :             *is_equal = (cmpval == 0);
    1646             : 
    1647        2230 :             if (*is_equal)
    1648          12 :                 break;
    1649             :         }
    1650             :         else
    1651          80 :             hi = mid - 1;
    1652             :     }
    1653             : 
    1654        1072 :     return lo;
    1655             : }
    1656             : 
    1657             : /*
    1658             :  * partition_range_bsearch
    1659             :  *      Returns the index of the greatest range bound that is less than or
    1660             :  *      equal to the given tuple or -1 if all of the range bounds are greater
    1661             :  *
    1662             :  * *is_equal is set to true if the range bound at the returned index is equal
    1663             :  * to the input tuple.
    1664             :  */
    1665             : int
    1666      308562 : partition_range_datum_bsearch(FmgrInfo *partsupfunc, Oid *partcollation,
    1667             :                               PartitionBoundInfo boundinfo,
    1668             :                               int nvalues, Datum *values, bool *is_equal)
    1669             : {
    1670             :     int         lo,
    1671             :                 hi,
    1672             :                 mid;
    1673             : 
    1674      308562 :     lo = -1;
    1675      308562 :     hi = boundinfo->ndatums - 1;
    1676     1266144 :     while (lo < hi)
    1677             :     {
    1678             :         int32       cmpval;
    1679             : 
    1680      683336 :         mid = (lo + hi + 1) / 2;
    1681     1366672 :         cmpval = partition_rbound_datum_cmp(partsupfunc,
    1682             :                                             partcollation,
    1683      683336 :                                             boundinfo->datums[mid],
    1684      683336 :                                             boundinfo->kind[mid],
    1685             :                                             values,
    1686             :                                             nvalues);
    1687      683336 :         if (cmpval <= 0)
    1688             :         {
    1689      395722 :             lo = mid;
    1690      395722 :             *is_equal = (cmpval == 0);
    1691             : 
    1692      395722 :             if (*is_equal)
    1693       34316 :                 break;
    1694             :         }
    1695             :         else
    1696      287614 :             hi = mid - 1;
    1697             :     }
    1698             : 
    1699      308562 :     return lo;
    1700             : }
    1701             : 
    1702             : /*
    1703             :  * partition_hash_bsearch
    1704             :  *      Returns the index of the greatest (modulus, remainder) pair that is
    1705             :  *      less than or equal to the given (modulus, remainder) pair or -1 if
    1706             :  *      all of them are greater
    1707             :  */
    1708             : int
    1709         152 : partition_hash_bsearch(PartitionBoundInfo boundinfo,
    1710             :                        int modulus, int remainder)
    1711             : {
    1712             :     int         lo,
    1713             :                 hi,
    1714             :                 mid;
    1715             : 
    1716         152 :     lo = -1;
    1717         152 :     hi = boundinfo->ndatums - 1;
    1718         534 :     while (lo < hi)
    1719             :     {
    1720             :         int32       cmpval,
    1721             :                     bound_modulus,
    1722             :                     bound_remainder;
    1723             : 
    1724         230 :         mid = (lo + hi + 1) / 2;
    1725         230 :         bound_modulus = DatumGetInt32(boundinfo->datums[mid][0]);
    1726         230 :         bound_remainder = DatumGetInt32(boundinfo->datums[mid][1]);
    1727         230 :         cmpval = partition_hbound_cmp(bound_modulus, bound_remainder,
    1728             :                                       modulus, remainder);
    1729         230 :         if (cmpval <= 0)
    1730             :         {
    1731         198 :             lo = mid;
    1732             : 
    1733         198 :             if (cmpval == 0)
    1734           0 :                 break;
    1735             :         }
    1736             :         else
    1737          32 :             hi = mid - 1;
    1738             :     }
    1739             : 
    1740         152 :     return lo;
    1741             : }
    1742             : 
    1743             : /*
    1744             :  * qsort_partition_hbound_cmp
    1745             :  *
    1746             :  * Hash bounds are sorted by modulus, then by remainder.
    1747             :  */
    1748             : static int32
    1749         378 : qsort_partition_hbound_cmp(const void *a, const void *b)
    1750             : {
    1751         378 :     PartitionHashBound *h1 = (*(PartitionHashBound *const *) a);
    1752         378 :     PartitionHashBound *h2 = (*(PartitionHashBound *const *) b);
    1753             : 
    1754         378 :     return partition_hbound_cmp(h1->modulus, h1->remainder,
    1755             :                                 h2->modulus, h2->remainder);
    1756             : }
    1757             : 
    1758             : /*
    1759             :  * qsort_partition_list_value_cmp
    1760             :  *
    1761             :  * Compare two list partition bound datums.
    1762             :  */
    1763             : static int32
    1764       15522 : qsort_partition_list_value_cmp(const void *a, const void *b, void *arg)
    1765             : {
    1766       15522 :     Datum       val1 = (*(PartitionListValue *const *) a)->value,
    1767       15522 :                 val2 = (*(PartitionListValue *const *) b)->value;
    1768       15522 :     PartitionKey key = (PartitionKey) arg;
    1769             : 
    1770       15522 :     return DatumGetInt32(FunctionCall2Coll(&key->partsupfunc[0],
    1771             :                                            key->partcollation[0],
    1772             :                                            val1, val2));
    1773             : }
    1774             : 
    1775             : /*
    1776             :  * qsort_partition_rbound_cmp
    1777             :  *
    1778             :  * Used when sorting range bounds across all range partitions.
    1779             :  */
    1780             : static int32
    1781       17678 : qsort_partition_rbound_cmp(const void *a, const void *b, void *arg)
    1782             : {
    1783       17678 :     PartitionRangeBound *b1 = (*(PartitionRangeBound *const *) a);
    1784       17678 :     PartitionRangeBound *b2 = (*(PartitionRangeBound *const *) b);
    1785       17678 :     PartitionKey key = (PartitionKey) arg;
    1786             : 
    1787       17678 :     return partition_rbound_cmp(key->partnatts, key->partsupfunc,
    1788             :                                 key->partcollation, b1->datums, b1->kind,
    1789       17678 :                                 b1->lower, b2);
    1790             : }
    1791             : 
    1792             : /*
    1793             :  * get_partition_bound_num_indexes
    1794             :  *
    1795             :  * Returns the number of the entries in the partition bound indexes array.
    1796             :  */
    1797             : static int
    1798       10944 : get_partition_bound_num_indexes(PartitionBoundInfo bound)
    1799             : {
    1800             :     int         num_indexes;
    1801             : 
    1802             :     Assert(bound);
    1803             : 
    1804       10944 :     switch (bound->strategy)
    1805             :     {
    1806             :         case PARTITION_STRATEGY_HASH:
    1807             : 
    1808             :             /*
    1809             :              * The number of the entries in the indexes array is same as the
    1810             :              * greatest modulus.
    1811             :              */
    1812         338 :             num_indexes = get_hash_partition_greatest_modulus(bound);
    1813         338 :             break;
    1814             : 
    1815             :         case PARTITION_STRATEGY_LIST:
    1816        5112 :             num_indexes = bound->ndatums;
    1817        5112 :             break;
    1818             : 
    1819             :         case PARTITION_STRATEGY_RANGE:
    1820             :             /* Range partitioned table has an extra index. */
    1821        5494 :             num_indexes = bound->ndatums + 1;
    1822        5494 :             break;
    1823             : 
    1824             :         default:
    1825           0 :             elog(ERROR, "unexpected partition strategy: %d",
    1826             :                  (int) bound->strategy);
    1827             :     }
    1828             : 
    1829       10944 :     return num_indexes;
    1830             : }
    1831             : 
    1832             : /*
    1833             :  * get_partition_operator
    1834             :  *
    1835             :  * Return oid of the operator of the given strategy for the given partition
    1836             :  * key column.  It is assumed that the partitioning key is of the same type as
    1837             :  * the chosen partitioning opclass, or at least binary-compatible.  In the
    1838             :  * latter case, *need_relabel is set to true if the opclass is not of a
    1839             :  * polymorphic type (indicating a RelabelType node needed on top), otherwise
    1840             :  * false.
    1841             :  */
    1842             : static Oid
    1843       11732 : get_partition_operator(PartitionKey key, int col, StrategyNumber strategy,
    1844             :                        bool *need_relabel)
    1845             : {
    1846             :     Oid         operoid;
    1847             : 
    1848             :     /*
    1849             :      * Get the operator in the partitioning opfamily using the opclass'
    1850             :      * declared input type as both left- and righttype.
    1851             :      */
    1852       35196 :     operoid = get_opfamily_member(key->partopfamily[col],
    1853       11732 :                                   key->partopcintype[col],
    1854       11732 :                                   key->partopcintype[col],
    1855             :                                   strategy);
    1856       11732 :     if (!OidIsValid(operoid))
    1857           0 :         elog(ERROR, "missing operator %d(%u,%u) in partition opfamily %u",
    1858             :              strategy, key->partopcintype[col], key->partopcintype[col],
    1859             :              key->partopfamily[col]);
    1860             : 
    1861             :     /*
    1862             :      * If the partition key column is not of the same type as the operator
    1863             :      * class and not polymorphic, tell caller to wrap the non-Const expression
    1864             :      * in a RelabelType.  This matches what parse_coerce.c does.
    1865             :      */
    1866       23552 :     *need_relabel = (key->parttypid[col] != key->partopcintype[col] &&
    1867       11900 :                      key->partopcintype[col] != RECORDOID &&
    1868         176 :                      !IsPolymorphicType(key->partopcintype[col]));
    1869             : 
    1870       11732 :     return operoid;
    1871             : }
    1872             : 
    1873             : /*
    1874             :  * make_partition_op_expr
    1875             :  *      Returns an Expr for the given partition key column with arg1 and
    1876             :  *      arg2 as its leftop and rightop, respectively
    1877             :  */
    1878             : static Expr *
    1879       11732 : make_partition_op_expr(PartitionKey key, int keynum,
    1880             :                        uint16 strategy, Expr *arg1, Expr *arg2)
    1881             : {
    1882             :     Oid         operoid;
    1883       11732 :     bool        need_relabel = false;
    1884       11732 :     Expr       *result = NULL;
    1885             : 
    1886             :     /* Get the correct btree operator for this partitioning column */
    1887       11732 :     operoid = get_partition_operator(key, keynum, strategy, &need_relabel);
    1888             : 
    1889             :     /*
    1890             :      * Chosen operator may be such that the non-Const operand needs to be
    1891             :      * coerced, so apply the same; see the comment in
    1892             :      * get_partition_operator().
    1893             :      */
    1894       20310 :     if (!IsA(arg1, Const) &&
    1895       17088 :         (need_relabel ||
    1896        8510 :          key->partcollation[keynum] != key->parttypcoll[keynum]))
    1897         136 :         arg1 = (Expr *) makeRelabelType(arg1,
    1898          68 :                                         key->partopcintype[keynum],
    1899             :                                         -1,
    1900          68 :                                         key->partcollation[keynum],
    1901             :                                         COERCE_EXPLICIT_CAST);
    1902             : 
    1903             :     /* Generate the actual expression */
    1904       11732 :     switch (key->strategy)
    1905             :     {
    1906             :         case PARTITION_STRATEGY_LIST:
    1907             :             {
    1908        1922 :                 List       *elems = (List *) arg2;
    1909        1922 :                 int         nelems = list_length(elems);
    1910             : 
    1911             :                 Assert(nelems >= 1);
    1912             :                 Assert(keynum == 0);
    1913             : 
    1914        2280 :                 if (nelems > 1 &&
    1915         358 :                     !type_is_array(key->parttypid[keynum]))
    1916         354 :                 {
    1917             :                     ArrayExpr  *arrexpr;
    1918             :                     ScalarArrayOpExpr *saopexpr;
    1919             : 
    1920             :                     /* Construct an ArrayExpr for the right-hand inputs */
    1921         354 :                     arrexpr = makeNode(ArrayExpr);
    1922         354 :                     arrexpr->array_typeid =
    1923         354 :                         get_array_type(key->parttypid[keynum]);
    1924         354 :                     arrexpr->array_collid = key->parttypcoll[keynum];
    1925         354 :                     arrexpr->element_typeid = key->parttypid[keynum];
    1926         354 :                     arrexpr->elements = elems;
    1927         354 :                     arrexpr->multidims = false;
    1928         354 :                     arrexpr->location = -1;
    1929             : 
    1930             :                     /* Build leftop = ANY (rightop) */
    1931         354 :                     saopexpr = makeNode(ScalarArrayOpExpr);
    1932         354 :                     saopexpr->opno = operoid;
    1933         354 :                     saopexpr->opfuncid = get_opcode(operoid);
    1934         354 :                     saopexpr->useOr = true;
    1935         354 :                     saopexpr->inputcollid = key->partcollation[keynum];
    1936         354 :                     saopexpr->args = list_make2(arg1, arrexpr);
    1937         354 :                     saopexpr->location = -1;
    1938             : 
    1939         354 :                     result = (Expr *) saopexpr;
    1940             :                 }
    1941             :                 else
    1942             :                 {
    1943        1568 :                     List       *elemops = NIL;
    1944             :                     ListCell   *lc;
    1945             : 
    1946        3140 :                     foreach(lc, elems)
    1947             :                     {
    1948        1572 :                         Expr       *elem = lfirst(lc),
    1949             :                                    *elemop;
    1950             : 
    1951        1572 :                         elemop = make_opclause(operoid,
    1952             :                                                BOOLOID,
    1953             :                                                false,
    1954             :                                                arg1, elem,
    1955             :                                                InvalidOid,
    1956        1572 :                                                key->partcollation[keynum]);
    1957        1572 :                         elemops = lappend(elemops, elemop);
    1958             :                     }
    1959             : 
    1960        1568 :                     result = nelems > 1 ? makeBoolExpr(OR_EXPR, elemops, -1) : linitial(elemops);
    1961             :                 }
    1962        1922 :                 break;
    1963             :             }
    1964             : 
    1965             :         case PARTITION_STRATEGY_RANGE:
    1966        9810 :             result = make_opclause(operoid,
    1967             :                                    BOOLOID,
    1968             :                                    false,
    1969             :                                    arg1, arg2,
    1970             :                                    InvalidOid,
    1971        9810 :                                    key->partcollation[keynum]);
    1972        9810 :             break;
    1973             : 
    1974             :         default:
    1975           0 :             elog(ERROR, "invalid partitioning strategy");
    1976             :             break;
    1977             :     }
    1978             : 
    1979       11732 :     return result;
    1980             : }
    1981             : 
    1982             : /*
    1983             :  * get_qual_for_hash
    1984             :  *
    1985             :  * Returns a CHECK constraint expression to use as a hash partition's
    1986             :  * constraint, given the parent relation and partition bound structure.
    1987             :  *
    1988             :  * The partition constraint for a hash partition is always a call to the
    1989             :  * built-in function satisfies_hash_partition().
    1990             :  */
    1991             : static List *
    1992         142 : get_qual_for_hash(Relation parent, PartitionBoundSpec *spec)
    1993             : {
    1994         142 :     PartitionKey key = RelationGetPartitionKey(parent);
    1995             :     FuncExpr   *fexpr;
    1996             :     Node       *relidConst;
    1997             :     Node       *modulusConst;
    1998             :     Node       *remainderConst;
    1999             :     List       *args;
    2000             :     ListCell   *partexprs_item;
    2001             :     int         i;
    2002             : 
    2003             :     /* Fixed arguments. */
    2004         142 :     relidConst = (Node *) makeConst(OIDOID,
    2005             :                                     -1,
    2006             :                                     InvalidOid,
    2007             :                                     sizeof(Oid),
    2008         142 :                                     ObjectIdGetDatum(RelationGetRelid(parent)),
    2009             :                                     false,
    2010             :                                     true);
    2011             : 
    2012         142 :     modulusConst = (Node *) makeConst(INT4OID,
    2013             :                                       -1,
    2014             :                                       InvalidOid,
    2015             :                                       sizeof(int32),
    2016         142 :                                       Int32GetDatum(spec->modulus),
    2017             :                                       false,
    2018             :                                       true);
    2019             : 
    2020         142 :     remainderConst = (Node *) makeConst(INT4OID,
    2021             :                                         -1,
    2022             :                                         InvalidOid,
    2023             :                                         sizeof(int32),
    2024         142 :                                         Int32GetDatum(spec->remainder),
    2025             :                                         false,
    2026             :                                         true);
    2027             : 
    2028         142 :     args = list_make3(relidConst, modulusConst, remainderConst);
    2029         142 :     partexprs_item = list_head(key->partexprs);
    2030             : 
    2031             :     /* Add an argument for each key column. */
    2032         316 :     for (i = 0; i < key->partnatts; i++)
    2033             :     {
    2034             :         Node       *keyCol;
    2035             : 
    2036             :         /* Left operand */
    2037         174 :         if (key->partattrs[i] != 0)
    2038             :         {
    2039         624 :             keyCol = (Node *) makeVar(1,
    2040         156 :                                       key->partattrs[i],
    2041         156 :                                       key->parttypid[i],
    2042         156 :                                       key->parttypmod[i],
    2043         156 :                                       key->parttypcoll[i],
    2044             :                                       0);
    2045             :         }
    2046             :         else
    2047             :         {
    2048          18 :             keyCol = (Node *) copyObject(lfirst(partexprs_item));
    2049          18 :             partexprs_item = lnext(key->partexprs, partexprs_item);
    2050             :         }
    2051             : 
    2052         174 :         args = lappend(args, keyCol);
    2053             :     }
    2054             : 
    2055         142 :     fexpr = makeFuncExpr(F_SATISFIES_HASH_PARTITION,
    2056             :                          BOOLOID,
    2057             :                          args,
    2058             :                          InvalidOid,
    2059             :                          InvalidOid,
    2060             :                          COERCE_EXPLICIT_CALL);
    2061             : 
    2062         142 :     return list_make1(fexpr);
    2063             : }
    2064             : 
    2065             : /*
    2066             :  * get_qual_for_list
    2067             :  *
    2068             :  * Returns an implicit-AND list of expressions to use as a list partition's
    2069             :  * constraint, given the parent relation and partition bound structure.
    2070             :  *
    2071             :  * The function returns NIL for a default partition when it's the only
    2072             :  * partition since in that case there is no constraint.
    2073             :  */
    2074             : static List *
    2075        1950 : get_qual_for_list(Relation parent, PartitionBoundSpec *spec)
    2076             : {
    2077        1950 :     PartitionKey key = RelationGetPartitionKey(parent);
    2078             :     List       *result;
    2079             :     Expr       *keyCol;
    2080             :     Expr       *opexpr;
    2081             :     NullTest   *nulltest;
    2082             :     ListCell   *cell;
    2083        1950 :     List       *elems = NIL;
    2084        1950 :     bool        list_has_null = false;
    2085             : 
    2086             :     /*
    2087             :      * Only single-column list partitioning is supported, so we are worried
    2088             :      * only about the partition key with index 0.
    2089             :      */
    2090             :     Assert(key->partnatts == 1);
    2091             : 
    2092             :     /* Construct Var or expression representing the partition column */
    2093        1950 :     if (key->partattrs[0] != 0)
    2094        7504 :         keyCol = (Expr *) makeVar(1,
    2095        1876 :                                   key->partattrs[0],
    2096        1876 :                                   key->parttypid[0],
    2097        1876 :                                   key->parttypmod[0],
    2098        1876 :                                   key->parttypcoll[0],
    2099             :                                   0);
    2100             :     else
    2101          74 :         keyCol = (Expr *) copyObject(linitial(key->partexprs));
    2102             : 
    2103             :     /*
    2104             :      * For default list partition, collect datums for all the partitions. The
    2105             :      * default partition constraint should check that the partition key is
    2106             :      * equal to none of those.
    2107             :      */
    2108        1950 :     if (spec->is_default)
    2109             :     {
    2110             :         int         i;
    2111         102 :         int         ndatums = 0;
    2112         102 :         PartitionDesc pdesc = RelationGetPartitionDesc(parent);
    2113         102 :         PartitionBoundInfo boundinfo = pdesc->boundinfo;
    2114             : 
    2115         102 :         if (boundinfo)
    2116             :         {
    2117         102 :             ndatums = boundinfo->ndatums;
    2118             : 
    2119         102 :             if (partition_bound_accepts_nulls(boundinfo))
    2120          28 :                 list_has_null = true;
    2121             :         }
    2122             : 
    2123             :         /*
    2124             :          * If default is the only partition, there need not be any partition
    2125             :          * constraint on it.
    2126             :          */
    2127         102 :         if (ndatums == 0 && !list_has_null)
    2128          12 :             return NIL;
    2129             : 
    2130         398 :         for (i = 0; i < ndatums; i++)
    2131             :         {
    2132             :             Const      *val;
    2133             : 
    2134             :             /*
    2135             :              * Construct Const from known-not-null datum.  We must be careful
    2136             :              * to copy the value, because our result has to be able to outlive
    2137             :              * the relcache entry we're copying from.
    2138             :              */
    2139        2156 :             val = makeConst(key->parttypid[0],
    2140         308 :                             key->parttypmod[0],
    2141         308 :                             key->parttypcoll[0],
    2142         308 :                             key->parttyplen[0],
    2143         308 :                             datumCopy(*boundinfo->datums[i],
    2144         308 :                                       key->parttypbyval[0],
    2145         308 :                                       key->parttyplen[0]),
    2146             :                             false,  /* isnull */
    2147         308 :                             key->parttypbyval[0]);
    2148             : 
    2149         308 :             elems = lappend(elems, val);
    2150             :         }
    2151             :     }
    2152             :     else
    2153             :     {
    2154             :         /*
    2155             :          * Create list of Consts for the allowed values, excluding any nulls.
    2156             :          */
    2157        4326 :         foreach(cell, spec->listdatums)
    2158             :         {
    2159        2478 :             Const      *val = castNode(Const, lfirst(cell));
    2160             : 
    2161        2478 :             if (val->constisnull)
    2162          42 :                 list_has_null = true;
    2163             :             else
    2164        2436 :                 elems = lappend(elems, copyObject(val));
    2165             :         }
    2166             :     }
    2167             : 
    2168        1938 :     if (elems)
    2169             :     {
    2170             :         /*
    2171             :          * Generate the operator expression from the non-null partition
    2172             :          * values.
    2173             :          */
    2174        1922 :         opexpr = make_partition_op_expr(key, 0, BTEqualStrategyNumber,
    2175             :                                         keyCol, (Expr *) elems);
    2176             :     }
    2177             :     else
    2178             :     {
    2179             :         /*
    2180             :          * If there are no partition values, we don't need an operator
    2181             :          * expression.
    2182             :          */
    2183          16 :         opexpr = NULL;
    2184             :     }
    2185             : 
    2186        1938 :     if (!list_has_null)
    2187             :     {
    2188             :         /*
    2189             :          * Gin up a "col IS NOT NULL" test that will be AND'd with the main
    2190             :          * expression.  This might seem redundant, but the partition routing
    2191             :          * machinery needs it.
    2192             :          */
    2193        1868 :         nulltest = makeNode(NullTest);
    2194        1868 :         nulltest->arg = keyCol;
    2195        1868 :         nulltest->nulltesttype = IS_NOT_NULL;
    2196        1868 :         nulltest->argisrow = false;
    2197        1868 :         nulltest->location = -1;
    2198             : 
    2199        1868 :         result = opexpr ? list_make2(nulltest, opexpr) : list_make1(nulltest);
    2200             :     }
    2201             :     else
    2202             :     {
    2203             :         /*
    2204             :          * Gin up a "col IS NULL" test that will be OR'd with the main
    2205             :          * expression.
    2206             :          */
    2207          70 :         nulltest = makeNode(NullTest);
    2208          70 :         nulltest->arg = keyCol;
    2209          70 :         nulltest->nulltesttype = IS_NULL;
    2210          70 :         nulltest->argisrow = false;
    2211          70 :         nulltest->location = -1;
    2212             : 
    2213          70 :         if (opexpr)
    2214             :         {
    2215             :             Expr       *or;
    2216             : 
    2217          54 :             or = makeBoolExpr(OR_EXPR, list_make2(nulltest, opexpr), -1);
    2218          54 :             result = list_make1(or);
    2219             :         }
    2220             :         else
    2221          16 :             result = list_make1(nulltest);
    2222             :     }
    2223             : 
    2224             :     /*
    2225             :      * Note that, in general, applying NOT to a constraint expression doesn't
    2226             :      * necessarily invert the set of rows it accepts, because NOT (NULL) is
    2227             :      * NULL.  However, the partition constraints we construct here never
    2228             :      * evaluate to NULL, so applying NOT works as intended.
    2229             :      */
    2230        1938 :     if (spec->is_default)
    2231             :     {
    2232          90 :         result = list_make1(make_ands_explicit(result));
    2233          90 :         result = list_make1(makeBoolExpr(NOT_EXPR, result, -1));
    2234             :     }
    2235             : 
    2236        1938 :     return result;
    2237             : }
    2238             : 
    2239             : /*
    2240             :  * get_qual_for_range
    2241             :  *
    2242             :  * Returns an implicit-AND list of expressions to use as a range partition's
    2243             :  * constraint, given the parent relation and partition bound structure.
    2244             :  *
    2245             :  * For a multi-column range partition key, say (a, b, c), with (al, bl, cl)
    2246             :  * as the lower bound tuple and (au, bu, cu) as the upper bound tuple, we
    2247             :  * generate an expression tree of the following form:
    2248             :  *
    2249             :  *  (a IS NOT NULL) and (b IS NOT NULL) and (c IS NOT NULL)
    2250             :  *      AND
    2251             :  *  (a > al OR (a = al AND b > bl) OR (a = al AND b = bl AND c >= cl))
    2252             :  *      AND
    2253             :  *  (a < au OR (a = au AND b < bu) OR (a = au AND b = bu AND c < cu))
    2254             :  *
    2255             :  * It is often the case that a prefix of lower and upper bound tuples contains
    2256             :  * the same values, for example, (al = au), in which case, we will emit an
    2257             :  * expression tree of the following form:
    2258             :  *
    2259             :  *  (a IS NOT NULL) and (b IS NOT NULL) and (c IS NOT NULL)
    2260             :  *      AND
    2261             :  *  (a = al)
    2262             :  *      AND
    2263             :  *  (b > bl OR (b = bl AND c >= cl))
    2264             :  *      AND
    2265             :  *  (b < bu) OR (b = bu AND c < cu))
    2266             :  *
    2267             :  * If a bound datum is either MINVALUE or MAXVALUE, these expressions are
    2268             :  * simplified using the fact that any value is greater than MINVALUE and less
    2269             :  * than MAXVALUE. So, for example, if cu = MAXVALUE, c < cu is automatically
    2270             :  * true, and we need not emit any expression for it, and the last line becomes
    2271             :  *
    2272             :  *  (b < bu) OR (b = bu), which is simplified to (b <= bu)
    2273             :  *
    2274             :  * In most common cases with only one partition column, say a, the following
    2275             :  * expression tree will be generated: a IS NOT NULL AND a >= al AND a < au
    2276             :  *
    2277             :  * For default partition, it returns the negation of the constraints of all
    2278             :  * the other partitions.
    2279             :  *
    2280             :  * External callers should pass for_default as false; we set it to true only
    2281             :  * when recursing.
    2282             :  */
    2283             : static List *
    2284        2752 : get_qual_for_range(Relation parent, PartitionBoundSpec *spec,
    2285             :                    bool for_default)
    2286             : {
    2287        2752 :     List       *result = NIL;
    2288             :     ListCell   *cell1,
    2289             :                *cell2,
    2290             :                *partexprs_item,
    2291             :                *partexprs_item_saved;
    2292             :     int         i,
    2293             :                 j;
    2294             :     PartitionRangeDatum *ldatum,
    2295             :                *udatum;
    2296        2752 :     PartitionKey key = RelationGetPartitionKey(parent);
    2297             :     Expr       *keyCol;
    2298             :     Const      *lower_val,
    2299             :                *upper_val;
    2300             :     List       *lower_or_arms,
    2301             :                *upper_or_arms;
    2302             :     int         num_or_arms,
    2303             :                 current_or_arm;
    2304             :     ListCell   *lower_or_start_datum,
    2305             :                *upper_or_start_datum;
    2306             :     bool        need_next_lower_arm,
    2307             :                 need_next_upper_arm;
    2308             : 
    2309        2752 :     if (spec->is_default)
    2310             :     {
    2311         130 :         List       *or_expr_args = NIL;
    2312         130 :         PartitionDesc pdesc = RelationGetPartitionDesc(parent);
    2313         130 :         Oid        *inhoids = pdesc->oids;
    2314         130 :         int         nparts = pdesc->nparts,
    2315             :                     i;
    2316             : 
    2317         556 :         for (i = 0; i < nparts; i++)
    2318             :         {
    2319         426 :             Oid         inhrelid = inhoids[i];
    2320             :             HeapTuple   tuple;
    2321             :             Datum       datum;
    2322             :             bool        isnull;
    2323             :             PartitionBoundSpec *bspec;
    2324             : 
    2325         426 :             tuple = SearchSysCache1(RELOID, inhrelid);
    2326         426 :             if (!HeapTupleIsValid(tuple))
    2327           0 :                 elog(ERROR, "cache lookup failed for relation %u", inhrelid);
    2328             : 
    2329         426 :             datum = SysCacheGetAttr(RELOID, tuple,
    2330             :                                     Anum_pg_class_relpartbound,
    2331             :                                     &isnull);
    2332         426 :             if (isnull)
    2333           0 :                 elog(ERROR, "null relpartbound for relation %u", inhrelid);
    2334             : 
    2335         426 :             bspec = (PartitionBoundSpec *)
    2336         426 :                 stringToNode(TextDatumGetCString(datum));
    2337         426 :             if (!IsA(bspec, PartitionBoundSpec))
    2338           0 :                 elog(ERROR, "expected PartitionBoundSpec");
    2339             : 
    2340         426 :             if (!bspec->is_default)
    2341             :             {
    2342             :                 List       *part_qual;
    2343             : 
    2344         296 :                 part_qual = get_qual_for_range(parent, bspec, true);
    2345             : 
    2346             :                 /*
    2347             :                  * AND the constraints of the partition and add to
    2348             :                  * or_expr_args
    2349             :                  */
    2350         308 :                 or_expr_args = lappend(or_expr_args, list_length(part_qual) > 1
    2351             :                                        ? makeBoolExpr(AND_EXPR, part_qual, -1)
    2352          12 :                                        : linitial(part_qual));
    2353             :             }
    2354         426 :             ReleaseSysCache(tuple);
    2355             :         }
    2356             : 
    2357         130 :         if (or_expr_args != NIL)
    2358             :         {
    2359             :             Expr       *other_parts_constr;
    2360             : 
    2361             :             /*
    2362             :              * Combine the constraints obtained for non-default partitions
    2363             :              * using OR.  As requested, each of the OR's args doesn't include
    2364             :              * the NOT NULL test for partition keys (which is to avoid its
    2365             :              * useless repetition).  Add the same now.
    2366             :              */
    2367         106 :             other_parts_constr =
    2368         130 :                 makeBoolExpr(AND_EXPR,
    2369             :                              lappend(get_range_nulltest(key),
    2370         106 :                                      list_length(or_expr_args) > 1
    2371             :                                      ? makeBoolExpr(OR_EXPR, or_expr_args,
    2372             :                                                     -1)
    2373          24 :                                      : linitial(or_expr_args)),
    2374             :                              -1);
    2375             : 
    2376             :             /*
    2377             :              * Finally, the default partition contains everything *NOT*
    2378             :              * contained in the non-default partitions.
    2379             :              */
    2380         106 :             result = list_make1(makeBoolExpr(NOT_EXPR,
    2381             :                                              list_make1(other_parts_constr), -1));
    2382             :         }
    2383             : 
    2384         130 :         return result;
    2385             :     }
    2386             : 
    2387        2622 :     lower_or_start_datum = list_head(spec->lowerdatums);
    2388        2622 :     upper_or_start_datum = list_head(spec->upperdatums);
    2389        2622 :     num_or_arms = key->partnatts;
    2390             : 
    2391             :     /*
    2392             :      * If it is the recursive call for default, we skip the get_range_nulltest
    2393             :      * to avoid accumulating the NullTest on the same keys for each partition.
    2394             :      */
    2395        2622 :     if (!for_default)
    2396        2326 :         result = get_range_nulltest(key);
    2397             : 
    2398             :     /*
    2399             :      * Iterate over the key columns and check if the corresponding lower and
    2400             :      * upper datums are equal using the btree equality operator for the
    2401             :      * column's type.  If equal, we emit single keyCol = common_value
    2402             :      * expression.  Starting from the first column for which the corresponding
    2403             :      * lower and upper bound datums are not equal, we generate OR expressions
    2404             :      * as shown in the function's header comment.
    2405             :      */
    2406        2622 :     i = 0;
    2407        2622 :     partexprs_item = list_head(key->partexprs);
    2408        2622 :     partexprs_item_saved = partexprs_item;  /* placate compiler */
    2409        3290 :     forboth(cell1, spec->lowerdatums, cell2, spec->upperdatums)
    2410             :     {
    2411             :         EState     *estate;
    2412             :         MemoryContext oldcxt;
    2413             :         Expr       *test_expr;
    2414             :         ExprState  *test_exprstate;
    2415             :         Datum       test_result;
    2416             :         bool        isNull;
    2417             : 
    2418        3290 :         ldatum = castNode(PartitionRangeDatum, lfirst(cell1));
    2419        3290 :         udatum = castNode(PartitionRangeDatum, lfirst(cell2));
    2420             : 
    2421             :         /*
    2422             :          * Since get_range_key_properties() modifies partexprs_item, and we
    2423             :          * might need to start over from the previous expression in the later
    2424             :          * part of this function, save away the current value.
    2425             :          */
    2426        3290 :         partexprs_item_saved = partexprs_item;
    2427             : 
    2428        3290 :         get_range_key_properties(key, i, ldatum, udatum,
    2429             :                                  &partexprs_item,
    2430             :                                  &keyCol,
    2431             :                                  &lower_val, &upper_val);
    2432             : 
    2433             :         /*
    2434             :          * If either value is NULL, the corresponding partition bound is
    2435             :          * either MINVALUE or MAXVALUE, and we treat them as unequal, because
    2436             :          * even if they're the same, there is no common value to equate the
    2437             :          * key column with.
    2438             :          */
    2439        3290 :         if (!lower_val || !upper_val)
    2440             :             break;
    2441             : 
    2442             :         /* Create the test expression */
    2443        3154 :         estate = CreateExecutorState();
    2444        3154 :         oldcxt = MemoryContextSwitchTo(estate->es_query_cxt);
    2445        3154 :         test_expr = make_partition_op_expr(key, i, BTEqualStrategyNumber,
    2446             :                                            (Expr *) lower_val,
    2447             :                                            (Expr *) upper_val);
    2448        3154 :         fix_opfuncids((Node *) test_expr);
    2449        3154 :         test_exprstate = ExecInitExpr(test_expr, NULL);
    2450        3154 :         test_result = ExecEvalExprSwitchContext(test_exprstate,
    2451        3154 :                                                 GetPerTupleExprContext(estate),
    2452             :                                                 &isNull);
    2453        3154 :         MemoryContextSwitchTo(oldcxt);
    2454        3154 :         FreeExecutorState(estate);
    2455             : 
    2456             :         /* If not equal, go generate the OR expressions */
    2457        3154 :         if (!DatumGetBool(test_result))
    2458        2486 :             break;
    2459             : 
    2460             :         /*
    2461             :          * The bounds for the last key column can't be equal, because such a
    2462             :          * range partition would never be allowed to be defined (it would have
    2463             :          * an empty range otherwise).
    2464             :          */
    2465         668 :         if (i == key->partnatts - 1)
    2466           0 :             elog(ERROR, "invalid range bound specification");
    2467             : 
    2468             :         /* Equal, so generate keyCol = lower_val expression */
    2469        1336 :         result = lappend(result,
    2470        1336 :                          make_partition_op_expr(key, i, BTEqualStrategyNumber,
    2471             :                                                 keyCol, (Expr *) lower_val));
    2472             : 
    2473         668 :         i++;
    2474             :     }
    2475             : 
    2476             :     /* First pair of lower_val and upper_val that are not equal. */
    2477        2622 :     lower_or_start_datum = cell1;
    2478        2622 :     upper_or_start_datum = cell2;
    2479             : 
    2480             :     /* OR will have as many arms as there are key columns left. */
    2481        2622 :     num_or_arms = key->partnatts - i;
    2482        2622 :     current_or_arm = 0;
    2483        2622 :     lower_or_arms = upper_or_arms = NIL;
    2484        2622 :     need_next_lower_arm = need_next_upper_arm = true;
    2485        5494 :     while (current_or_arm < num_or_arms)
    2486             :     {
    2487        2872 :         List       *lower_or_arm_args = NIL,
    2488        2872 :                    *upper_or_arm_args = NIL;
    2489             : 
    2490             :         /* Restart scan of columns from the i'th one */
    2491        2872 :         j = i;
    2492        2872 :         partexprs_item = partexprs_item_saved;
    2493             : 
    2494        3182 :         for_both_cell(cell1, spec->lowerdatums, lower_or_start_datum,
    2495             :                       cell2, spec->upperdatums, upper_or_start_datum)
    2496             :         {
    2497        3182 :             PartitionRangeDatum *ldatum_next = NULL,
    2498        3182 :                        *udatum_next = NULL;
    2499             : 
    2500        3182 :             ldatum = castNode(PartitionRangeDatum, lfirst(cell1));
    2501        3182 :             if (lnext(spec->lowerdatums, cell1))
    2502         616 :                 ldatum_next = castNode(PartitionRangeDatum,
    2503             :                                        lfirst(lnext(spec->lowerdatums, cell1)));
    2504        3182 :             udatum = castNode(PartitionRangeDatum, lfirst(cell2));
    2505        3182 :             if (lnext(spec->upperdatums, cell2))
    2506         616 :                 udatum_next = castNode(PartitionRangeDatum,
    2507             :                                        lfirst(lnext(spec->upperdatums, cell2)));
    2508        3182 :             get_range_key_properties(key, j, ldatum, udatum,
    2509             :                                      &partexprs_item,
    2510             :                                      &keyCol,
    2511             :                                      &lower_val, &upper_val);
    2512             : 
    2513        3182 :             if (need_next_lower_arm && lower_val)
    2514             :             {
    2515             :                 uint16      strategy;
    2516             : 
    2517             :                 /*
    2518             :                  * For the non-last columns of this arm, use the EQ operator.
    2519             :                  * For the last column of this arm, use GT, unless this is the
    2520             :                  * last column of the whole bound check, or the next bound
    2521             :                  * datum is MINVALUE, in which case use GE.
    2522             :                  */
    2523        3054 :                 if (j - i < current_or_arm)
    2524         274 :                     strategy = BTEqualStrategyNumber;
    2525        2780 :                 else if (j == key->partnatts - 1 ||
    2526         266 :                          (ldatum_next &&
    2527         266 :                           ldatum_next->kind == PARTITION_RANGE_DATUM_MINVALUE))
    2528        2546 :                     strategy = BTGreaterEqualStrategyNumber;
    2529             :                 else
    2530         234 :                     strategy = BTGreaterStrategyNumber;
    2531             : 
    2532        6108 :                 lower_or_arm_args = lappend(lower_or_arm_args,
    2533        6108 :                                             make_partition_op_expr(key, j,
    2534             :                                                                    strategy,
    2535             :                                                                    keyCol,
    2536             :                                                                    (Expr *) lower_val));
    2537             :             }
    2538             : 
    2539        3182 :             if (need_next_upper_arm && upper_val)
    2540             :             {
    2541             :                 uint16      strategy;
    2542             : 
    2543             :                 /*
    2544             :                  * For the non-last columns of this arm, use the EQ operator.
    2545             :                  * For the last column of this arm, use LT, unless the next
    2546             :                  * bound datum is MAXVALUE, in which case use LE.
    2547             :                  */
    2548        2934 :                 if (j - i < current_or_arm)
    2549         214 :                     strategy = BTEqualStrategyNumber;
    2550        2954 :                 else if (udatum_next &&
    2551         234 :                          udatum_next->kind == PARTITION_RANGE_DATUM_MAXVALUE)
    2552          24 :                     strategy = BTLessEqualStrategyNumber;
    2553             :                 else
    2554        2696 :                     strategy = BTLessStrategyNumber;
    2555             : 
    2556        5868 :                 upper_or_arm_args = lappend(upper_or_arm_args,
    2557        5868 :                                             make_partition_op_expr(key, j,
    2558             :                                                                    strategy,
    2559             :                                                                    keyCol,
    2560             :                                                                    (Expr *) upper_val));
    2561             :             }
    2562             : 
    2563             :             /*
    2564             :              * Did we generate enough of OR's arguments?  First arm considers
    2565             :              * the first of the remaining columns, second arm considers first
    2566             :              * two of the remaining columns, and so on.
    2567             :              */
    2568        3182 :             ++j;
    2569        3182 :             if (j - i > current_or_arm)
    2570             :             {
    2571             :                 /*
    2572             :                  * We must not emit any more arms if the new column that will
    2573             :                  * be considered is unbounded, or this one was.
    2574             :                  */
    2575        3138 :                 if (!lower_val || !ldatum_next ||
    2576         266 :                     ldatum_next->kind != PARTITION_RANGE_DATUM_VALUE)
    2577        2646 :                     need_next_lower_arm = false;
    2578        3106 :                 if (!upper_val || !udatum_next ||
    2579         234 :                     udatum_next->kind != PARTITION_RANGE_DATUM_VALUE)
    2580        2690 :                     need_next_upper_arm = false;
    2581        2872 :                 break;
    2582             :             }
    2583             :         }
    2584             : 
    2585        2872 :         if (lower_or_arm_args != NIL)
    2586        5334 :             lower_or_arms = lappend(lower_or_arms,
    2587        2780 :                                     list_length(lower_or_arm_args) > 1
    2588             :                                     ? makeBoolExpr(AND_EXPR, lower_or_arm_args, -1)
    2589        2554 :                                     : linitial(lower_or_arm_args));
    2590             : 
    2591        2872 :         if (upper_or_arm_args != NIL)
    2592        5258 :             upper_or_arms = lappend(upper_or_arms,
    2593        2720 :                                     list_length(upper_or_arm_args) > 1
    2594             :                                     ? makeBoolExpr(AND_EXPR, upper_or_arm_args, -1)
    2595        2538 :                                     : linitial(upper_or_arm_args));
    2596             : 
    2597             :         /* If no work to do in the next iteration, break away. */
    2598        2872 :         if (!need_next_lower_arm && !need_next_upper_arm)
    2599        2622 :             break;
    2600             : 
    2601         250 :         ++current_or_arm;
    2602             :     }
    2603             : 
    2604             :     /*
    2605             :      * Generate the OR expressions for each of lower and upper bounds (if
    2606             :      * required), and append to the list of implicitly ANDed list of
    2607             :      * expressions.
    2608             :      */
    2609        2622 :     if (lower_or_arms != NIL)
    2610        4930 :         result = lappend(result,
    2611        2554 :                          list_length(lower_or_arms) > 1
    2612             :                          ? makeBoolExpr(OR_EXPR, lower_or_arms, -1)
    2613        2376 :                          : linitial(lower_or_arms));
    2614        2622 :     if (upper_or_arms != NIL)
    2615        4926 :         result = lappend(result,
    2616        2538 :                          list_length(upper_or_arms) > 1
    2617             :                          ? makeBoolExpr(OR_EXPR, upper_or_arms, -1)
    2618        2388 :                          : linitial(upper_or_arms));
    2619             : 
    2620             :     /*
    2621             :      * As noted above, for non-default, we return list with constant TRUE. If
    2622             :      * the result is NIL during the recursive call for default, it implies
    2623             :      * this is the only other partition which can hold every value of the key
    2624             :      * except NULL. Hence we return the NullTest result skipped earlier.
    2625             :      */
    2626        2622 :     if (result == NIL)
    2627           0 :         result = for_default
    2628             :             ? get_range_nulltest(key)
    2629           0 :             : list_make1(makeBoolConst(true, false));
    2630             : 
    2631        2622 :     return result;
    2632             : }
    2633             : 
    2634             : /*
    2635             :  * get_range_key_properties
    2636             :  *      Returns range partition key information for a given column
    2637             :  *
    2638             :  * This is a subroutine for get_qual_for_range, and its API is pretty
    2639             :  * specialized to that caller.
    2640             :  *
    2641             :  * Constructs an Expr for the key column (returned in *keyCol) and Consts
    2642             :  * for the lower and upper range limits (returned in *lower_val and
    2643             :  * *upper_val).  For MINVALUE/MAXVALUE limits, NULL is returned instead of
    2644             :  * a Const.  All of these structures are freshly palloc'd.
    2645             :  *
    2646             :  * *partexprs_item points to the cell containing the next expression in
    2647             :  * the key->partexprs list, or NULL.  It may be advanced upon return.
    2648             :  */
    2649             : static void
    2650        6472 : get_range_key_properties(PartitionKey key, int keynum,
    2651             :                          PartitionRangeDatum *ldatum,
    2652             :                          PartitionRangeDatum *udatum,
    2653             :                          ListCell **partexprs_item,
    2654             :                          Expr **keyCol,
    2655             :                          Const **lower_val, Const **upper_val)
    2656             : {
    2657             :     /* Get partition key expression for this column */
    2658        6472 :     if (key->partattrs[keynum] != 0)
    2659             :     {
    2660       22072 :         *keyCol = (Expr *) makeVar(1,
    2661        5518 :                                    key->partattrs[keynum],
    2662        5518 :                                    key->parttypid[keynum],
    2663        5518 :                                    key->parttypmod[keynum],
    2664        5518 :                                    key->parttypcoll[keynum],
    2665             :                                    0);
    2666             :     }
    2667             :     else
    2668             :     {
    2669         954 :         if (*partexprs_item == NULL)
    2670           0 :             elog(ERROR, "wrong number of partition key expressions");
    2671         954 :         *keyCol = copyObject(lfirst(*partexprs_item));
    2672         954 :         *partexprs_item = lnext(key->partexprs, *partexprs_item);
    2673             :     }
    2674             : 
    2675             :     /* Get appropriate Const nodes for the bounds */
    2676        6472 :     if (ldatum->kind == PARTITION_RANGE_DATUM_VALUE)
    2677        6288 :         *lower_val = castNode(Const, copyObject(ldatum->value));
    2678             :     else
    2679         184 :         *lower_val = NULL;
    2680             : 
    2681        6472 :     if (udatum->kind == PARTITION_RANGE_DATUM_VALUE)
    2682        6164 :         *upper_val = castNode(Const, copyObject(udatum->value));
    2683             :     else
    2684         308 :         *upper_val = NULL;
    2685        6472 : }
    2686             : 
    2687             : /*
    2688             :  * get_range_nulltest
    2689             :  *
    2690             :  * A non-default range partition table does not currently allow partition
    2691             :  * keys to be null, so emit an IS NOT NULL expression for each key column.
    2692             :  */
    2693             : static List *
    2694        2432 : get_range_nulltest(PartitionKey key)
    2695             : {
    2696        2432 :     List       *result = NIL;
    2697             :     NullTest   *nulltest;
    2698             :     ListCell   *partexprs_item;
    2699             :     int         i;
    2700             : 
    2701        2432 :     partexprs_item = list_head(key->partexprs);
    2702        5726 :     for (i = 0; i < key->partnatts; i++)
    2703             :     {
    2704             :         Expr       *keyCol;
    2705             : 
    2706        3294 :         if (key->partattrs[i] != 0)
    2707             :         {
    2708       11264 :             keyCol = (Expr *) makeVar(1,
    2709        2816 :                                       key->partattrs[i],
    2710        2816 :                                       key->parttypid[i],
    2711        2816 :                                       key->parttypmod[i],
    2712        2816 :                                       key->parttypcoll[i],
    2713             :                                       0);
    2714             :         }
    2715             :         else
    2716             :         {
    2717         478 :             if (partexprs_item == NULL)
    2718           0 :                 elog(ERROR, "wrong number of partition key expressions");
    2719         478 :             keyCol = copyObject(lfirst(partexprs_item));
    2720         478 :             partexprs_item = lnext(key->partexprs, partexprs_item);
    2721             :         }
    2722             : 
    2723        3294 :         nulltest = makeNode(NullTest);
    2724        3294 :         nulltest->arg = keyCol;
    2725        3294 :         nulltest->nulltesttype = IS_NOT_NULL;
    2726        3294 :         nulltest->argisrow = false;
    2727        3294 :         nulltest->location = -1;
    2728        3294 :         result = lappend(result, nulltest);
    2729             :     }
    2730             : 
    2731        2432 :     return result;
    2732             : }
    2733             : 
    2734             : /*
    2735             :  * compute_partition_hash_value
    2736             :  *
    2737             :  * Compute the hash value for given partition key values.
    2738             :  */
    2739             : uint64
    2740        2784 : compute_partition_hash_value(int partnatts, FmgrInfo *partsupfunc, Oid *partcollation,
    2741             :                              Datum *values, bool *isnull)
    2742             : {
    2743             :     int         i;
    2744        2784 :     uint64      rowHash = 0;
    2745        2784 :     Datum       seed = UInt64GetDatum(HASH_PARTITION_SEED);
    2746             : 
    2747        5632 :     for (i = 0; i < partnatts; i++)
    2748             :     {
    2749             :         /* Nulls are just ignored */
    2750        2848 :         if (!isnull[i])
    2751             :         {
    2752             :             Datum       hash;
    2753             : 
    2754             :             Assert(OidIsValid(partsupfunc[i].fn_oid));
    2755             : 
    2756             :             /*
    2757             :              * Compute hash for each datum value by calling respective
    2758             :              * datatype-specific hash functions of each partition key
    2759             :              * attribute.
    2760             :              */
    2761        2808 :             hash = FunctionCall2Coll(&partsupfunc[i], partcollation[i],
    2762        2808 :                                      values[i], seed);
    2763             : 
    2764             :             /* Form a single 64-bit hash value */
    2765        2808 :             rowHash = hash_combine64(rowHash, DatumGetUInt64(hash));
    2766             :         }
    2767             :     }
    2768             : 
    2769        2784 :     return rowHash;
    2770             : }
    2771             : 
    2772             : /*
    2773             :  * satisfies_hash_partition
    2774             :  *
    2775             :  * This is an SQL-callable function for use in hash partition constraints.
    2776             :  * The first three arguments are the parent table OID, modulus, and remainder.
    2777             :  * The remaining arguments are the value of the partitioning columns (or
    2778             :  * expressions); these are hashed and the results are combined into a single
    2779             :  * hash value by calling hash_combine64.
    2780             :  *
    2781             :  * Returns true if remainder produced when this computed single hash value is
    2782             :  * divided by the given modulus is equal to given remainder, otherwise false.
    2783             :  *
    2784             :  * See get_qual_for_hash() for usage.
    2785             :  */
    2786             : Datum
    2787         132 : satisfies_hash_partition(PG_FUNCTION_ARGS)
    2788             : {
    2789             :     typedef struct ColumnsHashData
    2790             :     {
    2791             :         Oid         relid;
    2792             :         int         nkeys;
    2793             :         Oid         variadic_type;
    2794             :         int16       variadic_typlen;
    2795             :         bool        variadic_typbyval;
    2796             :         char        variadic_typalign;
    2797             :         Oid         partcollid[PARTITION_MAX_KEYS];
    2798             :         FmgrInfo    partsupfunc[FLEXIBLE_ARRAY_MEMBER];
    2799             :     } ColumnsHashData;
    2800             :     Oid         parentId;
    2801             :     int         modulus;
    2802             :     int         remainder;
    2803         132 :     Datum       seed = UInt64GetDatum(HASH_PARTITION_SEED);
    2804             :     ColumnsHashData *my_extra;
    2805         132 :     uint64      rowHash = 0;
    2806             : 
    2807             :     /* Return null if the parent OID, modulus, or remainder is NULL. */
    2808         132 :     if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(2))
    2809           8 :         PG_RETURN_NULL();
    2810         124 :     parentId = PG_GETARG_OID(0);
    2811         124 :     modulus = PG_GETARG_INT32(1);
    2812         124 :     remainder = PG_GETARG_INT32(2);
    2813             : 
    2814             :     /* Sanity check modulus and remainder. */
    2815         124 :     if (modulus <= 0)
    2816           4 :         ereport(ERROR,
    2817             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    2818             :                  errmsg("modulus for hash partition must be a positive integer")));
    2819         120 :     if (remainder < 0)
    2820           4 :         ereport(ERROR,
    2821             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    2822             :                  errmsg("remainder for hash partition must be a non-negative integer")));
    2823         116 :     if (remainder >= modulus)
    2824           4 :         ereport(ERROR,
    2825             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    2826             :                  errmsg("remainder for hash partition must be less than modulus")));
    2827             : 
    2828             :     /*
    2829             :      * Cache hash function information.
    2830             :      */
    2831         112 :     my_extra = (ColumnsHashData *) fcinfo->flinfo->fn_extra;
    2832         112 :     if (my_extra == NULL || my_extra->relid != parentId)
    2833             :     {
    2834             :         Relation    parent;
    2835             :         PartitionKey key;
    2836             :         int         j;
    2837             : 
    2838             :         /* Open parent relation and fetch partition key info */
    2839         108 :         parent = try_relation_open(parentId, AccessShareLock);
    2840         108 :         if (parent == NULL)
    2841           4 :             PG_RETURN_NULL();
    2842         104 :         key = RelationGetPartitionKey(parent);
    2843             : 
    2844             :         /* Reject parent table that is not hash-partitioned. */
    2845         200 :         if (parent->rd_rel->relkind != RELKIND_PARTITIONED_TABLE ||
    2846          96 :             key->strategy != PARTITION_STRATEGY_HASH)
    2847           8 :             ereport(ERROR,
    2848             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    2849             :                      errmsg("\"%s\" is not a hash partitioned table",
    2850             :                             get_rel_name(parentId))));
    2851             : 
    2852          96 :         if (!get_fn_expr_variadic(fcinfo->flinfo))
    2853             :         {
    2854          76 :             int         nargs = PG_NARGS() - 3;
    2855             : 
    2856             :             /* complain if wrong number of column values */
    2857          76 :             if (key->partnatts != nargs)
    2858           8 :                 ereport(ERROR,
    2859             :                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    2860             :                          errmsg("number of partitioning columns (%d) does not match number of partition keys provided (%d)",
    2861             :                                 key->partnatts, nargs)));
    2862             : 
    2863             :             /* allocate space for our cache */
    2864         136 :             fcinfo->flinfo->fn_extra =
    2865          68 :                 MemoryContextAllocZero(fcinfo->flinfo->fn_mcxt,
    2866             :                                        offsetof(ColumnsHashData, partsupfunc) +
    2867          68 :                                        sizeof(FmgrInfo) * nargs);
    2868          68 :             my_extra = (ColumnsHashData *) fcinfo->flinfo->fn_extra;
    2869          68 :             my_extra->relid = parentId;
    2870          68 :             my_extra->nkeys = key->partnatts;
    2871          68 :             memcpy(my_extra->partcollid, key->partcollation,
    2872          68 :                    key->partnatts * sizeof(Oid));
    2873             : 
    2874             :             /* check argument types and save fmgr_infos */
    2875         164 :             for (j = 0; j < key->partnatts; ++j)
    2876             :             {
    2877         100 :                 Oid         argtype = get_fn_expr_argtype(fcinfo->flinfo, j + 3);
    2878             : 
    2879         100 :                 if (argtype != key->parttypid[j] && !IsBinaryCoercible(argtype, key->parttypid[j]))
    2880           4 :                     ereport(ERROR,
    2881             :                             (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    2882             :                              errmsg("column %d of the partition key has type \"%s\", but supplied value is of type \"%s\"",
    2883             :                                     j + 1, format_type_be(key->parttypid[j]), format_type_be(argtype))));
    2884             : 
    2885         192 :                 fmgr_info_copy(&my_extra->partsupfunc[j],
    2886          96 :                                &key->partsupfunc[j],
    2887          96 :                                fcinfo->flinfo->fn_mcxt);
    2888             :             }
    2889             :         }
    2890             :         else
    2891             :         {
    2892          20 :             ArrayType  *variadic_array = PG_GETARG_ARRAYTYPE_P(3);
    2893             : 
    2894             :             /* allocate space for our cache -- just one FmgrInfo in this case */
    2895          40 :             fcinfo->flinfo->fn_extra =
    2896          20 :                 MemoryContextAllocZero(fcinfo->flinfo->fn_mcxt,
    2897             :                                        offsetof(ColumnsHashData, partsupfunc) +
    2898             :                                        sizeof(FmgrInfo));
    2899          20 :             my_extra = (ColumnsHashData *) fcinfo->flinfo->fn_extra;
    2900          20 :             my_extra->relid = parentId;
    2901          20 :             my_extra->nkeys = key->partnatts;
    2902          20 :             my_extra->variadic_type = ARR_ELEMTYPE(variadic_array);
    2903          20 :             get_typlenbyvalalign(my_extra->variadic_type,
    2904             :                                  &my_extra->variadic_typlen,
    2905             :                                  &my_extra->variadic_typbyval,
    2906             :                                  &my_extra->variadic_typalign);
    2907          20 :             my_extra->partcollid[0] = key->partcollation[0];
    2908             : 
    2909             :             /* check argument types */
    2910          48 :             for (j = 0; j < key->partnatts; ++j)
    2911          36 :                 if (key->parttypid[j] != my_extra->variadic_type)
    2912           8 :                     ereport(ERROR,
    2913             :                             (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    2914             :                              errmsg("column %d of the partition key has type \"%s\", but supplied value is of type \"%s\"",
    2915             :                                     j + 1,
    2916             :                                     format_type_be(key->parttypid[j]),
    2917             :                                     format_type_be(my_extra->variadic_type))));
    2918             : 
    2919          12 :             fmgr_info_copy(&my_extra->partsupfunc[0],
    2920             :                            &key->partsupfunc[0],
    2921          12 :                            fcinfo->flinfo->fn_mcxt);
    2922             :         }
    2923             : 
    2924             :         /* Hold lock until commit */
    2925          76 :         relation_close(parent, NoLock);
    2926             :     }
    2927             : 
    2928          80 :     if (!OidIsValid(my_extra->variadic_type))
    2929             :     {
    2930          68 :         int         nkeys = my_extra->nkeys;
    2931             :         int         i;
    2932             : 
    2933             :         /*
    2934             :          * For a non-variadic call, neither the number of arguments nor their
    2935             :          * types can change across calls, so avoid the expense of rechecking
    2936             :          * here.
    2937             :          */
    2938             : 
    2939         164 :         for (i = 0; i < nkeys; i++)
    2940             :         {
    2941             :             Datum       hash;
    2942             : 
    2943             :             /* keys start from fourth argument of function. */
    2944          96 :             int         argno = i + 3;
    2945             : 
    2946          96 :             if (PG_ARGISNULL(argno))
    2947           0 :                 continue;
    2948             : 
    2949          96 :             hash = FunctionCall2Coll(&my_extra->partsupfunc[i],
    2950             :                                      my_extra->partcollid[i],
    2951             :                                      PG_GETARG_DATUM(argno),
    2952             :                                      seed);
    2953             : 
    2954             :             /* Form a single 64-bit hash value */
    2955          96 :             rowHash = hash_combine64(rowHash, DatumGetUInt64(hash));
    2956             :         }
    2957             :     }
    2958             :     else
    2959             :     {
    2960          12 :         ArrayType  *variadic_array = PG_GETARG_ARRAYTYPE_P(3);
    2961             :         int         i;
    2962             :         int         nelems;
    2963             :         Datum      *datum;
    2964             :         bool       *isnull;
    2965             : 
    2966          36 :         deconstruct_array(variadic_array,
    2967             :                           my_extra->variadic_type,
    2968          12 :                           my_extra->variadic_typlen,
    2969          12 :                           my_extra->variadic_typbyval,
    2970          12 :                           my_extra->variadic_typalign,
    2971             :                           &datum, &isnull, &nelems);
    2972             : 
    2973             :         /* complain if wrong number of column values */
    2974          12 :         if (nelems != my_extra->nkeys)
    2975           4 :             ereport(ERROR,
    2976             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    2977             :                      errmsg("number of partitioning columns (%d) does not match number of partition keys provided (%d)",
    2978             :                             my_extra->nkeys, nelems)));
    2979             : 
    2980          24 :         for (i = 0; i < nelems; i++)
    2981             :         {
    2982             :             Datum       hash;
    2983             : 
    2984          16 :             if (isnull[i])
    2985           0 :                 continue;
    2986             : 
    2987          16 :             hash = FunctionCall2Coll(&my_extra->partsupfunc[0],
    2988             :                                      my_extra->partcollid[0],
    2989          16 :                                      datum[i],
    2990             :                                      seed);
    2991             : 
    2992             :             /* Form a single 64-bit hash value */
    2993          16 :             rowHash = hash_combine64(rowHash, DatumGetUInt64(hash));
    2994             :         }
    2995             :     }
    2996             : 
    2997          76 :     PG_RETURN_BOOL(rowHash % modulus == remainder);
    2998             : }

Generated by: LCOV version 1.13