LCOV - differential code coverage report
Current view: top level - src/backend/utils/adt - multirangetypes.c (source / functions) Coverage Total Hit LBC UIC UBC GBC GIC GNC CBC EUB ECB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 93.4 % 997 931 4 47 15 18 575 12 326 33 595 6
Current Date: 2023-04-08 17:13:01 Functions: 97.8 % 92 90 2 89 1 2 89
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (60,120] days: 100.0 % 11 11 11
Legend: Lines: hit not hit (180,240] days: 100.0 % 1 1 1
(240..) days: 93.3 % 985 919 4 47 15 18 575 326 33 592
Function coverage date bins:
(240..) days: 49.2 % 183 90 2 89 1 2 89

 Age         Owner                  TLA  Line data    Source code
                                  1                 : /*-------------------------------------------------------------------------
                                  2                 :  *
                                  3                 :  * multirangetypes.c
                                  4                 :  *    I/O functions, operators, and support functions for multirange types.
                                  5                 :  *
                                  6                 :  * The stored (serialized) format of a multirange value is:
                                  7                 :  *
                                  8                 :  *  12 bytes: MultirangeType struct including varlena header, multirange
                                  9                 :  *            type's OID and the number of ranges in the multirange.
                                 10                 :  *  4 * (rangesCount - 1) bytes: 32-bit items pointing to the each range
                                 11                 :  *                               in the multirange starting from
                                 12                 :  *                               the second one.
                                 13                 :  *  1 * rangesCount bytes : 8-bit flags for each range in the multirange
                                 14                 :  *  The rest of the multirange are range bound values pointed by multirange
                                 15                 :  *  items.
                                 16                 :  *
                                 17                 :  *  Majority of items contain lengths of corresponding range bound values.
                                 18                 :  *  Thanks to that items are typically low numbers.  This makes multiranges
                                 19                 :  *  compression-friendly.  Every MULTIRANGE_ITEM_OFFSET_STRIDE item contains
                                 20                 :  *  an offset of the corresponding range bound values.  That allows fast lookups
                                 21                 :  *  for a particular range index.  Offsets are counted starting from the end of
                                 22                 :  *  flags aligned to the bound type.
                                 23                 :  *
                                 24                 :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
                                 25                 :  * Portions Copyright (c) 1994, Regents of the University of California
                                 26                 :  *
                                 27                 :  *
                                 28                 :  * IDENTIFICATION
                                 29                 :  *    src/backend/utils/adt/multirangetypes.c
                                 30                 :  *
                                 31                 :  *-------------------------------------------------------------------------
                                 32                 :  */
                                 33                 : #include "postgres.h"
                                 34                 : 
                                 35                 : #include "access/tupmacs.h"
                                 36                 : #include "common/hashfn.h"
                                 37                 : #include "funcapi.h"
                                 38                 : #include "lib/stringinfo.h"
                                 39                 : #include "libpq/pqformat.h"
                                 40                 : #include "miscadmin.h"
                                 41                 : #include "port/pg_bitutils.h"
                                 42                 : #include "utils/builtins.h"
                                 43                 : #include "utils/lsyscache.h"
                                 44                 : #include "utils/rangetypes.h"
                                 45                 : #include "utils/multirangetypes.h"
                                 46                 : #include "utils/array.h"
                                 47                 : #include "utils/memutils.h"
                                 48                 : 
                                 49                 : /* fn_extra cache entry for one of the range I/O functions */
                                 50                 : typedef struct MultirangeIOData
                                 51                 : {
                                 52                 :     TypeCacheEntry *typcache;   /* multirange type's typcache entry */
                                 53                 :     FmgrInfo    typioproc;      /* range type's I/O proc */
                                 54                 :     Oid         typioparam;     /* range type's I/O parameter */
                                 55                 : } MultirangeIOData;
                                 56                 : 
                                 57                 : typedef enum
                                 58                 : {
                                 59                 :     MULTIRANGE_BEFORE_RANGE,
                                 60                 :     MULTIRANGE_IN_RANGE,
                                 61                 :     MULTIRANGE_IN_RANGE_ESCAPED,
                                 62                 :     MULTIRANGE_IN_RANGE_QUOTED,
                                 63                 :     MULTIRANGE_IN_RANGE_QUOTED_ESCAPED,
                                 64                 :     MULTIRANGE_AFTER_RANGE,
                                 65                 :     MULTIRANGE_FINISHED,
                                 66                 : } MultirangeParseState;
                                 67                 : 
                                 68                 : /*
                                 69                 :  * Macros for accessing past MultirangeType parts of multirange: items, flags
                                 70                 :  * and boundaries.
                                 71                 :  */
                                 72                 : #define MultirangeGetItemsPtr(mr) ((uint32 *) ((Pointer) (mr) + \
                                 73                 :     sizeof(MultirangeType)))
                                 74                 : #define MultirangeGetFlagsPtr(mr) ((uint8 *) ((Pointer) (mr) + \
                                 75                 :     sizeof(MultirangeType) + ((mr)->rangeCount - 1) * sizeof(uint32)))
                                 76                 : #define MultirangeGetBoundariesPtr(mr, align) ((Pointer) (mr) + \
                                 77                 :     att_align_nominal(sizeof(MultirangeType) + \
                                 78                 :         ((mr)->rangeCount - 1) * sizeof(uint32) + \
                                 79                 :         (mr)->rangeCount * sizeof(uint8), (align)))
                                 80                 : 
                                 81                 : #define MULTIRANGE_ITEM_OFF_BIT 0x80000000
                                 82                 : #define MULTIRANGE_ITEM_GET_OFFLEN(item) ((item) & 0x7FFFFFFF)
                                 83                 : #define MULTIRANGE_ITEM_HAS_OFF(item) ((item) & MULTIRANGE_ITEM_OFF_BIT)
                                 84                 : #define MULTIRANGE_ITEM_OFFSET_STRIDE 4
                                 85                 : 
                                 86                 : typedef int (*multirange_bsearch_comparison) (TypeCacheEntry *typcache,
                                 87                 :                                               RangeBound *lower,
                                 88                 :                                               RangeBound *upper,
                                 89                 :                                               void *key,
                                 90                 :                                               bool *match);
                                 91                 : 
                                 92                 : static MultirangeIOData *get_multirange_io_data(FunctionCallInfo fcinfo,
                                 93                 :                                                 Oid mltrngtypid,
                                 94                 :                                                 IOFuncSelector func);
                                 95                 : static int32 multirange_canonicalize(TypeCacheEntry *rangetyp,
                                 96                 :                                      int32 input_range_count,
                                 97                 :                                      RangeType **ranges);
                                 98                 : 
                                 99                 : /*
                                100                 :  *----------------------------------------------------------
                                101                 :  * I/O FUNCTIONS
                                102                 :  *----------------------------------------------------------
                                103                 :  */
                                104                 : 
                                105                 : /*
                                106                 :  * Converts string to multirange.
                                107                 :  *
                                108                 :  * We expect curly brackets to bound the list, with zero or more ranges
                                109                 :  * separated by commas.  We accept whitespace anywhere: before/after our
                                110                 :  * brackets and around the commas.  Ranges can be the empty literal or some
                                111                 :  * stuff inside parens/brackets.  Mostly we delegate parsing the individual
                                112                 :  * range contents to range_in, but we have to detect quoting and
                                113                 :  * backslash-escaping which can happen for range bounds.  Backslashes can
                                114                 :  * escape something inside or outside a quoted string, and a quoted string
                                115                 :  * can escape quote marks with either backslashes or double double-quotes.
                                116                 :  */
                                117                 : Datum
  840 akorotkov                 118 CBC         657 : multirange_in(PG_FUNCTION_ARGS)
                                119                 : {
                                120             657 :     char       *input_str = PG_GETARG_CSTRING(0);
                                121             657 :     Oid         mltrngtypoid = PG_GETARG_OID(1);
                                122             657 :     Oid         typmod = PG_GETARG_INT32(2);
  115 tgl                       123 GNC         657 :     Node       *escontext = fcinfo->context;
  840 akorotkov                 124 ECB             :     TypeCacheEntry *rangetyp;
  840 akorotkov                 125 GIC         657 :     int32       ranges_seen = 0;
  840 akorotkov                 126 CBC         657 :     int32       range_count = 0;
                                127             657 :     int32       range_capacity = 8;
  840 akorotkov                 128 ECB             :     RangeType  *range;
  840 akorotkov                 129 GIC         657 :     RangeType **ranges = palloc(range_capacity * sizeof(RangeType *));
  840 akorotkov                 130 ECB             :     MultirangeIOData *cache;
                                131                 :     MultirangeType *ret;
                                132                 :     MultirangeParseState parse_state;
  840 akorotkov                 133 GIC         657 :     const char *ptr = input_str;
  830 akorotkov                 134 CBC         657 :     const char *range_str_begin = NULL;
  840 akorotkov                 135 ECB             :     int32       range_str_len;
                                136                 :     char       *range_str;
                                137                 :     Datum       range_datum;
                                138                 : 
  840 akorotkov                 139 GIC         657 :     cache = get_multirange_io_data(fcinfo, mltrngtypoid, IOFunc_input);
                                140             657 :     rangetyp = cache->typcache->rngtype;
  840 akorotkov                 141 ECB             : 
                                142                 :     /* consume whitespace */
  840 akorotkov                 143 GIC         669 :     while (*ptr != '\0' && isspace((unsigned char) *ptr))
                                144              12 :         ptr++;
  840 akorotkov                 145 ECB             : 
  840 akorotkov                 146 CBC         657 :     if (*ptr == '{')
  840 akorotkov                 147 GIC         654 :         ptr++;
  840 akorotkov                 148 ECB             :     else
  115 tgl                       149 GNC           3 :         ereturn(escontext, (Datum) 0,
                                150                 :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
  840 akorotkov                 151 ECB             :                  errmsg("malformed multirange literal: \"%s\"",
                                152                 :                         input_str),
                                153                 :                  errdetail("Missing left brace.")));
                                154                 : 
                                155                 :     /* consume ranges */
  840 akorotkov                 156 GIC         654 :     parse_state = MULTIRANGE_BEFORE_RANGE;
                                157            6528 :     for (; parse_state != MULTIRANGE_FINISHED; ptr++)
  840 akorotkov                 158 ECB             :     {
  840 akorotkov                 159 CBC        5922 :         char        ch = *ptr;
                                160                 : 
                                161            5922 :         if (ch == '\0')
  115 tgl                       162 GNC           9 :             ereturn(escontext, (Datum) 0,
  840 akorotkov                 163 ECB             :                     (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                                164                 :                      errmsg("malformed multirange literal: \"%s\"",
                                165                 :                             input_str),
                                166                 :                      errdetail("Unexpected end of input.")));
                                167                 : 
                                168                 :         /* skip whitespace */
  840 akorotkov                 169 GIC        5913 :         if (isspace((unsigned char) ch))
                                170             288 :             continue;
  840 akorotkov                 171 ECB             : 
  840 akorotkov                 172 CBC        5625 :         switch (parse_state)
                                173                 :         {
                                174             894 :             case MULTIRANGE_BEFORE_RANGE:
  840 akorotkov                 175 GIC         894 :                 if (ch == '[' || ch == '(')
  840 akorotkov                 176 ECB             :                 {
  830 akorotkov                 177 CBC         750 :                     range_str_begin = ptr;
  840 akorotkov                 178 GIC         750 :                     parse_state = MULTIRANGE_IN_RANGE;
  840 akorotkov                 179 ECB             :                 }
  840 akorotkov                 180 CBC         144 :                 else if (ch == '}' && ranges_seen == 0)
  840 akorotkov                 181 GIC         123 :                     parse_state = MULTIRANGE_FINISHED;
  840 akorotkov                 182 CBC          21 :                 else if (pg_strncasecmp(ptr, RANGE_EMPTY_LITERAL,
  840 akorotkov                 183 ECB             :                                         strlen(RANGE_EMPTY_LITERAL)) == 0)
                                184                 :                 {
  840 akorotkov                 185 GIC           9 :                     ranges_seen++;
                                186                 :                     /* nothing to do with an empty range */
  840 akorotkov                 187 CBC           9 :                     ptr += strlen(RANGE_EMPTY_LITERAL) - 1;
  840 akorotkov                 188 GIC           9 :                     parse_state = MULTIRANGE_AFTER_RANGE;
  840 akorotkov                 189 ECB             :                 }
                                190                 :                 else
  115 tgl                       191 GNC          12 :                     ereturn(escontext, (Datum) 0,
                                192                 :                             (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
  840 akorotkov                 193 ECB             :                              errmsg("malformed multirange literal: \"%s\"",
                                194                 :                                     input_str),
                                195                 :                              errdetail("Expected range start.")));
  840 akorotkov                 196 GIC         882 :                 break;
                                197            3909 :             case MULTIRANGE_IN_RANGE:
  830 akorotkov                 198 CBC        3909 :                 if (ch == ']' || ch == ')')
  840 akorotkov                 199 ECB             :                 {
  830 akorotkov                 200 CBC         747 :                     range_str_len = ptr - range_str_begin + 1;
  830 akorotkov                 201 GIC         747 :                     range_str = pnstrdup(range_str_begin, range_str_len);
  840 akorotkov                 202 CBC         747 :                     if (range_capacity == range_count)
  840 akorotkov                 203 ECB             :                     {
  840 akorotkov                 204 LBC           0 :                         range_capacity *= 2;
                                205                 :                         ranges = (RangeType **)
  840 akorotkov                 206 UBC           0 :                             repalloc(ranges, range_capacity * sizeof(RangeType *));
                                207                 :                     }
  840 akorotkov                 208 GBC         747 :                     ranges_seen++;
  115 tgl                       209 GNC         747 :                     if (!InputFunctionCallSafe(&cache->typioproc,
                                210                 :                                                range_str,
                                211                 :                                                cache->typioparam,
                                212                 :                                                typmod,
                                213                 :                                                escontext,
                                214                 :                                                &range_datum))
                                215               6 :                         PG_RETURN_NULL();
                                216             729 :                     range = DatumGetRangeTypeP(range_datum);
  840 akorotkov                 217 GIC         729 :                     if (!RangeIsEmpty(range))
                                218             714 :                         ranges[range_count++] = range;
                                219             729 :                     parse_state = MULTIRANGE_AFTER_RANGE;
                                220                 :                 }
  840 akorotkov                 221 ECB             :                 else
  830                           222                 :                 {
  830 akorotkov                 223 CBC        3162 :                     if (ch == '"')
                                224              39 :                         parse_state = MULTIRANGE_IN_RANGE_QUOTED;
                                225            3123 :                     else if (ch == '\\')
  830 akorotkov                 226 GIC           3 :                         parse_state = MULTIRANGE_IN_RANGE_ESCAPED;
                                227                 : 
                                228                 :                     /*
  830 akorotkov                 229 ECB             :                      * We will include this character into range_str once we
                                230                 :                      * find the end of the range value.
                                231                 :                      */
                                232                 :                 }
  840 akorotkov                 233 GIC        3891 :                 break;
                                234               3 :             case MULTIRANGE_IN_RANGE_ESCAPED:
                                235                 : 
                                236                 :                 /*
                                237                 :                  * We will include this character into range_str once we find
                                238                 :                  * the end of the range value.
  830 akorotkov                 239 ECB             :                  */
  840 akorotkov                 240 CBC           3 :                 parse_state = MULTIRANGE_IN_RANGE;
  840 akorotkov                 241 GIC           3 :                 break;
                                242              78 :             case MULTIRANGE_IN_RANGE_QUOTED:
                                243              78 :                 if (ch == '"')
                                244              39 :                     if (*(ptr + 1) == '"')
                                245                 :                     {
  840 akorotkov                 246 ECB             :                         /* two quote marks means an escaped quote mark */
  840 akorotkov                 247 CBC           3 :                         ptr++;
  840 akorotkov                 248 ECB             :                     }
                                249                 :                     else
  840 akorotkov                 250 CBC          36 :                         parse_state = MULTIRANGE_IN_RANGE;
  840 akorotkov                 251 GIC          39 :                 else if (ch == '\\')
                                252               9 :                     parse_state = MULTIRANGE_IN_RANGE_QUOTED_ESCAPED;
  830 akorotkov                 253 ECB             : 
                                254                 :                 /*
                                255                 :                  * We will include this character into range_str once we find
  716                           256                 :                  * the end of the range value.
  830                           257                 :                  */
  840 akorotkov                 258 CBC          78 :                 break;
  840 akorotkov                 259 GIC         732 :             case MULTIRANGE_AFTER_RANGE:
                                260             732 :                 if (ch == ',')
                                261             240 :                     parse_state = MULTIRANGE_BEFORE_RANGE;
                                262             492 :                 else if (ch == '}')
                                263             483 :                     parse_state = MULTIRANGE_FINISHED;
  840 akorotkov                 264 ECB             :                 else
  115 tgl                       265 GNC           9 :                     ereturn(escontext, (Datum) 0,
  840 akorotkov                 266 ECB             :                             (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                                267                 :                              errmsg("malformed multirange literal: \"%s\"",
                                268                 :                                     input_str),
                                269                 :                              errdetail("Expected comma or end of multirange.")));
  840 akorotkov                 270 GIC         723 :                 break;
  840 akorotkov                 271 CBC           9 :             case MULTIRANGE_IN_RANGE_QUOTED_ESCAPED:
                                272                 : 
                                273                 :                 /*
                                274                 :                  * We will include this character into range_str once we find
                                275                 :                  * the end of the range value.
  830 akorotkov                 276 ECB             :                  */
  840 akorotkov                 277 CBC           9 :                 parse_state = MULTIRANGE_IN_RANGE_QUOTED;
  840 akorotkov                 278 GIC           9 :                 break;
  840 akorotkov                 279 UIC           0 :             default:
                                280               0 :                 elog(ERROR, "unknown parse state: %d", parse_state);
                                281                 :         }
                                282                 :     }
  840 akorotkov                 283 ECB             : 
                                284                 :     /* consume whitespace */
  840 akorotkov                 285 GBC         618 :     while (*ptr != '\0' && isspace((unsigned char) *ptr))
                                286              12 :         ptr++;
                                287                 : 
  840 akorotkov                 288 GIC         606 :     if (*ptr != '\0')
  115 tgl                       289 GNC           3 :         ereturn(escontext, (Datum) 0,
                                290                 :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
  840 akorotkov                 291 ECB             :                  errmsg("malformed multirange literal: \"%s\"",
                                292                 :                         input_str),
                                293                 :                  errdetail("Junk after closing right brace.")));
                                294                 : 
  840 akorotkov                 295 CBC         603 :     ret = make_multirange(mltrngtypoid, rangetyp, range_count, ranges);
  840 akorotkov                 296 GIC         603 :     PG_RETURN_MULTIRANGE_P(ret);
                                297                 : }
                                298                 : 
                                299                 : Datum
                                300            1100 : multirange_out(PG_FUNCTION_ARGS)
  840 akorotkov                 301 ECB             : {
  840 akorotkov                 302 CBC        1100 :     MultirangeType *multirange = PG_GETARG_MULTIRANGE_P(0);
  840 akorotkov                 303 GIC        1100 :     Oid         mltrngtypoid = MultirangeTypeGetOid(multirange);
                                304                 :     MultirangeIOData *cache;
                                305                 :     StringInfoData buf;
  840 akorotkov                 306 ECB             :     RangeType  *range;
                                307                 :     char       *rangeStr;
                                308                 :     int32       range_count;
                                309                 :     int32       i;
                                310                 :     RangeType **ranges;
                                311                 : 
  840 akorotkov                 312 GIC        1100 :     cache = get_multirange_io_data(fcinfo, mltrngtypoid, IOFunc_output);
                                313                 : 
                                314            1100 :     initStringInfo(&buf);
                                315                 : 
                                316            1100 :     appendStringInfoChar(&buf, '{');
                                317                 : 
  840 akorotkov                 318 CBC        1100 :     multirange_deserialize(cache->typcache->rngtype, multirange, &range_count, &ranges);
  840 akorotkov                 319 GIC        2078 :     for (i = 0; i < range_count; i++)
  840 akorotkov                 320 ECB             :     {
  840 akorotkov                 321 GIC         978 :         if (i > 0)
  840 akorotkov                 322 CBC         133 :             appendStringInfoChar(&buf, ',');
  840 akorotkov                 323 GIC         978 :         range = ranges[i];
  840 akorotkov                 324 CBC         978 :         rangeStr = OutputFunctionCall(&cache->typioproc, RangeTypePGetDatum(range));
                                325             978 :         appendStringInfoString(&buf, rangeStr);
                                326                 :     }
  840 akorotkov                 327 ECB             : 
  840 akorotkov                 328 CBC        1100 :     appendStringInfoChar(&buf, '}');
  840 akorotkov                 329 ECB             : 
  840 akorotkov                 330 CBC        1100 :     PG_RETURN_CSTRING(buf.data);
  840 akorotkov                 331 ECB             : }
                                332                 : 
                                333                 : /*
                                334                 :  * Binary representation: First a int32-sized count of ranges, followed by
                                335                 :  * ranges in their native binary representation.
                                336                 :  */
                                337                 : Datum
  840 akorotkov                 338 UIC           0 : multirange_recv(PG_FUNCTION_ARGS)
                                339                 : {
                                340               0 :     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
                                341               0 :     Oid         mltrngtypoid = PG_GETARG_OID(1);
                                342               0 :     int32       typmod = PG_GETARG_INT32(2);
                                343                 :     MultirangeIOData *cache;
  840 akorotkov                 344 EUB             :     uint32      range_count;
                                345                 :     RangeType **ranges;
                                346                 :     MultirangeType *ret;
                                347                 :     StringInfoData tmpbuf;
                                348                 : 
  840 akorotkov                 349 UIC           0 :     cache = get_multirange_io_data(fcinfo, mltrngtypoid, IOFunc_receive);
                                350                 : 
                                351               0 :     range_count = pq_getmsgint(buf, 4);
                                352               0 :     ranges = palloc(range_count * sizeof(RangeType *));
                                353                 : 
                                354               0 :     initStringInfo(&tmpbuf);
  840 akorotkov                 355 UBC           0 :     for (int i = 0; i < range_count; i++)
                                356                 :     {
                                357               0 :         uint32      range_len = pq_getmsgint(buf, 4);
                                358               0 :         const char *range_data = pq_getmsgbytes(buf, range_len);
                                359                 : 
                                360               0 :         resetStringInfo(&tmpbuf);
                                361               0 :         appendBinaryStringInfo(&tmpbuf, range_data, range_len);
                                362                 : 
                                363               0 :         ranges[i] = DatumGetRangeTypeP(ReceiveFunctionCall(&cache->typioproc,
  840 akorotkov                 364 EUB             :                                                            &tmpbuf,
                                365                 :                                                            cache->typioparam,
                                366                 :                                                            typmod));
                                367                 :     }
  840 akorotkov                 368 UIC           0 :     pfree(tmpbuf.data);
  840 akorotkov                 369 EUB             : 
  840 akorotkov                 370 UIC           0 :     pq_getmsgend(buf);
                                371                 : 
                                372               0 :     ret = make_multirange(mltrngtypoid, cache->typcache->rngtype,
                                373                 :                           range_count, ranges);
  840 akorotkov                 374 UBC           0 :     PG_RETURN_MULTIRANGE_P(ret);
                                375                 : }
  840 akorotkov                 376 EUB             : 
                                377                 : Datum
  840 akorotkov                 378 UBC           0 : multirange_send(PG_FUNCTION_ARGS)
                                379                 : {
                                380               0 :     MultirangeType *multirange = PG_GETARG_MULTIRANGE_P(0);
  840 akorotkov                 381 UIC           0 :     Oid         mltrngtypoid = MultirangeTypeGetOid(multirange);
                                382               0 :     StringInfo  buf = makeStringInfo();
                                383                 :     RangeType **ranges;
  840 akorotkov                 384 EUB             :     int32       range_count;
                                385                 :     MultirangeIOData *cache;
                                386                 : 
  840 akorotkov                 387 UBC           0 :     cache = get_multirange_io_data(fcinfo, mltrngtypoid, IOFunc_send);
  840 akorotkov                 388 EUB             : 
                                389                 :     /* construct output */
  840 akorotkov                 390 UIC           0 :     pq_begintypsend(buf);
                                391                 : 
                                392               0 :     pq_sendint32(buf, multirange->rangeCount);
  840 akorotkov                 393 EUB             : 
  840 akorotkov                 394 UIC           0 :     multirange_deserialize(cache->typcache->rngtype, multirange, &range_count, &ranges);
                                395               0 :     for (int i = 0; i < range_count; i++)
  840 akorotkov                 396 EUB             :     {
                                397                 :         Datum       range;
                                398                 : 
  840 akorotkov                 399 UIC           0 :         range = RangeTypePGetDatum(ranges[i]);
  840 akorotkov                 400 UBC           0 :         range = PointerGetDatum(SendFunctionCall(&cache->typioproc, range));
  840 akorotkov                 401 EUB             : 
  840 akorotkov                 402 UIC           0 :         pq_sendint32(buf, VARSIZE(range) - VARHDRSZ);
                                403               0 :         pq_sendbytes(buf, VARDATA(range), VARSIZE(range) - VARHDRSZ);
                                404                 :     }
  840 akorotkov                 405 EUB             : 
  840 akorotkov                 406 UBC           0 :     PG_RETURN_BYTEA_P(pq_endtypsend(buf));
                                407                 : }
  840 akorotkov                 408 EUB             : 
                                409                 : /*
                                410                 :  * get_multirange_io_data: get cached information needed for multirange type I/O
                                411                 :  *
                                412                 :  * The multirange I/O functions need a bit more cached info than other multirange
                                413                 :  * functions, so they store a MultirangeIOData struct in fn_extra, not just a
                                414                 :  * pointer to a type cache entry.
                                415                 :  */
                                416                 : static MultirangeIOData *
  840 akorotkov                 417 GIC        1757 : get_multirange_io_data(FunctionCallInfo fcinfo, Oid mltrngtypid, IOFuncSelector func)
                                418                 : {
                                419            1757 :     MultirangeIOData *cache = (MultirangeIOData *) fcinfo->flinfo->fn_extra;
                                420                 : 
                                421            1757 :     if (cache == NULL || cache->typcache->type_id != mltrngtypid)
                                422                 :     {
  840 akorotkov                 423 ECB             :         Oid         typiofunc;
                                424                 :         int16       typlen;
                                425                 :         bool        typbyval;
                                426                 :         char        typalign;
                                427                 :         char        typdelim;
                                428                 : 
  840 akorotkov                 429 GIC        1189 :         cache = (MultirangeIOData *) MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
                                430                 :                                                         sizeof(MultirangeIOData));
                                431            1189 :         cache->typcache = lookup_type_cache(mltrngtypid, TYPECACHE_MULTIRANGE_INFO);
                                432            1189 :         if (cache->typcache->rngtype == NULL)
  840 akorotkov                 433 UIC           0 :             elog(ERROR, "type %u is not a multirange type", mltrngtypid);
                                434                 : 
  840 akorotkov                 435 ECB             :         /* get_type_io_data does more than we need, but is convenient */
  840 akorotkov                 436 GIC        1189 :         get_type_io_data(cache->typcache->rngtype->type_id,
  840 akorotkov                 437 ECB             :                          func,
                                438                 :                          &typlen,
  840 akorotkov                 439 EUB             :                          &typbyval,
                                440                 :                          &typalign,
                                441                 :                          &typdelim,
  840 akorotkov                 442 ECB             :                          &cache->typioparam,
                                443                 :                          &typiofunc);
                                444                 : 
  840 akorotkov                 445 GIC        1189 :         if (!OidIsValid(typiofunc))
                                446                 :         {
                                447                 :             /* this could only happen for receive or send */
  840 akorotkov                 448 UIC           0 :             if (func == IOFunc_receive)
                                449               0 :                 ereport(ERROR,
                                450                 :                         (errcode(ERRCODE_UNDEFINED_FUNCTION),
  840 akorotkov                 451 ECB             :                          errmsg("no binary input function available for type %s",
                                452                 :                                 format_type_be(cache->typcache->rngtype->type_id))));
                                453                 :             else
  840 akorotkov                 454 UBC           0 :                 ereport(ERROR,
  840 akorotkov                 455 EUB             :                         (errcode(ERRCODE_UNDEFINED_FUNCTION),
                                456                 :                          errmsg("no binary output function available for type %s",
                                457                 :                                 format_type_be(cache->typcache->rngtype->type_id))));
                                458                 :         }
  840 akorotkov                 459 GIC        1189 :         fmgr_info_cxt(typiofunc, &cache->typioproc,
  840 akorotkov                 460 GBC        1189 :                       fcinfo->flinfo->fn_mcxt);
                                461                 : 
  840 akorotkov                 462 GIC        1189 :         fcinfo->flinfo->fn_extra = (void *) cache;
                                463                 :     }
                                464                 : 
  840 akorotkov                 465 CBC        1757 :     return cache;
  840 akorotkov                 466 ECB             : }
                                467                 : 
                                468                 : /*
                                469                 :  * Converts a list of arbitrary ranges into a list that is sorted and merged.
                                470                 :  * Changes the contents of `ranges`.
                                471                 :  *
                                472                 :  * Returns the number of slots actually used, which may be less than
                                473                 :  * input_range_count but never more.
                                474                 :  *
                                475                 :  * We assume that no input ranges are null, but empties are okay.
                                476                 :  */
                                477                 : static int32
  840 akorotkov                 478 GIC       11694 : multirange_canonicalize(TypeCacheEntry *rangetyp, int32 input_range_count,
                                479                 :                         RangeType **ranges)
                                480                 : {
                                481           11694 :     RangeType  *lastRange = NULL;
                                482                 :     RangeType  *currentRange;
                                483                 :     int32       i;
  840 akorotkov                 484 CBC       11694 :     int32       output_range_count = 0;
                                485                 : 
                                486                 :     /* Sort the ranges so we can find the ones that overlap/meet. */
                                487           11694 :     qsort_arg(ranges, input_range_count, sizeof(RangeType *), range_compare,
                                488                 :               rangetyp);
                                489                 : 
  840 akorotkov                 490 ECB             :     /* Now merge where possible: */
  840 akorotkov                 491 GIC       36297 :     for (i = 0; i < input_range_count; i++)
                                492                 :     {
  840 akorotkov                 493 CBC       24603 :         currentRange = ranges[i];
  840 akorotkov                 494 GIC       24603 :         if (RangeIsEmpty(currentRange))
                                495              93 :             continue;
                                496                 : 
  840 akorotkov                 497 CBC       24510 :         if (lastRange == NULL)
                                498                 :         {
                                499           11250 :             ranges[output_range_count++] = lastRange = currentRange;
                                500           11250 :             continue;
  840 akorotkov                 501 ECB             :         }
                                502                 : 
                                503                 :         /*
                                504                 :          * range_adjacent_internal gives true if *either* A meets B or B meets
                                505                 :          * A, which is not quite want we want, but we rely on the sorting
                                506                 :          * above to rule out B meets A ever happening.
                                507                 :          */
  840 akorotkov                 508 GIC       13260 :         if (range_adjacent_internal(rangetyp, lastRange, currentRange))
                                509                 :         {
                                510                 :             /* The two ranges touch (without overlap), so merge them: */
                                511             630 :             ranges[output_range_count - 1] = lastRange =
                                512             630 :                 range_union_internal(rangetyp, lastRange, currentRange, false);
                                513                 :         }
  840 akorotkov                 514 CBC       12630 :         else if (range_before_internal(rangetyp, lastRange, currentRange))
                                515                 :         {
                                516                 :             /* There's a gap, so make a new entry: */
                                517           12570 :             lastRange = ranges[output_range_count] = currentRange;
                                518           12570 :             output_range_count++;
                                519                 :         }
  840 akorotkov                 520 ECB             :         else
                                521                 :         {
                                522                 :             /* They must overlap, so merge them: */
  840 akorotkov                 523 CBC          60 :             ranges[output_range_count - 1] = lastRange =
                                524              60 :                 range_union_internal(rangetyp, lastRange, currentRange, true);
                                525                 :         }
                                526                 :     }
                                527                 : 
  840 akorotkov                 528 GIC       11694 :     return output_range_count;
  840 akorotkov                 529 ECB             : }
                                530                 : 
                                531                 : /*
                                532                 :  *----------------------------------------------------------
                                533                 :  * SUPPORT FUNCTIONS
                                534                 :  *
                                535                 :  *   These functions aren't in pg_proc, but are useful for
                                536                 :  *   defining new generic multirange functions in C.
                                537                 :  *----------------------------------------------------------
                                538                 :  */
                                539                 : 
                                540                 : /*
                                541                 :  * multirange_get_typcache: get cached information about a multirange type
                                542                 :  *
                                543                 :  * This is for use by multirange-related functions that follow the convention
                                544                 :  * of using the fn_extra field as a pointer to the type cache entry for
                                545                 :  * the multirange type.  Functions that need to cache more information than
                                546                 :  * that must fend for themselves.
                                547                 :  */
                                548                 : TypeCacheEntry *
  840 akorotkov                 549 GIC      625203 : multirange_get_typcache(FunctionCallInfo fcinfo, Oid mltrngtypid)
                                550                 : {
                                551          625203 :     TypeCacheEntry *typcache = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
                                552                 : 
                                553          625203 :     if (typcache == NULL ||
                                554          622485 :         typcache->type_id != mltrngtypid)
  840 akorotkov                 555 ECB             :     {
  840 akorotkov                 556 GIC        2718 :         typcache = lookup_type_cache(mltrngtypid, TYPECACHE_MULTIRANGE_INFO);
  840 akorotkov                 557 CBC        2718 :         if (typcache->rngtype == NULL)
  840 akorotkov                 558 UIC           0 :             elog(ERROR, "type %u is not a multirange type", mltrngtypid);
  840 akorotkov                 559 CBC        2718 :         fcinfo->flinfo->fn_extra = (void *) typcache;
  840 akorotkov                 560 ECB             :     }
                                561                 : 
  840 akorotkov                 562 CBC      625203 :     return typcache;
  840 akorotkov                 563 ECB             : }
  840 akorotkov                 564 EUB             : 
  840 akorotkov                 565 ECB             : 
                                566                 : /*
                                567                 :  * Estimate size occupied by serialized multirange.
                                568                 :  */
                                569                 : static Size
  840 akorotkov                 570 GIC       11694 : multirange_size_estimate(TypeCacheEntry *rangetyp, int32 range_count,
                                571                 :                          RangeType **ranges)
                                572                 : {
                                573           11694 :     char        elemalign = rangetyp->rngelemtype->typalign;
                                574                 :     Size        size;
                                575                 :     int32       i;
  840 akorotkov                 576 ECB             : 
                                577                 :     /*
                                578                 :      * Count space for MultirangeType struct, items and flags.
                                579                 :      */
  840 akorotkov                 580 GIC       11694 :     size = att_align_nominal(sizeof(MultirangeType) +
                                581                 :                              Max(range_count - 1, 0) * sizeof(uint32) +
                                582                 :                              range_count * sizeof(uint8), elemalign);
                                583                 : 
                                584                 :     /* Count space for range bounds */
                                585           35514 :     for (i = 0; i < range_count; i++)
  840 akorotkov                 586 CBC       23820 :         size += att_align_nominal(VARSIZE(ranges[i]) -
                                587                 :                                   sizeof(RangeType) -
                                588                 :                                   sizeof(char), elemalign);
                                589                 : 
  840 akorotkov                 590 GIC       11694 :     return size;
  840 akorotkov                 591 ECB             : }
                                592                 : 
                                593                 : /*
                                594                 :  * Write multirange data into pre-allocated space.
                                595                 :  */
                                596                 : static void
  840 akorotkov                 597 GIC       11694 : write_multirange_data(MultirangeType *multirange, TypeCacheEntry *rangetyp,
                                598                 :                       int32 range_count, RangeType **ranges)
                                599                 : {
                                600                 :     uint32     *items;
                                601           11694 :     uint32      prev_offset = 0;
                                602                 :     uint8      *flags;
  840 akorotkov                 603 ECB             :     int32       i;
                                604                 :     Pointer     begin,
                                605                 :                 ptr;
  840 akorotkov                 606 GIC       11694 :     char        elemalign = rangetyp->rngelemtype->typalign;
  840 akorotkov                 607 ECB             : 
  840 akorotkov                 608 GIC       11694 :     items = MultirangeGetItemsPtr(multirange);
                                609           11694 :     flags = MultirangeGetFlagsPtr(multirange);
                                610           11694 :     ptr = begin = MultirangeGetBoundariesPtr(multirange, elemalign);
                                611           35514 :     for (i = 0; i < range_count; i++)
  840 akorotkov                 612 ECB             :     {
                                613                 :         uint32      len;
                                614                 : 
  840 akorotkov                 615 CBC       23820 :         if (i > 0)
  840 akorotkov                 616 ECB             :         {
                                617                 :             /*
                                618                 :              * Every range, except the first one, has an item.  Every
                                619                 :              * MULTIRANGE_ITEM_OFFSET_STRIDE item contains an offset, others
                                620                 :              * contain lengths.
                                621                 :              */
  840 akorotkov                 622 GIC       12570 :             items[i - 1] = ptr - begin;
                                623           12570 :             if ((i % MULTIRANGE_ITEM_OFFSET_STRIDE) != 0)
                                624           12570 :                 items[i - 1] -= prev_offset;
                                625                 :             else
  840 akorotkov                 626 UIC           0 :                 items[i - 1] |= MULTIRANGE_ITEM_OFF_BIT;
  840 akorotkov                 627 GIC       12570 :             prev_offset = ptr - begin;
  840 akorotkov                 628 ECB             :         }
  840 akorotkov                 629 CBC       23820 :         flags[i] = *((Pointer) ranges[i] + VARSIZE(ranges[i]) - sizeof(char));
                                630           23820 :         len = VARSIZE(ranges[i]) - sizeof(RangeType) - sizeof(char);
  840 akorotkov                 631 GIC       23820 :         memcpy(ptr, (Pointer) (ranges[i] + 1), len);
  840 akorotkov                 632 GBC       23820 :         ptr += att_align_nominal(len, elemalign);
  840 akorotkov                 633 ECB             :     }
  840 akorotkov                 634 GIC       11694 : }
  840 akorotkov                 635 ECB             : 
                                636                 : 
                                637                 : /*
                                638                 :  * This serializes the multirange from a list of non-null ranges.  It also
                                639                 :  * sorts the ranges and merges any that touch.  The ranges should already be
                                640                 :  * detoasted, and there should be no NULLs.  This should be used by most
                                641                 :  * callers.
                                642                 :  *
                                643                 :  * Note that we may change the `ranges` parameter (the pointers, but not
                                644                 :  * any already-existing RangeType contents).
                                645                 :  */
                                646                 : MultirangeType *
  840 akorotkov                 647 GIC       11694 : make_multirange(Oid mltrngtypoid, TypeCacheEntry *rangetyp, int32 range_count,
                                648                 :                 RangeType **ranges)
                                649                 : {
                                650                 :     MultirangeType *multirange;
                                651                 :     Size        size;
                                652                 : 
  840 akorotkov                 653 ECB             :     /* Sort and merge input ranges. */
  840 akorotkov                 654 GIC       11694 :     range_count = multirange_canonicalize(rangetyp, range_count, ranges);
                                655                 : 
                                656                 :     /* Note: zero-fill is required here, just as in heap tuples */
                                657           11694 :     size = multirange_size_estimate(rangetyp, range_count, ranges);
                                658           11694 :     multirange = palloc0(size);
                                659           11694 :     SET_VARSIZE(multirange, size);
  840 akorotkov                 660 ECB             : 
                                661                 :     /* Now fill in the datum */
  840 akorotkov                 662 GIC       11694 :     multirange->multirangetypid = mltrngtypoid;
  840 akorotkov                 663 CBC       11694 :     multirange->rangeCount = range_count;
  840 akorotkov                 664 ECB             : 
  840 akorotkov                 665 CBC       11694 :     write_multirange_data(multirange, rangetyp, range_count, ranges);
                                666                 : 
  840 akorotkov                 667 GIC       11694 :     return multirange;
  840 akorotkov                 668 ECB             : }
                                669                 : 
                                670                 : /*
                                671                 :  * Get offset of bounds values of the i'th range in the multirange.
                                672                 :  */
                                673                 : static uint32
  840 akorotkov                 674 GIC      806990 : multirange_get_bounds_offset(const MultirangeType *multirange, int32 i)
                                675                 : {
                                676          806990 :     uint32     *items = MultirangeGetItemsPtr(multirange);
                                677          806990 :     uint32      offset = 0;
                                678                 : 
                                679                 :     /*
  840 akorotkov                 680 ECB             :      * Summarize lengths till we meet an offset.
                                681                 :      */
  840 akorotkov                 682 CBC     1309586 :     while (i > 0)
  840 akorotkov                 683 ECB             :     {
  840 akorotkov                 684 GIC      502596 :         offset += MULTIRANGE_ITEM_GET_OFFLEN(items[i - 1]);
                                685          502596 :         if (MULTIRANGE_ITEM_HAS_OFF(items[i - 1]))
  840 akorotkov                 686 UIC           0 :             break;
  840 akorotkov                 687 GIC      502596 :         i--;
  840 akorotkov                 688 ECB             :     }
  840 akorotkov                 689 GIC      806990 :     return offset;
  840 akorotkov                 690 ECB             : }
                                691                 : 
  840 akorotkov                 692 EUB             : /*
  840 akorotkov                 693 ECB             :  * Fetch the i'th range from the multirange.
                                694                 :  */
                                695                 : RangeType *
  840 akorotkov                 696 GIC        1395 : multirange_get_range(TypeCacheEntry *rangetyp,
                                697                 :                      const MultirangeType *multirange, int i)
                                698                 : {
                                699                 :     uint32      offset;
                                700                 :     uint8       flags;
                                701                 :     Pointer     begin,
  840 akorotkov                 702 ECB             :                 ptr;
  840 akorotkov                 703 GIC        1395 :     int16       typlen = rangetyp->rngelemtype->typlen;
                                704            1395 :     char        typalign = rangetyp->rngelemtype->typalign;
                                705                 :     uint32      len;
                                706                 :     RangeType  *range;
                                707                 : 
                                708            1395 :     Assert(i < multirange->rangeCount);
  840 akorotkov                 709 ECB             : 
  840 akorotkov                 710 CBC        1395 :     offset = multirange_get_bounds_offset(multirange, i);
  840 akorotkov                 711 GIC        1395 :     flags = MultirangeGetFlagsPtr(multirange)[i];
                                712            1395 :     ptr = begin = MultirangeGetBoundariesPtr(multirange, typalign) + offset;
                                713                 : 
  840 akorotkov                 714 ECB             :     /*
                                715                 :      * Calculate the size of bound values.  In principle, we could get offset
                                716                 :      * of the next range bound values and calculate accordingly.  But range
                                717                 :      * bound values are aligned, so we have to walk the values to get the
                                718                 :      * exact size.
                                719                 :      */
  840 akorotkov                 720 GIC        1395 :     if (RANGE_HAS_LBOUND(flags))
                                721            1071 :         ptr = (Pointer) att_addlength_pointer(ptr, typlen, ptr);
                                722            1395 :     if (RANGE_HAS_UBOUND(flags))
                                723                 :     {
  482                           724            1053 :         ptr = (Pointer) att_align_pointer(ptr, typalign, typlen, ptr);
  840                           725            1053 :         ptr = (Pointer) att_addlength_pointer(ptr, typlen, ptr);
  482 akorotkov                 726 ECB             :     }
  840 akorotkov                 727 CBC        1395 :     len = (ptr - begin) + sizeof(RangeType) + sizeof(uint8);
  840 akorotkov                 728 ECB             : 
  840 akorotkov                 729 GIC        1395 :     range = palloc0(len);
  840 akorotkov                 730 CBC        1395 :     SET_VARSIZE(range, len);
                                731            1395 :     range->rangetypid = rangetyp->type_id;
                                732                 : 
                                733            1395 :     memcpy(range + 1, begin, ptr - begin);
  840 akorotkov                 734 GIC        1395 :     *((uint8 *) (range + 1) + (ptr - begin)) = flags;
  840 akorotkov                 735 ECB             : 
  840 akorotkov                 736 CBC        1395 :     return range;
  840 akorotkov                 737 ECB             : }
                                738                 : 
                                739                 : /*
                                740                 :  * Fetch bounds from the i'th range of the multirange.  This is the shortcut for
                                741                 :  * doing the same thing as multirange_get_range() + range_deserialize(), but
                                742                 :  * performing fewer operations.
                                743                 :  */
                                744                 : void
  840 akorotkov                 745 GIC      805595 : multirange_get_bounds(TypeCacheEntry *rangetyp,
                                746                 :                       const MultirangeType *multirange,
                                747                 :                       uint32 i, RangeBound *lower, RangeBound *upper)
                                748                 : {
                                749                 :     uint32      offset;
                                750                 :     uint8       flags;
  840 akorotkov                 751 ECB             :     Pointer     ptr;
  840 akorotkov                 752 GIC      805595 :     int16       typlen = rangetyp->rngelemtype->typlen;
                                753          805595 :     char        typalign = rangetyp->rngelemtype->typalign;
                                754          805595 :     bool        typbyval = rangetyp->rngelemtype->typbyval;
                                755                 :     Datum       lbound;
                                756                 :     Datum       ubound;
                                757                 : 
  840 akorotkov                 758 CBC      805595 :     Assert(i < multirange->rangeCount);
  840 akorotkov                 759 ECB             : 
  840 akorotkov                 760 CBC      805595 :     offset = multirange_get_bounds_offset(multirange, i);
  840 akorotkov                 761 GIC      805595 :     flags = MultirangeGetFlagsPtr(multirange)[i];
                                762          805595 :     ptr = MultirangeGetBoundariesPtr(multirange, typalign) + offset;
                                763                 : 
  840 akorotkov                 764 ECB             :     /* multirange can't contain empty ranges */
  840 akorotkov                 765 GIC      805595 :     Assert((flags & RANGE_EMPTY) == 0);
  840 akorotkov                 766 ECB             : 
                                767                 :     /* fetch lower bound, if any */
  840 akorotkov                 768 CBC      805595 :     if (RANGE_HAS_LBOUND(flags))
                                769                 :     {
                                770                 :         /* att_align_pointer cannot be necessary here */
                                771          796805 :         lbound = fetch_att(ptr, typbyval, typlen);
  840 akorotkov                 772 GIC      796805 :         ptr = (Pointer) att_addlength_pointer(ptr, typlen, ptr);
                                773                 :     }
  840 akorotkov                 774 ECB             :     else
  840 akorotkov                 775 GIC        8790 :         lbound = (Datum) 0;
                                776                 : 
  840 akorotkov                 777 ECB             :     /* fetch upper bound, if any */
  840 akorotkov                 778 CBC      805595 :     if (RANGE_HAS_UBOUND(flags))
                                779                 :     {
  840 akorotkov                 780 GIC      797591 :         ptr = (Pointer) att_align_pointer(ptr, typalign, typlen, ptr);
  840 akorotkov                 781 CBC      797591 :         ubound = fetch_att(ptr, typbyval, typlen);
                                782                 :         /* no need for att_addlength_pointer */
                                783                 :     }
  840 akorotkov                 784 ECB             :     else
  840 akorotkov                 785 GIC        8004 :         ubound = (Datum) 0;
  840 akorotkov                 786 ECB             : 
                                787                 :     /* emit results */
  840 akorotkov                 788 GIC      805595 :     lower->val = lbound;
                                789          805595 :     lower->infinite = (flags & RANGE_LB_INF) != 0;
                                790          805595 :     lower->inclusive = (flags & RANGE_LB_INC) != 0;
  840 akorotkov                 791 CBC      805595 :     lower->lower = true;
                                792                 : 
  840 akorotkov                 793 GIC      805595 :     upper->val = ubound;
  840 akorotkov                 794 CBC      805595 :     upper->infinite = (flags & RANGE_UB_INF) != 0;
                                795          805595 :     upper->inclusive = (flags & RANGE_UB_INC) != 0;
                                796          805595 :     upper->lower = false;
                                797          805595 : }
                                798                 : 
  831 akorotkov                 799 ECB             : /*
                                800                 :  * Construct union range from the multirange.
                                801                 :  */
                                802                 : RangeType *
  831 akorotkov                 803 CBC       11100 : multirange_get_union_range(TypeCacheEntry *rangetyp,
                                804                 :                            const MultirangeType *mr)
                                805                 : {
                                806                 :     RangeBound  lower,
                                807                 :                 upper,
                                808                 :                 tmp;
  831 akorotkov                 809 ECB             : 
  831 akorotkov                 810 GIC       11100 :     if (MultirangeIsEmpty(mr))
                                811            1500 :         return make_empty_range(rangetyp);
                                812                 : 
                                813            9600 :     multirange_get_bounds(rangetyp, mr, 0, &lower, &tmp);
                                814            9600 :     multirange_get_bounds(rangetyp, mr, mr->rangeCount - 1, &tmp, &upper);
                                815                 : 
  115 tgl                       816 GNC        9600 :     return make_range(rangetyp, &lower, &upper, false, NULL);
  831 akorotkov                 817 ECB             : }
                                818                 : 
                                819                 : 
  840                           820                 : /*
                                821                 :  * multirange_deserialize: deconstruct a multirange value
                                822                 :  *
                                823                 :  * NB: the given multirange object must be fully detoasted; it cannot have a
                                824                 :  * short varlena header.
                                825                 :  */
                                826                 : void
  840 akorotkov                 827 GIC        1457 : multirange_deserialize(TypeCacheEntry *rangetyp,
                                828                 :                        const MultirangeType *multirange, int32 *range_count,
                                829                 :                        RangeType ***ranges)
                                830                 : {
                                831            1457 :     *range_count = multirange->rangeCount;
                                832                 : 
  840 akorotkov                 833 ECB             :     /* Convert each ShortRangeType into a RangeType */
  840 akorotkov                 834 GIC        1457 :     if (*range_count > 0)
                                835                 :     {
                                836                 :         int         i;
  840 akorotkov                 837 ECB             : 
  840 akorotkov                 838 GIC        1142 :         *ranges = palloc(*range_count * sizeof(RangeType *));
                                839            2507 :         for (i = 0; i < *range_count; i++)
  840 akorotkov                 840 CBC        1365 :             (*ranges)[i] = multirange_get_range(rangetyp, multirange, i);
                                841                 :     }
                                842                 :     else
                                843                 :     {
                                844             315 :         *ranges = NULL;
  840 akorotkov                 845 ECB             :     }
  840 akorotkov                 846 CBC        1457 : }
                                847                 : 
                                848                 : MultirangeType *
  840 akorotkov                 849 GIC           9 : make_empty_multirange(Oid mltrngtypoid, TypeCacheEntry *rangetyp)
  840 akorotkov                 850 ECB             : {
  840 akorotkov                 851 GIC           9 :     return make_multirange(mltrngtypoid, rangetyp, 0, NULL);
  840 akorotkov                 852 ECB             : }
                                853                 : 
                                854                 : /*
                                855                 :  * Similar to range_overlaps_internal(), but takes range bounds instead of
                                856                 :  * ranges as arguments.
                                857                 :  */
                                858                 : static bool
  840 akorotkov                 859 GIC       28962 : range_bounds_overlaps(TypeCacheEntry *typcache,
                                860                 :                       RangeBound *lower1, RangeBound *upper1,
                                861                 :                       RangeBound *lower2, RangeBound *upper2)
                                862                 : {
                                863           56913 :     if (range_cmp_bounds(typcache, lower1, lower2) >= 0 &&
                                864           27951 :         range_cmp_bounds(typcache, lower1, upper2) <= 0)
  840 akorotkov                 865 CBC         345 :         return true;
                                866                 : 
  840 akorotkov                 867 GIC       29628 :     if (range_cmp_bounds(typcache, lower2, lower1) >= 0 &&
                                868            1011 :         range_cmp_bounds(typcache, lower2, upper1) <= 0)
  840 akorotkov                 869 CBC        1011 :         return true;
  840 akorotkov                 870 ECB             : 
  840 akorotkov                 871 CBC       27606 :     return false;
                                872                 : }
  840 akorotkov                 873 ECB             : 
                                874                 : /*
                                875                 :  * Similar to range_contains_internal(), but takes range bounds instead of
                                876                 :  * ranges as arguments.
                                877                 :  */
                                878                 : static bool
  840 akorotkov                 879 GIC       47826 : range_bounds_contains(TypeCacheEntry *typcache,
                                880                 :                       RangeBound *lower1, RangeBound *upper1,
                                881                 :                       RangeBound *lower2, RangeBound *upper2)
                                882                 : {
                                883           63091 :     if (range_cmp_bounds(typcache, lower1, lower2) <= 0 &&
                                884           15265 :         range_cmp_bounds(typcache, upper1, upper2) >= 0)
  840 akorotkov                 885 CBC        4285 :         return true;
                                886                 : 
  840 akorotkov                 887 GIC       43541 :     return false;
                                888                 : }
  840 akorotkov                 889 ECB             : 
                                890                 : /*
                                891                 :  * Check if the given key matches any range in multirange using binary search.
                                892                 :  * If the required range isn't found, that counts as a mismatch.  When the
                                893                 :  * required range is found, the comparison function can still report this as
                                894                 :  * either match or mismatch.  For instance, if we search for containment, we can
                                895                 :  * found a range, which is overlapping but not containing the key range, and
                                896                 :  * that would count as a mismatch.
                                897                 :  */
                                898                 : static bool
  831 akorotkov                 899 GIC       78663 : multirange_bsearch_match(TypeCacheEntry *typcache, const MultirangeType *mr,
                                900                 :                          void *key, multirange_bsearch_comparison cmp_func)
                                901                 : {
                                902                 :     uint32      l,
                                903                 :                 u,
                                904                 :                 idx;
  840 akorotkov                 905 ECB             :     int         comparison;
  840 akorotkov                 906 GIC       78663 :     bool        match = false;
                                907                 : 
                                908           78663 :     l = 0;
                                909           78663 :     u = mr->rangeCount;
                                910          208740 :     while (l < u)
                                911                 :     {
  840 akorotkov                 912 ECB             :         RangeBound  lower,
                                913                 :                     upper;
                                914                 : 
  840 akorotkov                 915 CBC      140101 :         idx = (l + u) / 2;
                                916          140101 :         multirange_get_bounds(typcache, mr, idx, &lower, &upper);
  840 akorotkov                 917 GIC      140101 :         comparison = (*cmp_func) (typcache, &lower, &upper, key, &match);
                                918                 : 
                                919          140101 :         if (comparison < 0)
                                920           46887 :             u = idx;
  840 akorotkov                 921 CBC       93214 :         else if (comparison > 0)
                                922           83190 :             l = idx + 1;
  840 akorotkov                 923 ECB             :         else
  840 akorotkov                 924 GIC       10024 :             return match;
  840 akorotkov                 925 ECB             :     }
                                926                 : 
  840 akorotkov                 927 CBC       68639 :     return false;
  840 akorotkov                 928 ECB             : }
                                929                 : 
                                930                 : /*
                                931                 :  *----------------------------------------------------------
                                932                 :  * GENERIC FUNCTIONS
                                933                 :  *----------------------------------------------------------
                                934                 :  */
                                935                 : 
                                936                 : /*
                                937                 :  * Construct multirange value from zero or more ranges.  Since this is a
                                938                 :  * variadic function we get passed an array.  The array must contain ranges
                                939                 :  * that match our return value, and there must be no NULLs.
                                940                 :  */
                                941                 : Datum
  840 akorotkov                 942 GIC        6903 : multirange_constructor2(PG_FUNCTION_ARGS)
                                943                 : {
                                944            6903 :     Oid         mltrngtypid = get_fn_expr_rettype(fcinfo->flinfo);
                                945                 :     Oid         rngtypid;
                                946                 :     TypeCacheEntry *typcache;
                                947                 :     TypeCacheEntry *rangetyp;
  840 akorotkov                 948 ECB             :     ArrayType  *rangeArray;
                                949                 :     int         range_count;
                                950                 :     Datum      *elements;
                                951                 :     bool       *nulls;
                                952                 :     RangeType **ranges;
                                953                 :     int         dims;
                                954                 :     int         i;
                                955                 : 
  840 akorotkov                 956 GIC        6903 :     typcache = multirange_get_typcache(fcinfo, mltrngtypid);
                                957            6903 :     rangetyp = typcache->rngtype;
                                958                 : 
                                959                 :     /*
                                960                 :      * A no-arg invocation should call multirange_constructor0 instead, but
                                961                 :      * returning an empty range is what that does.
  840 akorotkov                 962 ECB             :      */
                                963                 : 
  840 akorotkov                 964 GIC        6903 :     if (PG_NARGS() == 0)
  840 akorotkov                 965 UIC           0 :         PG_RETURN_MULTIRANGE_P(make_multirange(mltrngtypid, rangetyp, 0, NULL));
                                966                 : 
                                967                 :     /*
                                968                 :      * This check should be guaranteed by our signature, but let's do it just
                                969                 :      * in case.
  840 akorotkov                 970 ECB             :      */
  840 akorotkov                 971 EUB             : 
  840 akorotkov                 972 GIC        6903 :     if (PG_ARGISNULL(0))
  716 akorotkov                 973 UIC           0 :         elog(ERROR,
                                974                 :              "multirange values cannot contain null members");
                                975                 : 
  840 akorotkov                 976 GIC        6903 :     rangeArray = PG_GETARG_ARRAYTYPE_P(0);
                                977                 : 
  840 akorotkov                 978 CBC        6903 :     dims = ARR_NDIM(rangeArray);
  840 akorotkov                 979 GBC        6903 :     if (dims > 1)
  840 akorotkov                 980 UIC           0 :         ereport(ERROR,
                                981                 :                 (errcode(ERRCODE_CARDINALITY_VIOLATION),
  650 peter                     982 ECB             :                  errmsg("multiranges cannot be constructed from multidimensional arrays")));
                                983                 : 
  840 akorotkov                 984 CBC        6903 :     rngtypid = ARR_ELEMTYPE(rangeArray);
                                985            6903 :     if (rngtypid != rangetyp->type_id)
  570 peter                     986 UBC           0 :         elog(ERROR, "type %u does not match constructor type", rngtypid);
                                987                 : 
                                988                 :     /*
                                989                 :      * Be careful: we can still be called with zero ranges, like this:
  840 akorotkov                 990 ECB             :      * `int4multirange(variadic '{}'::int4range[])
                                991                 :      */
  840 akorotkov                 992 GBC        6903 :     if (dims == 0)
                                993                 :     {
  840 akorotkov                 994 GIC           3 :         range_count = 0;
                                995               3 :         ranges = NULL;
                                996                 :     }
                                997                 :     else
  840 akorotkov                 998 ECB             :     {
  840 akorotkov                 999 GIC        6900 :         deconstruct_array(rangeArray, rngtypid, rangetyp->typlen, rangetyp->typbyval,
  840 akorotkov                1000 CBC        6900 :                           rangetyp->typalign, &elements, &nulls, &range_count);
  840 akorotkov                1001 ECB             : 
  840 akorotkov                1002 GIC        6900 :         ranges = palloc0(range_count * sizeof(RangeType *));
                               1003           26706 :         for (i = 0; i < range_count; i++)
                               1004                 :         {
  840 akorotkov                1005 CBC       19806 :             if (nulls[i])
  840 akorotkov                1006 LBC           0 :                 ereport(ERROR,
                               1007                 :                         (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
  570 peter                    1008 ECB             :                          errmsg("multirange values cannot contain null members")));
  840 akorotkov                1009                 : 
                               1010                 :             /* make_multirange will do its own copy */
  840 akorotkov                1011 CBC       19806 :             ranges[i] = DatumGetRangeTypeP(elements[i]);
  840 akorotkov                1012 EUB             :         }
                               1013                 :     }
                               1014                 : 
  840 akorotkov                1015 GIC        6903 :     PG_RETURN_MULTIRANGE_P(make_multirange(mltrngtypid, rangetyp, range_count, ranges));
                               1016                 : }
  840 akorotkov                1017 ECB             : 
                               1018                 : /*
                               1019                 :  * Construct multirange value from a single range.  It'd be nice if we could
                               1020                 :  * just use multirange_constructor2 for this case, but we need a non-variadic
                               1021                 :  * single-arg function to let us define a CAST from a range to its multirange.
                               1022                 :  */
                               1023                 : Datum
  840 akorotkov                1024 GIC        3687 : multirange_constructor1(PG_FUNCTION_ARGS)
                               1025                 : {
                               1026            3687 :     Oid         mltrngtypid = get_fn_expr_rettype(fcinfo->flinfo);
                               1027                 :     Oid         rngtypid;
                               1028                 :     TypeCacheEntry *typcache;
                               1029                 :     TypeCacheEntry *rangetyp;
  840 akorotkov                1030 ECB             :     RangeType  *range;
                               1031                 : 
  840 akorotkov                1032 CBC        3687 :     typcache = multirange_get_typcache(fcinfo, mltrngtypid);
  840 akorotkov                1033 GIC        3687 :     rangetyp = typcache->rngtype;
                               1034                 : 
                               1035                 :     /*
                               1036                 :      * This check should be guaranteed by our signature, but let's do it just
                               1037                 :      * in case.
  840 akorotkov                1038 ECB             :      */
                               1039                 : 
  840 akorotkov                1040 GIC        3687 :     if (PG_ARGISNULL(0))
  716 akorotkov                1041 UIC           0 :         elog(ERROR,
                               1042                 :              "multirange values cannot contain null members");
                               1043                 : 
  840 akorotkov                1044 GIC        3687 :     range = PG_GETARG_RANGE_P(0);
                               1045                 : 
  840 akorotkov                1046 ECB             :     /* Make sure the range type matches. */
  840 akorotkov                1047 GBC        3687 :     rngtypid = RangeTypeGetOid(range);
  840 akorotkov                1048 GIC        3687 :     if (rngtypid != rangetyp->type_id)
  570 peter                    1049 UIC           0 :         elog(ERROR, "type %u does not match constructor type", rngtypid);
  840 akorotkov                1050 ECB             : 
  840 akorotkov                1051 GIC        3687 :     PG_RETURN_MULTIRANGE_P(make_multirange(mltrngtypid, rangetyp, 1, &range));
                               1052                 : }
  840 akorotkov                1053 ECB             : 
                               1054                 : /*
  840 akorotkov                1055 EUB             :  * Constructor just like multirange_constructor1, but opr_sanity gets angry
                               1056                 :  * if the same internal function handles multiple functions with different arg
  840 akorotkov                1057 ECB             :  * counts.
                               1058                 :  */
                               1059                 : Datum
  840 akorotkov                1060 GIC         186 : multirange_constructor0(PG_FUNCTION_ARGS)
                               1061                 : {
                               1062                 :     Oid         mltrngtypid;
                               1063                 :     TypeCacheEntry *typcache;
                               1064                 :     TypeCacheEntry *rangetyp;
                               1065                 : 
  839 akorotkov                1066 ECB             :     /* This should always be called without arguments */
  839 akorotkov                1067 GIC         186 :     if (PG_NARGS() != 0)
  839 akorotkov                1068 UIC           0 :         elog(ERROR,
                               1069                 :              "niladic multirange constructor must not receive arguments");
                               1070                 : 
  839 akorotkov                1071 GIC         186 :     mltrngtypid = get_fn_expr_rettype(fcinfo->flinfo);
  840                          1072             186 :     typcache = multirange_get_typcache(fcinfo, mltrngtypid);
  840 akorotkov                1073 CBC         186 :     rangetyp = typcache->rngtype;
  840 akorotkov                1074 EUB             : 
  839 akorotkov                1075 GIC         186 :     PG_RETURN_MULTIRANGE_P(make_multirange(mltrngtypid, rangetyp, 0, NULL));
                               1076                 : }
  840 akorotkov                1077 ECB             : 
                               1078                 : 
                               1079                 : /* multirange, multirange -> multirange type functions */
                               1080                 : 
                               1081                 : /* multirange union */
                               1082                 : Datum
  840 akorotkov                1083 GIC          27 : multirange_union(PG_FUNCTION_ARGS)
                               1084                 : {
                               1085              27 :     MultirangeType *mr1 = PG_GETARG_MULTIRANGE_P(0);
                               1086              27 :     MultirangeType *mr2 = PG_GETARG_MULTIRANGE_P(1);
                               1087                 :     TypeCacheEntry *typcache;
                               1088                 :     int32       range_count1;
  840 akorotkov                1089 ECB             :     int32       range_count2;
                               1090                 :     int32       range_count3;
                               1091                 :     RangeType **ranges1;
                               1092                 :     RangeType **ranges2;
                               1093                 :     RangeType **ranges3;
                               1094                 : 
  840 akorotkov                1095 GIC          27 :     if (MultirangeIsEmpty(mr1))
                               1096               6 :         PG_RETURN_MULTIRANGE_P(mr2);
                               1097              21 :     if (MultirangeIsEmpty(mr2))
                               1098               3 :         PG_RETURN_MULTIRANGE_P(mr1);
                               1099                 : 
                               1100              18 :     typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1));
  840 akorotkov                1101 ECB             : 
  840 akorotkov                1102 CBC          18 :     multirange_deserialize(typcache->rngtype, mr1, &range_count1, &ranges1);
                               1103              18 :     multirange_deserialize(typcache->rngtype, mr2, &range_count2, &ranges2);
  840 akorotkov                1104 ECB             : 
  840 akorotkov                1105 GIC          18 :     range_count3 = range_count1 + range_count2;
  840 akorotkov                1106 CBC          18 :     ranges3 = palloc0(range_count3 * sizeof(RangeType *));
  840 akorotkov                1107 GIC          18 :     memcpy(ranges3, ranges1, range_count1 * sizeof(RangeType *));
  840 akorotkov                1108 CBC          18 :     memcpy(ranges3 + range_count1, ranges2, range_count2 * sizeof(RangeType *));
                               1109              18 :     PG_RETURN_MULTIRANGE_P(make_multirange(typcache->type_id, typcache->rngtype,
                               1110                 :                                            range_count3, ranges3));
  840 akorotkov                1111 ECB             : }
                               1112                 : 
                               1113                 : /* multirange minus */
                               1114                 : Datum
  840 akorotkov                1115 CBC          60 : multirange_minus(PG_FUNCTION_ARGS)
                               1116                 : {
  840 akorotkov                1117 GIC          60 :     MultirangeType *mr1 = PG_GETARG_MULTIRANGE_P(0);
                               1118              60 :     MultirangeType *mr2 = PG_GETARG_MULTIRANGE_P(1);
                               1119              60 :     Oid         mltrngtypoid = MultirangeTypeGetOid(mr1);
                               1120                 :     TypeCacheEntry *typcache;
  840 akorotkov                1121 ECB             :     TypeCacheEntry *rangetyp;
                               1122                 :     int32       range_count1;
                               1123                 :     int32       range_count2;
                               1124                 :     RangeType **ranges1;
                               1125                 :     RangeType **ranges2;
                               1126                 : 
  840 akorotkov                1127 GIC          60 :     typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
                               1128              60 :     rangetyp = typcache->rngtype;
                               1129                 : 
                               1130              60 :     if (MultirangeIsEmpty(mr1) || MultirangeIsEmpty(mr2))
                               1131              12 :         PG_RETURN_MULTIRANGE_P(mr1);
                               1132                 : 
  840 akorotkov                1133 CBC          48 :     multirange_deserialize(typcache->rngtype, mr1, &range_count1, &ranges1);
                               1134              48 :     multirange_deserialize(typcache->rngtype, mr2, &range_count2, &ranges2);
                               1135                 : 
                               1136              48 :     PG_RETURN_MULTIRANGE_P(multirange_minus_internal(mltrngtypoid,
  840 akorotkov                1137 ECB             :                                                      rangetyp,
                               1138                 :                                                      range_count1,
                               1139                 :                                                      ranges1,
                               1140                 :                                                      range_count2,
                               1141                 :                                                      ranges2));
                               1142                 : }
                               1143                 : 
                               1144                 : MultirangeType *
  840 akorotkov                1145 GIC          48 : multirange_minus_internal(Oid mltrngtypoid, TypeCacheEntry *rangetyp,
                               1146                 :                           int32 range_count1, RangeType **ranges1,
                               1147                 :                           int32 range_count2, RangeType **ranges2)
                               1148                 : {
                               1149                 :     RangeType  *r1;
                               1150                 :     RangeType  *r2;
  840 akorotkov                1151 ECB             :     RangeType **ranges3;
                               1152                 :     int32       range_count3;
                               1153                 :     int32       i1;
                               1154                 :     int32       i2;
                               1155                 : 
                               1156                 :     /*
                               1157                 :      * Worst case: every range in ranges1 makes a different cut to some range
                               1158                 :      * in ranges2.
                               1159                 :      */
  840 akorotkov                1160 GIC          48 :     ranges3 = palloc0((range_count1 + range_count2) * sizeof(RangeType *));
                               1161              48 :     range_count3 = 0;
                               1162                 : 
                               1163                 :     /*
                               1164                 :      * For each range in mr1, keep subtracting until it's gone or the ranges
                               1165                 :      * in mr2 have passed it. After a subtraction we assign what's left back
  840 akorotkov                1166 ECB             :      * to r1. The parallel progress through mr1 and mr2 is similar to
                               1167                 :      * multirange_overlaps_multirange_internal.
                               1168                 :      */
  840 akorotkov                1169 GIC          48 :     r2 = ranges2[0];
                               1170             117 :     for (i1 = 0, i2 = 0; i1 < range_count1; i1++)
                               1171                 :     {
                               1172              69 :         r1 = ranges1[i1];
                               1173                 : 
                               1174                 :         /* Discard r2s while r2 << r1 */
  840 akorotkov                1175 CBC          78 :         while (r2 != NULL && range_before_internal(rangetyp, r2, r1))
  840 akorotkov                1176 ECB             :         {
  840 akorotkov                1177 GIC           9 :             r2 = ++i2 >= range_count2 ? NULL : ranges2[i2];
  840 akorotkov                1178 ECB             :         }
                               1179                 : 
  840 akorotkov                1180 GIC          87 :         while (r2 != NULL)
  840 akorotkov                1181 ECB             :         {
  840 akorotkov                1182 GIC          66 :             if (range_split_internal(rangetyp, r1, r2, &ranges3[range_count3], &r1))
  840 akorotkov                1183 ECB             :             {
                               1184                 :                 /*
                               1185                 :                  * If r2 takes a bite out of the middle of r1, we need two
                               1186                 :                  * outputs
                               1187                 :                  */
  840 akorotkov                1188 CBC           9 :                 range_count3++;
  840 akorotkov                1189 GIC           9 :                 r2 = ++i2 >= range_count2 ? NULL : ranges2[i2];
                               1190                 :             }
                               1191              57 :             else if (range_overlaps_internal(rangetyp, r1, r2))
                               1192                 :             {
                               1193                 :                 /*
  840 akorotkov                1194 ECB             :                  * If r2 overlaps r1, replace r1 with r1 - r2.
                               1195                 :                  */
  840 akorotkov                1196 GIC          33 :                 r1 = range_minus_internal(rangetyp, r1, r2);
  840 akorotkov                1197 ECB             : 
                               1198                 :                 /*
                               1199                 :                  * If r2 goes past r1, then we need to stay with it, in case
                               1200                 :                  * it hits future r1s. Otherwise we need to keep r1, in case
                               1201                 :                  * future r2s hit it. Since we already subtracted, there's no
                               1202                 :                  * point in using the overright/overleft calls.
                               1203                 :                  */
  840 akorotkov                1204 GIC          33 :                 if (RangeIsEmpty(r1) || range_before_internal(rangetyp, r1, r2))
                               1205                 :                     break;
                               1206                 :                 else
                               1207               9 :                     r2 = ++i2 >= range_count2 ? NULL : ranges2[i2];
                               1208                 :             }
                               1209                 :             else
  840 akorotkov                1210 ECB             :             {
                               1211                 :                 /*
                               1212                 :                  * This and all future r2s are past r1, so keep them. Also
                               1213                 :                  * assign whatever is left of r1 to the result.
                               1214                 :                  */
  840 akorotkov                1215 GIC          24 :                 break;
                               1216                 :             }
                               1217                 :         }
                               1218                 : 
                               1219                 :         /*
                               1220                 :          * Nothing else can remove anything from r1, so keep it. Even if r1 is
  840 akorotkov                1221 ECB             :          * empty here, make_multirange will remove it.
                               1222                 :          */
  840 akorotkov                1223 GIC          69 :         ranges3[range_count3++] = r1;
                               1224                 :     }
                               1225                 : 
                               1226              48 :     return make_multirange(mltrngtypoid, rangetyp, range_count3, ranges3);
                               1227                 : }
                               1228                 : 
  840 akorotkov                1229 ECB             : /* multirange intersection */
                               1230                 : Datum
  840 akorotkov                1231 GIC          42 : multirange_intersect(PG_FUNCTION_ARGS)
  840 akorotkov                1232 ECB             : {
  840 akorotkov                1233 GIC          42 :     MultirangeType *mr1 = PG_GETARG_MULTIRANGE_P(0);
                               1234              42 :     MultirangeType *mr2 = PG_GETARG_MULTIRANGE_P(1);
                               1235              42 :     Oid         mltrngtypoid = MultirangeTypeGetOid(mr1);
                               1236                 :     TypeCacheEntry *typcache;
  840 akorotkov                1237 ECB             :     TypeCacheEntry *rangetyp;
                               1238                 :     int32       range_count1;
                               1239                 :     int32       range_count2;
                               1240                 :     RangeType **ranges1;
                               1241                 :     RangeType **ranges2;
                               1242                 : 
  840 akorotkov                1243 GIC          42 :     typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
                               1244              42 :     rangetyp = typcache->rngtype;
                               1245                 : 
                               1246              42 :     if (MultirangeIsEmpty(mr1) || MultirangeIsEmpty(mr2))
                               1247               9 :         PG_RETURN_MULTIRANGE_P(make_empty_multirange(mltrngtypoid, rangetyp));
                               1248                 : 
  840 akorotkov                1249 CBC          33 :     multirange_deserialize(rangetyp, mr1, &range_count1, &ranges1);
                               1250              33 :     multirange_deserialize(rangetyp, mr2, &range_count2, &ranges2);
                               1251                 : 
                               1252              33 :     PG_RETURN_MULTIRANGE_P(multirange_intersect_internal(mltrngtypoid,
  840 akorotkov                1253 ECB             :                                                          rangetyp,
                               1254                 :                                                          range_count1,
                               1255                 :                                                          ranges1,
                               1256                 :                                                          range_count2,
                               1257                 :                                                          ranges2));
                               1258                 : }
                               1259                 : 
                               1260                 : MultirangeType *
  840 akorotkov                1261 GIC          81 : multirange_intersect_internal(Oid mltrngtypoid, TypeCacheEntry *rangetyp,
                               1262                 :                               int32 range_count1, RangeType **ranges1,
                               1263                 :                               int32 range_count2, RangeType **ranges2)
                               1264                 : {
                               1265                 :     RangeType  *r1;
                               1266                 :     RangeType  *r2;
  840 akorotkov                1267 ECB             :     RangeType **ranges3;
                               1268                 :     int32       range_count3;
                               1269                 :     int32       i1;
                               1270                 :     int32       i2;
                               1271                 : 
  840 akorotkov                1272 GIC          81 :     if (range_count1 == 0 || range_count2 == 0)
                               1273              30 :         return make_multirange(mltrngtypoid, rangetyp, 0, NULL);
                               1274                 : 
                               1275                 :     /*-----------------------------------------------
                               1276                 :      * Worst case is a stitching pattern like this:
                               1277                 :      *
  840 akorotkov                1278 ECB             :      * mr1: --- --- --- ---
                               1279                 :      * mr2:   --- --- ---
                               1280                 :      * mr3:   - - - - - -
                               1281                 :      *
                               1282                 :      * That seems to be range_count1 + range_count2 - 1,
                               1283                 :      * but one extra won't hurt.
                               1284                 :      *-----------------------------------------------
                               1285                 :      */
  840 akorotkov                1286 GIC          51 :     ranges3 = palloc0((range_count1 + range_count2) * sizeof(RangeType *));
                               1287              51 :     range_count3 = 0;
                               1288                 : 
                               1289                 :     /*
                               1290                 :      * For each range in mr1, keep intersecting until the ranges in mr2 have
                               1291                 :      * passed it. The parallel progress through mr1 and mr2 is similar to
  840 akorotkov                1292 ECB             :      * multirange_minus_multirange_internal, but we don't have to assign back
                               1293                 :      * to r1.
                               1294                 :      */
  840 akorotkov                1295 GIC          51 :     r2 = ranges2[0];
                               1296             114 :     for (i1 = 0, i2 = 0; i1 < range_count1; i1++)
                               1297                 :     {
                               1298              69 :         r1 = ranges1[i1];
                               1299                 : 
                               1300                 :         /* Discard r2s while r2 << r1 */
  840 akorotkov                1301 CBC          75 :         while (r2 != NULL && range_before_internal(rangetyp, r2, r1))
  840 akorotkov                1302 ECB             :         {
  840 akorotkov                1303 GIC           6 :             r2 = ++i2 >= range_count2 ? NULL : ranges2[i2];
  840 akorotkov                1304 ECB             :         }
                               1305                 : 
  840 akorotkov                1306 GIC          93 :         while (r2 != NULL)
  840 akorotkov                1307 ECB             :         {
  840 akorotkov                1308 GIC          87 :             if (range_overlaps_internal(rangetyp, r1, r2))
  840 akorotkov                1309 ECB             :             {
                               1310                 :                 /* Keep the overlapping part */
  840 akorotkov                1311 GIC          78 :                 ranges3[range_count3++] = range_intersect_internal(rangetyp, r1, r2);
  840 akorotkov                1312 ECB             : 
                               1313                 :                 /* If we "used up" all of r2, go to the next one... */
  840 akorotkov                1314 CBC          78 :                 if (range_overleft_internal(rangetyp, r2, r1))
  840 akorotkov                1315 GIC          24 :                     r2 = ++i2 >= range_count2 ? NULL : ranges2[i2];
                               1316                 : 
  840 akorotkov                1317 ECB             :                 /* ...otherwise go to the next r1 */
                               1318                 :                 else
  840 akorotkov                1319 GIC          54 :                     break;
  840 akorotkov                1320 ECB             :             }
                               1321                 :             else
                               1322                 :                 /* We're past r1, so move to the next one */
  840 akorotkov                1323 GIC           9 :                 break;
                               1324                 :         }
  840 akorotkov                1325 ECB             : 
                               1326                 :         /* If we're out of r2s, there can be no more intersections */
  840 akorotkov                1327 GIC          69 :         if (r2 == NULL)
                               1328               6 :             break;
  840 akorotkov                1329 ECB             :     }
                               1330                 : 
  840 akorotkov                1331 GIC          51 :     return make_multirange(mltrngtypoid, rangetyp, range_count3, ranges3);
                               1332                 : }
  840 akorotkov                1333 ECB             : 
                               1334                 : /*
                               1335                 :  * range_agg_transfn: combine adjacent/overlapping ranges.
                               1336                 :  *
                               1337                 :  * All we do here is gather the input ranges into an array
                               1338                 :  * so that the finalfn can sort and combine them.
                               1339                 :  */
                               1340                 : Datum
  840 akorotkov                1341 GIC          57 : range_agg_transfn(PG_FUNCTION_ARGS)
                               1342                 : {
                               1343                 :     MemoryContext aggContext;
                               1344                 :     Oid         rngtypoid;
                               1345                 :     ArrayBuildState *state;
                               1346                 : 
  840 akorotkov                1347 CBC          57 :     if (!AggCheckCallContext(fcinfo, &aggContext))
  840 akorotkov                1348 UIC           0 :         elog(ERROR, "range_agg_transfn called in non-aggregate context");
                               1349                 : 
  840 akorotkov                1350 GIC          57 :     rngtypoid = get_fn_expr_argtype(fcinfo->flinfo, 1);
                               1351              57 :     if (!type_is_range(rngtypoid))
  375 peter                    1352 UIC           0 :         elog(ERROR, "range_agg must be called with a range");
  840 akorotkov                1353 ECB             : 
  840 akorotkov                1354 GBC          57 :     if (PG_ARGISNULL(0))
  840 akorotkov                1355 GIC          27 :         state = initArrayResult(rngtypoid, aggContext, false);
  840 akorotkov                1356 ECB             :     else
  840 akorotkov                1357 CBC          30 :         state = (ArrayBuildState *) PG_GETARG_POINTER(0);
  840 akorotkov                1358 EUB             : 
                               1359                 :     /* skip NULLs */
  840 akorotkov                1360 CBC          57 :     if (!PG_ARGISNULL(1))
                               1361              45 :         accumArrayResult(state, PG_GETARG_DATUM(1), false, rngtypoid, aggContext);
                               1362                 : 
                               1363              57 :     PG_RETURN_POINTER(state);
                               1364                 : }
                               1365                 : 
  840 akorotkov                1366 ECB             : /*
                               1367                 :  * range_agg_finalfn: use our internal array to merge touching ranges.
                               1368                 :  *
  375 peter                    1369                 :  * Shared by range_agg_finalfn(anyrange) and
                               1370                 :  * multirange_agg_finalfn(anymultirange).
                               1371                 :  */
                               1372                 : Datum
  840 akorotkov                1373 GIC          57 : range_agg_finalfn(PG_FUNCTION_ARGS)
                               1374                 : {
                               1375                 :     MemoryContext aggContext;
                               1376                 :     Oid         mltrngtypoid;
                               1377                 :     TypeCacheEntry *typcache;
                               1378                 :     ArrayBuildState *state;
  840 akorotkov                1379 ECB             :     int32       range_count;
                               1380                 :     RangeType **ranges;
                               1381                 :     int         i;
                               1382                 : 
  840 akorotkov                1383 GIC          57 :     if (!AggCheckCallContext(fcinfo, &aggContext))
  840 akorotkov                1384 UIC           0 :         elog(ERROR, "range_agg_finalfn called in non-aggregate context");
                               1385                 : 
  840 akorotkov                1386 GIC          57 :     state = PG_ARGISNULL(0) ? NULL : (ArrayBuildState *) PG_GETARG_POINTER(0);
                               1387              57 :     if (state == NULL)
                               1388                 :         /* This shouldn't be possible, but just in case.... */
  840 akorotkov                1389 CBC           3 :         PG_RETURN_NULL();
  840 akorotkov                1390 EUB             : 
                               1391                 :     /* Also return NULL if we had zero inputs, like other aggregates */
  840 akorotkov                1392 CBC          54 :     range_count = state->nelems;
                               1393              54 :     if (range_count == 0)
  840 akorotkov                1394 GIC           9 :         PG_RETURN_NULL();
  840 akorotkov                1395 ECB             : 
  840 akorotkov                1396 GIC          45 :     mltrngtypoid = get_fn_expr_rettype(fcinfo->flinfo);
                               1397              45 :     typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
  840 akorotkov                1398 ECB             : 
  840 akorotkov                1399 CBC          45 :     ranges = palloc0(range_count * sizeof(RangeType *));
                               1400             159 :     for (i = 0; i < range_count; i++)
  840 akorotkov                1401 GIC         114 :         ranges[i] = DatumGetRangeTypeP(state->dvalues[i]);
  840 akorotkov                1402 ECB             : 
  840 akorotkov                1403 CBC          45 :     PG_RETURN_MULTIRANGE_P(make_multirange(mltrngtypoid, typcache->rngtype, range_count, ranges));
                               1404                 : }
  840 akorotkov                1405 ECB             : 
  375 peter                    1406                 : /*
                               1407                 :  * multirange_agg_transfn: combine adjacent/overlapping multiranges.
                               1408                 :  *
                               1409                 :  * All we do here is gather the input multiranges' ranges into an array so
                               1410                 :  * that the finalfn can sort and combine them.
                               1411                 :  */
                               1412                 : Datum
  375 peter                    1413 GIC          96 : multirange_agg_transfn(PG_FUNCTION_ARGS)
                               1414                 : {
                               1415                 :     MemoryContext aggContext;
                               1416                 :     Oid         mltrngtypoid;
                               1417                 :     TypeCacheEntry *typcache;
                               1418                 :     TypeCacheEntry *rngtypcache;
  375 peter                    1419 ECB             :     ArrayBuildState *state;
                               1420                 : 
  375 peter                    1421 GIC          96 :     if (!AggCheckCallContext(fcinfo, &aggContext))
  375 peter                    1422 UIC           0 :         elog(ERROR, "multirange_agg_transfn called in non-aggregate context");
                               1423                 : 
  375 peter                    1424 GIC          96 :     mltrngtypoid = get_fn_expr_argtype(fcinfo->flinfo, 1);
                               1425              96 :     if (!type_is_multirange(mltrngtypoid))
  375 peter                    1426 UIC           0 :         elog(ERROR, "range_agg must be called with a multirange");
  375 peter                    1427 ECB             : 
  375 peter                    1428 GBC          96 :     typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
  375 peter                    1429 GIC          96 :     rngtypcache = typcache->rngtype;
  375 peter                    1430 ECB             : 
  375 peter                    1431 CBC          96 :     if (PG_ARGISNULL(0))
  375 peter                    1432 GBC          27 :         state = initArrayResult(rngtypcache->type_id, aggContext, false);
                               1433                 :     else
  375 peter                    1434 CBC          69 :         state = (ArrayBuildState *) PG_GETARG_POINTER(0);
  375 peter                    1435 ECB             : 
                               1436                 :     /* skip NULLs */
  375 peter                    1437 CBC          96 :     if (!PG_ARGISNULL(1))
  375 peter                    1438 ECB             :     {
                               1439                 :         MultirangeType *current;
                               1440                 :         int32       range_count;
                               1441                 :         RangeType **ranges;
                               1442                 : 
  375 peter                    1443 CBC          63 :         current = PG_GETARG_MULTIRANGE_P(1);
  375 peter                    1444 GIC          63 :         multirange_deserialize(rngtypcache, current, &range_count, &ranges);
                               1445              63 :         if (range_count == 0)
                               1446                 :         {
                               1447                 :             /*
                               1448                 :              * Add an empty range so we get an empty result (not a null
  332 tgl                      1449 ECB             :              * result).
  375 peter                    1450                 :              */
  375 peter                    1451 CBC          21 :             accumArrayResult(state,
  375 peter                    1452 GIC          21 :                              RangeTypePGetDatum(make_empty_range(rngtypcache)),
                               1453                 :                              false, rngtypcache->type_id, aggContext);
                               1454                 :         }
                               1455                 :         else
                               1456                 :         {
  375 peter                    1457 CBC          90 :             for (int32 i = 0; i < range_count; i++)
                               1458              48 :                 accumArrayResult(state, RangeTypePGetDatum(ranges[i]), false, rngtypcache->type_id, aggContext);
                               1459                 :         }
                               1460                 :     }
                               1461                 : 
  375 peter                    1462 GIC          96 :     PG_RETURN_POINTER(state);
  375 peter                    1463 ECB             : }
                               1464                 : 
                               1465                 : Datum
  840 akorotkov                1466 GIC          48 : multirange_intersect_agg_transfn(PG_FUNCTION_ARGS)
                               1467                 : {
  840 akorotkov                1468 ECB             :     MemoryContext aggContext;
                               1469                 :     Oid         mltrngtypoid;
                               1470                 :     TypeCacheEntry *typcache;
                               1471                 :     MultirangeType *result;
                               1472                 :     MultirangeType *current;
                               1473                 :     int32       range_count1;
                               1474                 :     int32       range_count2;
                               1475                 :     RangeType **ranges1;
                               1476                 :     RangeType **ranges2;
                               1477                 : 
  840 akorotkov                1478 GIC          48 :     if (!AggCheckCallContext(fcinfo, &aggContext))
  840 akorotkov                1479 UIC           0 :         elog(ERROR, "multirange_intersect_agg_transfn called in non-aggregate context");
                               1480                 : 
  840 akorotkov                1481 GIC          48 :     mltrngtypoid = get_fn_expr_argtype(fcinfo->flinfo, 1);
                               1482              48 :     if (!type_is_multirange(mltrngtypoid))
  375 peter                    1483 UIC           0 :         elog(ERROR, "range_intersect_agg must be called with a multirange");
  840 akorotkov                1484 ECB             : 
  840 akorotkov                1485 GBC          48 :     typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
                               1486                 : 
  840 akorotkov                1487 ECB             :     /* strictness ensures these are non-null */
  840 akorotkov                1488 CBC          48 :     result = PG_GETARG_MULTIRANGE_P(0);
  840 akorotkov                1489 GBC          48 :     current = PG_GETARG_MULTIRANGE_P(1);
                               1490                 : 
  840 akorotkov                1491 CBC          48 :     multirange_deserialize(typcache->rngtype, result, &range_count1, &ranges1);
  840 akorotkov                1492 GIC          48 :     multirange_deserialize(typcache->rngtype, current, &range_count2, &ranges2);
                               1493                 : 
  840 akorotkov                1494 CBC          48 :     result = multirange_intersect_internal(mltrngtypoid,
                               1495              48 :                                            typcache->rngtype,
                               1496                 :                                            range_count1,
  840 akorotkov                1497 ECB             :                                            ranges1,
                               1498                 :                                            range_count2,
                               1499                 :                                            ranges2);
  224 peter                    1500 GNC          48 :     PG_RETURN_MULTIRANGE_P(result);
  840 akorotkov                1501 ECB             : }
                               1502                 : 
                               1503                 : 
                               1504                 : /* multirange -> element type functions */
                               1505                 : 
                               1506                 : /* extract lower bound value */
                               1507                 : Datum
  840 akorotkov                1508 GIC          66 : multirange_lower(PG_FUNCTION_ARGS)
                               1509                 : {
                               1510              66 :     MultirangeType *mr = PG_GETARG_MULTIRANGE_P(0);
                               1511                 :     TypeCacheEntry *typcache;
                               1512                 :     RangeBound  lower;
                               1513                 :     RangeBound  upper;
  840 akorotkov                1514 ECB             : 
  840 akorotkov                1515 GIC          66 :     if (MultirangeIsEmpty(mr))
  840 akorotkov                1516 CBC          12 :         PG_RETURN_NULL();
                               1517                 : 
  840 akorotkov                1518 GIC          54 :     typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
                               1519                 : 
                               1520              54 :     multirange_get_bounds(typcache->rngtype, mr, 0,
  840 akorotkov                1521 ECB             :                           &lower, &upper);
                               1522                 : 
  840 akorotkov                1523 GIC          54 :     if (!lower.infinite)
  840 akorotkov                1524 CBC          45 :         PG_RETURN_DATUM(lower.val);
                               1525                 :     else
                               1526               9 :         PG_RETURN_NULL();
                               1527                 : }
                               1528                 : 
  840 akorotkov                1529 ECB             : /* extract upper bound value */
                               1530                 : Datum
  840 akorotkov                1531 GIC          69 : multirange_upper(PG_FUNCTION_ARGS)
  840 akorotkov                1532 ECB             : {
  840 akorotkov                1533 GIC          69 :     MultirangeType *mr = PG_GETARG_MULTIRANGE_P(0);
                               1534                 :     TypeCacheEntry *typcache;
                               1535                 :     RangeBound  lower;
                               1536                 :     RangeBound  upper;
  840 akorotkov                1537 ECB             : 
  840 akorotkov                1538 GIC          69 :     if (MultirangeIsEmpty(mr))
  840 akorotkov                1539 CBC          12 :         PG_RETURN_NULL();
                               1540                 : 
  840 akorotkov                1541 GIC          57 :     typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
                               1542                 : 
                               1543              57 :     multirange_get_bounds(typcache->rngtype, mr, mr->rangeCount - 1,
  840 akorotkov                1544 ECB             :                           &lower, &upper);
                               1545                 : 
  840 akorotkov                1546 GIC          57 :     if (!upper.infinite)
  840 akorotkov                1547 CBC          48 :         PG_RETURN_DATUM(upper.val);
                               1548                 :     else
                               1549               9 :         PG_RETURN_NULL();
                               1550                 : }
                               1551                 : 
  840 akorotkov                1552 ECB             : 
                               1553                 : /* multirange -> bool functions */
                               1554                 : 
                               1555                 : /* is multirange empty? */
                               1556                 : Datum
  840 akorotkov                1557 GIC          33 : multirange_empty(PG_FUNCTION_ARGS)
                               1558                 : {
                               1559              33 :     MultirangeType *mr = PG_GETARG_MULTIRANGE_P(0);
                               1560                 : 
                               1561              33 :     PG_RETURN_BOOL(MultirangeIsEmpty(mr));
                               1562                 : }
  840 akorotkov                1563 ECB             : 
                               1564                 : /* is lower bound inclusive? */
                               1565                 : Datum
  840 akorotkov                1566 GIC          33 : multirange_lower_inc(PG_FUNCTION_ARGS)
  840 akorotkov                1567 ECB             : {
  840 akorotkov                1568 GIC          33 :     MultirangeType *mr = PG_GETARG_MULTIRANGE_P(0);
                               1569                 :     TypeCacheEntry *typcache;
                               1570                 :     RangeBound  lower;
                               1571                 :     RangeBound  upper;
  840 akorotkov                1572 ECB             : 
  840 akorotkov                1573 GIC          33 :     if (MultirangeIsEmpty(mr))
  840 akorotkov                1574 CBC          12 :         PG_RETURN_BOOL(false);
                               1575                 : 
  840 akorotkov                1576 GIC          21 :     typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
                               1577              21 :     multirange_get_bounds(typcache->rngtype, mr, 0,
                               1578                 :                           &lower, &upper);
  840 akorotkov                1579 ECB             : 
  840 akorotkov                1580 CBC          21 :     PG_RETURN_BOOL(lower.inclusive);
                               1581                 : }
  840 akorotkov                1582 ECB             : 
                               1583                 : /* is upper bound inclusive? */
                               1584                 : Datum
  840 akorotkov                1585 GIC          33 : multirange_upper_inc(PG_FUNCTION_ARGS)
  840 akorotkov                1586 ECB             : {
  840 akorotkov                1587 GIC          33 :     MultirangeType *mr = PG_GETARG_MULTIRANGE_P(0);
                               1588                 :     TypeCacheEntry *typcache;
                               1589                 :     RangeBound  lower;
                               1590                 :     RangeBound  upper;
  840 akorotkov                1591 ECB             : 
  840 akorotkov                1592 GIC          33 :     if (MultirangeIsEmpty(mr))
  840 akorotkov                1593 CBC          12 :         PG_RETURN_BOOL(false);
                               1594                 : 
  840 akorotkov                1595 GIC          21 :     typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
                               1596              21 :     multirange_get_bounds(typcache->rngtype, mr, mr->rangeCount - 1,
                               1597                 :                           &lower, &upper);
  840 akorotkov                1598 ECB             : 
  840 akorotkov                1599 CBC          21 :     PG_RETURN_BOOL(upper.inclusive);
                               1600                 : }
  840 akorotkov                1601 ECB             : 
                               1602                 : /* is lower bound infinite? */
                               1603                 : Datum
  840 akorotkov                1604 GIC          33 : multirange_lower_inf(PG_FUNCTION_ARGS)
  840 akorotkov                1605 ECB             : {
  840 akorotkov                1606 GIC          33 :     MultirangeType *mr = PG_GETARG_MULTIRANGE_P(0);
                               1607                 :     TypeCacheEntry *typcache;
                               1608                 :     RangeBound  lower;
                               1609                 :     RangeBound  upper;
  840 akorotkov                1610 ECB             : 
  840 akorotkov                1611 GIC          33 :     if (MultirangeIsEmpty(mr))
  840 akorotkov                1612 CBC          12 :         PG_RETURN_BOOL(false);
                               1613                 : 
  840 akorotkov                1614 GIC          21 :     typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
                               1615              21 :     multirange_get_bounds(typcache->rngtype, mr, 0,
                               1616                 :                           &lower, &upper);
  840 akorotkov                1617 ECB             : 
  840 akorotkov                1618 CBC          21 :     PG_RETURN_BOOL(lower.infinite);
                               1619                 : }
  840 akorotkov                1620 ECB             : 
                               1621                 : /* is upper bound infinite? */
                               1622                 : Datum
  840 akorotkov                1623 GIC          33 : multirange_upper_inf(PG_FUNCTION_ARGS)
  840 akorotkov                1624 ECB             : {
  840 akorotkov                1625 GIC          33 :     MultirangeType *mr = PG_GETARG_MULTIRANGE_P(0);
                               1626                 :     TypeCacheEntry *typcache;
                               1627                 :     RangeBound  lower;
                               1628                 :     RangeBound  upper;
  840 akorotkov                1629 ECB             : 
  840 akorotkov                1630 GIC          33 :     if (MultirangeIsEmpty(mr))
  840 akorotkov                1631 CBC          12 :         PG_RETURN_BOOL(false);
                               1632                 : 
  840 akorotkov                1633 GIC          21 :     typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
                               1634              21 :     multirange_get_bounds(typcache->rngtype, mr, mr->rangeCount - 1,
                               1635                 :                           &lower, &upper);
  840 akorotkov                1636 ECB             : 
  840 akorotkov                1637 CBC          21 :     PG_RETURN_BOOL(upper.infinite);
                               1638                 : }
  840 akorotkov                1639 ECB             : 
                               1640                 : 
                               1641                 : 
                               1642                 : /* multirange, element -> bool functions */
                               1643                 : 
                               1644                 : /* contains? */
                               1645                 : Datum
  840 akorotkov                1646 GIC       11571 : multirange_contains_elem(PG_FUNCTION_ARGS)
                               1647                 : {
                               1648           11571 :     MultirangeType *mr = PG_GETARG_MULTIRANGE_P(0);
                               1649           11571 :     Datum       val = PG_GETARG_DATUM(1);
                               1650                 :     TypeCacheEntry *typcache;
                               1651                 : 
  840 akorotkov                1652 CBC       11571 :     typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
                               1653                 : 
  831                          1654           11571 :     PG_RETURN_BOOL(multirange_contains_elem_internal(typcache->rngtype, mr, val));
  840 akorotkov                1655 ECB             : }
                               1656                 : 
                               1657                 : /* contained by? */
                               1658                 : Datum
  840 akorotkov                1659 GIC          72 : elem_contained_by_multirange(PG_FUNCTION_ARGS)
  840 akorotkov                1660 ECB             : {
  840 akorotkov                1661 GIC          72 :     Datum       val = PG_GETARG_DATUM(0);
                               1662              72 :     MultirangeType *mr = PG_GETARG_MULTIRANGE_P(1);
                               1663                 :     TypeCacheEntry *typcache;
                               1664                 : 
  840 akorotkov                1665 CBC          72 :     typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
                               1666                 : 
  831                          1667              72 :     PG_RETURN_BOOL(multirange_contains_elem_internal(typcache->rngtype, mr, val));
  840 akorotkov                1668 ECB             : }
                               1669                 : 
                               1670                 : /*
                               1671                 :  * Comparison function for checking if any range of multirange contains given
                               1672                 :  * key element using binary search.
                               1673                 :  */
                               1674                 : static int
  840 akorotkov                1675 GIC       16113 : multirange_elem_bsearch_comparison(TypeCacheEntry *typcache,
                               1676                 :                                    RangeBound *lower, RangeBound *upper,
                               1677                 :                                    void *key, bool *match)
                               1678                 : {
                               1679           16113 :     Datum       val = *((Datum *) key);
                               1680                 :     int         cmp;
  840 akorotkov                1681 ECB             : 
  840 akorotkov                1682 GIC       16113 :     if (!lower->infinite)
                               1683                 :     {
                               1684           15468 :         cmp = DatumGetInt32(FunctionCall2Coll(&typcache->rng_cmp_proc_finfo,
  840 akorotkov                1685 ECB             :                                               typcache->rng_collation,
                               1686                 :                                               lower->val, val));
  840 akorotkov                1687 GIC       15468 :         if (cmp > 0 || (cmp == 0 && !lower->inclusive))
  840 akorotkov                1688 CBC       15273 :             return -1;
                               1689                 :     }
  840 akorotkov                1690 ECB             : 
  840 akorotkov                1691 GIC         840 :     if (!upper->infinite)
                               1692                 :     {
  840 akorotkov                1693 CBC         795 :         cmp = DatumGetInt32(FunctionCall2Coll(&typcache->rng_cmp_proc_finfo,
  840 akorotkov                1694 ECB             :                                               typcache->rng_collation,
                               1695                 :                                               upper->val, val));
  840 akorotkov                1696 GIC         795 :         if (cmp < 0 || (cmp == 0 && !upper->inclusive))
  840 akorotkov                1697 CBC          48 :             return 1;
                               1698                 :     }
  840 akorotkov                1699 ECB             : 
  840 akorotkov                1700 GIC         792 :     *match = true;
                               1701             792 :     return 0;
  840 akorotkov                1702 ECB             : }
                               1703                 : 
                               1704                 : /*
                               1705                 :  * Test whether multirange mr contains a specific element value.
                               1706                 :  */
                               1707                 : bool
  831 akorotkov                1708 GIC       11643 : multirange_contains_elem_internal(TypeCacheEntry *rangetyp,
                               1709                 :                                   const MultirangeType *mr, Datum val)
                               1710                 : {
  840                          1711           11643 :     if (MultirangeIsEmpty(mr))
                               1712            1560 :         return false;
                               1713                 : 
  831 akorotkov                1714 CBC       10083 :     return multirange_bsearch_match(rangetyp, mr, &val,
                               1715                 :                                     multirange_elem_bsearch_comparison);
                               1716                 : }
  840 akorotkov                1717 ECB             : 
                               1718                 : /* multirange, range -> bool functions */
                               1719                 : 
                               1720                 : /* contains? */
                               1721                 : Datum
  840 akorotkov                1722 GIC       44877 : multirange_contains_range(PG_FUNCTION_ARGS)
                               1723                 : {
                               1724           44877 :     MultirangeType *mr = PG_GETARG_MULTIRANGE_P(0);
                               1725           44877 :     RangeType  *r = PG_GETARG_RANGE_P(1);
                               1726                 :     TypeCacheEntry *typcache;
                               1727                 : 
  840 akorotkov                1728 CBC       44877 :     typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
                               1729                 : 
  831                          1730           44877 :     PG_RETURN_BOOL(multirange_contains_range_internal(typcache->rngtype, mr, r));
  840 akorotkov                1731 ECB             : }
                               1732                 : 
                               1733                 : Datum
  831 akorotkov                1734 CBC       37245 : range_contains_multirange(PG_FUNCTION_ARGS)
                               1735                 : {
                               1736           37245 :     RangeType  *r = PG_GETARG_RANGE_P(0);
  831 akorotkov                1737 GIC       37245 :     MultirangeType *mr = PG_GETARG_MULTIRANGE_P(1);
                               1738                 :     TypeCacheEntry *typcache;
                               1739                 : 
  831 akorotkov                1740 CBC       37245 :     typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
                               1741                 : 
                               1742           37245 :     PG_RETURN_BOOL(range_contains_multirange_internal(typcache->rngtype, r, mr));
  831 akorotkov                1743 ECB             : }
                               1744                 : 
                               1745                 : /* contained by? */
  840                          1746                 : Datum
  840 akorotkov                1747 GIC       18714 : range_contained_by_multirange(PG_FUNCTION_ARGS)
  840 akorotkov                1748 ECB             : {
  840 akorotkov                1749 GIC       18714 :     RangeType  *r = PG_GETARG_RANGE_P(0);
                               1750           18714 :     MultirangeType *mr = PG_GETARG_MULTIRANGE_P(1);
                               1751                 :     TypeCacheEntry *typcache;
                               1752                 : 
  840 akorotkov                1753 CBC       18714 :     typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
                               1754                 : 
  831                          1755           18714 :     PG_RETURN_BOOL(multirange_contains_range_internal(typcache->rngtype, mr, r));
  840 akorotkov                1756 ECB             : }
                               1757                 : 
                               1758                 : Datum
  831 akorotkov                1759 CBC       25245 : multirange_contained_by_range(PG_FUNCTION_ARGS)
                               1760                 : {
                               1761           25245 :     MultirangeType *mr = PG_GETARG_MULTIRANGE_P(0);
  831 akorotkov                1762 GIC       25245 :     RangeType  *r = PG_GETARG_RANGE_P(1);
                               1763                 :     TypeCacheEntry *typcache;
                               1764                 : 
  831 akorotkov                1765 CBC       25245 :     typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
                               1766                 : 
                               1767           25245 :     PG_RETURN_BOOL(range_contains_multirange_internal(typcache->rngtype, r, mr));
  831 akorotkov                1768 ECB             : }
                               1769                 : 
                               1770                 : /*
  840                          1771                 :  * Comparison function for checking if any range of multirange contains given
                               1772                 :  * key range using binary search.
                               1773                 :  */
                               1774                 : static int
  840 akorotkov                1775 GIC       61429 : multirange_range_contains_bsearch_comparison(TypeCacheEntry *typcache,
                               1776                 :                                              RangeBound *lower, RangeBound *upper,
                               1777                 :                                              void *key, bool *match)
                               1778                 : {
                               1779           61429 :     RangeBound *keyLower = (RangeBound *) key;
                               1780           61429 :     RangeBound *keyUpper = (RangeBound *) key + 1;
  840 akorotkov                1781 ECB             : 
                               1782                 :     /* Check if key range is strictly in the left or in the right */
  840 akorotkov                1783 GIC       61429 :     if (range_cmp_bounds(typcache, keyUpper, lower) < 0)
                               1784           15888 :         return -1;
  840 akorotkov                1785 CBC       45541 :     if (range_cmp_bounds(typcache, keyLower, upper) > 0)
  831                          1786           40501 :         return 1;
                               1787                 : 
                               1788                 :     /*
  840 akorotkov                1789 ECB             :      * At this point we found overlapping range.  But we have to check if it
                               1790                 :      * really contains the key range.  Anyway, we have to stop our search
                               1791                 :      * here, because multirange contains only non-overlapping ranges.
                               1792                 :      */
  840 akorotkov                1793 GIC        5040 :     *match = range_bounds_contains(typcache, lower, upper, keyLower, keyUpper);
                               1794                 : 
                               1795            5040 :     return 0;
                               1796                 : }
                               1797                 : 
                               1798                 : /*
  840 akorotkov                1799 ECB             :  * Test whether multirange mr contains a specific range r.
                               1800                 :  */
                               1801                 : bool
  831 akorotkov                1802 GIC       80918 : multirange_contains_range_internal(TypeCacheEntry *rangetyp,
                               1803                 :                                    const MultirangeType *mr,
                               1804                 :                                    const RangeType *r)
                               1805                 : {
                               1806                 :     RangeBound  bounds[2];
                               1807                 :     bool        empty;
  840 akorotkov                1808 ECB             : 
                               1809                 :     /*
                               1810                 :      * Every multirange contains an infinite number of empty ranges, even an
                               1811                 :      * empty one.
                               1812                 :      */
  840 akorotkov                1813 GIC       80918 :     if (RangeIsEmpty(r))
                               1814           45306 :         return true;
                               1815                 : 
                               1816           35612 :     if (MultirangeIsEmpty(mr))
                               1817            1548 :         return false;
                               1818                 : 
  840 akorotkov                1819 CBC       34064 :     range_deserialize(rangetyp, r, &bounds[0], &bounds[1], &empty);
                               1820           34064 :     Assert(!empty);
                               1821                 : 
                               1822           34064 :     return multirange_bsearch_match(rangetyp, mr, bounds,
  840 akorotkov                1823 ECB             :                                     multirange_range_contains_bsearch_comparison);
                               1824                 : }
                               1825                 : 
  831                          1826                 : /*
                               1827                 :  * Test whether range r contains a multirange mr.
                               1828                 :  */
                               1829                 : bool
  831 akorotkov                1830 GIC      139265 : range_contains_multirange_internal(TypeCacheEntry *rangetyp,
                               1831                 :                                    const RangeType *r,
                               1832                 :                                    const MultirangeType *mr)
                               1833                 : {
                               1834                 :     RangeBound  lower1,
                               1835                 :                 upper1,
  831 akorotkov                1836 ECB             :                 lower2,
                               1837                 :                 upper2,
                               1838                 :                 tmp;
                               1839                 :     bool        empty;
                               1840                 : 
                               1841                 :     /*
                               1842                 :      * Every range contains an infinite number of empty multiranges, even an
                               1843                 :      * empty one.
                               1844                 :      */
  831 akorotkov                1845 GIC      139265 :     if (MultirangeIsEmpty(mr))
                               1846           95540 :         return true;
                               1847                 : 
                               1848           43725 :     if (RangeIsEmpty(r))
                               1849           12636 :         return false;
                               1850                 : 
  831 akorotkov                1851 ECB             :     /* Range contains multirange iff it contains its union range. */
  831 akorotkov                1852 CBC       31089 :     range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
  831 akorotkov                1853 GIC       31089 :     Assert(!empty);
  831 akorotkov                1854 CBC       31089 :     multirange_get_bounds(rangetyp, mr, 0, &lower2, &tmp);
                               1855           31089 :     multirange_get_bounds(rangetyp, mr, mr->rangeCount - 1, &tmp, &upper2);
                               1856                 : 
  831 akorotkov                1857 GIC       31089 :     return range_bounds_contains(rangetyp, &lower1, &upper1, &lower2, &upper2);
  831 akorotkov                1858 ECB             : }
                               1859                 : 
  840                          1860                 : 
                               1861                 : /* multirange, multirange -> bool functions */
                               1862                 : 
                               1863                 : /* equality (internal version) */
                               1864                 : bool
  831 akorotkov                1865 GIC       23877 : multirange_eq_internal(TypeCacheEntry *rangetyp,
                               1866                 :                        const MultirangeType *mr1,
                               1867                 :                        const MultirangeType *mr2)
                               1868                 : {
                               1869                 :     int32       range_count_1;
                               1870                 :     int32       range_count_2;
  840 akorotkov                1871 ECB             :     int32       i;
                               1872                 :     RangeBound  lower1,
                               1873                 :                 upper1,
                               1874                 :                 lower2,
                               1875                 :                 upper2;
                               1876                 : 
                               1877                 :     /* Different types should be prevented by ANYMULTIRANGE matching rules */
  840 akorotkov                1878 GIC       23877 :     if (MultirangeTypeGetOid(mr1) != MultirangeTypeGetOid(mr2))
  840 akorotkov                1879 UIC           0 :         elog(ERROR, "multirange types do not match");
                               1880                 : 
  840 akorotkov                1881 GIC       23877 :     range_count_1 = mr1->rangeCount;
                               1882           23877 :     range_count_2 = mr2->rangeCount;
                               1883                 : 
  840 akorotkov                1884 CBC       23877 :     if (range_count_1 != range_count_2)
  840 akorotkov                1885 GBC       14745 :         return false;
                               1886                 : 
  840 akorotkov                1887 CBC        9198 :     for (i = 0; i < range_count_1; i++)
  840 akorotkov                1888 ECB             :     {
  840 akorotkov                1889 GIC        6084 :         multirange_get_bounds(rangetyp, mr1, i, &lower1, &upper1);
  840 akorotkov                1890 CBC        6084 :         multirange_get_bounds(rangetyp, mr2, i, &lower2, &upper2);
  840 akorotkov                1891 ECB             : 
  840 akorotkov                1892 GIC        6159 :         if (range_cmp_bounds(rangetyp, &lower1, &lower2) != 0 ||
  840 akorotkov                1893 CBC          75 :             range_cmp_bounds(rangetyp, &upper1, &upper2) != 0)
  840 akorotkov                1894 GIC        6018 :             return false;
  840 akorotkov                1895 ECB             :     }
                               1896                 : 
  840 akorotkov                1897 GIC        3114 :     return true;
  840 akorotkov                1898 ECB             : }
                               1899                 : 
                               1900                 : /* equality */
                               1901                 : Datum
  840 akorotkov                1902 GIC       23811 : multirange_eq(PG_FUNCTION_ARGS)
  840 akorotkov                1903 ECB             : {
  840 akorotkov                1904 GIC       23811 :     MultirangeType *mr1 = PG_GETARG_MULTIRANGE_P(0);
                               1905           23811 :     MultirangeType *mr2 = PG_GETARG_MULTIRANGE_P(1);
                               1906                 :     TypeCacheEntry *typcache;
                               1907                 : 
  840 akorotkov                1908 CBC       23811 :     typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1));
                               1909                 : 
  831                          1910           23811 :     PG_RETURN_BOOL(multirange_eq_internal(typcache->rngtype, mr1, mr2));
  840 akorotkov                1911 ECB             : }
                               1912                 : 
                               1913                 : /* inequality (internal version) */
                               1914                 : bool
  831 akorotkov                1915 GIC          66 : multirange_ne_internal(TypeCacheEntry *rangetyp,
  831 akorotkov                1916 ECB             :                        const MultirangeType *mr1,
                               1917                 :                        const MultirangeType *mr2)
                               1918                 : {
  831 akorotkov                1919 GIC          66 :     return (!multirange_eq_internal(rangetyp, mr1, mr2));
                               1920                 : }
  840 akorotkov                1921 ECB             : 
                               1922                 : /* inequality */
                               1923                 : Datum
  840 akorotkov                1924 GIC          66 : multirange_ne(PG_FUNCTION_ARGS)
  840 akorotkov                1925 ECB             : {
  840 akorotkov                1926 GIC          66 :     MultirangeType *mr1 = PG_GETARG_MULTIRANGE_P(0);
                               1927              66 :     MultirangeType *mr2 = PG_GETARG_MULTIRANGE_P(1);
                               1928                 :     TypeCacheEntry *typcache;
                               1929                 : 
  840 akorotkov                1930 CBC          66 :     typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1));
                               1931                 : 
  831                          1932              66 :     PG_RETURN_BOOL(multirange_ne_internal(typcache->rngtype, mr1, mr2));
  840 akorotkov                1933 ECB             : }
                               1934                 : 
                               1935                 : /* overlaps? */
                               1936                 : Datum
  840 akorotkov                1937 GIC       18672 : range_overlaps_multirange(PG_FUNCTION_ARGS)
  840 akorotkov                1938 ECB             : {
  840 akorotkov                1939 GIC       18672 :     RangeType  *r = PG_GETARG_RANGE_P(0);
                               1940           18672 :     MultirangeType *mr = PG_GETARG_MULTIRANGE_P(1);
                               1941                 :     TypeCacheEntry *typcache;
                               1942                 : 
  840 akorotkov                1943 CBC       18672 :     typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
                               1944                 : 
  831                          1945           18672 :     PG_RETURN_BOOL(range_overlaps_multirange_internal(typcache->rngtype, r, mr));
  840 akorotkov                1946 ECB             : }
                               1947                 : 
                               1948                 : Datum
  840 akorotkov                1949 CBC       22695 : multirange_overlaps_range(PG_FUNCTION_ARGS)
                               1950                 : {
                               1951           22695 :     MultirangeType *mr = PG_GETARG_MULTIRANGE_P(0);
  840 akorotkov                1952 GIC       22695 :     RangeType  *r = PG_GETARG_RANGE_P(1);
                               1953                 :     TypeCacheEntry *typcache;
                               1954                 : 
  840 akorotkov                1955 CBC       22695 :     typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
                               1956                 : 
  831                          1957           22695 :     PG_RETURN_BOOL(range_overlaps_multirange_internal(typcache->rngtype, r, mr));
  840 akorotkov                1958 ECB             : }
                               1959                 : 
                               1960                 : Datum
  840 akorotkov                1961 CBC       23022 : multirange_overlaps_multirange(PG_FUNCTION_ARGS)
                               1962                 : {
                               1963           23022 :     MultirangeType *mr1 = PG_GETARG_MULTIRANGE_P(0);
  840 akorotkov                1964 GIC       23022 :     MultirangeType *mr2 = PG_GETARG_MULTIRANGE_P(1);
                               1965                 :     TypeCacheEntry *typcache;
                               1966                 : 
  840 akorotkov                1967 CBC       23022 :     typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1));
                               1968                 : 
  831                          1969           23022 :     PG_RETURN_BOOL(multirange_overlaps_multirange_internal(typcache->rngtype, mr1, mr2));
  840 akorotkov                1970 ECB             : }
                               1971                 : 
                               1972                 : /*
                               1973                 :  * Comparison function for checking if any range of multirange overlaps given
                               1974                 :  * key range using binary search.
                               1975                 :  */
                               1976                 : static int
  840 akorotkov                1977 GIC       62559 : multirange_range_overlaps_bsearch_comparison(TypeCacheEntry *typcache,
                               1978                 :                                              RangeBound *lower, RangeBound *upper,
                               1979                 :                                              void *key, bool *match)
                               1980                 : {
                               1981           62559 :     RangeBound *keyLower = (RangeBound *) key;
                               1982           62559 :     RangeBound *keyUpper = (RangeBound *) key + 1;
  840 akorotkov                1983 ECB             : 
  840 akorotkov                1984 GIC       62559 :     if (range_cmp_bounds(typcache, keyUpper, lower) < 0)
                               1985           15726 :         return -1;
                               1986           46833 :     if (range_cmp_bounds(typcache, keyLower, upper) > 0)
  831 akorotkov                1987 CBC       42641 :         return 1;
  840 akorotkov                1988 ECB             : 
  840 akorotkov                1989 GIC        4192 :     *match = true;
  840 akorotkov                1990 CBC        4192 :     return 0;
  840 akorotkov                1991 ECB             : }
                               1992                 : 
                               1993                 : bool
  831 akorotkov                1994 GIC       50362 : range_overlaps_multirange_internal(TypeCacheEntry *rangetyp,
  831 akorotkov                1995 ECB             :                                    const RangeType *r,
                               1996                 :                                    const MultirangeType *mr)
                               1997                 : {
                               1998                 :     RangeBound  bounds[2];
                               1999                 :     bool        empty;
  840                          2000                 : 
                               2001                 :     /*
                               2002                 :      * Empties never overlap, even with empties. (This seems strange since
                               2003                 :      * they *do* contain each other, but we want to follow how ranges work.)
                               2004                 :      */
  840 akorotkov                2005 GIC       50362 :     if (RangeIsEmpty(r) || MultirangeIsEmpty(mr))
                               2006           15846 :         return false;
                               2007                 : 
                               2008           34516 :     range_deserialize(rangetyp, r, &bounds[0], &bounds[1], &empty);
                               2009           34516 :     Assert(!empty);
                               2010                 : 
  840 akorotkov                2011 CBC       34516 :     return multirange_bsearch_match(rangetyp, mr, bounds,
  840 akorotkov                2012 ECB             :                                     multirange_range_overlaps_bsearch_comparison);
                               2013                 : }
                               2014                 : 
                               2015                 : bool
  831 akorotkov                2016 GIC       23022 : multirange_overlaps_multirange_internal(TypeCacheEntry *rangetyp,
  831 akorotkov                2017 ECB             :                                         const MultirangeType *mr1,
                               2018                 :                                         const MultirangeType *mr2)
                               2019                 : {
                               2020                 :     int32       range_count1;
                               2021                 :     int32       range_count2;
  840                          2022                 :     int32       i1;
                               2023                 :     int32       i2;
                               2024                 :     RangeBound  lower1,
                               2025                 :                 upper1,
                               2026                 :                 lower2,
                               2027                 :                 upper2;
                               2028                 : 
                               2029                 :     /*
                               2030                 :      * Empties never overlap, even with empties. (This seems strange since
                               2031                 :      * they *do* contain each other, but we want to follow how ranges work.)
                               2032                 :      */
  840 akorotkov                2033 GIC       23022 :     if (MultirangeIsEmpty(mr1) || MultirangeIsEmpty(mr2))
                               2034           12657 :         return false;
                               2035                 : 
                               2036           10365 :     range_count1 = mr1->rangeCount;
                               2037           10365 :     range_count2 = mr2->rangeCount;
                               2038                 : 
  840 akorotkov                2039 ECB             :     /*
                               2040                 :      * Every range in mr1 gets a chance to overlap with the ranges in mr2, but
                               2041                 :      * we can use their ordering to avoid O(n^2). This is similar to
                               2042                 :      * range_overlaps_multirange where r1 : r2 :: mrr : r, but there if we
                               2043                 :      * don't find an overlap with r we're done, and here if we don't find an
                               2044                 :      * overlap with r2 we try the next r2.
                               2045                 :      */
  840 akorotkov                2046 GIC       10365 :     i1 = 0;
                               2047           10365 :     multirange_get_bounds(rangetyp, mr1, i1, &lower1, &upper1);
                               2048           37971 :     for (i1 = 0, i2 = 0; i2 < range_count2; i2++)
                               2049                 :     {
                               2050           29013 :         multirange_get_bounds(rangetyp, mr2, i2, &lower2, &upper2);
                               2051                 : 
  840 akorotkov                2052 ECB             :         /* Discard r1s while r1 << r2 */
  840 akorotkov                2053 CBC       29079 :         while (range_cmp_bounds(rangetyp, &upper1, &lower2) < 0)
  840 akorotkov                2054 ECB             :         {
  840 akorotkov                2055 GIC         117 :             if (++i1 >= range_count1)
  840 akorotkov                2056 CBC          51 :                 return false;
  840 akorotkov                2057 GIC          66 :             multirange_get_bounds(rangetyp, mr1, i1, &lower1, &upper1);
                               2058                 :         }
  840 akorotkov                2059 ECB             : 
                               2060                 :         /*
                               2061                 :          * If r1 && r2, we're done, otherwise we failed to find an overlap for
                               2062                 :          * r2, so go to the next one.
                               2063                 :          */
  840 akorotkov                2064 GIC       28962 :         if (range_bounds_overlaps(rangetyp, &lower1, &upper1, &lower2, &upper2))
                               2065            1356 :             return true;
                               2066                 :     }
                               2067                 : 
                               2068                 :     /* We looked through all of mr2 without finding an overlap */
                               2069            8958 :     return false;
  840 akorotkov                2070 ECB             : }
                               2071                 : 
                               2072                 : /* does not extend to right of? */
                               2073                 : bool
  831 akorotkov                2074 GIC       36874 : range_overleft_multirange_internal(TypeCacheEntry *rangetyp,
  831 akorotkov                2075 ECB             :                                    const RangeType *r,
                               2076                 :                                    const MultirangeType *mr)
                               2077                 : {
                               2078                 :     RangeBound  lower1,
                               2079                 :                 upper1,
  840                          2080                 :                 lower2,
                               2081                 :                 upper2;
                               2082                 :     bool        empty;
                               2083                 : 
  840 akorotkov                2084 GIC       36874 :     if (RangeIsEmpty(r) || MultirangeIsEmpty(mr))
                               2085            3006 :         PG_RETURN_BOOL(false);
                               2086                 : 
                               2087                 : 
  831                          2088           33868 :     range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
  840                          2089           33868 :     Assert(!empty);
  831 akorotkov                2090 CBC       33868 :     multirange_get_bounds(rangetyp, mr, mr->rangeCount - 1,
  840 akorotkov                2091 ECB             :                           &lower2, &upper2);
                               2092                 : 
  831 akorotkov                2093 GIC       33868 :     PG_RETURN_BOOL(range_cmp_bounds(rangetyp, &upper1, &upper2) <= 0);
  831 akorotkov                2094 ECB             : }
                               2095                 : 
                               2096                 : Datum
  831 akorotkov                2097 GIC       18621 : range_overleft_multirange(PG_FUNCTION_ARGS)
                               2098                 : {
  831 akorotkov                2099 CBC       18621 :     RangeType  *r = PG_GETARG_RANGE_P(0);
  831 akorotkov                2100 GIC       18621 :     MultirangeType *mr = PG_GETARG_MULTIRANGE_P(1);
                               2101                 :     TypeCacheEntry *typcache;
                               2102                 : 
  831 akorotkov                2103 CBC       18621 :     typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
                               2104                 : 
                               2105           18621 :     PG_RETURN_BOOL(range_overleft_multirange_internal(typcache->rngtype, r, mr));
  840 akorotkov                2106 ECB             : }
                               2107                 : 
                               2108                 : Datum
  840 akorotkov                2109 CBC       23643 : multirange_overleft_range(PG_FUNCTION_ARGS)
                               2110                 : {
                               2111           23643 :     MultirangeType *mr = PG_GETARG_MULTIRANGE_P(0);
  840 akorotkov                2112 GIC       23643 :     RangeType  *r = PG_GETARG_RANGE_P(1);
                               2113                 :     TypeCacheEntry *typcache;
                               2114                 :     RangeBound  lower1,
  840 akorotkov                2115 ECB             :                 upper1,
                               2116                 :                 lower2,
                               2117                 :                 upper2;
                               2118                 :     bool        empty;
                               2119                 : 
  840 akorotkov                2120 GIC       23643 :     if (MultirangeIsEmpty(mr) || RangeIsEmpty(r))
                               2121           12606 :         PG_RETURN_BOOL(false);
                               2122                 : 
                               2123           11037 :     typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
                               2124                 : 
                               2125           11037 :     multirange_get_bounds(typcache->rngtype, mr, mr->rangeCount - 1,
  840 akorotkov                2126 ECB             :                           &lower1, &upper1);
  840 akorotkov                2127 CBC       11037 :     range_deserialize(typcache->rngtype, r, &lower2, &upper2, &empty);
  840 akorotkov                2128 GIC       11037 :     Assert(!empty);
  840 akorotkov                2129 ECB             : 
  840 akorotkov                2130 GIC       11037 :     PG_RETURN_BOOL(range_cmp_bounds(typcache->rngtype, &upper1, &upper2) <= 0);
  840 akorotkov                2131 ECB             : }
                               2132                 : 
                               2133                 : Datum
  840 akorotkov                2134 CBC       23646 : multirange_overleft_multirange(PG_FUNCTION_ARGS)
                               2135                 : {
                               2136           23646 :     MultirangeType *mr1 = PG_GETARG_MULTIRANGE_P(0);
  840 akorotkov                2137 GIC       23646 :     MultirangeType *mr2 = PG_GETARG_MULTIRANGE_P(1);
                               2138                 :     TypeCacheEntry *typcache;
                               2139                 :     RangeBound  lower1,
  840 akorotkov                2140 ECB             :                 upper1,
                               2141                 :                 lower2,
                               2142                 :                 upper2;
                               2143                 : 
  840 akorotkov                2144 GIC       23646 :     if (MultirangeIsEmpty(mr1) || MultirangeIsEmpty(mr2))
                               2145           12609 :         PG_RETURN_BOOL(false);
                               2146                 : 
                               2147           11037 :     typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1));
                               2148                 : 
                               2149           11037 :     multirange_get_bounds(typcache->rngtype, mr1, mr1->rangeCount - 1,
  840 akorotkov                2150 ECB             :                           &lower1, &upper1);
  840 akorotkov                2151 CBC       11037 :     multirange_get_bounds(typcache->rngtype, mr2, mr2->rangeCount - 1,
                               2152                 :                           &lower2, &upper2);
  840 akorotkov                2153 ECB             : 
  840 akorotkov                2154 GIC       11037 :     PG_RETURN_BOOL(range_cmp_bounds(typcache->rngtype, &upper1, &upper2) <= 0);
  840 akorotkov                2155 ECB             : }
                               2156                 : 
                               2157                 : /* does not extend to left of? */
                               2158                 : bool
  831 akorotkov                2159 GIC       59669 : range_overright_multirange_internal(TypeCacheEntry *rangetyp,
  831 akorotkov                2160 ECB             :                                     const RangeType *r,
                               2161                 :                                     const MultirangeType *mr)
                               2162                 : {
                               2163                 :     RangeBound  lower1,
                               2164                 :                 upper1,
  840                          2165                 :                 lower2,
                               2166                 :                 upper2;
                               2167                 :     bool        empty;
                               2168                 : 
  840 akorotkov                2169 GIC       59669 :     if (RangeIsEmpty(r) || MultirangeIsEmpty(mr))
                               2170            3006 :         PG_RETURN_BOOL(false);
                               2171                 : 
  831                          2172           56663 :     range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
  840                          2173           56663 :     Assert(!empty);
  831                          2174           56663 :     multirange_get_bounds(rangetyp, mr, 0, &lower2, &upper2);
  840 akorotkov                2175 ECB             : 
  831 akorotkov                2176 CBC       56663 :     return (range_cmp_bounds(rangetyp, &lower1, &lower2) >= 0);
                               2177                 : }
  831 akorotkov                2178 ECB             : 
                               2179                 : Datum
  831 akorotkov                2180 CBC       18621 : range_overright_multirange(PG_FUNCTION_ARGS)
                               2181                 : {
                               2182           18621 :     RangeType  *r = PG_GETARG_RANGE_P(0);
  831 akorotkov                2183 GIC       18621 :     MultirangeType *mr = PG_GETARG_MULTIRANGE_P(1);
                               2184                 :     TypeCacheEntry *typcache;
                               2185                 : 
  831 akorotkov                2186 CBC       18621 :     typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
                               2187                 : 
                               2188           18621 :     PG_RETURN_BOOL(range_overright_multirange_internal(typcache->rngtype, r, mr));
  840 akorotkov                2189 ECB             : }
                               2190                 : 
                               2191                 : Datum
  840 akorotkov                2192 CBC       30900 : multirange_overright_range(PG_FUNCTION_ARGS)
                               2193                 : {
                               2194           30900 :     MultirangeType *mr = PG_GETARG_MULTIRANGE_P(0);
  840 akorotkov                2195 GIC       30900 :     RangeType  *r = PG_GETARG_RANGE_P(1);
                               2196                 :     TypeCacheEntry *typcache;
                               2197                 :     RangeBound  lower1,
  840 akorotkov                2198 ECB             :                 upper1,
                               2199                 :                 lower2,
                               2200                 :                 upper2;
                               2201                 :     bool        empty;
                               2202                 : 
  840 akorotkov                2203 GIC       30900 :     if (MultirangeIsEmpty(mr) || RangeIsEmpty(r))
                               2204           12606 :         PG_RETURN_BOOL(false);
                               2205                 : 
                               2206           18294 :     typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
                               2207                 : 
                               2208           18294 :     multirange_get_bounds(typcache->rngtype, mr, 0, &lower1, &upper1);
  840 akorotkov                2209 CBC       18294 :     range_deserialize(typcache->rngtype, r, &lower2, &upper2, &empty);
                               2210           18294 :     Assert(!empty);
                               2211                 : 
                               2212           18294 :     PG_RETURN_BOOL(range_cmp_bounds(typcache->rngtype, &lower1, &lower2) >= 0);
                               2213                 : }
  840 akorotkov                2214 ECB             : 
                               2215                 : Datum
  840 akorotkov                2216 CBC       30903 : multirange_overright_multirange(PG_FUNCTION_ARGS)
                               2217                 : {
                               2218           30903 :     MultirangeType *mr1 = PG_GETARG_MULTIRANGE_P(0);
  840 akorotkov                2219 GIC       30903 :     MultirangeType *mr2 = PG_GETARG_MULTIRANGE_P(1);
                               2220                 :     TypeCacheEntry *typcache;
                               2221                 :     RangeBound  lower1,
  840 akorotkov                2222 ECB             :                 upper1,
                               2223                 :                 lower2,
                               2224                 :                 upper2;
                               2225                 : 
  840 akorotkov                2226 GIC       30903 :     if (MultirangeIsEmpty(mr1) || MultirangeIsEmpty(mr2))
                               2227           12609 :         PG_RETURN_BOOL(false);
                               2228                 : 
                               2229           18294 :     typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1));
                               2230                 : 
                               2231           18294 :     multirange_get_bounds(typcache->rngtype, mr1, 0, &lower1, &upper1);
  840 akorotkov                2232 CBC       18294 :     multirange_get_bounds(typcache->rngtype, mr2, 0, &lower2, &upper2);
  840 akorotkov                2233 ECB             : 
  840 akorotkov                2234 GIC       18294 :     PG_RETURN_BOOL(range_cmp_bounds(typcache->rngtype, &lower1, &lower2) >= 0);
  840 akorotkov                2235 ECB             : }
                               2236                 : 
                               2237                 : /* contains? */
                               2238                 : Datum
  840 akorotkov                2239 GIC       78156 : multirange_contains_multirange(PG_FUNCTION_ARGS)
  840 akorotkov                2240 ECB             : {
  840 akorotkov                2241 GIC       78156 :     MultirangeType *mr1 = PG_GETARG_MULTIRANGE_P(0);
                               2242           78156 :     MultirangeType *mr2 = PG_GETARG_MULTIRANGE_P(1);
                               2243                 :     TypeCacheEntry *typcache;
                               2244                 : 
  840 akorotkov                2245 CBC       78156 :     typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1));
                               2246                 : 
  831                          2247           78156 :     PG_RETURN_BOOL(multirange_contains_multirange_internal(typcache->rngtype, mr1, mr2));
  840 akorotkov                2248 ECB             : }
                               2249                 : 
                               2250                 : /* contained by? */
                               2251                 : Datum
  840 akorotkov                2252 GIC       25299 : multirange_contained_by_multirange(PG_FUNCTION_ARGS)
  840 akorotkov                2253 ECB             : {
  840 akorotkov                2254 GIC       25299 :     MultirangeType *mr1 = PG_GETARG_MULTIRANGE_P(0);
                               2255           25299 :     MultirangeType *mr2 = PG_GETARG_MULTIRANGE_P(1);
                               2256                 :     TypeCacheEntry *typcache;
                               2257                 : 
  840 akorotkov                2258 CBC       25299 :     typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1));
                               2259                 : 
  831                          2260           25299 :     PG_RETURN_BOOL(multirange_contains_multirange_internal(typcache->rngtype, mr2, mr1));
  840 akorotkov                2261 ECB             : }
                               2262                 : 
                               2263                 : /*
                               2264                 :  * Test whether multirange mr1 contains every range from another multirange mr2.
                               2265                 :  */
                               2266                 : bool
  831 akorotkov                2267 GIC      103455 : multirange_contains_multirange_internal(TypeCacheEntry *rangetyp,
                               2268                 :                                         const MultirangeType *mr1,
                               2269                 :                                         const MultirangeType *mr2)
                               2270                 : {
  840                          2271          103455 :     int32       range_count1 = mr1->rangeCount;
                               2272          103455 :     int32       range_count2 = mr2->rangeCount;
  840 akorotkov                2273 ECB             :     int         i1,
                               2274                 :                 i2;
                               2275                 :     RangeBound  lower1,
                               2276                 :                 upper1,
                               2277                 :                 lower2,
                               2278                 :                 upper2;
                               2279                 : 
                               2280                 :     /*
                               2281                 :      * We follow the same logic for empties as ranges: - an empty multirange
                               2282                 :      * contains an empty range/multirange. - an empty multirange can't contain
                               2283                 :      * any other range/multirange. - an empty multirange is contained by any
                               2284                 :      * other range/multirange.
                               2285                 :      */
                               2286                 : 
  840 akorotkov                2287 GIC      103455 :     if (range_count2 == 0)
                               2288           72606 :         return true;
                               2289           30849 :     if (range_count1 == 0)
                               2290           11148 :         return false;
                               2291                 : 
                               2292                 :     /*
  840 akorotkov                2293 ECB             :      * Every range in mr2 must be contained by some range in mr1. To avoid
                               2294                 :      * O(n^2) we walk through both ranges in tandem.
                               2295                 :      */
  840 akorotkov                2296 CBC       19701 :     i1 = 0;
  840 akorotkov                2297 GIC       19701 :     multirange_get_bounds(rangetyp, mr1, i1, &lower1, &upper1);
                               2298           21258 :     for (i2 = 0; i2 < range_count2; i2++)
                               2299                 :     {
                               2300           20520 :         multirange_get_bounds(rangetyp, mr2, i2, &lower2, &upper2);
                               2301                 : 
  840 akorotkov                2302 ECB             :         /* Discard r1s while r1 << r2 */
  840 akorotkov                2303 CBC       38667 :         while (range_cmp_bounds(rangetyp, &upper1, &lower2) < 0)
  840 akorotkov                2304 ECB             :         {
  840 akorotkov                2305 GIC       26970 :             if (++i1 >= range_count1)
  840 akorotkov                2306 CBC        8823 :                 return false;
  840 akorotkov                2307 GIC       18147 :             multirange_get_bounds(rangetyp, mr1, i1, &lower1, &upper1);
                               2308                 :         }
  840 akorotkov                2309 ECB             : 
                               2310                 :         /*
                               2311                 :          * If r1 @> r2, go to the next r2, otherwise return false (since every
                               2312                 :          * r1[n] and r1[n+1] must have a gap). Note this will give weird
                               2313                 :          * answers if you don't canonicalize, e.g. with a custom
                               2314                 :          * int2multirange {[1,1], [2,2]} there is a "gap". But that is
                               2315                 :          * consistent with other range operators, e.g. '[1,1]'::int2range -|-
                               2316                 :          * '[2,2]'::int2range is false.
                               2317                 :          */
  840 akorotkov                2318 GIC       11697 :         if (!range_bounds_contains(rangetyp, &lower1, &upper1,
                               2319                 :                                    &lower2, &upper2))
                               2320           10140 :             return false;
                               2321                 :     }
                               2322                 : 
                               2323                 :     /* All ranges in mr2 are satisfied */
  840 akorotkov                2324 CBC         738 :     return true;
                               2325                 : }
  840 akorotkov                2326 ECB             : 
                               2327                 : /* strictly left of? */
                               2328                 : Datum
  840 akorotkov                2329 GIC       18615 : range_before_multirange(PG_FUNCTION_ARGS)
  840 akorotkov                2330 ECB             : {
  840 akorotkov                2331 GIC       18615 :     RangeType  *r = PG_GETARG_RANGE_P(0);
                               2332           18615 :     MultirangeType *mr = PG_GETARG_MULTIRANGE_P(1);
                               2333                 :     TypeCacheEntry *typcache;
                               2334                 : 
  840 akorotkov                2335 CBC       18615 :     typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
                               2336                 : 
  831                          2337           18615 :     PG_RETURN_BOOL(range_before_multirange_internal(typcache->rngtype, r, mr));
  840 akorotkov                2338 ECB             : }
                               2339                 : 
                               2340                 : Datum
  840 akorotkov                2341 CBC       22380 : multirange_before_range(PG_FUNCTION_ARGS)
                               2342                 : {
                               2343           22380 :     MultirangeType *mr = PG_GETARG_MULTIRANGE_P(0);
  840 akorotkov                2344 GIC       22380 :     RangeType  *r = PG_GETARG_RANGE_P(1);
                               2345                 :     TypeCacheEntry *typcache;
                               2346                 : 
  840 akorotkov                2347 CBC       22380 :     typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
                               2348                 : 
  831                          2349           22380 :     PG_RETURN_BOOL(range_after_multirange_internal(typcache->rngtype, r, mr));
  840 akorotkov                2350 ECB             : }
                               2351                 : 
                               2352                 : Datum
  840 akorotkov                2353 CBC       22383 : multirange_before_multirange(PG_FUNCTION_ARGS)
                               2354                 : {
                               2355           22383 :     MultirangeType *mr1 = PG_GETARG_MULTIRANGE_P(0);
  840 akorotkov                2356 GIC       22383 :     MultirangeType *mr2 = PG_GETARG_MULTIRANGE_P(1);
                               2357                 :     TypeCacheEntry *typcache;
                               2358                 : 
  840 akorotkov                2359 CBC       22383 :     typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1));
                               2360                 : 
  831                          2361           22383 :     PG_RETURN_BOOL(multirange_before_multirange_internal(typcache->rngtype, mr1, mr2));
  840 akorotkov                2362 ECB             : }
                               2363                 : 
                               2364                 : /* strictly right of? */
                               2365                 : Datum
  840 akorotkov                2366 GIC       18618 : range_after_multirange(PG_FUNCTION_ARGS)
  840 akorotkov                2367 ECB             : {
  840 akorotkov                2368 GIC       18618 :     RangeType  *r = PG_GETARG_RANGE_P(0);
                               2369           18618 :     MultirangeType *mr = PG_GETARG_MULTIRANGE_P(1);
                               2370                 :     TypeCacheEntry *typcache;
                               2371                 : 
  840 akorotkov                2372 CBC       18618 :     typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
                               2373                 : 
  831                          2374           18618 :     PG_RETURN_BOOL(range_after_multirange_internal(typcache->rngtype, r, mr));
  840 akorotkov                2375 ECB             : }
                               2376                 : 
                               2377                 : Datum
  840 akorotkov                2378 CBC       28374 : multirange_after_range(PG_FUNCTION_ARGS)
                               2379                 : {
                               2380           28374 :     MultirangeType *mr = PG_GETARG_MULTIRANGE_P(0);
  840 akorotkov                2381 GIC       28374 :     RangeType  *r = PG_GETARG_RANGE_P(1);
                               2382                 :     TypeCacheEntry *typcache;
                               2383                 : 
  840 akorotkov                2384 CBC       28374 :     typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
                               2385                 : 
  831                          2386           28374 :     PG_RETURN_BOOL(range_before_multirange_internal(typcache->rngtype, r, mr));
  840 akorotkov                2387 ECB             : }
                               2388                 : 
                               2389                 : Datum
  840 akorotkov                2390 CBC       28380 : multirange_after_multirange(PG_FUNCTION_ARGS)
                               2391                 : {
                               2392           28380 :     MultirangeType *mr1 = PG_GETARG_MULTIRANGE_P(0);
  840 akorotkov                2393 GIC       28380 :     MultirangeType *mr2 = PG_GETARG_MULTIRANGE_P(1);
                               2394                 :     TypeCacheEntry *typcache;
                               2395                 : 
  840 akorotkov                2396 CBC       28380 :     typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1));
                               2397                 : 
  831                          2398           28380 :     PG_RETURN_BOOL(multirange_before_multirange_internal(typcache->rngtype, mr2, mr1));
  840 akorotkov                2399 ECB             : }
                               2400                 : 
                               2401                 : /* strictly left of? (internal version) */
                               2402                 : bool
  831 akorotkov                2403 GIC       56257 : range_before_multirange_internal(TypeCacheEntry *rangetyp,
  831 akorotkov                2404 ECB             :                                  const RangeType *r,
                               2405                 :                                  const MultirangeType *mr)
                               2406                 : {
                               2407                 :     RangeBound  lower1,
                               2408                 :                 upper1,
  840                          2409                 :                 lower2,
                               2410                 :                 upper2;
                               2411                 :     bool        empty;
                               2412                 : 
  840 akorotkov                2413 GIC       56257 :     if (RangeIsEmpty(r) || MultirangeIsEmpty(mr))
                               2414           15612 :         return false;
                               2415                 : 
  831                          2416           40645 :     range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
  840                          2417           40645 :     Assert(!empty);
                               2418                 : 
  831 akorotkov                2419 CBC       40645 :     multirange_get_bounds(rangetyp, mr, 0, &lower2, &upper2);
  840 akorotkov                2420 ECB             : 
  831 akorotkov                2421 GIC       40645 :     return (range_cmp_bounds(rangetyp, &upper1, &lower2) < 0);
  840 akorotkov                2422 ECB             : }
                               2423                 : 
                               2424                 : bool
  831 akorotkov                2425 CBC       50763 : multirange_before_multirange_internal(TypeCacheEntry *rangetyp,
                               2426                 :                                       const MultirangeType *mr1,
  831 akorotkov                2427 ECB             :                                       const MultirangeType *mr2)
                               2428                 : {
                               2429                 :     RangeBound  lower1,
                               2430                 :                 upper1,
  840                          2431                 :                 lower2,
                               2432                 :                 upper2;
                               2433                 : 
  840 akorotkov                2434 GIC       50763 :     if (MultirangeIsEmpty(mr1) || MultirangeIsEmpty(mr2))
                               2435           25218 :         return false;
                               2436                 : 
  831                          2437           25545 :     multirange_get_bounds(rangetyp, mr1, mr1->rangeCount - 1,
                               2438                 :                           &lower1, &upper1);
                               2439           25545 :     multirange_get_bounds(rangetyp, mr2, 0,
  840 akorotkov                2440 ECB             :                           &lower2, &upper2);
                               2441                 : 
  831 akorotkov                2442 GIC       25545 :     return (range_cmp_bounds(rangetyp, &upper1, &lower2) < 0);
  840 akorotkov                2443 ECB             : }
                               2444                 : 
                               2445                 : /* strictly right of? (internal version) */
                               2446                 : bool
  831 akorotkov                2447 GIC       78533 : range_after_multirange_internal(TypeCacheEntry *rangetyp,
  831 akorotkov                2448 ECB             :                                 const RangeType *r,
                               2449                 :                                 const MultirangeType *mr)
                               2450                 : {
                               2451                 :     RangeBound  lower1,
                               2452                 :                 upper1,
  840                          2453                 :                 lower2,
                               2454                 :                 upper2;
                               2455                 :     bool        empty;
                               2456                 :     int32       range_count;
                               2457                 : 
  840 akorotkov                2458 GIC       78533 :     if (RangeIsEmpty(r) || MultirangeIsEmpty(mr))
                               2459           15612 :         return false;
                               2460                 : 
  831                          2461           62921 :     range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
  840                          2462           62921 :     Assert(!empty);
                               2463                 : 
  840 akorotkov                2464 CBC       62921 :     range_count = mr->rangeCount;
  831                          2465           62921 :     multirange_get_bounds(rangetyp, mr, range_count - 1,
                               2466                 :                           &lower2, &upper2);
  840 akorotkov                2467 ECB             : 
  831 akorotkov                2468 CBC       62921 :     return (range_cmp_bounds(rangetyp, &lower1, &upper2) > 0);
                               2469                 : }
  840 akorotkov                2470 ECB             : 
                               2471                 : bool
  831 akorotkov                2472 GIC       46480 : range_adjacent_multirange_internal(TypeCacheEntry *rangetyp,
                               2473                 :                                    const RangeType *r,
  831 akorotkov                2474 ECB             :                                    const MultirangeType *mr)
                               2475                 : {
                               2476                 :     RangeBound  lower1,
                               2477                 :                 upper1,
  840                          2478                 :                 lower2,
                               2479                 :                 upper2;
                               2480                 :     bool        empty;
                               2481                 :     int32       range_count;
                               2482                 : 
  840 akorotkov                2483 GIC       46480 :     if (RangeIsEmpty(r) || MultirangeIsEmpty(mr))
                               2484            3006 :         return false;
                               2485                 : 
  831                          2486           43474 :     range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
  840                          2487           43474 :     Assert(!empty);
                               2488                 : 
  840 akorotkov                2489 CBC       43474 :     range_count = mr->rangeCount;
  831                          2490           43474 :     multirange_get_bounds(rangetyp, mr, 0,
                               2491                 :                           &lower2, &upper2);
  840 akorotkov                2492 ECB             : 
  831 akorotkov                2493 CBC       43474 :     if (bounds_adjacent(rangetyp, upper1, lower2))
  840 akorotkov                2494 GIC          36 :         return true;
  840 akorotkov                2495 ECB             : 
  840 akorotkov                2496 CBC       43438 :     if (range_count > 1)
  831 akorotkov                2497 GIC       39832 :         multirange_get_bounds(rangetyp, mr, range_count - 1,
                               2498                 :                               &lower2, &upper2);
  840 akorotkov                2499 ECB             : 
  831 akorotkov                2500 CBC       43438 :     if (bounds_adjacent(rangetyp, upper2, lower1))
  840 akorotkov                2501 GIC          42 :         return true;
  840 akorotkov                2502 ECB             : 
  840 akorotkov                2503 CBC       43396 :     return false;
                               2504                 : }
                               2505                 : 
  840 akorotkov                2506 ECB             : /* adjacent to? */
                               2507                 : Datum
  840 akorotkov                2508 GIC       18612 : range_adjacent_multirange(PG_FUNCTION_ARGS)
  840 akorotkov                2509 ECB             : {
  840 akorotkov                2510 GIC       18612 :     RangeType  *r = PG_GETARG_RANGE_P(0);
                               2511           18612 :     MultirangeType *mr = PG_GETARG_MULTIRANGE_P(1);
                               2512                 :     TypeCacheEntry *typcache;
                               2513                 : 
  840 akorotkov                2514 CBC       18612 :     typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
                               2515                 : 
  831                          2516           18612 :     PG_RETURN_BOOL(range_adjacent_multirange_internal(typcache->rngtype, r, mr));
  840 akorotkov                2517 ECB             : }
                               2518                 : 
                               2519                 : Datum
  840 akorotkov                2520 CBC       22221 : multirange_adjacent_range(PG_FUNCTION_ARGS)
                               2521                 : {
                               2522           22221 :     MultirangeType *mr = PG_GETARG_MULTIRANGE_P(0);
  840 akorotkov                2523 GIC       22221 :     RangeType  *r = PG_GETARG_RANGE_P(1);
                               2524                 :     TypeCacheEntry *typcache;
                               2525                 : 
  840 akorotkov                2526 CBC       22221 :     if (RangeIsEmpty(r) || MultirangeIsEmpty(mr))
  840 akorotkov                2527 GIC       12606 :         return false;
  840 akorotkov                2528 ECB             : 
  840 akorotkov                2529 CBC        9615 :     typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
                               2530                 : 
  831 akorotkov                2531 GIC        9615 :     PG_RETURN_BOOL(range_adjacent_multirange_internal(typcache->rngtype, r, mr));
  840 akorotkov                2532 ECB             : }
                               2533                 : 
                               2534                 : Datum
  840 akorotkov                2535 CBC       22236 : multirange_adjacent_multirange(PG_FUNCTION_ARGS)
                               2536                 : {
                               2537           22236 :     MultirangeType *mr1 = PG_GETARG_MULTIRANGE_P(0);
  840 akorotkov                2538 GIC       22236 :     MultirangeType *mr2 = PG_GETARG_MULTIRANGE_P(1);
                               2539                 :     TypeCacheEntry *typcache;
                               2540                 :     int32       range_count1;
  840 akorotkov                2541 ECB             :     int32       range_count2;
                               2542                 :     RangeBound  lower1,
                               2543                 :                 upper1,
                               2544                 :                 lower2,
                               2545                 :                 upper2;
                               2546                 : 
  840 akorotkov                2547 GIC       22236 :     if (MultirangeIsEmpty(mr1) || MultirangeIsEmpty(mr2))
                               2548           12609 :         return false;
                               2549                 : 
                               2550            9627 :     typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1));
                               2551                 : 
                               2552            9627 :     range_count1 = mr1->rangeCount;
  840 akorotkov                2553 CBC        9627 :     range_count2 = mr2->rangeCount;
                               2554            9627 :     multirange_get_bounds(typcache->rngtype, mr1, range_count1 - 1,
                               2555                 :                           &lower1, &upper1);
                               2556            9627 :     multirange_get_bounds(typcache->rngtype, mr2, 0,
                               2557                 :                           &lower2, &upper2);
                               2558            9627 :     if (bounds_adjacent(typcache->rngtype, upper1, lower2))
                               2559              15 :         PG_RETURN_BOOL(true);
  840 akorotkov                2560 ECB             : 
  840 akorotkov                2561 GIC        9612 :     if (range_count1 > 1)
  840 akorotkov                2562 CBC        6006 :         multirange_get_bounds(typcache->rngtype, mr1, 0,
                               2563                 :                               &lower1, &upper1);
                               2564            9612 :     if (range_count2 > 1)
                               2565            9603 :         multirange_get_bounds(typcache->rngtype, mr2, range_count2 - 1,
                               2566                 :                               &lower2, &upper2);
                               2567            9612 :     if (bounds_adjacent(typcache->rngtype, upper2, lower1))
                               2568              12 :         PG_RETURN_BOOL(true);
  840 akorotkov                2569 GIC        9600 :     PG_RETURN_BOOL(false);
  840 akorotkov                2570 ECB             : }
                               2571                 : 
                               2572                 : /* Btree support */
                               2573                 : 
                               2574                 : /* btree comparator */
                               2575                 : Datum
  840 akorotkov                2576 GIC         402 : multirange_cmp(PG_FUNCTION_ARGS)
                               2577                 : {
                               2578             402 :     MultirangeType *mr1 = PG_GETARG_MULTIRANGE_P(0);
                               2579             402 :     MultirangeType *mr2 = PG_GETARG_MULTIRANGE_P(1);
                               2580                 :     int32       range_count_1;
                               2581                 :     int32       range_count_2;
  840 akorotkov                2582 ECB             :     int32       range_count_max;
                               2583                 :     int32       i;
                               2584                 :     TypeCacheEntry *typcache;
  840 akorotkov                2585 CBC         402 :     int         cmp = 0;        /* If both are empty we'll use this. */
                               2586                 : 
                               2587                 :     /* Different types should be prevented by ANYMULTIRANGE matching rules */
  840 akorotkov                2588 GIC         402 :     if (MultirangeTypeGetOid(mr1) != MultirangeTypeGetOid(mr2))
  840 akorotkov                2589 UIC           0 :         elog(ERROR, "multirange types do not match");
                               2590                 : 
  840 akorotkov                2591 CBC         402 :     typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1));
                               2592                 : 
  840 akorotkov                2593 GIC         402 :     range_count_1 = mr1->rangeCount;
  840 akorotkov                2594 CBC         402 :     range_count_2 = mr2->rangeCount;
  840 akorotkov                2595 EUB             : 
                               2596                 :     /* Loop over source data */
  840 akorotkov                2597 CBC         402 :     range_count_max = Max(range_count_1, range_count_2);
  840 akorotkov                2598 GIC         429 :     for (i = 0; i < range_count_max; i++)
  840 akorotkov                2599 ECB             :     {
                               2600                 :         RangeBound  lower1,
                               2601                 :                     upper1,
                               2602                 :                     lower2,
                               2603                 :                     upper2;
                               2604                 : 
                               2605                 :         /*
                               2606                 :          * If one multirange is shorter, it's as if it had empty ranges at the
                               2607                 :          * end to extend its length. An empty range compares earlier than any
                               2608                 :          * other range, so the shorter multirange comes before the longer.
                               2609                 :          * This is the same behavior as in other types, e.g. in strings 'aaa'
                               2610                 :          * < 'aaaaaa'.
                               2611                 :          */
  840 akorotkov                2612 GIC         351 :         if (i >= range_count_1)
                               2613                 :         {
                               2614              60 :             cmp = -1;
                               2615             324 :             break;
                               2616                 :         }
                               2617             291 :         if (i >= range_count_2)
  840 akorotkov                2618 ECB             :         {
  840 akorotkov                2619 GIC          69 :             cmp = 1;
  840 akorotkov                2620 CBC          69 :             break;
  840 akorotkov                2621 ECB             :         }
                               2622                 : 
  840 akorotkov                2623 CBC         222 :         multirange_get_bounds(typcache->rngtype, mr1, i, &lower1, &upper1);
  840 akorotkov                2624 GIC         222 :         multirange_get_bounds(typcache->rngtype, mr2, i, &lower2, &upper2);
  840 akorotkov                2625 ECB             : 
  840 akorotkov                2626 CBC         222 :         cmp = range_cmp_bounds(typcache->rngtype, &lower1, &lower2);
  840 akorotkov                2627 GIC         222 :         if (cmp == 0)
                               2628              39 :             cmp = range_cmp_bounds(typcache->rngtype, &upper1, &upper2);
  840 akorotkov                2629 CBC         222 :         if (cmp != 0)
                               2630             195 :             break;
                               2631                 :     }
  840 akorotkov                2632 ECB             : 
  840 akorotkov                2633 CBC         402 :     PG_FREE_IF_COPY(mr1, 0);
                               2634             402 :     PG_FREE_IF_COPY(mr2, 1);
  840 akorotkov                2635 ECB             : 
  840 akorotkov                2636 CBC         402 :     PG_RETURN_INT32(cmp);
                               2637                 : }
                               2638                 : 
  840 akorotkov                2639 ECB             : /* inequality operators using the multirange_cmp function */
                               2640                 : Datum
  840 akorotkov                2641 GIC          84 : multirange_lt(PG_FUNCTION_ARGS)
  840 akorotkov                2642 ECB             : {
  840 akorotkov                2643 GIC          84 :     int         cmp = multirange_cmp(fcinfo);
                               2644                 : 
                               2645              84 :     PG_RETURN_BOOL(cmp < 0);
                               2646                 : }
  840 akorotkov                2647 ECB             : 
                               2648                 : Datum
  840 akorotkov                2649 CBC          48 : multirange_le(PG_FUNCTION_ARGS)
                               2650                 : {
                               2651              48 :     int         cmp = multirange_cmp(fcinfo);
                               2652                 : 
  840 akorotkov                2653 GIC          48 :     PG_RETURN_BOOL(cmp <= 0);
                               2654                 : }
  840 akorotkov                2655 ECB             : 
                               2656                 : Datum
  840 akorotkov                2657 CBC          36 : multirange_ge(PG_FUNCTION_ARGS)
                               2658                 : {
                               2659              36 :     int         cmp = multirange_cmp(fcinfo);
                               2660                 : 
  840 akorotkov                2661 GIC          36 :     PG_RETURN_BOOL(cmp >= 0);
                               2662                 : }
  840 akorotkov                2663 ECB             : 
                               2664                 : Datum
  840 akorotkov                2665 CBC          57 : multirange_gt(PG_FUNCTION_ARGS)
                               2666                 : {
                               2667              57 :     int         cmp = multirange_cmp(fcinfo);
                               2668                 : 
  840 akorotkov                2669 GIC          57 :     PG_RETURN_BOOL(cmp > 0);
                               2670                 : }
  840 akorotkov                2671 ECB             : 
                               2672                 : /* multirange -> range functions */
                               2673                 : 
                               2674                 : /* Find the smallest range that includes everything in the multirange */
                               2675                 : Datum
  840 akorotkov                2676 GIC          18 : range_merge_from_multirange(PG_FUNCTION_ARGS)
                               2677                 : {
                               2678              18 :     MultirangeType *mr = PG_GETARG_MULTIRANGE_P(0);
                               2679              18 :     Oid         mltrngtypoid = MultirangeTypeGetOid(mr);
                               2680                 :     TypeCacheEntry *typcache;
                               2681                 :     RangeType  *result;
  840 akorotkov                2682 ECB             : 
  840 akorotkov                2683 GIC          18 :     typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
  840 akorotkov                2684 ECB             : 
  840 akorotkov                2685 CBC          18 :     if (MultirangeIsEmpty(mr))
                               2686                 :     {
  840 akorotkov                2687 GIC           3 :         result = make_empty_range(typcache->rngtype);
                               2688                 :     }
  840 akorotkov                2689 CBC          15 :     else if (mr->rangeCount == 1)
                               2690                 :     {
                               2691               6 :         result = multirange_get_range(typcache->rngtype, mr, 0);
                               2692                 :     }
  840 akorotkov                2693 ECB             :     else
                               2694                 :     {
                               2695                 :         RangeBound  firstLower,
                               2696                 :                     firstUpper,
                               2697                 :                     lastLower,
                               2698                 :                     lastUpper;
                               2699                 : 
  840 akorotkov                2700 GIC           9 :         multirange_get_bounds(typcache->rngtype, mr, 0,
                               2701                 :                               &firstLower, &firstUpper);
                               2702               9 :         multirange_get_bounds(typcache->rngtype, mr, mr->rangeCount - 1,
                               2703                 :                               &lastLower, &lastUpper);
                               2704                 : 
  115 tgl                      2705 GNC           9 :         result = make_range(typcache->rngtype, &firstLower, &lastUpper,
                               2706                 :                             false, NULL);
  840 akorotkov                2707 ECB             :     }
                               2708                 : 
  840 akorotkov                2709 CBC          18 :     PG_RETURN_RANGE_P(result);
                               2710                 : }
                               2711                 : 
  630 akorotkov                2712 ECB             : /* Turn multirange into a set of ranges */
                               2713                 : Datum
  630 akorotkov                2714 GIC          36 : multirange_unnest(PG_FUNCTION_ARGS)
                               2715                 : {
  630 akorotkov                2716 ECB             :     typedef struct
                               2717                 :     {
                               2718                 :         MultirangeType *mr;
                               2719                 :         TypeCacheEntry *typcache;
                               2720                 :         int         index;
                               2721                 :     } multirange_unnest_fctx;
                               2722                 : 
                               2723                 :     FuncCallContext *funcctx;
                               2724                 :     multirange_unnest_fctx *fctx;
                               2725                 :     MemoryContext oldcontext;
                               2726                 : 
                               2727                 :     /* stuff done only on the first call of the function */
  630 akorotkov                2728 GIC          36 :     if (SRF_IS_FIRSTCALL())
                               2729                 :     {
                               2730                 :         MultirangeType *mr;
                               2731                 : 
                               2732                 :         /* create a function context for cross-call persistence */
                               2733              12 :         funcctx = SRF_FIRSTCALL_INIT();
                               2734                 : 
  630 akorotkov                2735 ECB             :         /*
                               2736                 :          * switch to memory context appropriate for multiple function calls
                               2737                 :          */
  630 akorotkov                2738 GIC          12 :         oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
                               2739                 : 
  630 akorotkov                2740 ECB             :         /*
                               2741                 :          * Get the multirange value and detoast if needed.  We can't do this
                               2742                 :          * earlier because if we have to detoast, we want the detoasted copy
                               2743                 :          * to be in multi_call_memory_ctx, so it will go away when we're done
                               2744                 :          * and not before.  (If no detoast happens, we assume the originally
                               2745                 :          * passed multirange will stick around till then.)
                               2746                 :          */
  630 akorotkov                2747 GIC          12 :         mr = PG_GETARG_MULTIRANGE_P(0);
                               2748                 : 
                               2749                 :         /* allocate memory for user context */
                               2750              12 :         fctx = (multirange_unnest_fctx *) palloc(sizeof(multirange_unnest_fctx));
                               2751                 : 
                               2752                 :         /* initialize state */
                               2753              12 :         fctx->mr = mr;
  630 akorotkov                2754 CBC          12 :         fctx->index = 0;
  630 akorotkov                2755 GIC          12 :         fctx->typcache = lookup_type_cache(MultirangeTypeGetOid(mr),
                               2756                 :                                            TYPECACHE_MULTIRANGE_INFO);
  630 akorotkov                2757 ECB             : 
  630 akorotkov                2758 GIC          12 :         funcctx->user_fctx = fctx;
                               2759              12 :         MemoryContextSwitchTo(oldcontext);
  630 akorotkov                2760 ECB             :     }
                               2761                 : 
                               2762                 :     /* stuff done on every call of the function */
  630 akorotkov                2763 GIC          36 :     funcctx = SRF_PERCALL_SETUP();
                               2764              36 :     fctx = funcctx->user_fctx;
  630 akorotkov                2765 ECB             : 
  630 akorotkov                2766 CBC          36 :     if (fctx->index < fctx->mr->rangeCount)
                               2767                 :     {
                               2768                 :         RangeType  *range;
                               2769                 : 
                               2770              24 :         range = multirange_get_range(fctx->typcache->rngtype,
                               2771              24 :                                      fctx->mr,
                               2772                 :                                      fctx->index);
                               2773              24 :         fctx->index++;
                               2774                 : 
  630 akorotkov                2775 GIC          24 :         SRF_RETURN_NEXT(funcctx, RangeTypePGetDatum(range));
                               2776                 :     }
  630 akorotkov                2777 ECB             :     else
                               2778                 :     {
                               2779                 :         /* do when there is no more left */
  630 akorotkov                2780 CBC          12 :         SRF_RETURN_DONE(funcctx);
                               2781                 :     }
  630 akorotkov                2782 ECB             : }
                               2783                 : 
                               2784                 : /* Hash support */
                               2785                 : 
                               2786                 : /* hash a multirange value */
  840                          2787                 : Datum
  840 akorotkov                2788 GIC         153 : hash_multirange(PG_FUNCTION_ARGS)
                               2789                 : {
                               2790             153 :     MultirangeType *mr = PG_GETARG_MULTIRANGE_P(0);
                               2791             153 :     uint32      result = 1;
                               2792                 :     TypeCacheEntry *typcache,
                               2793                 :                *scache;
                               2794                 :     int32       range_count,
  840 akorotkov                2795 ECB             :                 i;
                               2796                 : 
  840 akorotkov                2797 CBC         153 :     typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
                               2798             153 :     scache = typcache->rngtype->rngelemtype;
  840 akorotkov                2799 GIC         153 :     if (!OidIsValid(scache->hash_proc_finfo.fn_oid))
                               2800                 :     {
                               2801               3 :         scache = lookup_type_cache(scache->type_id,
                               2802                 :                                    TYPECACHE_HASH_PROC_FINFO);
                               2803               3 :         if (!OidIsValid(scache->hash_proc_finfo.fn_oid))
  840 akorotkov                2804 LBC           0 :             ereport(ERROR,
  840 akorotkov                2805 ECB             :                     (errcode(ERRCODE_UNDEFINED_FUNCTION),
                               2806                 :                      errmsg("could not identify a hash function for type %s",
                               2807                 :                             format_type_be(scache->type_id))));
                               2808                 :     }
                               2809                 : 
  840 akorotkov                2810 CBC         153 :     range_count = mr->rangeCount;
  840 akorotkov                2811 GBC         273 :     for (i = 0; i < range_count; i++)
                               2812                 :     {
                               2813                 :         RangeBound  lower,
                               2814                 :                     upper;
  840 akorotkov                2815 GIC         120 :         uint8       flags = MultirangeGetFlagsPtr(mr)[i];
                               2816                 :         uint32      lower_hash;
  840 akorotkov                2817 ECB             :         uint32      upper_hash;
                               2818                 :         uint32      range_hash;
                               2819                 : 
  840 akorotkov                2820 GIC         120 :         multirange_get_bounds(typcache->rngtype, mr, i, &lower, &upper);
                               2821                 : 
  840 akorotkov                2822 CBC         120 :         if (RANGE_HAS_LBOUND(flags))
  840 akorotkov                2823 GIC          90 :             lower_hash = DatumGetUInt32(FunctionCall1Coll(&scache->hash_proc_finfo,
                               2824              90 :                                                           typcache->rngtype->rng_collation,
                               2825                 :                                                           lower.val));
                               2826                 :         else
  840 akorotkov                2827 CBC          30 :             lower_hash = 0;
                               2828                 : 
                               2829             120 :         if (RANGE_HAS_UBOUND(flags))
                               2830              93 :             upper_hash = DatumGetUInt32(FunctionCall1Coll(&scache->hash_proc_finfo,
                               2831              93 :                                                           typcache->rngtype->rng_collation,
                               2832                 :                                                           upper.val));
                               2833                 :         else
                               2834              27 :             upper_hash = 0;
                               2835                 : 
  840 akorotkov                2836 ECB             :         /* Merge hashes of flags and bounds */
  840 akorotkov                2837 CBC         120 :         range_hash = hash_uint32((uint32) flags);
                               2838             120 :         range_hash ^= lower_hash;
  413 john.naylor              2839 GIC         120 :         range_hash = pg_rotate_left32(range_hash, 1);
  840 akorotkov                2840             120 :         range_hash ^= upper_hash;
  840 akorotkov                2841 ECB             : 
                               2842                 :         /*
                               2843                 :          * Use the same approach as hash_array to combine the individual
                               2844                 :          * elements' hash values:
                               2845                 :          */
  840 akorotkov                2846 CBC         120 :         result = (result << 5) - result + range_hash;
  840 akorotkov                2847 ECB             :     }
                               2848                 : 
  840 akorotkov                2849 GIC         153 :     PG_FREE_IF_COPY(mr, 0);
                               2850                 : 
                               2851             153 :     PG_RETURN_UINT32(result);
                               2852                 : }
  840 akorotkov                2853 ECB             : 
                               2854                 : /*
                               2855                 :  * Returns 64-bit value by hashing a value to a 64-bit value, with a seed.
                               2856                 :  * Otherwise, similar to hash_multirange.
                               2857                 :  */
                               2858                 : Datum
  840 akorotkov                2859 GIC          30 : hash_multirange_extended(PG_FUNCTION_ARGS)
                               2860                 : {
                               2861              30 :     MultirangeType *mr = PG_GETARG_MULTIRANGE_P(0);
                               2862              30 :     Datum       seed = PG_GETARG_DATUM(1);
                               2863              30 :     uint64      result = 1;
                               2864                 :     TypeCacheEntry *typcache,
                               2865                 :                *scache;
  840 akorotkov                2866 ECB             :     int32       range_count,
                               2867                 :                 i;
                               2868                 : 
  840 akorotkov                2869 CBC          30 :     typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
                               2870              30 :     scache = typcache->rngtype->rngelemtype;
  840 akorotkov                2871 GIC          30 :     if (!OidIsValid(scache->hash_extended_proc_finfo.fn_oid))
                               2872                 :     {
  840 akorotkov                2873 UIC           0 :         scache = lookup_type_cache(scache->type_id,
                               2874                 :                                    TYPECACHE_HASH_EXTENDED_PROC_FINFO);
                               2875               0 :         if (!OidIsValid(scache->hash_extended_proc_finfo.fn_oid))
  840 akorotkov                2876 LBC           0 :             ereport(ERROR,
  840 akorotkov                2877 ECB             :                     (errcode(ERRCODE_UNDEFINED_FUNCTION),
                               2878                 :                      errmsg("could not identify a hash function for type %s",
                               2879                 :                             format_type_be(scache->type_id))));
  840 akorotkov                2880 EUB             :     }
                               2881                 : 
  840 akorotkov                2882 GBC          30 :     range_count = mr->rangeCount;
                               2883              60 :     for (i = 0; i < range_count; i++)
                               2884                 :     {
                               2885                 :         RangeBound  lower,
                               2886                 :                     upper;
  840 akorotkov                2887 GIC          30 :         uint8       flags = MultirangeGetFlagsPtr(mr)[i];
                               2888                 :         uint64      lower_hash;
  840 akorotkov                2889 ECB             :         uint64      upper_hash;
                               2890                 :         uint64      range_hash;
                               2891                 : 
  840 akorotkov                2892 GIC          30 :         multirange_get_bounds(typcache->rngtype, mr, i, &lower, &upper);
                               2893                 : 
  840 akorotkov                2894 CBC          30 :         if (RANGE_HAS_LBOUND(flags))
  840 akorotkov                2895 GIC          30 :             lower_hash = DatumGetUInt64(FunctionCall2Coll(&scache->hash_extended_proc_finfo,
                               2896              30 :                                                           typcache->rngtype->rng_collation,
                               2897                 :                                                           lower.val,
                               2898                 :                                                           seed));
  840 akorotkov                2899 ECB             :         else
  840 akorotkov                2900 UIC           0 :             lower_hash = 0;
  840 akorotkov                2901 ECB             : 
  840 akorotkov                2902 CBC          30 :         if (RANGE_HAS_UBOUND(flags))
                               2903              30 :             upper_hash = DatumGetUInt64(FunctionCall2Coll(&scache->hash_extended_proc_finfo,
  840 akorotkov                2904 GIC          30 :                                                           typcache->rngtype->rng_collation,
                               2905                 :                                                           upper.val,
                               2906                 :                                                           seed));
  840 akorotkov                2907 EUB             :         else
  840 akorotkov                2908 UIC           0 :             upper_hash = 0;
  840 akorotkov                2909 ECB             : 
                               2910                 :         /* Merge hashes of flags and bounds */
  840 akorotkov                2911 CBC          30 :         range_hash = DatumGetUInt64(hash_uint32_extended((uint32) flags,
  840 akorotkov                2912 GIC          30 :                                                          DatumGetInt64(seed)));
                               2913              30 :         range_hash ^= lower_hash;
                               2914              30 :         range_hash = ROTATE_HIGH_AND_LOW_32BITS(range_hash);
  840 akorotkov                2915 GBC          30 :         range_hash ^= upper_hash;
                               2916                 : 
                               2917                 :         /*
  840 akorotkov                2918 ECB             :          * Use the same approach as hash_array to combine the individual
                               2919                 :          * elements' hash values:
                               2920                 :          */
  840 akorotkov                2921 CBC          30 :         result = (result << 5) - result + range_hash;
  840 akorotkov                2922 ECB             :     }
                               2923                 : 
  840 akorotkov                2924 GIC          30 :     PG_FREE_IF_COPY(mr, 0);
                               2925                 : 
                               2926              30 :     PG_RETURN_UINT64(result);
                               2927                 : }
        

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