LCOV - differential code coverage report
Current view: top level - src/backend/utils/adt - rangetypes.c (source / functions) Coverage Total Hit UNC LBC UIC UBC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 85.5 % 963 823 11 25 80 24 21 489 71 242 93 544 2 12
Current Date: 2023-04-08 17:13:01 Functions: 90.0 % 80 72 8 72 8 71 1
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (60,120] days: 86.6 % 82 71 11 71
Legend: Lines: hit not hit (240..) days: 85.4 % 881 752 25 80 24 21 489 242 84 516
Function coverage date bins:
(240..) days: 45.9 % 157 72 8 72 8 69

 Age         Owner                  TLA  Line data    Source code
                                  1                 : /*-------------------------------------------------------------------------
                                  2                 :  *
                                  3                 :  * rangetypes.c
                                  4                 :  *    I/O functions, operators, and support functions for range types.
                                  5                 :  *
                                  6                 :  * The stored (serialized) format of a range value is:
                                  7                 :  *
                                  8                 :  *  4 bytes: varlena header
                                  9                 :  *  4 bytes: range type's OID
                                 10                 :  *  Lower boundary value, if any, aligned according to subtype's typalign
                                 11                 :  *  Upper boundary value, if any, aligned according to subtype's typalign
                                 12                 :  *  1 byte for flags
                                 13                 :  *
                                 14                 :  * This representation is chosen to avoid needing any padding before the
                                 15                 :  * lower boundary value, even when it requires double alignment.  We can
                                 16                 :  * expect that the varlena header is presented to us on a suitably aligned
                                 17                 :  * boundary (possibly after detoasting), and then the lower boundary is too.
                                 18                 :  * Note that this means we can't work with a packed (short varlena header)
                                 19                 :  * value; we must detoast it first.
                                 20                 :  *
                                 21                 :  *
                                 22                 :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
                                 23                 :  * Portions Copyright (c) 1994, Regents of the University of California
                                 24                 :  *
                                 25                 :  *
                                 26                 :  * IDENTIFICATION
                                 27                 :  *    src/backend/utils/adt/rangetypes.c
                                 28                 :  *
                                 29                 :  *-------------------------------------------------------------------------
                                 30                 :  */
                                 31                 : #include "postgres.h"
                                 32                 : 
                                 33                 : #include "access/tupmacs.h"
                                 34                 : #include "common/hashfn.h"
                                 35                 : #include "lib/stringinfo.h"
                                 36                 : #include "libpq/pqformat.h"
                                 37                 : #include "miscadmin.h"
                                 38                 : #include "nodes/miscnodes.h"
                                 39                 : #include "port/pg_bitutils.h"
                                 40                 : #include "utils/builtins.h"
                                 41                 : #include "utils/date.h"
                                 42                 : #include "utils/lsyscache.h"
                                 43                 : #include "utils/rangetypes.h"
                                 44                 : #include "utils/timestamp.h"
                                 45                 : #include "varatt.h"
                                 46                 : 
                                 47                 : 
                                 48                 : /* fn_extra cache entry for one of the range I/O functions */
                                 49                 : typedef struct RangeIOData
                                 50                 : {
                                 51                 :     TypeCacheEntry *typcache;   /* range type's typcache entry */
                                 52                 :     FmgrInfo    typioproc;      /* element type's I/O function */
                                 53                 :     Oid         typioparam;     /* element type's I/O parameter */
                                 54                 : } RangeIOData;
                                 55                 : 
                                 56                 : 
                                 57                 : static RangeIOData *get_range_io_data(FunctionCallInfo fcinfo, Oid rngtypid,
                                 58                 :                                       IOFuncSelector func);
                                 59                 : static char range_parse_flags(const char *flags_str);
                                 60                 : static bool range_parse(const char *string, char *flags, char **lbound_str,
                                 61                 :                         char **ubound_str, Node *escontext);
                                 62                 : static const char *range_parse_bound(const char *string, const char *ptr,
                                 63                 :                                      char **bound_str, bool *infinite,
                                 64                 :                                      Node *escontext);
                                 65                 : static char *range_deparse(char flags, const char *lbound_str,
                                 66                 :                            const char *ubound_str);
                                 67                 : static char *range_bound_escape(const char *value);
                                 68                 : static Size datum_compute_size(Size data_length, Datum val, bool typbyval,
                                 69                 :                                char typalign, int16 typlen, char typstorage);
                                 70                 : static Pointer datum_write(Pointer ptr, Datum datum, bool typbyval,
                                 71                 :                            char typalign, int16 typlen, char typstorage);
                                 72                 : 
                                 73                 : 
                                 74                 : /*
                                 75                 :  *----------------------------------------------------------
                                 76                 :  * I/O FUNCTIONS
                                 77                 :  *----------------------------------------------------------
                                 78                 :  */
                                 79                 : 
                                 80                 : Datum
 4175 heikki.linnakangas         81 GIC        1471 : range_in(PG_FUNCTION_ARGS)
                                 82                 : {
 4164 bruce                      83            1471 :     char       *input_str = PG_GETARG_CSTRING(0);
 4164 bruce                      84 CBC        1471 :     Oid         rngtypoid = PG_GETARG_OID(1);
 4164 bruce                      85 GIC        1471 :     Oid         typmod = PG_GETARG_INT32(2);
  115 tgl                        86 GNC        1471 :     Node       *escontext = fcinfo->context;
 4163 tgl                        87 ECB             :     RangeType  *range;
                                 88                 :     RangeIOData *cache;
 4164                            89                 :     char        flags;
      bruce                      90                 :     char       *lbound_str;
                                 91                 :     char       *ubound_str;
                                 92                 :     RangeBound  lower;
                                 93                 :     RangeBound  upper;
                                 94                 : 
 2743 noah                       95 GIC        1471 :     check_stack_depth();        /* recurses when subtype is a range type */
                                 96                 : 
 4163 tgl                        97            1471 :     cache = get_range_io_data(fcinfo, rngtypoid, IOFunc_input);
                                 98                 : 
 4175 heikki.linnakangas         99 ECB             :     /* parse */
  115 tgl                       100 GNC        1471 :     if (!range_parse(input_str, &flags, &lbound_str, &ubound_str, escontext))
                                101               6 :         PG_RETURN_NULL();
 4175 heikki.linnakangas        102 ECB             : 
                                103                 :     /* call element type's input function */
 4175 heikki.linnakangas        104 GIC        1429 :     if (RANGE_HAS_LBOUND(flags))
  115 tgl                       105 GNC        1096 :         if (!InputFunctionCallSafe(&cache->typioproc, lbound_str,
                                106                 :                                    cache->typioparam, typmod,
                                107                 :                                    escontext, &lower.val))
  115 tgl                       108 UNC           0 :             PG_RETURN_NULL();
 4175 heikki.linnakangas        109 GIC        1429 :     if (RANGE_HAS_UBOUND(flags))
  115 tgl                       110 GNC        1048 :         if (!InputFunctionCallSafe(&cache->typioproc, ubound_str,
                                111                 :                                    cache->typioparam, typmod,
                                112                 :                                    escontext, &upper.val))
                                113              12 :             PG_RETURN_NULL();
 4175 heikki.linnakangas        114 ECB             : 
 4163 tgl                       115 GIC        1417 :     lower.infinite = (flags & RANGE_LB_INF) != 0;
                                116            1417 :     lower.inclusive = (flags & RANGE_LB_INC) != 0;
 4163 tgl                       117 GBC        1417 :     lower.lower = true;
 4163 tgl                       118 CBC        1417 :     upper.infinite = (flags & RANGE_UB_INF) != 0;
                                119            1417 :     upper.inclusive = (flags & RANGE_UB_INC) != 0;
 4163 tgl                       120 GIC        1417 :     upper.lower = false;
                                121                 : 
 4175 heikki.linnakangas        122 ECB             :     /* serialize and canonicalize */
  115 tgl                       123 GNC        1417 :     range = make_range(cache->typcache, &lower, &upper,
                                124            1417 :                        flags & RANGE_EMPTY, escontext);
 4175 heikki.linnakangas        125 ECB             : 
 2029 tgl                       126 CBC        1408 :     PG_RETURN_RANGE_P(range);
 4175 heikki.linnakangas        127 ECB             : }
                                128                 : 
                                129                 : Datum
 4175 heikki.linnakangas        130 CBC       52061 : range_out(PG_FUNCTION_ARGS)
                                131                 : {
 2029 tgl                       132 GIC       52061 :     RangeType  *range = PG_GETARG_RANGE_P(0);
 4164 tgl                       133 ECB             :     char       *output_str;
 4163                           134                 :     RangeIOData *cache;
                                135                 :     char        flags;
 4175 heikki.linnakangas        136 CBC       52061 :     char       *lbound_str = NULL;
 4175 heikki.linnakangas        137 GIC       52061 :     char       *ubound_str = NULL;
                                138                 :     RangeBound  lower;
                                139                 :     RangeBound  upper;
 4163 tgl                       140 ECB             :     bool        empty;
                                141                 : 
 2743 noah                      142 CBC       52061 :     check_stack_depth();        /* recurses when subtype is a range type */
                                143                 : 
 4163 tgl                       144 GIC       52061 :     cache = get_range_io_data(fcinfo, RangeTypeGetOid(range), IOFunc_output);
                                145                 : 
 4163 tgl                       146 ECB             :     /* deserialize */
 4163 tgl                       147 CBC       52061 :     range_deserialize(cache->typcache, range, &lower, &upper, &empty);
 4163 tgl                       148 GIC       52061 :     flags = range_get_flags(range);
                                149                 : 
                                150                 :     /* call element type's output function */
 4175 heikki.linnakangas        151           52061 :     if (RANGE_HAS_LBOUND(flags))
 1130 alvherre                  152 CBC       42382 :         lbound_str = OutputFunctionCall(&cache->typioproc, lower.val);
 4175 heikki.linnakangas        153 GIC       52061 :     if (RANGE_HAS_UBOUND(flags))
 1130 alvherre                  154 CBC       42349 :         ubound_str = OutputFunctionCall(&cache->typioproc, upper.val);
                                155                 : 
                                156                 :     /* construct result string */
 4175 heikki.linnakangas        157           52061 :     output_str = range_deparse(flags, lbound_str, ubound_str);
 4175 heikki.linnakangas        158 ECB             : 
 4175 heikki.linnakangas        159 GIC       52061 :     PG_RETURN_CSTRING(output_str);
                                160                 : }
 4175 heikki.linnakangas        161 ECB             : 
                                162                 : /*
 4163 tgl                       163                 :  * Binary representation: The first byte is the flags, then the lower bound
                                164                 :  * (if present), then the upper bound (if present).  Each bound is represented
                                165                 :  * by a 4-byte length header and the binary representation of that bound (as
                                166                 :  * returned by a call to the send function for the subtype).
 4175 heikki.linnakangas        167                 :  */
                                168                 : 
                                169                 : Datum
 4175 heikki.linnakangas        170 UIC           0 : range_recv(PG_FUNCTION_ARGS)
                                171                 : {
 4164 bruce                     172               0 :     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
 4163 tgl                       173               0 :     Oid         rngtypoid = PG_GETARG_OID(1);
 4164 bruce                     174               0 :     int32       typmod = PG_GETARG_INT32(2);
                                175                 :     RangeType  *range;
                                176                 :     RangeIOData *cache;
                                177                 :     char        flags;
                                178                 :     RangeBound  lower;
                                179                 :     RangeBound  upper;
 4175 heikki.linnakangas        180 EUB             : 
 2743 noah                      181 UIC           0 :     check_stack_depth();        /* recurses when subtype is a range type */
 2743 noah                      182 EUB             : 
 4163 tgl                       183 UBC           0 :     cache = get_range_io_data(fcinfo, rngtypoid, IOFunc_receive);
 4175 heikki.linnakangas        184 EUB             : 
                                185                 :     /* receive the flags... */
 4163 tgl                       186 UIC           0 :     flags = (unsigned char) pq_getmsgbyte(buf);
                                187                 : 
                                188                 :     /*
                                189                 :      * Mask out any unsupported flags, particularly RANGE_xB_NULL which would
                                190                 :      * confuse following tests.  Note that range_serialize will take care of
 4156 tgl                       191 EUB             :      * cleaning up any inconsistencies in the remaining flags.
                                192                 :      */
 4163 tgl                       193 UBC           0 :     flags &= (RANGE_EMPTY |
                                194                 :               RANGE_LB_INC |
                                195                 :               RANGE_LB_INF |
 4163 tgl                       196 EUB             :               RANGE_UB_INC |
                                197                 :               RANGE_UB_INF);
                                198                 : 
                                199                 :     /* receive the bounds ... */
 4175 heikki.linnakangas        200 UIC           0 :     if (RANGE_HAS_LBOUND(flags))
                                201                 :     {
 4164 bruce                     202               0 :         uint32      bound_len = pq_getmsgint(buf, 4);
 4164 bruce                     203 UBC           0 :         const char *bound_data = pq_getmsgbytes(buf, bound_len);
                                204                 :         StringInfoData bound_buf;
                                205                 : 
 4175 heikki.linnakangas        206 UIC           0 :         initStringInfo(&bound_buf);
                                207               0 :         appendBinaryStringInfo(&bound_buf, bound_data, bound_len);
                                208                 : 
 1130 alvherre                  209               0 :         lower.val = ReceiveFunctionCall(&cache->typioproc,
 4163 tgl                       210 EUB             :                                         &bound_buf,
                                211                 :                                         cache->typioparam,
                                212                 :                                         typmod);
 4175 heikki.linnakangas        213 UBC           0 :         pfree(bound_buf.data);
                                214                 :     }
                                215                 :     else
                                216               0 :         lower.val = (Datum) 0;
 4175 heikki.linnakangas        217 EUB             : 
 4175 heikki.linnakangas        218 UIC           0 :     if (RANGE_HAS_UBOUND(flags))
 4175 heikki.linnakangas        219 EUB             :     {
 4164 bruce                     220 UIC           0 :         uint32      bound_len = pq_getmsgint(buf, 4);
                                221               0 :         const char *bound_data = pq_getmsgbytes(buf, bound_len);
                                222                 :         StringInfoData bound_buf;
 4175 heikki.linnakangas        223 EUB             : 
 4175 heikki.linnakangas        224 UIC           0 :         initStringInfo(&bound_buf);
                                225               0 :         appendBinaryStringInfo(&bound_buf, bound_data, bound_len);
 4175 heikki.linnakangas        226 EUB             : 
 1130 alvherre                  227 UIC           0 :         upper.val = ReceiveFunctionCall(&cache->typioproc,
 4163 tgl                       228 EUB             :                                         &bound_buf,
                                229                 :                                         cache->typioparam,
                                230                 :                                         typmod);
 4175 heikki.linnakangas        231 UBC           0 :         pfree(bound_buf.data);
                                232                 :     }
                                233                 :     else
                                234               0 :         upper.val = (Datum) 0;
 4175 heikki.linnakangas        235 EUB             : 
 4175 heikki.linnakangas        236 UIC           0 :     pq_getmsgend(buf);
 4175 heikki.linnakangas        237 EUB             : 
                                238                 :     /* finish constructing RangeBound representation */
 4164 bruce                     239 UIC           0 :     lower.infinite = (flags & RANGE_LB_INF) != 0;
 4175 heikki.linnakangas        240               0 :     lower.inclusive = (flags & RANGE_LB_INC) != 0;
 4164 bruce                     241 UBC           0 :     lower.lower = true;
 4164 bruce                     242 UIC           0 :     upper.infinite = (flags & RANGE_UB_INF) != 0;
 4175 heikki.linnakangas        243               0 :     upper.inclusive = (flags & RANGE_UB_INC) != 0;
 4164 bruce                     244 UBC           0 :     upper.lower = false;
                                245                 : 
 4175 heikki.linnakangas        246 EUB             :     /* serialize and canonicalize */
  115 tgl                       247 UNC           0 :     range = make_range(cache->typcache, &lower, &upper,
                                248               0 :                        flags & RANGE_EMPTY, NULL);
                                249                 : 
 2029 tgl                       250 UBC           0 :     PG_RETURN_RANGE_P(range);
 4175 heikki.linnakangas        251 EUB             : }
                                252                 : 
                                253                 : Datum
 4175 heikki.linnakangas        254 UBC           0 : range_send(PG_FUNCTION_ARGS)
 4175 heikki.linnakangas        255 EUB             : {
 2029 tgl                       256 UIC           0 :     RangeType  *range = PG_GETARG_RANGE_P(0);
 4164 bruce                     257               0 :     StringInfo  buf = makeStringInfo();
 4163 tgl                       258 EUB             :     RangeIOData *cache;
                                259                 :     char        flags;
                                260                 :     RangeBound  lower;
 4164 bruce                     261                 :     RangeBound  upper;
                                262                 :     bool        empty;
                                263                 : 
 2743 noah                      264 UIC           0 :     check_stack_depth();        /* recurses when subtype is a range type */
 2743 noah                      265 EUB             : 
 4163 tgl                       266 UIC           0 :     cache = get_range_io_data(fcinfo, RangeTypeGetOid(range), IOFunc_send);
 4163 tgl                       267 EUB             : 
                                268                 :     /* deserialize */
 4163 tgl                       269 UIC           0 :     range_deserialize(cache->typcache, range, &lower, &upper, &empty);
                                270               0 :     flags = range_get_flags(range);
                                271                 : 
                                272                 :     /* construct output */
 4175 heikki.linnakangas        273               0 :     pq_begintypsend(buf);
                                274                 : 
 4175 heikki.linnakangas        275 UBC           0 :     pq_sendbyte(buf, flags);
                                276                 : 
                                277               0 :     if (RANGE_HAS_LBOUND(flags))
                                278                 :     {
 1130 alvherre                  279 UIC           0 :         Datum       bound = PointerGetDatum(SendFunctionCall(&cache->typioproc,
 4163 tgl                       280 EUB             :                                                              lower.val));
 4164 bruce                     281 UBC           0 :         uint32      bound_len = VARSIZE(bound) - VARHDRSZ;
 4164 bruce                     282 UIC           0 :         char       *bound_data = VARDATA(bound);
                                283                 : 
 2006 andres                    284 UBC           0 :         pq_sendint32(buf, bound_len);
 4175 heikki.linnakangas        285 UIC           0 :         pq_sendbytes(buf, bound_data, bound_len);
 4175 heikki.linnakangas        286 EUB             :     }
                                287                 : 
 4175 heikki.linnakangas        288 UBC           0 :     if (RANGE_HAS_UBOUND(flags))
                                289                 :     {
 1130 alvherre                  290               0 :         Datum       bound = PointerGetDatum(SendFunctionCall(&cache->typioproc,
                                291                 :                                                              upper.val));
 4164 bruce                     292               0 :         uint32      bound_len = VARSIZE(bound) - VARHDRSZ;
                                293               0 :         char       *bound_data = VARDATA(bound);
                                294                 : 
 2006 andres                    295               0 :         pq_sendint32(buf, bound_len);
 4175 heikki.linnakangas        296               0 :         pq_sendbytes(buf, bound_data, bound_len);
                                297                 :     }
                                298                 : 
                                299               0 :     PG_RETURN_BYTEA_P(pq_endtypsend(buf));
                                300                 : }
 4175 heikki.linnakangas        301 EUB             : 
                                302                 : /*
 4163 tgl                       303                 :  * get_range_io_data: get cached information needed for range type I/O
                                304                 :  *
                                305                 :  * The range I/O functions need a bit more cached info than other range
                                306                 :  * functions, so they store a RangeIOData struct in fn_extra, not just a
                                307                 :  * pointer to a type cache entry.
                                308                 :  */
                                309                 : static RangeIOData *
 4163 tgl                       310 GBC       53532 : get_range_io_data(FunctionCallInfo fcinfo, Oid rngtypid, IOFuncSelector func)
                                311                 : {
 4163 tgl                       312 GIC       53532 :     RangeIOData *cache = (RangeIOData *) fcinfo->flinfo->fn_extra;
                                313                 : 
                                314           53532 :     if (cache == NULL || cache->typcache->type_id != rngtypid)
                                315                 :     {
                                316                 :         int16       typlen;
                                317                 :         bool        typbyval;
                                318                 :         char        typalign;
                                319                 :         char        typdelim;
                                320                 :         Oid         typiofunc;
 4163 tgl                       321 ECB             : 
 4163 tgl                       322 GIC        2298 :         cache = (RangeIOData *) MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
 4163 tgl                       323 ECB             :                                                    sizeof(RangeIOData));
 4163 tgl                       324 GIC        2298 :         cache->typcache = lookup_type_cache(rngtypid, TYPECACHE_RANGE_INFO);
 4163 tgl                       325 CBC        2298 :         if (cache->typcache->rngelemtype == NULL)
 4163 tgl                       326 UIC           0 :             elog(ERROR, "type %u is not a range type", rngtypid);
                                327                 : 
                                328                 :         /* get_type_io_data does more than we need, but is convenient */
 4163 tgl                       329 GIC        2298 :         get_type_io_data(cache->typcache->rngelemtype->type_id,
                                330                 :                          func,
                                331                 :                          &typlen,
                                332                 :                          &typbyval,
 4163 tgl                       333 ECB             :                          &typalign,
                                334                 :                          &typdelim,
                                335                 :                          &cache->typioparam,
 1130 alvherre                  336                 :                          &typiofunc);
 4163 tgl                       337 EUB             : 
 1130 alvherre                  338 GIC        2298 :         if (!OidIsValid(typiofunc))
                                339                 :         {
 4163 tgl                       340 ECB             :             /* this could only happen for receive or send */
 4163 tgl                       341 UIC           0 :             if (func == IOFunc_receive)
                                342               0 :                 ereport(ERROR,
                                343                 :                         (errcode(ERRCODE_UNDEFINED_FUNCTION),
                                344                 :                          errmsg("no binary input function available for type %s",
                                345                 :                                 format_type_be(cache->typcache->rngelemtype->type_id))));
                                346                 :             else
                                347               0 :                 ereport(ERROR,
                                348                 :                         (errcode(ERRCODE_UNDEFINED_FUNCTION),
 2118 tgl                       349 ECB             :                          errmsg("no binary output function available for type %s",
                                350                 :                                 format_type_be(cache->typcache->rngelemtype->type_id))));
                                351                 :         }
 1130 alvherre                  352 GBC        2298 :         fmgr_info_cxt(typiofunc, &cache->typioproc,
 4163 tgl                       353            2298 :                       fcinfo->flinfo->fn_mcxt);
                                354                 : 
 4163 tgl                       355 GIC        2298 :         fcinfo->flinfo->fn_extra = (void *) cache;
                                356                 :     }
                                357                 : 
 4163 tgl                       358 GBC       53532 :     return cache;
                                359                 : }
                                360                 : 
                                361                 : 
                                362                 : /*
 4175 heikki.linnakangas        363 ECB             :  *----------------------------------------------------------
                                364                 :  * GENERIC FUNCTIONS
                                365                 :  *----------------------------------------------------------
                                366                 :  */
                                367                 : 
                                368                 : /* Construct standard-form range value from two arguments */
                                369                 : Datum
 4175 heikki.linnakangas        370 GIC       53973 : range_constructor2(PG_FUNCTION_ARGS)
                                371                 : {
 4164 bruce                     372           53973 :     Datum       arg1 = PG_GETARG_DATUM(0);
                                373           53973 :     Datum       arg2 = PG_GETARG_DATUM(1);
                                374           53973 :     Oid         rngtypid = get_fn_expr_rettype(fcinfo->flinfo);
                                375                 :     RangeType  *range;
                                376                 :     TypeCacheEntry *typcache;
                                377                 :     RangeBound  lower;
                                378                 :     RangeBound  upper;
                                379                 : 
 4163 tgl                       380           53973 :     typcache = range_get_typcache(fcinfo, rngtypid);
 4163 tgl                       381 ECB             : 
 4164 bruce                     382 GIC       53973 :     lower.val = PG_ARGISNULL(0) ? (Datum) 0 : arg1;
 4164 bruce                     383 CBC       53973 :     lower.infinite = PG_ARGISNULL(0);
 4163 tgl                       384           53973 :     lower.inclusive = true;
 4164 bruce                     385           53973 :     lower.lower = true;
                                386                 : 
 4164 bruce                     387 GIC       53973 :     upper.val = PG_ARGISNULL(1) ? (Datum) 0 : arg2;
                                388           53973 :     upper.infinite = PG_ARGISNULL(1);
 4163 tgl                       389           53973 :     upper.inclusive = false;
 4164 bruce                     390           53973 :     upper.lower = false;
 4175 heikki.linnakangas        391 ECB             : 
  115 tgl                       392 GNC       53973 :     range = make_range(typcache, &lower, &upper, false, NULL);
 4175 heikki.linnakangas        393 ECB             : 
 2029 tgl                       394 CBC       53955 :     PG_RETURN_RANGE_P(range);
 4175 heikki.linnakangas        395 ECB             : }
                                396                 : 
                                397                 : /* Construct general range value from three arguments */
                                398                 : Datum
 4175 heikki.linnakangas        399 CBC        2559 : range_constructor3(PG_FUNCTION_ARGS)
 4175 heikki.linnakangas        400 ECB             : {
 4164 bruce                     401 CBC        2559 :     Datum       arg1 = PG_GETARG_DATUM(0);
 4164 bruce                     402 GIC        2559 :     Datum       arg2 = PG_GETARG_DATUM(1);
 4164 bruce                     403 CBC        2559 :     Oid         rngtypid = get_fn_expr_rettype(fcinfo->flinfo);
                                404                 :     RangeType  *range;
 4163 tgl                       405 ECB             :     TypeCacheEntry *typcache;
                                406                 :     RangeBound  lower;
                                407                 :     RangeBound  upper;
                                408                 :     char        flags;
                                409                 : 
 4163 tgl                       410 CBC        2559 :     typcache = range_get_typcache(fcinfo, rngtypid);
                                411                 : 
 4175 heikki.linnakangas        412            2559 :     if (PG_ARGISNULL(2))
 4175 heikki.linnakangas        413 LBC           0 :         ereport(ERROR,
 4175 heikki.linnakangas        414 ECB             :                 (errcode(ERRCODE_DATA_EXCEPTION),
                                415                 :                  errmsg("range constructor flags argument must not be null")));
                                416                 : 
 2219 noah                      417 GIC        2559 :     flags = range_parse_flags(text_to_cstring(PG_GETARG_TEXT_PP(2)));
                                418                 : 
 4164 bruce                     419            2559 :     lower.val = PG_ARGISNULL(0) ? (Datum) 0 : arg1;
                                420            2559 :     lower.infinite = PG_ARGISNULL(0);
 4163 tgl                       421 CBC        2559 :     lower.inclusive = (flags & RANGE_LB_INC) != 0;
 4164 bruce                     422 GIC        2559 :     lower.lower = true;
 4175 heikki.linnakangas        423 ECB             : 
 4164 bruce                     424 GBC        2559 :     upper.val = PG_ARGISNULL(1) ? (Datum) 0 : arg2;
 4164 bruce                     425 GIC        2559 :     upper.infinite = PG_ARGISNULL(1);
 4163 tgl                       426            2559 :     upper.inclusive = (flags & RANGE_UB_INC) != 0;
 4164 bruce                     427            2559 :     upper.lower = false;
 4175 heikki.linnakangas        428 ECB             : 
  115 tgl                       429 GNC        2559 :     range = make_range(typcache, &lower, &upper, false, NULL);
 4175 heikki.linnakangas        430 ECB             : 
 2029 tgl                       431 CBC        2559 :     PG_RETURN_RANGE_P(range);
 4175 heikki.linnakangas        432 ECB             : }
                                433                 : 
                                434                 : 
 4156 tgl                       435                 : /* range -> subtype functions */
                                436                 : 
                                437                 : /* extract lower bound value */
 4175 heikki.linnakangas        438                 : Datum
 4175 heikki.linnakangas        439 GIC         120 : range_lower(PG_FUNCTION_ARGS)
 4175 heikki.linnakangas        440 ECB             : {
 2029 tgl                       441 GIC         120 :     RangeType  *r1 = PG_GETARG_RANGE_P(0);
 4163 tgl                       442 ECB             :     TypeCacheEntry *typcache;
                                443                 :     RangeBound  lower;
                                444                 :     RangeBound  upper;
                                445                 :     bool        empty;
                                446                 : 
 4163 tgl                       447 GIC         120 :     typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
                                448                 : 
                                449             120 :     range_deserialize(typcache, r1, &lower, &upper, &empty);
 4175 heikki.linnakangas        450 ECB             : 
                                451                 :     /* Return NULL if there's no finite lower bound */
 4164 tgl                       452 CBC         120 :     if (empty || lower.infinite)
 4164 tgl                       453 GIC          18 :         PG_RETURN_NULL();
                                454                 : 
 4175 heikki.linnakangas        455             102 :     PG_RETURN_DATUM(lower.val);
                                456                 : }
                                457                 : 
 4156 tgl                       458 ECB             : /* extract upper bound value */
                                459                 : Datum
 4175 heikki.linnakangas        460 CBC         114 : range_upper(PG_FUNCTION_ARGS)
                                461                 : {
 2029 tgl                       462 GIC         114 :     RangeType  *r1 = PG_GETARG_RANGE_P(0);
 4163 tgl                       463 ECB             :     TypeCacheEntry *typcache;
 4164 bruce                     464                 :     RangeBound  lower;
                                465                 :     RangeBound  upper;
                                466                 :     bool        empty;
                                467                 : 
 4163 tgl                       468 GIC         114 :     typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
                                469                 : 
                                470             114 :     range_deserialize(typcache, r1, &lower, &upper, &empty);
 4175 heikki.linnakangas        471 ECB             : 
                                472                 :     /* Return NULL if there's no finite upper bound */
 4164 tgl                       473 CBC         114 :     if (empty || upper.infinite)
 4164 tgl                       474 GIC          18 :         PG_RETURN_NULL();
                                475                 : 
 4175 heikki.linnakangas        476              96 :     PG_RETURN_DATUM(upper.val);
                                477                 : }
                                478                 : 
 4175 heikki.linnakangas        479 ECB             : 
                                480                 : /* range -> bool functions */
 4156 tgl                       481                 : 
                                482                 : /* is range empty? */
                                483                 : Datum
 4175 heikki.linnakangas        484 CBC        1098 : range_empty(PG_FUNCTION_ARGS)
 4175 heikki.linnakangas        485 ECB             : {
 2029 tgl                       486 GIC        1098 :     RangeType  *r1 = PG_GETARG_RANGE_P(0);
 4163 tgl                       487 CBC        1098 :     char        flags = range_get_flags(r1);
                                488                 : 
 4163 tgl                       489 GIC        1098 :     PG_RETURN_BOOL(flags & RANGE_EMPTY);
                                490                 : }
                                491                 : 
                                492                 : /* is lower bound inclusive? */
                                493                 : Datum
 4175 heikki.linnakangas        494              36 : range_lower_inc(PG_FUNCTION_ARGS)
 4175 heikki.linnakangas        495 ECB             : {
 2029 tgl                       496 GIC          36 :     RangeType  *r1 = PG_GETARG_RANGE_P(0);
 4163 tgl                       497 CBC          36 :     char        flags = range_get_flags(r1);
 4175 heikki.linnakangas        498 ECB             : 
 4163 tgl                       499 GIC          36 :     PG_RETURN_BOOL(flags & RANGE_LB_INC);
 4175 heikki.linnakangas        500 ECB             : }
                                501                 : 
                                502                 : /* is upper bound inclusive? */
                                503                 : Datum
 4175 heikki.linnakangas        504 GIC          36 : range_upper_inc(PG_FUNCTION_ARGS)
 4175 heikki.linnakangas        505 ECB             : {
 2029 tgl                       506 GIC          36 :     RangeType  *r1 = PG_GETARG_RANGE_P(0);
 4163 tgl                       507 CBC          36 :     char        flags = range_get_flags(r1);
 4175 heikki.linnakangas        508 ECB             : 
 4163 tgl                       509 GIC          36 :     PG_RETURN_BOOL(flags & RANGE_UB_INC);
 4175 heikki.linnakangas        510 ECB             : }
                                511                 : 
                                512                 : /* is lower bound infinite? */
                                513                 : Datum
 4175 heikki.linnakangas        514 GIC          36 : range_lower_inf(PG_FUNCTION_ARGS)
 4175 heikki.linnakangas        515 ECB             : {
 2029 tgl                       516 GIC          36 :     RangeType  *r1 = PG_GETARG_RANGE_P(0);
 4163 tgl                       517 CBC          36 :     char        flags = range_get_flags(r1);
 4175 heikki.linnakangas        518 ECB             : 
 4163 tgl                       519 GIC          36 :     PG_RETURN_BOOL(flags & RANGE_LB_INF);
 4175 heikki.linnakangas        520 ECB             : }
                                521                 : 
                                522                 : /* is upper bound infinite? */
                                523                 : Datum
 4175 heikki.linnakangas        524 GIC          36 : range_upper_inf(PG_FUNCTION_ARGS)
 4175 heikki.linnakangas        525 ECB             : {
 2029 tgl                       526 GIC          36 :     RangeType  *r1 = PG_GETARG_RANGE_P(0);
 4163 tgl                       527 CBC          36 :     char        flags = range_get_flags(r1);
 4175 heikki.linnakangas        528 ECB             : 
 4163 tgl                       529 GIC          36 :     PG_RETURN_BOOL(flags & RANGE_UB_INF);
 4175 heikki.linnakangas        530 ECB             : }
                                531                 : 
                                532                 : 
                                533                 : /* range, element -> bool functions */
                                534                 : 
 4156 tgl                       535                 : /* contains? */
                                536                 : Datum
 4156 tgl                       537 CBC       38019 : range_contains_elem(PG_FUNCTION_ARGS)
 4156 tgl                       538 ECB             : {
 2029 tgl                       539 GIC       38019 :     RangeType  *r = PG_GETARG_RANGE_P(0);
 4156 tgl                       540 CBC       38019 :     Datum       val = PG_GETARG_DATUM(1);
                                541                 :     TypeCacheEntry *typcache;
                                542                 : 
 4156 tgl                       543 GIC       38019 :     typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r));
                                544                 : 
                                545           38019 :     PG_RETURN_BOOL(range_contains_elem_internal(typcache, r, val));
                                546                 : }
                                547                 : 
 4156 tgl                       548 ECB             : /* contained by? */
                                549                 : Datum
 4156 tgl                       550 CBC         342 : elem_contained_by_range(PG_FUNCTION_ARGS)
 4156 tgl                       551 ECB             : {
 4156 tgl                       552 GIC         342 :     Datum       val = PG_GETARG_DATUM(0);
 2029                           553             342 :     RangeType  *r = PG_GETARG_RANGE_P(1);
 4156 tgl                       554 ECB             :     TypeCacheEntry *typcache;
                                555                 : 
 4156 tgl                       556 CBC         342 :     typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r));
                                557                 : 
 4156 tgl                       558 GIC         342 :     PG_RETURN_BOOL(range_contains_elem_internal(typcache, r, val));
                                559                 : }
                                560                 : 
 4156 tgl                       561 ECB             : 
                                562                 : /* range, range -> bool functions */
                                563                 : 
 3917 heikki.linnakangas        564                 : /* equality (internal version) */
                                565                 : bool
 1256 peter                     566 GIC       89394 : range_eq_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
 4175 heikki.linnakangas        567 ECB             : {
                                568                 :     RangeBound  lower1,
 4164 bruce                     569                 :                 lower2;
                                570                 :     RangeBound  upper1,
                                571                 :                 upper2;
                                572                 :     bool        empty1,
                                573                 :                 empty2;
                                574                 : 
                                575                 :     /* Different types should be prevented by ANYRANGE matching rules */
 4163 tgl                       576 GIC       89394 :     if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
 4175 heikki.linnakangas        577 LBC           0 :         elog(ERROR, "range types do not match");
                                578                 : 
 4163 tgl                       579 GIC       89394 :     range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
                                580           89394 :     range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
                                581                 : 
 4175 heikki.linnakangas        582           89394 :     if (empty1 && empty2)
 3917                           583            6231 :         return true;
 4175                           584           83163 :     if (empty1 != empty2)
 3917                           585            6756 :         return false;
                                586                 : 
 4163 tgl                       587 CBC       76407 :     if (range_cmp_bounds(typcache, &lower1, &lower2) != 0)
 3917 heikki.linnakangas        588 GBC       36252 :         return false;
                                589                 : 
 4163 tgl                       590 CBC       40155 :     if (range_cmp_bounds(typcache, &upper1, &upper2) != 0)
 3917 heikki.linnakangas        591           25171 :         return false;
                                592                 : 
                                593           14984 :     return true;
 3917 heikki.linnakangas        594 ECB             : }
 4175                           595                 : 
 3917                           596                 : /* equality */
                                597                 : Datum
 3917 heikki.linnakangas        598 CBC       38622 : range_eq(PG_FUNCTION_ARGS)
 3917 heikki.linnakangas        599 ECB             : {
 2029 tgl                       600 GIC       38622 :     RangeType  *r1 = PG_GETARG_RANGE_P(0);
 2029 tgl                       601 CBC       38622 :     RangeType  *r2 = PG_GETARG_RANGE_P(1);
 3917 heikki.linnakangas        602 ECB             :     TypeCacheEntry *typcache;
                                603                 : 
 3917 heikki.linnakangas        604 CBC       38622 :     typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
                                605                 : 
 3917 heikki.linnakangas        606 GIC       38622 :     PG_RETURN_BOOL(range_eq_internal(typcache, r1, r2));
                                607                 : }
                                608                 : 
 3917 heikki.linnakangas        609 ECB             : /* inequality (internal version) */
                                610                 : bool
 1256 peter                     611 LBC           0 : range_ne_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
 3917 heikki.linnakangas        612 ECB             : {
 3917 heikki.linnakangas        613 UIC           0 :     return (!range_eq_internal(typcache, r1, r2));
                                614                 : }
 4175 heikki.linnakangas        615 ECB             : 
                                616                 : /* inequality */
                                617                 : Datum
 4175 heikki.linnakangas        618 UIC           0 : range_ne(PG_FUNCTION_ARGS)
                                619                 : {
 2029 tgl                       620               0 :     RangeType  *r1 = PG_GETARG_RANGE_P(0);
                                621               0 :     RangeType  *r2 = PG_GETARG_RANGE_P(1);
 3917 heikki.linnakangas        622 EUB             :     TypeCacheEntry *typcache;
                                623                 : 
 3917 heikki.linnakangas        624 UBC           0 :     typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
                                625                 : 
 3917 heikki.linnakangas        626 UIC           0 :     PG_RETURN_BOOL(range_ne_internal(typcache, r1, r2));
                                627                 : }
                                628                 : 
 4156 tgl                       629 EUB             : /* contains? */
                                630                 : Datum
 4175 heikki.linnakangas        631 GBC       77235 : range_contains(PG_FUNCTION_ARGS)
 4175 heikki.linnakangas        632 EUB             : {
 2029 tgl                       633 GIC       77235 :     RangeType  *r1 = PG_GETARG_RANGE_P(0);
                                634           77235 :     RangeType  *r2 = PG_GETARG_RANGE_P(1);
 4163 tgl                       635 EUB             :     TypeCacheEntry *typcache;
                                636                 : 
 4163 tgl                       637 GBC       77235 :     typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
                                638                 : 
 4163 tgl                       639 GIC       77235 :     PG_RETURN_BOOL(range_contains_internal(typcache, r1, r2));
                                640                 : }
                                641                 : 
 4156 tgl                       642 ECB             : /* contained by? */
                                643                 : Datum
 4175 heikki.linnakangas        644 CBC       38454 : range_contained_by(PG_FUNCTION_ARGS)
 4175 heikki.linnakangas        645 ECB             : {
 2029 tgl                       646 GIC       38454 :     RangeType  *r1 = PG_GETARG_RANGE_P(0);
                                647           38454 :     RangeType  *r2 = PG_GETARG_RANGE_P(1);
 4163 tgl                       648 ECB             :     TypeCacheEntry *typcache;
                                649                 : 
 4163 tgl                       650 CBC       38454 :     typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
                                651                 : 
 3917 heikki.linnakangas        652 GIC       38454 :     PG_RETURN_BOOL(range_contained_by_internal(typcache, r1, r2));
                                653                 : }
                                654                 : 
 3917 heikki.linnakangas        655 ECB             : /* strictly left of? (internal version) */
                                656                 : bool
 1256 peter                     657 CBC       62944 : range_before_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
 4175 heikki.linnakangas        658 ECB             : {
                                659                 :     RangeBound  lower1,
                                660                 :                 lower2;
 4164 bruce                     661                 :     RangeBound  upper1,
                                662                 :                 upper2;
                                663                 :     bool        empty1,
                                664                 :                 empty2;
                                665                 : 
                                666                 :     /* Different types should be prevented by ANYRANGE matching rules */
 4163 tgl                       667 GIC       62944 :     if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
 4175 heikki.linnakangas        668 LBC           0 :         elog(ERROR, "range types do not match");
                                669                 : 
 4163 tgl                       670 GIC       62944 :     range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
                                671           62944 :     range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
                                672                 : 
                                673                 :     /* An empty range is neither before nor after any other range */
 4175 heikki.linnakangas        674           62944 :     if (empty1 || empty2)
 3917                           675            7455 :         return false;
                                676                 : 
                                677           55489 :     return (range_cmp_bounds(typcache, &upper1, &lower2) < 0);
 4175 heikki.linnakangas        678 ECB             : }
 4175 heikki.linnakangas        679 EUB             : 
                                680                 : /* strictly left of? */
 4175 heikki.linnakangas        681 ECB             : Datum
 3917 heikki.linnakangas        682 CBC       39459 : range_before(PG_FUNCTION_ARGS)
                                683                 : {
 2029 tgl                       684 GIC       39459 :     RangeType  *r1 = PG_GETARG_RANGE_P(0);
 2029 tgl                       685 CBC       39459 :     RangeType  *r2 = PG_GETARG_RANGE_P(1);
 4163 tgl                       686 ECB             :     TypeCacheEntry *typcache;
                                687                 : 
 3917 heikki.linnakangas        688 CBC       39459 :     typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
                                689                 : 
 3917 heikki.linnakangas        690 GIC       39459 :     PG_RETURN_BOOL(range_before_internal(typcache, r1, r2));
                                691                 : }
                                692                 : 
 3917 heikki.linnakangas        693 ECB             : /* strictly right of? (internal version) */
                                694                 : bool
 1256 peter                     695 CBC       98402 : range_after_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
 3917 heikki.linnakangas        696 ECB             : {
                                697                 :     RangeBound  lower1,
                                698                 :                 lower2;
 4164 bruce                     699                 :     RangeBound  upper1,
                                700                 :                 upper2;
                                701                 :     bool        empty1,
                                702                 :                 empty2;
                                703                 : 
                                704                 :     /* Different types should be prevented by ANYRANGE matching rules */
 4163 tgl                       705 GIC       98402 :     if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
 4175 heikki.linnakangas        706 LBC           0 :         elog(ERROR, "range types do not match");
                                707                 : 
 4163 tgl                       708 GIC       98402 :     range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
                                709           98402 :     range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
                                710                 : 
                                711                 :     /* An empty range is neither before nor after any other range */
 4175 heikki.linnakangas        712           98402 :     if (empty1 || empty2)
 3917                           713            7155 :         return false;
                                714                 : 
                                715           91247 :     return (range_cmp_bounds(typcache, &lower1, &upper2) > 0);
 4175 heikki.linnakangas        716 ECB             : }
 4175 heikki.linnakangas        717 EUB             : 
                                718                 : /* strictly right of? */
 4164 bruce                     719 ECB             : Datum
 3917 heikki.linnakangas        720 CBC       39153 : range_after(PG_FUNCTION_ARGS)
                                721                 : {
 2029 tgl                       722 GIC       39153 :     RangeType  *r1 = PG_GETARG_RANGE_P(0);
 2029 tgl                       723 CBC       39153 :     RangeType  *r2 = PG_GETARG_RANGE_P(1);
 4163 tgl                       724 ECB             :     TypeCacheEntry *typcache;
                                725                 : 
 3917 heikki.linnakangas        726 CBC       39153 :     typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
                                727                 : 
 3917 heikki.linnakangas        728 GIC       39153 :     PG_RETURN_BOOL(range_after_internal(typcache, r1, r2));
                                729                 : }
                                730                 : 
 3684 heikki.linnakangas        731 ECB             : /*
                                732                 :  * Check if two bounds A and B are "adjacent", where A is an upper bound and B
                                733                 :  * is a lower bound. For the bounds to be adjacent, each subtype value must
                                734                 :  * satisfy strictly one of the bounds: there are no values which satisfy both
                                735                 :  * bounds (i.e. less than A and greater than B); and there are no values which
                                736                 :  * satisfy neither bound (i.e. greater than A and less than B).
                                737                 :  *
                                738                 :  * For discrete ranges, we rely on the canonicalization function to see if A..B
                                739                 :  * normalizes to empty. (If there is no canonicalization function, it's
                                740                 :  * impossible for such a range to normalize to empty, so we needn't bother to
                                741                 :  * try.)
                                742                 :  *
                                743                 :  * If A == B, the ranges are adjacent only if the bounds have different
                                744                 :  * inclusive flags (i.e., exactly one of the ranges includes the common
                                745                 :  * boundary point).
                                746                 :  *
                                747                 :  * And if A > B then the ranges are not adjacent in this order.
                                748                 :  */
                                749                 : bool
 3684 heikki.linnakangas        750 GIC      236310 : bounds_adjacent(TypeCacheEntry *typcache, RangeBound boundA, RangeBound boundB)
                                751                 : {
                                752                 :     int         cmp;
                                753                 : 
                                754          236310 :     Assert(!boundA.lower && boundB.lower);
                                755                 : 
                                756          236310 :     cmp = range_cmp_bound_values(typcache, &boundA, &boundB);
                                757          236310 :     if (cmp < 0)
                                758                 :     {
                                759                 :         RangeType  *r;
                                760                 : 
 3684 heikki.linnakangas        761 ECB             :         /*
                                762                 :          * Bounds do not overlap; see if there are points in between.
                                763                 :          */
                                764                 : 
                                765                 :         /* in a continuous subtype, there are assumed to be points between */
 3684 heikki.linnakangas        766 GIC       72527 :         if (!OidIsValid(typcache->rng_canonical_finfo.fn_oid))
 3684 heikki.linnakangas        767 CBC         408 :             return false;
 3684 heikki.linnakangas        768 ECB             : 
                                769                 :         /*
                                770                 :          * The bounds are of a discrete range type; so make a range A..B and
                                771                 :          * see if it's empty.
                                772                 :          */
                                773                 : 
                                774                 :         /* flip the inclusion flags */
 3684 heikki.linnakangas        775 GIC       72119 :         boundA.inclusive = !boundA.inclusive;
                                776           72119 :         boundB.inclusive = !boundB.inclusive;
 3684 heikki.linnakangas        777 ECB             :         /* change upper/lower labels to avoid Assert failures */
 3684 heikki.linnakangas        778 CBC       72119 :         boundA.lower = true;
 3684 heikki.linnakangas        779 GIC       72119 :         boundB.lower = false;
  115 tgl                       780 GNC       72119 :         r = make_range(typcache, &boundA, &boundB, false, NULL);
 3684 heikki.linnakangas        781 GIC       72119 :         return RangeIsEmpty(r);
                                782                 :     }
                                783          163783 :     else if (cmp == 0)
                                784             873 :         return boundA.inclusive != boundB.inclusive;
                                785                 :     else
 3602 bruce                     786 CBC      162910 :         return false;           /* bounds overlap */
 3684 heikki.linnakangas        787 ECB             : }
                                788                 : 
 3917                           789                 : /* adjacent to (but not overlapping)? (internal version) */
                                790                 : bool
 1256 peter                     791 CBC       71402 : range_adjacent_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
 3917 heikki.linnakangas        792 ECB             : {
                                793                 :     RangeBound  lower1,
 4164 bruce                     794                 :                 lower2;
                                795                 :     RangeBound  upper1,
                                796                 :                 upper2;
                                797                 :     bool        empty1,
                                798                 :                 empty2;
                                799                 : 
                                800                 :     /* Different types should be prevented by ANYRANGE matching rules */
 4163 tgl                       801 GIC       71402 :     if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
 4175 heikki.linnakangas        802 LBC           0 :         elog(ERROR, "range types do not match");
                                803                 : 
 4163 tgl                       804 GIC       71402 :     range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
                                805           71402 :     range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
                                806                 : 
                                807                 :     /* An empty range is not adjacent to any other range */
 4175 heikki.linnakangas        808           71402 :     if (empty1 || empty2)
 3917                           809            6000 :         return false;
                                810                 : 
                                811                 :     /*
 3684 heikki.linnakangas        812 ECB             :      * Given two ranges A..B and C..D, the ranges are adjacent if and only if
 3684 heikki.linnakangas        813 EUB             :      * B is adjacent to C, or D is adjacent to A.
                                814                 :      */
 3684 heikki.linnakangas        815 CBC      130123 :     return (bounds_adjacent(typcache, upper1, lower2) ||
                                816           64721 :             bounds_adjacent(typcache, upper2, lower1));
                                817                 : }
                                818                 : 
 3917 heikki.linnakangas        819 ECB             : /* adjacent to (but not overlapping)? */
 4175                           820                 : Datum
 3917 heikki.linnakangas        821 GIC       37218 : range_adjacent(PG_FUNCTION_ARGS)
                                822                 : {
 2029 tgl                       823           37218 :     RangeType  *r1 = PG_GETARG_RANGE_P(0);
                                824           37218 :     RangeType  *r2 = PG_GETARG_RANGE_P(1);
                                825                 :     TypeCacheEntry *typcache;
 3917 heikki.linnakangas        826 ECB             : 
 3917 heikki.linnakangas        827 CBC       37218 :     typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
                                828                 : 
 3917 heikki.linnakangas        829 GIC       37218 :     PG_RETURN_BOOL(range_adjacent_internal(typcache, r1, r2));
                                830                 : }
                                831                 : 
 3917 heikki.linnakangas        832 ECB             : /* overlaps? (internal version) */
                                833                 : bool
 1256 peter                     834 CBC       48353 : range_overlaps_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
 3917 heikki.linnakangas        835 ECB             : {
                                836                 :     RangeBound  lower1,
                                837                 :                 lower2;
 4164 bruce                     838                 :     RangeBound  upper1,
                                839                 :                 upper2;
                                840                 :     bool        empty1,
                                841                 :                 empty2;
                                842                 : 
                                843                 :     /* Different types should be prevented by ANYRANGE matching rules */
 4163 tgl                       844 GIC       48353 :     if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
 4175 heikki.linnakangas        845 LBC           0 :         elog(ERROR, "range types do not match");
                                846                 : 
 4163 tgl                       847 GIC       48353 :     range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
                                848           48353 :     range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
                                849                 : 
                                850                 :     /* An empty range does not overlap any other range */
 4175 heikki.linnakangas        851           48353 :     if (empty1 || empty2)
 3917                           852            7044 :         return false;
                                853                 : 
 4163 tgl                       854           79669 :     if (range_cmp_bounds(typcache, &lower1, &lower2) >= 0 &&
 4163 tgl                       855 CBC       38360 :         range_cmp_bounds(typcache, &lower1, &upper2) <= 0)
 3917 heikki.linnakangas        856 GBC        1341 :         return true;
                                857                 : 
 4163 tgl                       858 CBC       42917 :     if (range_cmp_bounds(typcache, &lower2, &lower1) >= 0 &&
                                859            2949 :         range_cmp_bounds(typcache, &lower2, &upper1) <= 0)
 3917 heikki.linnakangas        860 GIC        2901 :         return true;
                                861                 : 
 3917 heikki.linnakangas        862 CBC       37067 :     return false;
 4175 heikki.linnakangas        863 ECB             : }
                                864                 : 
 3917                           865                 : /* overlaps? */
 4175                           866                 : Datum
 3917 heikki.linnakangas        867 CBC       38705 : range_overlaps(PG_FUNCTION_ARGS)
                                868                 : {
 2029 tgl                       869           38705 :     RangeType  *r1 = PG_GETARG_RANGE_P(0);
                                870           38705 :     RangeType  *r2 = PG_GETARG_RANGE_P(1);
 4163 tgl                       871 ECB             :     TypeCacheEntry *typcache;
                                872                 : 
 3917 heikki.linnakangas        873 CBC       38705 :     typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
                                874                 : 
 3917 heikki.linnakangas        875 GIC       38705 :     PG_RETURN_BOOL(range_overlaps_internal(typcache, r1, r2));
                                876                 : }
                                877                 : 
 3917 heikki.linnakangas        878 ECB             : /* does not extend to right of? (internal version) */
                                879                 : bool
 1256 peter                     880 CBC       65695 : range_overleft_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
 3917 heikki.linnakangas        881 ECB             : {
                                882                 :     RangeBound  lower1,
                                883                 :                 lower2;
 4164 bruce                     884                 :     RangeBound  upper1,
                                885                 :                 upper2;
                                886                 :     bool        empty1,
                                887                 :                 empty2;
                                888                 : 
                                889                 :     /* Different types should be prevented by ANYRANGE matching rules */
 4163 tgl                       890 GIC       65695 :     if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
 4175 heikki.linnakangas        891 LBC           0 :         elog(ERROR, "range types do not match");
                                892                 : 
 4163 tgl                       893 GIC       65695 :     range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
                                894           65695 :     range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
                                895                 : 
                                896                 :     /* An empty range is neither before nor after any other range */
 4175 heikki.linnakangas        897           65695 :     if (empty1 || empty2)
 3917                           898            6573 :         return false;
                                899                 : 
 4163 tgl                       900           59122 :     if (range_cmp_bounds(typcache, &upper1, &upper2) <= 0)
 3917 heikki.linnakangas        901 CBC       20309 :         return true;
 4175 heikki.linnakangas        902 EUB             : 
 3917 heikki.linnakangas        903 GIC       38813 :     return false;
 4175 heikki.linnakangas        904 ECB             : }
                                905                 : 
                                906                 : /* does not extend to right of? */
                                907                 : Datum
 3917 heikki.linnakangas        908 CBC       38253 : range_overleft(PG_FUNCTION_ARGS)
 4175 heikki.linnakangas        909 ECB             : {
 2029 tgl                       910 GIC       38253 :     RangeType  *r1 = PG_GETARG_RANGE_P(0);
 2029 tgl                       911 CBC       38253 :     RangeType  *r2 = PG_GETARG_RANGE_P(1);
 4163 tgl                       912 ECB             :     TypeCacheEntry *typcache;
                                913                 : 
 3917 heikki.linnakangas        914 CBC       38253 :     typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
                                915                 : 
 3917 heikki.linnakangas        916 GIC       38253 :     PG_RETURN_BOOL(range_overleft_internal(typcache, r1, r2));
                                917                 : }
                                918                 : 
 3917 heikki.linnakangas        919 ECB             : /* does not extend to left of? (internal version) */
                                920                 : bool
 1256 peter                     921 CBC      109035 : range_overright_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
 3917 heikki.linnakangas        922 ECB             : {
                                923                 :     RangeBound  lower1,
                                924                 :                 lower2;
 4164 bruce                     925                 :     RangeBound  upper1,
                                926                 :                 upper2;
                                927                 :     bool        empty1,
                                928                 :                 empty2;
                                929                 : 
                                930                 :     /* Different types should be prevented by ANYRANGE matching rules */
 4163 tgl                       931 GIC      109035 :     if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
 4175 heikki.linnakangas        932 LBC           0 :         elog(ERROR, "range types do not match");
                                933                 : 
 4163 tgl                       934 GIC      109035 :     range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
                                935          109035 :     range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
                                936                 : 
                                937                 :     /* An empty range is neither before nor after any other range */
 4175 heikki.linnakangas        938          109035 :     if (empty1 || empty2)
 3158 tgl                       939            6573 :         return false;
                                940                 : 
 4163                           941          102462 :     if (range_cmp_bounds(typcache, &lower1, &lower2) >= 0)
 3158 tgl                       942 CBC       95487 :         return true;
 4175 heikki.linnakangas        943 EUB             : 
 3158 tgl                       944 GIC        6975 :     return false;
 4175 heikki.linnakangas        945 ECB             : }
                                946                 : 
                                947                 : /* does not extend to left of? */
                                948                 : Datum
 3917 heikki.linnakangas        949 CBC       38250 : range_overright(PG_FUNCTION_ARGS)
 3917 heikki.linnakangas        950 ECB             : {
 2029 tgl                       951 GIC       38250 :     RangeType  *r1 = PG_GETARG_RANGE_P(0);
 2029 tgl                       952 CBC       38250 :     RangeType  *r2 = PG_GETARG_RANGE_P(1);
 3917 heikki.linnakangas        953 ECB             :     TypeCacheEntry *typcache;
                                954                 : 
 3917 heikki.linnakangas        955 CBC       38250 :     typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
                                956                 : 
 3917 heikki.linnakangas        957 GIC       38250 :     PG_RETURN_BOOL(range_overright_internal(typcache, r1, r2));
                                958                 : }
                                959                 : 
 4175 heikki.linnakangas        960 ECB             : 
                                961                 : /* range, range -> range functions */
 4156 tgl                       962                 : 
                                963                 : /* set difference */
                                964                 : Datum
 4175 heikki.linnakangas        965 GIC          15 : range_minus(PG_FUNCTION_ARGS)
 4175 heikki.linnakangas        966 ECB             : {
 2029 tgl                       967 GIC          15 :     RangeType  *r1 = PG_GETARG_RANGE_P(0);
 2029 tgl                       968 CBC          15 :     RangeType  *r2 = PG_GETARG_RANGE_P(1);
                                969                 :     RangeType  *ret;
                                970                 :     TypeCacheEntry *typcache;
                                971                 : 
                                972                 :     /* Different types should be prevented by ANYRANGE matching rules */
  840 akorotkov                 973 GIC          15 :     if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
  840 akorotkov                 974 UIC           0 :         elog(ERROR, "range types do not match");
                                975                 : 
  840 akorotkov                 976 CBC          15 :     typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
                                977                 : 
                                978              15 :     ret = range_minus_internal(typcache, r1, r2);
                                979              15 :     if (ret)
  840 akorotkov                 980 GIC          15 :         PG_RETURN_RANGE_P(ret);
                                981                 :     else
  840 akorotkov                 982 UIC           0 :         PG_RETURN_NULL();
                                983                 : }
  840 akorotkov                 984 ECB             : 
  840 akorotkov                 985 EUB             : RangeType *
  840 akorotkov                 986 GIC          48 : range_minus_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2)
  840 akorotkov                 987 ECB             : {
                                988                 :     RangeBound  lower1,
 4164 bruce                     989                 :                 lower2;
                                990                 :     RangeBound  upper1,
                                991                 :                 upper2;
                                992                 :     bool        empty1,
 4164 bruce                     993 EUB             :                 empty2;
                                994                 :     int         cmp_l1l2,
                                995                 :                 cmp_l1u2,
                                996                 :                 cmp_u1l2,
 4164 bruce                     997 ECB             :                 cmp_u1u2;
                                998                 : 
 4163 tgl                       999 GIC          48 :     range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
                               1000              48 :     range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
                               1001                 : 
                               1002                 :     /* if either is empty, r1 is the correct answer */
 4175 heikki.linnakangas       1003              48 :     if (empty1 || empty2)
  840 akorotkov                1004 UIC           0 :         return r1;
                               1005                 : 
 4163 tgl                      1006 GIC          48 :     cmp_l1l2 = range_cmp_bounds(typcache, &lower1, &lower2);
                               1007              48 :     cmp_l1u2 = range_cmp_bounds(typcache, &lower1, &upper2);
                               1008              48 :     cmp_u1l2 = range_cmp_bounds(typcache, &upper1, &lower2);
                               1009              48 :     cmp_u1u2 = range_cmp_bounds(typcache, &upper1, &upper2);
 4175 heikki.linnakangas       1010 ECB             : 
 4175 heikki.linnakangas       1011 CBC          48 :     if (cmp_l1l2 < 0 && cmp_u1u2 > 0)
 4175 heikki.linnakangas       1012 UIC           0 :         ereport(ERROR,
                               1013                 :                 (errcode(ERRCODE_DATA_EXCEPTION),
 2118 tgl                      1014 ECB             :                  errmsg("result of range difference would not be contiguous")));
 4175 heikki.linnakangas       1015 EUB             : 
 4175 heikki.linnakangas       1016 GIC          48 :     if (cmp_l1u2 > 0 || cmp_u1l2 < 0)
  840 akorotkov                1017 CBC           6 :         return r1;
 4175 heikki.linnakangas       1018 ECB             : 
 4175 heikki.linnakangas       1019 CBC          42 :     if (cmp_l1l2 >= 0 && cmp_u1u2 <= 0)
  840 akorotkov                1020              21 :         return make_empty_range(typcache);
                               1021                 : 
 4175 heikki.linnakangas       1022              21 :     if (cmp_l1l2 <= 0 && cmp_u1l2 >= 0 && cmp_u1u2 <= 0)
 4175 heikki.linnakangas       1023 EUB             :     {
 4175 heikki.linnakangas       1024 GIC          12 :         lower2.inclusive = !lower2.inclusive;
 4164 bruce                    1025              12 :         lower2.lower = false;   /* it will become the upper bound */
  115 tgl                      1026 GNC          12 :         return make_range(typcache, &lower1, &lower2, false, NULL);
 4175 heikki.linnakangas       1027 ECB             :     }
                               1028                 : 
 4175 heikki.linnakangas       1029 GIC           9 :     if (cmp_l1l2 >= 0 && cmp_u1u2 >= 0 && cmp_l1u2 <= 0)
 4175 heikki.linnakangas       1030 ECB             :     {
 4175 heikki.linnakangas       1031 CBC           9 :         upper2.inclusive = !upper2.inclusive;
 4164 bruce                    1032 GIC           9 :         upper2.lower = true;    /* it will become the lower bound */
  115 tgl                      1033 GNC           9 :         return make_range(typcache, &upper2, &upper1, false, NULL);
                               1034                 :     }
 4175 heikki.linnakangas       1035 ECB             : 
 4164 tgl                      1036 LBC           0 :     elog(ERROR, "unexpected case in range_minus");
  840 akorotkov                1037 ECB             :     return NULL;
                               1038                 : }
                               1039                 : 
 2896 alvherre                 1040                 : /*
                               1041                 :  * Set union.  If strict is true, it is an error that the two input ranges
                               1042                 :  * are not adjacent or overlapping.
                               1043                 :  */
  840 akorotkov                1044                 : RangeType *
 2896 alvherre                 1045 GIC         714 : range_union_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2,
                               1046                 :                      bool strict)
 4175 heikki.linnakangas       1047 EUB             : {
                               1048                 :     RangeBound  lower1,
                               1049                 :                 lower2;
                               1050                 :     RangeBound  upper1,
                               1051                 :                 upper2;
                               1052                 :     bool        empty1,
                               1053                 :                 empty2;
                               1054                 :     RangeBound *result_lower;
                               1055                 :     RangeBound *result_upper;
 4175 heikki.linnakangas       1056 ECB             : 
                               1057                 :     /* Different types should be prevented by ANYRANGE matching rules */
 4163 tgl                      1058 GIC         714 :     if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
 4164 tgl                      1059 UIC           0 :         elog(ERROR, "range types do not match");
                               1060                 : 
 4163 tgl                      1061 GIC         714 :     range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
                               1062             714 :     range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
                               1063                 : 
                               1064                 :     /* if either is empty, the other is the correct answer */
 4175 heikki.linnakangas       1065             714 :     if (empty1)
 2896 alvherre                 1066               3 :         return r2;
 4175 heikki.linnakangas       1067             711 :     if (empty2)
 2896 alvherre                 1068 UIC           0 :         return r1;
 4175 heikki.linnakangas       1069 ECB             : 
 2896 alvherre                 1070 GBC         711 :     if (strict &&
 2896 alvherre                 1071 GIC          69 :         !DatumGetBool(range_overlaps_internal(typcache, r1, r2)) &&
 2896 alvherre                 1072 CBC           6 :         !DatumGetBool(range_adjacent_internal(typcache, r1, r2)))
 4175 heikki.linnakangas       1073               3 :         ereport(ERROR,
                               1074                 :                 (errcode(ERRCODE_DATA_EXCEPTION),
                               1075                 :                  errmsg("result of range union would not be contiguous")));
 4175 heikki.linnakangas       1076 ECB             : 
 4163 tgl                      1077 CBC         708 :     if (range_cmp_bounds(typcache, &lower1, &lower2) < 0)
 4175 heikki.linnakangas       1078             690 :         result_lower = &lower1;
 4175 heikki.linnakangas       1079 EUB             :     else
 4175 heikki.linnakangas       1080 GIC          18 :         result_lower = &lower2;
 4175 heikki.linnakangas       1081 ECB             : 
 4163 tgl                      1082 CBC         708 :     if (range_cmp_bounds(typcache, &upper1, &upper2) > 0)
 4175 heikki.linnakangas       1083              24 :         result_upper = &upper1;
 4175 heikki.linnakangas       1084 ECB             :     else
 4175 heikki.linnakangas       1085 GIC         684 :         result_upper = &upper2;
                               1086                 : 
  115 tgl                      1087 GNC         708 :     return make_range(typcache, result_lower, result_upper, false, NULL);
 2896 alvherre                 1088 ECB             : }
                               1089                 : 
                               1090                 : Datum
 2896 alvherre                 1091 CBC           9 : range_union(PG_FUNCTION_ARGS)
                               1092                 : {
 2029 tgl                      1093               9 :     RangeType  *r1 = PG_GETARG_RANGE_P(0);
                               1094               9 :     RangeType  *r2 = PG_GETARG_RANGE_P(1);
                               1095                 :     TypeCacheEntry *typcache;
 2896 alvherre                 1096 ECB             : 
 2896 alvherre                 1097 GIC           9 :     typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
 2896 alvherre                 1098 ECB             : 
 2029 tgl                      1099 GIC           9 :     PG_RETURN_RANGE_P(range_union_internal(typcache, r1, r2, true));
                               1100                 : }
                               1101                 : 
 2896 alvherre                 1102 ECB             : /*
                               1103                 :  * range merge: like set union, except also allow and account for non-adjacent
                               1104                 :  * input ranges.
                               1105                 :  */
                               1106                 : Datum
 2896 alvherre                 1107 GIC          15 : range_merge(PG_FUNCTION_ARGS)
 2896 alvherre                 1108 ECB             : {
 2029 tgl                      1109 GIC          15 :     RangeType  *r1 = PG_GETARG_RANGE_P(0);
 2029 tgl                      1110 CBC          15 :     RangeType  *r2 = PG_GETARG_RANGE_P(1);
                               1111                 :     TypeCacheEntry *typcache;
                               1112                 : 
 2896 alvherre                 1113 GIC          15 :     typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
                               1114                 : 
 2029 tgl                      1115              15 :     PG_RETURN_RANGE_P(range_union_internal(typcache, r1, r2, false));
                               1116                 : }
                               1117                 : 
 4156 tgl                      1118 ECB             : /* set intersection */
                               1119                 : Datum
 4175 heikki.linnakangas       1120 CBC           9 : range_intersect(PG_FUNCTION_ARGS)
 4175 heikki.linnakangas       1121 ECB             : {
 2029 tgl                      1122 GIC           9 :     RangeType  *r1 = PG_GETARG_RANGE_P(0);
                               1123               9 :     RangeType  *r2 = PG_GETARG_RANGE_P(1);
 4163 tgl                      1124 ECB             :     TypeCacheEntry *typcache;
                               1125                 : 
  840 akorotkov                1126                 :     /* Different types should be prevented by ANYRANGE matching rules */
  840 akorotkov                1127 GIC           9 :     if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
  840 akorotkov                1128 UIC           0 :         elog(ERROR, "range types do not match");
                               1129                 : 
  840 akorotkov                1130 GIC           9 :     typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
  840 akorotkov                1131 ECB             : 
  840 akorotkov                1132 GIC           9 :     PG_RETURN_RANGE_P(range_intersect_internal(typcache, r1, r2));
  840 akorotkov                1133 ECB             : }
                               1134                 : 
                               1135                 : RangeType *
  840 akorotkov                1136 GIC         108 : range_intersect_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
                               1137                 : {
 4164 bruce                    1138 ECB             :     RangeBound  lower1,
 4164 bruce                    1139 EUB             :                 lower2;
                               1140                 :     RangeBound  upper1,
 4164 bruce                    1141 ECB             :                 upper2;
                               1142                 :     bool        empty1,
                               1143                 :                 empty2;
                               1144                 :     RangeBound *result_lower;
                               1145                 :     RangeBound *result_upper;
                               1146                 : 
 4163 tgl                      1147 CBC         108 :     range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
 4163 tgl                      1148 GIC         108 :     range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
                               1149                 : 
  840 akorotkov                1150             108 :     if (empty1 || empty2 || !range_overlaps_internal(typcache, r1, r2))
                               1151              15 :         return make_empty_range(typcache);
                               1152                 : 
 4163 tgl                      1153              93 :     if (range_cmp_bounds(typcache, &lower1, &lower2) >= 0)
 4175 heikki.linnakangas       1154              45 :         result_lower = &lower1;
                               1155                 :     else
                               1156              48 :         result_lower = &lower2;
                               1157                 : 
 4163 tgl                      1158 CBC          93 :     if (range_cmp_bounds(typcache, &upper1, &upper2) <= 0)
 4175 heikki.linnakangas       1159              63 :         result_upper = &upper1;
                               1160                 :     else
                               1161              30 :         result_upper = &upper2;
 4175 heikki.linnakangas       1162 ECB             : 
  115 tgl                      1163 GNC          93 :     return make_range(typcache, result_lower, result_upper, false, NULL);
  840 akorotkov                1164 ECB             : }
                               1165                 : 
                               1166                 : /* range, range -> range, range functions */
                               1167                 : 
                               1168                 : /*
                               1169                 :  * range_split_internal - if r2 intersects the middle of r1, leaving non-empty
                               1170                 :  * ranges on both sides, then return true and set output1 and output2 to the
                               1171                 :  * results of r1 - r2 (in order). Otherwise return false and don't set output1
                               1172                 :  * or output2. Neither input range should be empty.
                               1173                 :  */
                               1174                 : bool
  840 akorotkov                1175 GIC          66 : range_split_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2,
                               1176                 :                      RangeType **output1, RangeType **output2)
                               1177                 : {
                               1178                 :     RangeBound  lower1,
                               1179                 :                 lower2;
                               1180                 :     RangeBound  upper1,
                               1181                 :                 upper2;
                               1182                 :     bool        empty1,
                               1183                 :                 empty2;
                               1184                 : 
                               1185              66 :     range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
  840 akorotkov                1186 CBC          66 :     range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
                               1187                 : 
  840 akorotkov                1188 GIC         105 :     if (range_cmp_bounds(typcache, &lower1, &lower2) < 0 &&
                               1189              39 :         range_cmp_bounds(typcache, &upper1, &upper2) > 0)
                               1190                 :     {
                               1191                 :         /*
                               1192                 :          * Need to invert inclusive/exclusive for the lower2 and upper2
                               1193                 :          * points. They can't be infinite though. We're allowed to overwrite
                               1194                 :          * these RangeBounds since they only exist locally.
                               1195                 :          */
  840 akorotkov                1196 CBC           9 :         lower2.inclusive = !lower2.inclusive;
                               1197               9 :         lower2.lower = false;
  840 akorotkov                1198 GIC           9 :         upper2.inclusive = !upper2.inclusive;
  840 akorotkov                1199 CBC           9 :         upper2.lower = true;
  840 akorotkov                1200 ECB             : 
  115 tgl                      1201 GNC           9 :         *output1 = make_range(typcache, &lower1, &lower2, false, NULL);
                               1202               9 :         *output2 = make_range(typcache, &upper2, &upper1, false, NULL);
  840 akorotkov                1203 GIC           9 :         return true;
                               1204                 :     }
                               1205                 : 
                               1206              57 :     return false;
  840 akorotkov                1207 ECB             : }
                               1208                 : 
                               1209                 : /* range -> range aggregate functions */
                               1210                 : 
                               1211                 : Datum
  840 akorotkov                1212 CBC          21 : range_intersect_agg_transfn(PG_FUNCTION_ARGS)
  840 akorotkov                1213 ECB             : {
                               1214                 :     MemoryContext aggContext;
                               1215                 :     Oid         rngtypoid;
                               1216                 :     TypeCacheEntry *typcache;
                               1217                 :     RangeType  *result;
                               1218                 :     RangeType  *current;
                               1219                 : 
  840 akorotkov                1220 GIC          21 :     if (!AggCheckCallContext(fcinfo, &aggContext))
  840 akorotkov                1221 UIC           0 :         elog(ERROR, "range_intersect_agg_transfn called in non-aggregate context");
                               1222                 : 
  840 akorotkov                1223 CBC          21 :     rngtypoid = get_fn_expr_argtype(fcinfo->flinfo, 1);
  840 akorotkov                1224 GIC          21 :     if (!type_is_range(rngtypoid))
  375 peter                    1225 UIC           0 :         elog(ERROR, "range_intersect_agg must be called with a range");
                               1226                 : 
  840 akorotkov                1227 GIC          21 :     typcache = range_get_typcache(fcinfo, rngtypoid);
                               1228                 : 
                               1229                 :     /* strictness ensures these are non-null */
                               1230              21 :     result = PG_GETARG_RANGE_P(0);
  840 akorotkov                1231 CBC          21 :     current = PG_GETARG_RANGE_P(1);
  840 akorotkov                1232 EUB             : 
  840 akorotkov                1233 GIC          21 :     result = range_intersect_internal(typcache, result, current);
  840 akorotkov                1234 CBC          21 :     PG_RETURN_RANGE_P(result);
 4175 heikki.linnakangas       1235 ECB             : }
 4175 heikki.linnakangas       1236 EUB             : 
                               1237                 : 
 4175 heikki.linnakangas       1238 ECB             : /* Btree support */
                               1239                 : 
                               1240                 : /* btree comparator */
                               1241                 : Datum
 4175 heikki.linnakangas       1242 CBC        5511 : range_cmp(PG_FUNCTION_ARGS)
                               1243                 : {
 2029 tgl                      1244            5511 :     RangeType  *r1 = PG_GETARG_RANGE_P(0);
                               1245            5511 :     RangeType  *r2 = PG_GETARG_RANGE_P(1);
                               1246                 :     TypeCacheEntry *typcache;
                               1247                 :     RangeBound  lower1,
                               1248                 :                 lower2;
                               1249                 :     RangeBound  upper1,
                               1250                 :                 upper2;
                               1251                 :     bool        empty1,
                               1252                 :                 empty2;
 4164 bruce                    1253 ECB             :     int         cmp;
                               1254                 : 
 2743 noah                     1255 CBC        5511 :     check_stack_depth();        /* recurses when subtype is a range type */
 2743 noah                     1256 ECB             : 
                               1257                 :     /* Different types should be prevented by ANYRANGE matching rules */
 4163 tgl                      1258 GIC        5511 :     if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
 4175 heikki.linnakangas       1259 UIC           0 :         elog(ERROR, "range types do not match");
                               1260                 : 
 4163 tgl                      1261 GIC        5511 :     typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
                               1262                 : 
                               1263            5511 :     range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
                               1264            5511 :     range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
                               1265                 : 
 4164 tgl                      1266 ECB             :     /* For b-tree use, empty ranges sort before all else */
 4175 heikki.linnakangas       1267 GIC        5511 :     if (empty1 && empty2)
 3483                          1268            1320 :         cmp = 0;
 4175 heikki.linnakangas       1269 CBC        4191 :     else if (empty1)
 3483 heikki.linnakangas       1270 GBC        1740 :         cmp = -1;
 4175 heikki.linnakangas       1271 GIC        2451 :     else if (empty2)
 3483 heikki.linnakangas       1272 CBC        1065 :         cmp = 1;
                               1273                 :     else
 3483 heikki.linnakangas       1274 ECB             :     {
 3483 heikki.linnakangas       1275 CBC        1386 :         cmp = range_cmp_bounds(typcache, &lower1, &lower2);
 3483 heikki.linnakangas       1276 GIC        1386 :         if (cmp == 0)
                               1277              54 :             cmp = range_cmp_bounds(typcache, &upper1, &upper2);
 3483 heikki.linnakangas       1278 ECB             :     }
 4175                          1279                 : 
 3483 heikki.linnakangas       1280 CBC        5511 :     PG_FREE_IF_COPY(r1, 0);
                               1281            5511 :     PG_FREE_IF_COPY(r2, 1);
 4175 heikki.linnakangas       1282 ECB             : 
 3483 heikki.linnakangas       1283 CBC        5511 :     PG_RETURN_INT32(cmp);
                               1284                 : }
                               1285                 : 
 4156 tgl                      1286 ECB             : /* inequality operators using the range_cmp function */
 4175 heikki.linnakangas       1287                 : Datum
 4175 heikki.linnakangas       1288 CBC         669 : range_lt(PG_FUNCTION_ARGS)
                               1289                 : {
 4164 bruce                    1290 GIC         669 :     int         cmp = range_cmp(fcinfo);
 4164 bruce                    1291 ECB             : 
 4175 heikki.linnakangas       1292 CBC         669 :     PG_RETURN_BOOL(cmp < 0);
                               1293                 : }
 4175 heikki.linnakangas       1294 ECB             : 
                               1295                 : Datum
 4175 heikki.linnakangas       1296 GIC        1506 : range_le(PG_FUNCTION_ARGS)
                               1297                 : {
 4164 bruce                    1298            1506 :     int         cmp = range_cmp(fcinfo);
 4164 bruce                    1299 ECB             : 
 4175 heikki.linnakangas       1300 GIC        1506 :     PG_RETURN_BOOL(cmp <= 0);
 4175 heikki.linnakangas       1301 ECB             : }
                               1302                 : 
                               1303                 : Datum
 4175 heikki.linnakangas       1304 GIC        1518 : range_ge(PG_FUNCTION_ARGS)
                               1305                 : {
 4164 bruce                    1306            1518 :     int         cmp = range_cmp(fcinfo);
 4164 bruce                    1307 ECB             : 
 4175 heikki.linnakangas       1308 GIC        1518 :     PG_RETURN_BOOL(cmp >= 0);
 4175 heikki.linnakangas       1309 ECB             : }
                               1310                 : 
                               1311                 : Datum
 4175 heikki.linnakangas       1312 GIC        1536 : range_gt(PG_FUNCTION_ARGS)
                               1313                 : {
 4164 bruce                    1314            1536 :     int         cmp = range_cmp(fcinfo);
 4164 bruce                    1315 ECB             : 
 4175 heikki.linnakangas       1316 GIC        1536 :     PG_RETURN_BOOL(cmp > 0);
 4175 heikki.linnakangas       1317 ECB             : }
                               1318                 : 
                               1319                 : /* Hash support */
                               1320                 : 
                               1321                 : /* hash a range value */
                               1322                 : Datum
 4175 heikki.linnakangas       1323 CBC         105 : hash_range(PG_FUNCTION_ARGS)
                               1324                 : {
 2029 tgl                      1325             105 :     RangeType  *r = PG_GETARG_RANGE_P(0);
                               1326                 :     uint32      result;
 4163 tgl                      1327 ECB             :     TypeCacheEntry *typcache;
                               1328                 :     TypeCacheEntry *scache;
                               1329                 :     RangeBound  lower;
                               1330                 :     RangeBound  upper;
                               1331                 :     bool        empty;
                               1332                 :     char        flags;
                               1333                 :     uint32      lower_hash;
                               1334                 :     uint32      upper_hash;
                               1335                 : 
 2743 noah                     1336 CBC         105 :     check_stack_depth();        /* recurses when subtype is a range type */
                               1337                 : 
 4163 tgl                      1338 GIC         105 :     typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r));
                               1339                 : 
                               1340                 :     /* deserialize */
                               1341             105 :     range_deserialize(typcache, r, &lower, &upper, &empty);
                               1342             105 :     flags = range_get_flags(r);
                               1343                 : 
                               1344                 :     /*
                               1345                 :      * Look up the element type's hash function, if not done already.
                               1346                 :      */
 4163 tgl                      1347 CBC         105 :     scache = typcache->rngelemtype;
 4163 tgl                      1348 GIC         105 :     if (!OidIsValid(scache->hash_proc_finfo.fn_oid))
 4175 heikki.linnakangas       1349 ECB             :     {
 4163 tgl                      1350 GIC           3 :         scache = lookup_type_cache(scache->type_id, TYPECACHE_HASH_PROC_FINFO);
                               1351               3 :         if (!OidIsValid(scache->hash_proc_finfo.fn_oid))
 4175 heikki.linnakangas       1352 LBC           0 :             ereport(ERROR,
 4175 heikki.linnakangas       1353 ECB             :                     (errcode(ERRCODE_UNDEFINED_FUNCTION),
                               1354                 :                      errmsg("could not identify a hash function for type %s",
                               1355                 :                             format_type_be(scache->type_id))));
                               1356                 :     }
                               1357                 : 
                               1358                 :     /*
 4163 tgl                      1359                 :      * Apply the hash function to each bound.
                               1360                 :      */
 4175 heikki.linnakangas       1361 CBC         105 :     if (RANGE_HAS_LBOUND(flags))
 4163 tgl                      1362              72 :         lower_hash = DatumGetUInt32(FunctionCall1Coll(&scache->hash_proc_finfo,
 4163 tgl                      1363 EUB             :                                                       typcache->rng_collation,
                               1364                 :                                                       lower.val));
                               1365                 :     else
 4163 tgl                      1366 GIC          33 :         lower_hash = 0;
                               1367                 : 
 4175 heikki.linnakangas       1368             105 :     if (RANGE_HAS_UBOUND(flags))
 4163 tgl                      1369              78 :         upper_hash = DatumGetUInt32(FunctionCall1Coll(&scache->hash_proc_finfo,
                               1370                 :                                                       typcache->rng_collation,
                               1371                 :                                                       upper.val));
 4163 tgl                      1372 ECB             :     else
 4163 tgl                      1373 CBC          27 :         upper_hash = 0;
                               1374                 : 
                               1375                 :     /* Merge hashes of flags and bounds */
 4164 bruce                    1376 GIC         105 :     result = hash_uint32((uint32) flags);
 4175 heikki.linnakangas       1377 CBC         105 :     result ^= lower_hash;
  413 john.naylor              1378 GIC         105 :     result = pg_rotate_left32(result, 1);
 4175 heikki.linnakangas       1379 CBC         105 :     result ^= upper_hash;
 4175 heikki.linnakangas       1380 ECB             : 
 4175 heikki.linnakangas       1381 GIC         105 :     PG_RETURN_INT32(result);
                               1382                 : }
                               1383                 : 
 2047 rhaas                    1384 ECB             : /*
                               1385                 :  * Returns 64-bit value by hashing a value to a 64-bit value, with a seed.
                               1386                 :  * Otherwise, similar to hash_range.
                               1387                 :  */
                               1388                 : Datum
 2047 rhaas                    1389 CBC          30 : hash_range_extended(PG_FUNCTION_ARGS)
 2047 rhaas                    1390 ECB             : {
 2029 tgl                      1391 GIC          30 :     RangeType  *r = PG_GETARG_RANGE_P(0);
 2046 rhaas                    1392 CBC          30 :     Datum       seed = PG_GETARG_DATUM(1);
                               1393                 :     uint64      result;
                               1394                 :     TypeCacheEntry *typcache;
                               1395                 :     TypeCacheEntry *scache;
                               1396                 :     RangeBound  lower;
                               1397                 :     RangeBound  upper;
                               1398                 :     bool        empty;
                               1399                 :     char        flags;
 2047 rhaas                    1400 ECB             :     uint64      lower_hash;
                               1401                 :     uint64      upper_hash;
                               1402                 : 
 2047 rhaas                    1403 CBC          30 :     check_stack_depth();
                               1404                 : 
 2047 rhaas                    1405 GIC          30 :     typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r));
                               1406                 : 
                               1407              30 :     range_deserialize(typcache, r, &lower, &upper, &empty);
                               1408              30 :     flags = range_get_flags(r);
                               1409                 : 
                               1410              30 :     scache = typcache->rngelemtype;
                               1411              30 :     if (!OidIsValid(scache->hash_extended_proc_finfo.fn_oid))
                               1412                 :     {
 2047 rhaas                    1413 UIC           0 :         scache = lookup_type_cache(scache->type_id,
 2047 rhaas                    1414 ECB             :                                    TYPECACHE_HASH_EXTENDED_PROC_FINFO);
 2047 rhaas                    1415 UIC           0 :         if (!OidIsValid(scache->hash_extended_proc_finfo.fn_oid))
 2047 rhaas                    1416 LBC           0 :             ereport(ERROR,
                               1417                 :                     (errcode(ERRCODE_UNDEFINED_FUNCTION),
 2047 rhaas                    1418 ECB             :                      errmsg("could not identify a hash function for type %s",
                               1419                 :                             format_type_be(scache->type_id))));
                               1420                 :     }
                               1421                 : 
 2047 rhaas                    1422 CBC          30 :     if (RANGE_HAS_LBOUND(flags))
 2047 rhaas                    1423 GIC          30 :         lower_hash = DatumGetUInt64(FunctionCall2Coll(&scache->hash_extended_proc_finfo,
 2047 rhaas                    1424 EUB             :                                                       typcache->rng_collation,
                               1425                 :                                                       lower.val,
                               1426                 :                                                       seed));
                               1427                 :     else
 2047 rhaas                    1428 UIC           0 :         lower_hash = 0;
                               1429                 : 
 2047 rhaas                    1430 GIC          30 :     if (RANGE_HAS_UBOUND(flags))
                               1431              30 :         upper_hash = DatumGetUInt64(FunctionCall2Coll(&scache->hash_extended_proc_finfo,
                               1432                 :                                                       typcache->rng_collation,
 2047 rhaas                    1433 ECB             :                                                       upper.val,
                               1434                 :                                                       seed));
                               1435                 :     else
 2047 rhaas                    1436 UIC           0 :         upper_hash = 0;
                               1437                 : 
                               1438                 :     /* Merge hashes of flags and bounds */
 2046 rhaas                    1439 GBC          30 :     result = DatumGetUInt64(hash_uint32_extended((uint32) flags,
 2046 rhaas                    1440 GIC          30 :                                                  DatumGetInt64(seed)));
 2047 rhaas                    1441 CBC          30 :     result ^= lower_hash;
                               1442              30 :     result = ROTATE_HIGH_AND_LOW_32BITS(result);
 2047 rhaas                    1443 GIC          30 :     result ^= upper_hash;
                               1444                 : 
                               1445              30 :     PG_RETURN_UINT64(result);
                               1446                 : }
 2047 rhaas                    1447 EUB             : 
                               1448                 : /*
                               1449                 :  *----------------------------------------------------------
 4175 heikki.linnakangas       1450 ECB             :  * CANONICAL FUNCTIONS
                               1451                 :  *
 4164 bruce                    1452                 :  *   Functions for specific built-in range types.
 4175 heikki.linnakangas       1453                 :  *----------------------------------------------------------
                               1454                 :  */
                               1455                 : 
                               1456                 : Datum
 4175 heikki.linnakangas       1457 GIC      231834 : int4range_canonical(PG_FUNCTION_ARGS)
                               1458                 : {
 2029 tgl                      1459          231834 :     RangeType  *r = PG_GETARG_RANGE_P(0);
  115 tgl                      1460 GNC      231834 :     Node       *escontext = fcinfo->context;
                               1461                 :     TypeCacheEntry *typcache;
                               1462                 :     RangeBound  lower;
                               1463                 :     RangeBound  upper;
                               1464                 :     bool        empty;
                               1465                 : 
 4163 tgl                      1466 GIC      231834 :     typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r));
                               1467                 : 
                               1468          231834 :     range_deserialize(typcache, r, &lower, &upper, &empty);
 4175 heikki.linnakangas       1469 ECB             : 
 4175 heikki.linnakangas       1470 GIC      231834 :     if (empty)
 2029 tgl                      1471 LBC           0 :         PG_RETURN_RANGE_P(r);
 4175 heikki.linnakangas       1472 ECB             : 
 4175 heikki.linnakangas       1473 GIC      231834 :     if (!lower.infinite && !lower.inclusive)
                               1474                 :     {
  115 tgl                      1475 GNC        1624 :         int32       bnd = DatumGetInt32(lower.val);
                               1476                 : 
                               1477                 :         /* Handle possible overflow manually */
                               1478            1624 :         if (unlikely(bnd == PG_INT32_MAX))
  115 tgl                      1479 UNC           0 :             ereturn(escontext, (Datum) 0,
                               1480                 :                     (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                               1481                 :                      errmsg("integer out of range")));
  115 tgl                      1482 GNC        1624 :         lower.val = Int32GetDatum(bnd + 1);
 4175 heikki.linnakangas       1483 GIC        1624 :         lower.inclusive = true;
                               1484                 :     }
 4175 heikki.linnakangas       1485 ECB             : 
 4175 heikki.linnakangas       1486 GIC      231834 :     if (!upper.infinite && upper.inclusive)
 4175 heikki.linnakangas       1487 ECB             :     {
  115 tgl                      1488 GNC        1609 :         int32       bnd = DatumGetInt32(upper.val);
                               1489                 : 
                               1490                 :         /* Handle possible overflow manually */
                               1491            1609 :         if (unlikely(bnd == PG_INT32_MAX))
                               1492               6 :             ereturn(escontext, (Datum) 0,
                               1493                 :                     (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                               1494                 :                      errmsg("integer out of range")));
                               1495            1603 :         upper.val = Int32GetDatum(bnd + 1);
 4175 heikki.linnakangas       1496 CBC        1603 :         upper.inclusive = false;
 4175 heikki.linnakangas       1497 EUB             :     }
                               1498                 : 
  115 tgl                      1499 GNC      231828 :     PG_RETURN_RANGE_P(range_serialize(typcache, &lower, &upper,
                               1500                 :                                       false, escontext));
                               1501                 : }
 4175 heikki.linnakangas       1502 ECB             : 
                               1503                 : Datum
 4175 heikki.linnakangas       1504 GIC          43 : int8range_canonical(PG_FUNCTION_ARGS)
 4175 heikki.linnakangas       1505 ECB             : {
 2029 tgl                      1506 GBC          43 :     RangeType  *r = PG_GETARG_RANGE_P(0);
  115 tgl                      1507 GNC          43 :     Node       *escontext = fcinfo->context;
                               1508                 :     TypeCacheEntry *typcache;
                               1509                 :     RangeBound  lower;
 4175 heikki.linnakangas       1510 ECB             :     RangeBound  upper;
                               1511                 :     bool        empty;
                               1512                 : 
 4163 tgl                      1513 GIC          43 :     typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r));
 4163 tgl                      1514 ECB             : 
 4163 tgl                      1515 GIC          43 :     range_deserialize(typcache, r, &lower, &upper, &empty);
 4175 heikki.linnakangas       1516 ECB             : 
 4175 heikki.linnakangas       1517 GIC          43 :     if (empty)
 2029 tgl                      1518 UIC           0 :         PG_RETURN_RANGE_P(r);
 4175 heikki.linnakangas       1519 ECB             : 
 4175 heikki.linnakangas       1520 CBC          43 :     if (!lower.infinite && !lower.inclusive)
                               1521                 :     {
  115 tgl                      1522 GNC           9 :         int64       bnd = DatumGetInt64(lower.val);
                               1523                 : 
                               1524                 :         /* Handle possible overflow manually */
                               1525               9 :         if (unlikely(bnd == PG_INT64_MAX))
  115 tgl                      1526 UNC           0 :             ereturn(escontext, (Datum) 0,
                               1527                 :                     (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                               1528                 :                      errmsg("bigint out of range")));
  115 tgl                      1529 GNC           9 :         lower.val = Int64GetDatum(bnd + 1);
 4175 heikki.linnakangas       1530 CBC           9 :         lower.inclusive = true;
 4175 heikki.linnakangas       1531 ECB             :     }
                               1532                 : 
 4175 heikki.linnakangas       1533 GIC          43 :     if (!upper.infinite && upper.inclusive)
 4175 heikki.linnakangas       1534 ECB             :     {
  115 tgl                      1535 GNC          12 :         int64       bnd = DatumGetInt64(upper.val);
                               1536                 : 
                               1537                 :         /* Handle possible overflow manually */
                               1538              12 :         if (unlikely(bnd == PG_INT64_MAX))
  115 tgl                      1539 UNC           0 :             ereturn(escontext, (Datum) 0,
                               1540                 :                     (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                               1541                 :                      errmsg("bigint out of range")));
  115 tgl                      1542 GNC          12 :         upper.val = Int64GetDatum(bnd + 1);
 4175 heikki.linnakangas       1543 GIC          12 :         upper.inclusive = false;
                               1544                 :     }
                               1545                 : 
  115 tgl                      1546 GNC          43 :     PG_RETURN_RANGE_P(range_serialize(typcache, &lower, &upper,
                               1547                 :                                       false, escontext));
                               1548                 : }
 4175 heikki.linnakangas       1549 ECB             : 
                               1550                 : Datum
 4175 heikki.linnakangas       1551 GIC          81 : daterange_canonical(PG_FUNCTION_ARGS)
                               1552                 : {
 2029 tgl                      1553              81 :     RangeType  *r = PG_GETARG_RANGE_P(0);
  115 tgl                      1554 GNC          81 :     Node       *escontext = fcinfo->context;
                               1555                 :     TypeCacheEntry *typcache;
                               1556                 :     RangeBound  lower;
 4175 heikki.linnakangas       1557 ECB             :     RangeBound  upper;
                               1558                 :     bool        empty;
                               1559                 : 
 4163 tgl                      1560 GIC          81 :     typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r));
 4163 tgl                      1561 ECB             : 
 4163 tgl                      1562 GBC          81 :     range_deserialize(typcache, r, &lower, &upper, &empty);
                               1563                 : 
 4175 heikki.linnakangas       1564 CBC          81 :     if (empty)
 2029 tgl                      1565 UIC           0 :         PG_RETURN_RANGE_P(r);
 4175 heikki.linnakangas       1566 ECB             : 
 1361 jdavis                   1567 GIC          81 :     if (!lower.infinite && !DATE_NOT_FINITE(DatumGetDateADT(lower.val)) &&
                               1568              75 :         !lower.inclusive)
 4175 heikki.linnakangas       1569 ECB             :     {
  115 tgl                      1570 GNC          18 :         DateADT     bnd = DatumGetDateADT(lower.val);
                               1571                 : 
                               1572                 :         /* Check for overflow -- note we already eliminated PG_INT32_MAX */
                               1573              18 :         bnd++;
                               1574              18 :         if (unlikely(!IS_VALID_DATE(bnd)))
  115 tgl                      1575 UNC           0 :             ereturn(escontext, (Datum) 0,
                               1576                 :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
                               1577                 :                      errmsg("date out of range")));
  115 tgl                      1578 GNC          18 :         lower.val = DateADTGetDatum(bnd);
 4175 heikki.linnakangas       1579 GIC          18 :         lower.inclusive = true;
                               1580                 :     }
 4175 heikki.linnakangas       1581 ECB             : 
 1361 jdavis                   1582 CBC          81 :     if (!upper.infinite && !DATE_NOT_FINITE(DatumGetDateADT(upper.val)) &&
 1361 jdavis                   1583 GIC          75 :         upper.inclusive)
                               1584                 :     {
  115 tgl                      1585 GNC          15 :         DateADT     bnd = DatumGetDateADT(upper.val);
                               1586                 : 
                               1587                 :         /* Check for overflow -- note we already eliminated PG_INT32_MAX */
                               1588              15 :         bnd++;
                               1589              15 :         if (unlikely(!IS_VALID_DATE(bnd)))
                               1590               6 :             ereturn(escontext, (Datum) 0,
                               1591                 :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
                               1592                 :                      errmsg("date out of range")));
                               1593               9 :         upper.val = DateADTGetDatum(bnd);
 4175 heikki.linnakangas       1594 GIC           9 :         upper.inclusive = false;
 4175 heikki.linnakangas       1595 ECB             :     }
                               1596                 : 
  115 tgl                      1597 GNC          75 :     PG_RETURN_RANGE_P(range_serialize(typcache, &lower, &upper,
                               1598                 :                                       false, escontext));
 4175 heikki.linnakangas       1599 ECB             : }
 4175 heikki.linnakangas       1600 EUB             : 
                               1601                 : /*
                               1602                 :  *----------------------------------------------------------
 4175 heikki.linnakangas       1603 ECB             :  * SUBTYPE_DIFF FUNCTIONS
                               1604                 :  *
                               1605                 :  * Functions for specific built-in range types.
                               1606                 :  *
 4156 tgl                      1607                 :  * Note that subtype_diff does return the difference, not the absolute value
                               1608                 :  * of the difference, and it must take care to avoid overflow.
                               1609                 :  * (numrange_subdiff is at some risk there ...)
                               1610                 :  *----------------------------------------------------------
                               1611                 :  */
 4175 heikki.linnakangas       1612                 : 
                               1613                 : Datum
 4175 heikki.linnakangas       1614 CBC      610854 : int4range_subdiff(PG_FUNCTION_ARGS)
 4175 heikki.linnakangas       1615 ECB             : {
 4164 bruce                    1616 GIC      610854 :     int32       v1 = PG_GETARG_INT32(0);
                               1617          610854 :     int32       v2 = PG_GETARG_INT32(1);
                               1618                 : 
      tgl                      1619          610854 :     PG_RETURN_FLOAT8((float8) v1 - (float8) v2);
                               1620                 : }
 4175 heikki.linnakangas       1621 ECB             : 
                               1622                 : Datum
 4175 heikki.linnakangas       1623 LBC           0 : int8range_subdiff(PG_FUNCTION_ARGS)
                               1624                 : {
 4164 bruce                    1625               0 :     int64       v1 = PG_GETARG_INT64(0);
 4164 bruce                    1626 UBC           0 :     int64       v2 = PG_GETARG_INT64(1);
                               1627                 : 
 4164 tgl                      1628 LBC           0 :     PG_RETURN_FLOAT8((float8) v1 - (float8) v2);
 4175 heikki.linnakangas       1629 ECB             : }
                               1630                 : 
                               1631                 : Datum
 4175 heikki.linnakangas       1632 GIC         123 : numrange_subdiff(PG_FUNCTION_ARGS)
                               1633                 : {
 4175 heikki.linnakangas       1634 CBC         123 :     Datum       v1 = PG_GETARG_DATUM(0);
                               1635             123 :     Datum       v2 = PG_GETARG_DATUM(1);
 4175 heikki.linnakangas       1636 EUB             :     Datum       numresult;
                               1637                 :     float8      floatresult;
                               1638                 : 
 4175 heikki.linnakangas       1639 CBC         123 :     numresult = DirectFunctionCall2(numeric_sub, v1, v2);
 4175 heikki.linnakangas       1640 ECB             : 
 4164 tgl                      1641 GIC         123 :     floatresult = DatumGetFloat8(DirectFunctionCall1(numeric_float8,
                               1642                 :                                                      numresult));
 4175 heikki.linnakangas       1643 ECB             : 
 4175 heikki.linnakangas       1644 CBC         123 :     PG_RETURN_FLOAT8(floatresult);
                               1645                 : }
 4175 heikki.linnakangas       1646 ECB             : 
                               1647                 : Datum
 4164 tgl                      1648 UIC           0 : daterange_subdiff(PG_FUNCTION_ARGS)
 4164 tgl                      1649 ECB             : {
 4164 tgl                      1650 LBC           0 :     int32       v1 = PG_GETARG_INT32(0);
                               1651               0 :     int32       v2 = PG_GETARG_INT32(1);
                               1652                 : 
 4164 tgl                      1653 UIC           0 :     PG_RETURN_FLOAT8((float8) v1 - (float8) v2);
 4164 tgl                      1654 ECB             : }
                               1655                 : 
                               1656                 : Datum
 4175 heikki.linnakangas       1657 UIC           0 : tsrange_subdiff(PG_FUNCTION_ARGS)
 4175 heikki.linnakangas       1658 ECB             : {
 4175 heikki.linnakangas       1659 UIC           0 :     Timestamp   v1 = PG_GETARG_TIMESTAMP(0);
                               1660               0 :     Timestamp   v2 = PG_GETARG_TIMESTAMP(1);
                               1661                 :     float8      result;
                               1662                 : 
 4164 tgl                      1663               0 :     result = ((float8) v1 - (float8) v2) / USECS_PER_SEC;
 4175 heikki.linnakangas       1664               0 :     PG_RETURN_FLOAT8(result);
                               1665                 : }
                               1666                 : 
                               1667                 : Datum
                               1668               0 : tstzrange_subdiff(PG_FUNCTION_ARGS)
                               1669                 : {
                               1670               0 :     Timestamp   v1 = PG_GETARG_TIMESTAMP(0);
                               1671               0 :     Timestamp   v2 = PG_GETARG_TIMESTAMP(1);
                               1672                 :     float8      result;
                               1673                 : 
 4164 tgl                      1674               0 :     result = ((float8) v1 - (float8) v2) / USECS_PER_SEC;
 4175 heikki.linnakangas       1675 LBC           0 :     PG_RETURN_FLOAT8(result);
                               1676                 : }
 4175 heikki.linnakangas       1677 ECB             : 
                               1678                 : /*
                               1679                 :  *----------------------------------------------------------
                               1680                 :  * SUPPORT FUNCTIONS
                               1681                 :  *
                               1682                 :  *   These functions aren't in pg_proc, but are useful for
                               1683                 :  *   defining new generic range functions in C.
 4175 heikki.linnakangas       1684 EUB             :  *----------------------------------------------------------
                               1685                 :  */
                               1686                 : 
 4163 tgl                      1687                 : /*
                               1688                 :  * range_get_typcache: get cached information about a range type
                               1689                 :  *
                               1690                 :  * This is for use by range-related functions that follow the convention
                               1691                 :  * of using the fn_extra field as a pointer to the type cache entry for
                               1692                 :  * the range type.  Functions that need to cache more information than
 4163 tgl                      1693 ECB             :  * that must fend for themselves.
                               1694                 :  */
                               1695                 : TypeCacheEntry *
 4163 tgl                      1696 CBC     2357008 : range_get_typcache(FunctionCallInfo fcinfo, Oid rngtypid)
                               1697                 : {
 4163 tgl                      1698 GIC     2357008 :     TypeCacheEntry *typcache = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
                               1699                 : 
 4163 tgl                      1700 CBC     2357008 :     if (typcache == NULL ||
 4163 tgl                      1701 GIC     2352722 :         typcache->type_id != rngtypid)
 4163 tgl                      1702 ECB             :     {
 4163 tgl                      1703 GIC        4286 :         typcache = lookup_type_cache(rngtypid, TYPECACHE_RANGE_INFO);
                               1704            4286 :         if (typcache->rngelemtype == NULL)
 4163 tgl                      1705 LBC           0 :             elog(ERROR, "type %u is not a range type", rngtypid);
 4163 tgl                      1706 GIC        4286 :         fcinfo->flinfo->fn_extra = (void *) typcache;
                               1707                 :     }
                               1708                 : 
 4163 tgl                      1709 GBC     2357008 :     return typcache;
                               1710                 : }
 4163 tgl                      1711 EUB             : 
 4175 heikki.linnakangas       1712                 : /*
                               1713                 :  * range_serialize: construct a range value from bounds and empty-flag
 4164 tgl                      1714                 :  *
                               1715                 :  * This does not force canonicalization of the range value.  In most cases,
                               1716                 :  * external callers should only be canonicalization functions.  Note that
                               1717                 :  * we perform some datatype-independent canonicalization checks anyway.
 4175 heikki.linnakangas       1718                 :  */
                               1719                 : RangeType *
 4163 tgl                      1720 GBC      469852 : range_serialize(TypeCacheEntry *typcache, RangeBound *lower, RangeBound *upper,
                               1721                 :                 bool empty, struct Node *escontext)
                               1722                 : {
                               1723                 :     RangeType  *range;
 4156 tgl                      1724 EUB             :     int         cmp;
 4163                          1725                 :     Size        msize;
                               1726                 :     Pointer     ptr;
                               1727                 :     int16       typlen;
                               1728                 :     bool        typbyval;
                               1729                 :     char        typalign;
                               1730                 :     char        typstorage;
 4164 bruce                    1731 GBC      469852 :     char        flags = 0;
 4175 heikki.linnakangas       1732 EUB             : 
                               1733                 :     /*
                               1734                 :      * Verify range is not invalid on its face, and construct flags value,
 4156 tgl                      1735                 :      * preventing any non-canonical combinations such as infinite+inclusive.
                               1736                 :      */
 4156 tgl                      1737 GIC      469852 :     Assert(lower->lower);
                               1738          469852 :     Assert(!upper->lower);
                               1739                 : 
 4175 heikki.linnakangas       1740          469852 :     if (empty)
                               1741            1830 :         flags |= RANGE_EMPTY;
                               1742                 :     else
                               1743                 :     {
 4156 tgl                      1744          468022 :         cmp = range_cmp_bound_values(typcache, lower, upper);
                               1745                 : 
                               1746                 :         /* error check: if lower bound value is above upper, it's wrong */
                               1747          468022 :         if (cmp > 0)
  115 tgl                      1748 GNC          33 :             ereturn(escontext, NULL,
                               1749                 :                     (errcode(ERRCODE_DATA_EXCEPTION),
                               1750                 :                      errmsg("range lower bound must be less than or equal to range upper bound")));
                               1751                 : 
                               1752                 :         /* if bounds are equal, and not both inclusive, range is empty */
 4156 tgl                      1753 GIC      467989 :         if (cmp == 0 && !(lower->inclusive && upper->inclusive))
                               1754             192 :             flags |= RANGE_EMPTY;
                               1755                 :         else
                               1756                 :         {
 4156 tgl                      1757 ECB             :             /* infinite boundaries are never inclusive */
 4156 tgl                      1758 GIC      467797 :             if (lower->infinite)
 4156 tgl                      1759 CBC        4911 :                 flags |= RANGE_LB_INF;
 4156 tgl                      1760 GIC      462886 :             else if (lower->inclusive)
 4156 tgl                      1761 CBC      461082 :                 flags |= RANGE_LB_INC;
                               1762          467797 :             if (upper->infinite)
 4156 tgl                      1763 GIC        3363 :                 flags |= RANGE_UB_INF;
 4156 tgl                      1764 CBC      464434 :             else if (upper->inclusive)
                               1765            1969 :                 flags |= RANGE_UB_INC;
 4156 tgl                      1766 EUB             :         }
 4163 tgl                      1767 ECB             :     }
                               1768                 : 
                               1769                 :     /* Fetch information about range's element type */
 4156 tgl                      1770 CBC      469819 :     typlen = typcache->rngelemtype->typlen;
 4156 tgl                      1771 GIC      469819 :     typbyval = typcache->rngelemtype->typbyval;
                               1772          469819 :     typalign = typcache->rngelemtype->typalign;
                               1773          469819 :     typstorage = typcache->rngelemtype->typstorage;
                               1774                 : 
                               1775                 :     /* Count space for varlena header and range type's OID */
 4163                          1776          469819 :     msize = sizeof(RangeType);
                               1777          469819 :     Assert(msize == MAXALIGN(msize));
                               1778                 : 
                               1779                 :     /* Count space for bounds */
 4175 heikki.linnakangas       1780          469819 :     if (RANGE_HAS_LBOUND(flags))
 4175 heikki.linnakangas       1781 ECB             :     {
                               1782                 :         /*
                               1783                 :          * Make sure item to be inserted is not toasted.  It is essential that
                               1784                 :          * we not insert an out-of-line toast value pointer into a range
                               1785                 :          * object, for the same reasons that arrays and records can't contain
                               1786                 :          * them.  It would work to store a compressed-in-line value, but we
                               1787                 :          * prefer to decompress and then let compression be applied to the
                               1788                 :          * whole range object if necessary.  But, unlike arrays, we do allow
                               1789                 :          * short-header varlena objects to stay as-is.
                               1790                 :          */
 4164 tgl                      1791 GIC      462886 :         if (typlen == -1)
 4164 tgl                      1792 CBC        2361 :             lower->val = PointerGetDatum(PG_DETOAST_DATUM_PACKED(lower->val));
                               1793                 : 
 4175 heikki.linnakangas       1794 GIC      462886 :         msize = datum_compute_size(msize, lower->val, typbyval, typalign,
                               1795                 :                                    typlen, typstorage);
                               1796                 :     }
                               1797                 : 
 4175 heikki.linnakangas       1798 CBC      469819 :     if (RANGE_HAS_UBOUND(flags))
 4175 heikki.linnakangas       1799 ECB             :     {
                               1800                 :         /* Make sure item to be inserted is not toasted */
 4164 tgl                      1801 CBC      464434 :         if (typlen == -1)
                               1802            2343 :             upper->val = PointerGetDatum(PG_DETOAST_DATUM_PACKED(upper->val));
                               1803                 : 
 4175 heikki.linnakangas       1804 GIC      464434 :         msize = datum_compute_size(msize, upper->val, typbyval, typalign,
 4175 heikki.linnakangas       1805 ECB             :                                    typlen, typstorage);
                               1806                 :     }
                               1807                 : 
 4163 tgl                      1808                 :     /* Add space for flag byte */
 4175 heikki.linnakangas       1809 CBC      469819 :     msize += sizeof(char);
                               1810                 : 
                               1811                 :     /* Note: zero-fill is required here, just as in heap tuples */
 4163 tgl                      1812 GIC      469819 :     range = (RangeType *) palloc0(msize);
                               1813          469819 :     SET_VARSIZE(range, msize);
 4175 heikki.linnakangas       1814 ECB             : 
 4163 tgl                      1815                 :     /* Now fill in the datum */
 4163 tgl                      1816 GIC      469819 :     range->rangetypid = typcache->type_id;
                               1817                 : 
                               1818          469819 :     ptr = (char *) (range + 1);
 4175 heikki.linnakangas       1819 ECB             : 
 4175 heikki.linnakangas       1820 CBC      469819 :     if (RANGE_HAS_LBOUND(flags))
 4175 heikki.linnakangas       1821 ECB             :     {
 4175 heikki.linnakangas       1822 CBC      462886 :         Assert(lower->lower);
                               1823          462886 :         ptr = datum_write(ptr, lower->val, typbyval, typalign, typlen,
 4175 heikki.linnakangas       1824 ECB             :                           typstorage);
                               1825                 :     }
                               1826                 : 
 4175 heikki.linnakangas       1827 GIC      469819 :     if (RANGE_HAS_UBOUND(flags))
                               1828                 :     {
                               1829          464434 :         Assert(!upper->lower);
                               1830          464434 :         ptr = datum_write(ptr, upper->val, typbyval, typalign, typlen,
 4175 heikki.linnakangas       1831 ECB             :                           typstorage);
                               1832                 :     }
                               1833                 : 
 4163 tgl                      1834 CBC      469819 :     *((char *) ptr) = flags;
                               1835                 : 
 4163 tgl                      1836 GIC      469819 :     return range;
 4175 heikki.linnakangas       1837 ECB             : }
                               1838                 : 
                               1839                 : /*
                               1840                 :  * range_deserialize: deconstruct a range value
 4164 tgl                      1841                 :  *
                               1842                 :  * NB: the given range object must be fully detoasted; it cannot have a
                               1843                 :  * short varlena header.
                               1844                 :  *
                               1845                 :  * Note that if the element type is pass-by-reference, the datums in the
                               1846                 :  * RangeBound structs will be pointers into the given range object.
                               1847                 :  */
                               1848                 : void
 1256 peter                    1849 GIC     4814011 : range_deserialize(TypeCacheEntry *typcache, const RangeType *range,
                               1850                 :                   RangeBound *lower, RangeBound *upper, bool *empty)
                               1851                 : {
 4175 heikki.linnakangas       1852 ECB             :     char        flags;
 4163 tgl                      1853                 :     int16       typlen;
                               1854                 :     bool        typbyval;
                               1855                 :     char        typalign;
                               1856                 :     Pointer     ptr;
                               1857                 :     Datum       lbound;
                               1858                 :     Datum       ubound;
                               1859                 : 
                               1860                 :     /* assert caller passed the right typcache entry */
 4163 tgl                      1861 GIC     4814011 :     Assert(RangeTypeGetOid(range) == typcache->type_id);
 4175 heikki.linnakangas       1862 ECB             : 
 4164 tgl                      1863                 :     /* fetch the flag byte from datum's last byte */
 1256 peter                    1864 GIC     4814011 :     flags = *((const char *) range + VARSIZE(range) - 1);
 4175 heikki.linnakangas       1865 ECB             : 
                               1866                 :     /* fetch information about range's element type */
 4163 tgl                      1867 GIC     4814011 :     typlen = typcache->rngelemtype->typlen;
                               1868         4814011 :     typbyval = typcache->rngelemtype->typbyval;
                               1869         4814011 :     typalign = typcache->rngelemtype->typalign;
 4175 heikki.linnakangas       1870 ECB             : 
                               1871                 :     /* initialize data pointer just after the range OID */
 4163 tgl                      1872 GIC     4814011 :     ptr = (Pointer) (range + 1);
 4175 heikki.linnakangas       1873 ECB             : 
 4164 tgl                      1874                 :     /* fetch lower bound, if any */
 4175 heikki.linnakangas       1875 GIC     4814011 :     if (RANGE_HAS_LBOUND(flags))
                               1876                 :     {
 4164 tgl                      1877 ECB             :         /* att_align_pointer cannot be necessary here */
 4175 heikki.linnakangas       1878 GIC     4258782 :         lbound = fetch_att(ptr, typbyval, typlen);
 4164 tgl                      1879 CBC     4258782 :         ptr = (Pointer) att_addlength_pointer(ptr, typlen, ptr);
                               1880                 :     }
 4175 heikki.linnakangas       1881 ECB             :     else
 4175 heikki.linnakangas       1882 GIC      555229 :         lbound = (Datum) 0;
 4175 heikki.linnakangas       1883 ECB             : 
 4164 tgl                      1884                 :     /* fetch upper bound, if any */
 4175 heikki.linnakangas       1885 GIC     4814011 :     if (RANGE_HAS_UBOUND(flags))
                               1886                 :     {
                               1887         4266555 :         ptr = (Pointer) att_align_pointer(ptr, typalign, typlen, ptr);
 4175 heikki.linnakangas       1888 CBC     4266555 :         ubound = fetch_att(ptr, typbyval, typlen);
                               1889                 :         /* no need for att_addlength_pointer */
 4175 heikki.linnakangas       1890 ECB             :     }
                               1891                 :     else
 4175 heikki.linnakangas       1892 GIC      547456 :         ubound = (Datum) 0;
                               1893                 : 
                               1894                 :     /* emit results */
 4164 tgl                      1895 ECB             : 
 4163 tgl                      1896 GIC     4814011 :     *empty = (flags & RANGE_EMPTY) != 0;
 4175 heikki.linnakangas       1897 ECB             : 
 4164 bruce                    1898 GIC     4814011 :     lower->val = lbound;
      tgl                      1899         4814011 :     lower->infinite = (flags & RANGE_LB_INF) != 0;
 4163                          1900         4814011 :     lower->inclusive = (flags & RANGE_LB_INC) != 0;
 4164 bruce                    1901         4814011 :     lower->lower = true;
                               1902                 : 
                               1903         4814011 :     upper->val = ubound;
      tgl                      1904         4814011 :     upper->infinite = (flags & RANGE_UB_INF) != 0;
 4163                          1905         4814011 :     upper->inclusive = (flags & RANGE_UB_INC) != 0;
 4164 bruce                    1906         4814011 :     upper->lower = false;
 4175 heikki.linnakangas       1907         4814011 : }
                               1908                 : 
                               1909                 : /*
 4163 tgl                      1910 ECB             :  * range_get_flags: just get the flags from a RangeType value.
                               1911                 :  *
                               1912                 :  * This is frequently useful in places that only need the flags and not
                               1913                 :  * the full results of range_deserialize.
                               1914                 :  */
                               1915                 : char
 1256 peter                    1916 GIC     1477088 : range_get_flags(const RangeType *range)
                               1917                 : {
                               1918                 :     /* fetch the flag byte from datum's last byte */
 4163 tgl                      1919         1477088 :     return *((char *) range + VARSIZE(range) - 1);
                               1920                 : }
                               1921                 : 
 4151 tgl                      1922 ECB             : /*
                               1923                 :  * range_set_contain_empty: set the RANGE_CONTAIN_EMPTY bit in the value.
                               1924                 :  *
                               1925                 :  * This is only needed in GiST operations, so we don't include a provision
                               1926                 :  * for setting it in range_serialize; rather, this function must be applied
                               1927                 :  * afterwards.
                               1928                 :  */
                               1929                 : void
 4151 tgl                      1930 CBC           9 : range_set_contain_empty(RangeType *range)
                               1931                 : {
                               1932                 :     char       *flagsp;
 4151 tgl                      1933 ECB             : 
                               1934                 :     /* flag byte is datum's last byte */
 4151 tgl                      1935 GIC           9 :     flagsp = (char *) range + VARSIZE(range) - 1;
 4151 tgl                      1936 ECB             : 
 4151 tgl                      1937 GIC           9 :     *flagsp |= RANGE_CONTAIN_EMPTY;
                               1938               9 : }
 4151 tgl                      1939 ECB             : 
 4175 heikki.linnakangas       1940                 : /*
                               1941                 :  * This both serializes and canonicalizes (if applicable) the range.
                               1942                 :  * This should be used by most callers.
                               1943                 :  */
                               1944                 : RangeType *
 4163 tgl                      1945 GIC      236600 : make_range(TypeCacheEntry *typcache, RangeBound *lower, RangeBound *upper,
                               1946                 :            bool empty, struct Node *escontext)
                               1947                 : {
 4163 tgl                      1948 ECB             :     RangeType  *range;
 4175 heikki.linnakangas       1949                 : 
  115 tgl                      1950 GNC      236600 :     range = range_serialize(typcache, lower, upper, empty, escontext);
                               1951                 : 
                               1952          236573 :     if (SOFT_ERROR_OCCURRED(escontext))
                               1953               6 :         return NULL;
                               1954                 : 
                               1955                 :     /* no need to call canonical on empty ranges ... */
 4156 tgl                      1956 CBC      236567 :     if (OidIsValid(typcache->rng_canonical_finfo.fn_oid) &&
 4156 tgl                      1957 GIC      233773 :         !RangeIsEmpty(range))
                               1958                 :     {
                               1959                 :         /* Do this the hard way so that we can pass escontext */
  115 tgl                      1960 GNC      231958 :         LOCAL_FCINFO(fcinfo, 1);
                               1961                 :         Datum       result;
                               1962                 : 
                               1963          231958 :         InitFunctionCallInfoData(*fcinfo, &typcache->rng_canonical_finfo, 1,
                               1964                 :                                  InvalidOid, escontext, NULL);
                               1965                 : 
                               1966          231958 :         fcinfo->args[0].value = RangeTypePGetDatum(range);
                               1967          231958 :         fcinfo->args[0].isnull = false;
                               1968                 : 
                               1969          231958 :         result = FunctionCallInvoke(fcinfo);
                               1970                 : 
                               1971          231958 :         if (SOFT_ERROR_OCCURRED(escontext))
                               1972              12 :             return NULL;
                               1973                 : 
                               1974                 :         /* Should not get a null result if there was no error */
                               1975          231946 :         if (fcinfo->isnull)
  115 tgl                      1976 UNC           0 :             elog(ERROR, "function %u returned NULL",
                               1977                 :                  typcache->rng_canonical_finfo.fn_oid);
                               1978                 : 
  115 tgl                      1979 GNC      231946 :         range = DatumGetRangeTypeP(result);
                               1980                 :     }
 4175 heikki.linnakangas       1981 ECB             : 
 4163 tgl                      1982 GIC      236555 :     return range;
 4175 heikki.linnakangas       1983 ECB             : }
                               1984                 : 
 4161 tgl                      1985                 : /*
                               1986                 :  * Compare two range boundary points, returning <0, 0, or >0 according to
                               1987                 :  * whether b1 is less than, equal to, or greater than b2.
                               1988                 :  *
                               1989                 :  * The boundaries can be any combination of upper and lower; so it's useful
                               1990                 :  * for a variety of operators.
                               1991                 :  *
                               1992                 :  * The simple case is when b1 and b2 are both finite and inclusive, in which
                               1993                 :  * case the result is just a comparison of the values held in b1 and b2.
                               1994                 :  *
                               1995                 :  * If a bound is exclusive, then we need to know whether it's a lower bound,
                               1996                 :  * in which case we treat the boundary point as "just greater than" the held
                               1997                 :  * value; or an upper bound, in which case we treat the boundary point as
                               1998                 :  * "just less than" the held value.
                               1999                 :  *
                               2000                 :  * If a bound is infinite, it represents minus infinity (less than every other
                               2001                 :  * point) if it's a lower bound; or plus infinity (greater than every other
                               2002                 :  * point) if it's an upper bound.
                               2003                 :  *
                               2004                 :  * There is only one case where two boundaries compare equal but are not
                               2005                 :  * identical: when both bounds are inclusive and hold the same finite value,
                               2006                 :  * but one is an upper bound and the other a lower bound.
                               2007                 :  */
                               2008                 : int
 1256 peter                    2009 GIC     6066546 : range_cmp_bounds(TypeCacheEntry *typcache, const RangeBound *b1, const RangeBound *b2)
                               2010                 : {
                               2011                 :     int32       result;
                               2012                 : 
                               2013                 :     /*
                               2014                 :      * First, handle cases involving infinity, which don't require invoking
 4161 tgl                      2015 ECB             :      * the comparison proc.
                               2016                 :      */
 4175 heikki.linnakangas       2017 GIC     6066546 :     if (b1->infinite && b2->infinite)
                               2018                 :     {
                               2019                 :         /*
 4161 tgl                      2020 ECB             :          * Both are infinity, so they are equal unless one is lower and the
                               2021                 :          * other not.
                               2022                 :          */
 4175 heikki.linnakangas       2023 CBC        8101 :         if (b1->lower == b2->lower)
 4175 heikki.linnakangas       2024 GIC        8059 :             return 0;
                               2025                 :         else
 4161 tgl                      2026              42 :             return b1->lower ? -1 : 1;
                               2027                 :     }
                               2028         6058445 :     else if (b1->infinite)
                               2029           47572 :         return b1->lower ? -1 : 1;
 4161 tgl                      2030 CBC     6010873 :     else if (b2->infinite)
 4161 tgl                      2031 GIC       14006 :         return b2->lower ? 1 : -1;
                               2032                 : 
                               2033                 :     /*
                               2034                 :      * Both boundaries are finite, so compare the held values.
 4161 tgl                      2035 ECB             :      */
 4163 tgl                      2036 GIC     5996867 :     result = DatumGetInt32(FunctionCall2Coll(&typcache->rng_cmp_proc_finfo,
 4163 tgl                      2037 ECB             :                                              typcache->rng_collation,
 4175 heikki.linnakangas       2038 CBC     5996867 :                                              b1->val, b2->val));
                               2039                 : 
                               2040                 :     /*
 4161 tgl                      2041 ECB             :      * If the comparison is anything other than equal, we're done. If they
                               2042                 :      * compare equal though, we still have to consider whether the boundaries
                               2043                 :      * are inclusive or exclusive.
                               2044                 :      */
 4175 heikki.linnakangas       2045 CBC     5996867 :     if (result == 0)
                               2046                 :     {
 4161 tgl                      2047 GIC      346864 :         if (!b1->inclusive && !b2->inclusive)
 4161 tgl                      2048 ECB             :         {
                               2049                 :             /* both are exclusive */
 4161 tgl                      2050 GIC      153823 :             if (b1->lower == b2->lower)
 4161 tgl                      2051 CBC      153820 :                 return 0;
 4161 tgl                      2052 ECB             :             else
 4161 tgl                      2053 GIC           3 :                 return b1->lower ? 1 : -1;
 4161 tgl                      2054 ECB             :         }
 4161 tgl                      2055 GIC      193041 :         else if (!b1->inclusive)
 4161 tgl                      2056 CBC         315 :             return b1->lower ? 1 : -1;
                               2057          192726 :         else if (!b2->inclusive)
 4161 tgl                      2058 GIC         413 :             return b2->lower ? -1 : 1;
                               2059                 :         else
 4161 tgl                      2060 ECB             :         {
 4161 tgl                      2061 EUB             :             /*
                               2062                 :              * Both are inclusive and the values held are equal, so they are
                               2063                 :              * equal regardless of whether they are upper or lower boundaries,
 4161 tgl                      2064 ECB             :              * or a mix.
                               2065                 :              */
 4161 tgl                      2066 GIC      192313 :             return 0;
 4161 tgl                      2067 ECB             :         }
                               2068                 :     }
                               2069                 : 
 4175 heikki.linnakangas       2070 GIC     5650003 :     return result;
                               2071                 : }
                               2072                 : 
                               2073                 : /*
                               2074                 :  * Compare two range boundary point values, returning <0, 0, or >0 according
                               2075                 :  * to whether b1 is less than, equal to, or greater than b2.
                               2076                 :  *
                               2077                 :  * This is similar to but simpler than range_cmp_bounds().  We just compare
                               2078                 :  * the values held in b1 and b2, ignoring inclusive/exclusive flags.  The
                               2079                 :  * lower/upper flags only matter for infinities, where they tell us if the
                               2080                 :  * infinity is plus or minus.
                               2081                 :  */
                               2082                 : int
 1256 peter                    2083          704332 : range_cmp_bound_values(TypeCacheEntry *typcache, const RangeBound *b1,
                               2084                 :                        const RangeBound *b2)
                               2085                 : {
                               2086                 :     /*
                               2087                 :      * First, handle cases involving infinity, which don't require invoking
                               2088                 :      * the comparison proc.
                               2089                 :      */
 4156 tgl                      2090          704332 :     if (b1->infinite && b2->infinite)
                               2091                 :     {
                               2092                 :         /*
                               2093                 :          * Both are infinity, so they are equal unless one is lower and the
 4156 tgl                      2094 ECB             :          * other not.
                               2095                 :          */
 4156 tgl                      2096 GIC         137 :         if (b1->lower == b2->lower)
 4156 tgl                      2097 UIC           0 :             return 0;
                               2098                 :         else
 4156 tgl                      2099 GIC         137 :             return b1->lower ? -1 : 1;
                               2100                 :     }
                               2101          704195 :     else if (b1->infinite)
 4156 tgl                      2102 CBC        8166 :         return b1->lower ? -1 : 1;
 4156 tgl                      2103 GIC      696029 :     else if (b2->infinite)
                               2104            6910 :         return b2->lower ? 1 : -1;
                               2105                 : 
                               2106                 :     /*
                               2107                 :      * Both boundaries are finite, so compare the held values.
 4156 tgl                      2108 ECB             :      */
 4156 tgl                      2109 CBC      689119 :     return DatumGetInt32(FunctionCall2Coll(&typcache->rng_cmp_proc_finfo,
                               2110                 :                                            typcache->rng_collation,
                               2111          689119 :                                            b1->val, b2->val));
                               2112                 : }
 4156 tgl                      2113 ECB             : 
  840 akorotkov                2114                 : /*
                               2115                 :  * qsort callback for sorting ranges.
                               2116                 :  *
                               2117                 :  * Two empty ranges compare equal; an empty range sorts to the left of any
                               2118                 :  * non-empty range.  Two non-empty ranges are sorted by lower bound first
                               2119                 :  * and by upper bound next.
                               2120                 :  */
                               2121                 : int
  840 akorotkov                2122 GIC       13359 : range_compare(const void *key1, const void *key2, void *arg)
  840 akorotkov                2123 ECB             : {
  840 akorotkov                2124 GIC       13359 :     RangeType  *r1 = *(RangeType **) key1;
                               2125           13359 :     RangeType  *r2 = *(RangeType **) key2;
                               2126           13359 :     TypeCacheEntry *typcache = (TypeCacheEntry *) arg;
                               2127                 :     RangeBound  lower1;
                               2128                 :     RangeBound  upper1;
                               2129                 :     RangeBound  lower2;
  840 akorotkov                2130 ECB             :     RangeBound  upper2;
                               2131                 :     bool        empty1;
                               2132                 :     bool        empty2;
                               2133                 :     int         cmp;
                               2134                 : 
  840 akorotkov                2135 CBC       13359 :     range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
                               2136           13359 :     range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
                               2137                 : 
                               2138           13359 :     if (empty1 && empty2)
  840 akorotkov                2139 GIC          24 :         cmp = 0;
  840 akorotkov                2140 CBC       13335 :     else if (empty1)
                               2141              21 :         cmp = -1;
                               2142           13314 :     else if (empty2)
                               2143               6 :         cmp = 1;
                               2144                 :     else
                               2145                 :     {
  840 akorotkov                2146 GIC       13308 :         cmp = range_cmp_bounds(typcache, &lower1, &lower2);
                               2147           13308 :         if (cmp == 0)
                               2148              24 :             cmp = range_cmp_bounds(typcache, &upper1, &upper2);
                               2149                 :     }
                               2150                 : 
  840 akorotkov                2151 CBC       13359 :     return cmp;
                               2152                 : }
                               2153                 : 
                               2154                 : /*
 4156 tgl                      2155 ECB             :  * Build an empty range value of the type indicated by the typcache entry.
                               2156                 :  */
                               2157                 : RangeType *
 4163 tgl                      2158 GIC        1560 : make_empty_range(TypeCacheEntry *typcache)
                               2159                 : {
                               2160                 :     RangeBound  lower;
                               2161                 :     RangeBound  upper;
                               2162                 : 
                               2163            1560 :     lower.val = (Datum) 0;
                               2164            1560 :     lower.infinite = false;
                               2165            1560 :     lower.inclusive = false;
 4175 heikki.linnakangas       2166            1560 :     lower.lower = true;
                               2167                 : 
 4163 tgl                      2168 CBC        1560 :     upper.val = (Datum) 0;
 4163 tgl                      2169 GIC        1560 :     upper.infinite = false;
                               2170            1560 :     upper.inclusive = false;
 4175 heikki.linnakangas       2171            1560 :     upper.lower = false;
                               2172                 : 
  115 tgl                      2173 GNC        1560 :     return make_range(typcache, &lower, &upper, true, NULL);
                               2174                 : }
 4175 heikki.linnakangas       2175 ECB             : 
                               2176                 : 
                               2177                 : /*
                               2178                 :  *----------------------------------------------------------
                               2179                 :  * STATIC FUNCTIONS
                               2180                 :  *----------------------------------------------------------
 4164 tgl                      2181                 :  */
 4164 tgl                      2182 EUB             : 
                               2183                 : /*
 4175 heikki.linnakangas       2184 ECB             :  * Given a string representing the flags for the range type, return the flags
                               2185                 :  * represented as a char.
                               2186                 :  */
 4164 tgl                      2187                 : static char
 4164 tgl                      2188 CBC        2559 : range_parse_flags(const char *flags_str)
 4175 heikki.linnakangas       2189 ECB             : {
 4164 bruce                    2190 GIC        2559 :     char        flags = 0;
                               2191                 : 
 4175 heikki.linnakangas       2192            2559 :     if (flags_str[0] == '\0' ||
                               2193            2559 :         flags_str[1] == '\0' ||
 4175 heikki.linnakangas       2194 CBC        2559 :         flags_str[2] != '\0')
 4175 heikki.linnakangas       2195 UIC           0 :         ereport(ERROR,
 4175 heikki.linnakangas       2196 ECB             :                 (errcode(ERRCODE_SYNTAX_ERROR),
                               2197                 :                  errmsg("invalid range bound flags"),
                               2198                 :                  errhint("Valid values are \"[]\", \"[)\", \"(]\", and \"()\".")));
                               2199                 : 
 4175 heikki.linnakangas       2200 GIC        2559 :     switch (flags_str[0])
                               2201                 :     {
                               2202             105 :         case '[':
                               2203             105 :             flags |= RANGE_LB_INC;
                               2204             105 :             break;
                               2205            2454 :         case '(':
                               2206            2454 :             break;
 4175 heikki.linnakangas       2207 LBC           0 :         default:
 4175 heikki.linnakangas       2208 UIC           0 :             ereport(ERROR,
 4175 heikki.linnakangas       2209 ECB             :                     (errcode(ERRCODE_SYNTAX_ERROR),
                               2210                 :                      errmsg("invalid range bound flags"),
 2118 tgl                      2211                 :                      errhint("Valid values are \"[]\", \"[)\", \"(]\", and \"()\".")));
                               2212                 :     }
                               2213                 : 
 4175 heikki.linnakangas       2214 GIC        2559 :     switch (flags_str[1])
                               2215                 :     {
                               2216            2517 :         case ']':
                               2217            2517 :             flags |= RANGE_UB_INC;
                               2218            2517 :             break;
                               2219              42 :         case ')':
 4175 heikki.linnakangas       2220 CBC          42 :             break;
 4175 heikki.linnakangas       2221 LBC           0 :         default:
 4175 heikki.linnakangas       2222 UIC           0 :             ereport(ERROR,
 4175 heikki.linnakangas       2223 ECB             :                     (errcode(ERRCODE_SYNTAX_ERROR),
                               2224                 :                      errmsg("invalid range bound flags"),
 2118 tgl                      2225                 :                      errhint("Valid values are \"[]\", \"[)\", \"(]\", and \"()\".")));
 4175 heikki.linnakangas       2226                 :     }
                               2227                 : 
 4175 heikki.linnakangas       2228 CBC        2559 :     return flags;
                               2229                 : }
                               2230                 : 
 4175 heikki.linnakangas       2231 ECB             : /*
 4156 tgl                      2232                 :  * Parse range input.
 4175 heikki.linnakangas       2233                 :  *
                               2234                 :  * Input parameters:
                               2235                 :  *  string: input string to be parsed
 4156 tgl                      2236                 :  * Output parameters:
                               2237                 :  *  *flags: receives flags bitmask
                               2238                 :  *  *lbound_str: receives palloc'd lower bound string, or NULL if none
                               2239                 :  *  *ubound_str: receives palloc'd upper bound string, or NULL if none
                               2240                 :  *
                               2241                 :  * This is modeled somewhat after record_in in rowtypes.c.
                               2242                 :  * The input syntax is:
 4164 bruce                    2243                 :  *  <range>   := EMPTY
                               2244                 :  *             | <lb-inc> <string>, <string> <ub-inc>
                               2245                 :  *  <lb-inc>  := '[' | '('
                               2246                 :  *  <ub-inc>  := ']' | ')'
                               2247                 :  *
 4156 tgl                      2248                 :  * Whitespace before or after <range> is ignored.  Whitespace within a <string>
                               2249                 :  * is taken literally and becomes part of the input string for that bound.
 4175 heikki.linnakangas       2250                 :  *
 4156 tgl                      2251                 :  * A <string> of length zero is taken as "infinite" (i.e. no bound), unless it
                               2252                 :  * is surrounded by double-quotes, in which case it is the literal empty
 4175 heikki.linnakangas       2253                 :  * string.
                               2254                 :  *
                               2255                 :  * Within a <string>, special characters (such as comma, parenthesis, or
                               2256                 :  * brackets) can be enclosed in double-quotes or escaped with backslash. Within
                               2257                 :  * double-quotes, a double-quote can be escaped with double-quote or backslash.
                               2258                 :  *
                               2259                 :  * Returns true on success, false on failure (but failures will return only if
                               2260                 :  * escontext is an ErrorSaveContext).
                               2261                 :  */
                               2262                 : static bool
 4156 tgl                      2263 GIC        1471 : range_parse(const char *string, char *flags, char **lbound_str,
                               2264                 :             char **ubound_str, Node *escontext)
                               2265                 : {
                               2266            1471 :     const char *ptr = string;
                               2267                 :     bool        infinite;
                               2268                 : 
 4175 heikki.linnakangas       2269            1471 :     *flags = 0;
                               2270                 : 
                               2271                 :     /* consume whitespace */
 4163 tgl                      2272            1483 :     while (*ptr != '\0' && isspace((unsigned char) *ptr))
 4175 heikki.linnakangas       2273              12 :         ptr++;
                               2274                 : 
                               2275                 :     /* check for empty range */
 4175 heikki.linnakangas       2276 CBC        1471 :     if (pg_strncasecmp(ptr, RANGE_EMPTY_LITERAL,
                               2277                 :                        strlen(RANGE_EMPTY_LITERAL)) == 0)
 4175 heikki.linnakangas       2278 ECB             :     {
 4175 heikki.linnakangas       2279 GIC         270 :         *flags = RANGE_EMPTY;
 4156 tgl                      2280 CBC         270 :         *lbound_str = NULL;
                               2281             270 :         *ubound_str = NULL;
 4175 heikki.linnakangas       2282 ECB             : 
 4175 heikki.linnakangas       2283 GBC         270 :         ptr += strlen(RANGE_EMPTY_LITERAL);
                               2284                 : 
                               2285                 :         /* the rest should be whitespace */
 4163 tgl                      2286 GIC         276 :         while (*ptr != '\0' && isspace((unsigned char) *ptr))
 4175 heikki.linnakangas       2287               6 :             ptr++;
 4175 heikki.linnakangas       2288 ECB             : 
                               2289                 :         /* should have consumed everything */
 4175 heikki.linnakangas       2290 CBC         270 :         if (*ptr != '\0')
  115 tgl                      2291 UNC           0 :             ereturn(escontext, false,
 4175 heikki.linnakangas       2292 ECB             :                     (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                               2293                 :                      errmsg("malformed range literal: \"%s\"",
                               2294                 :                             string),
 3738 peter_e                  2295 EUB             :                      errdetail("Junk after \"empty\" key word.")));
 4175 heikki.linnakangas       2296                 : 
  115 tgl                      2297 GNC         270 :         return true;
                               2298                 :     }
                               2299                 : 
 4156 tgl                      2300 GIC        1201 :     if (*ptr == '[')
                               2301                 :     {
 4156 tgl                      2302 CBC         864 :         *flags |= RANGE_LB_INC;
 4175 heikki.linnakangas       2303 GIC         864 :         ptr++;
 4175 heikki.linnakangas       2304 ECB             :     }
 4156 tgl                      2305 CBC         337 :     else if (*ptr == '(')
                               2306             331 :         ptr++;
 4175 heikki.linnakangas       2307 ECB             :     else
  115 tgl                      2308 GNC           6 :         ereturn(escontext, false,
 4175 heikki.linnakangas       2309 EUB             :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                               2310                 :                  errmsg("malformed range literal: \"%s\"",
                               2311                 :                         string),
                               2312                 :                  errdetail("Missing left parenthesis or bracket.")));
                               2313                 : 
  115 tgl                      2314 GNC        1195 :     ptr = range_parse_bound(string, ptr, lbound_str, &infinite, escontext);
                               2315            1192 :     if (ptr == NULL)
  115 tgl                      2316 UNC           0 :         return false;
 4175 heikki.linnakangas       2317 GIC        1192 :     if (infinite)
 4175 heikki.linnakangas       2318 CBC          81 :         *flags |= RANGE_LB_INF;
                               2319                 : 
 4156 tgl                      2320 GIC        1192 :     if (*ptr == ',')
                               2321            1180 :         ptr++;
                               2322                 :     else
  115 tgl                      2323 GNC          12 :         ereturn(escontext, false,
                               2324                 :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                               2325                 :                  errmsg("malformed range literal: \"%s\"",
                               2326                 :                         string),
                               2327                 :                  errdetail("Missing comma after lower bound.")));
                               2328                 : 
                               2329            1180 :     ptr = range_parse_bound(string, ptr, ubound_str, &infinite, escontext);
                               2330            1180 :     if (ptr == NULL)
                               2331               6 :         return false;
 4156 tgl                      2332 GIC        1174 :     if (infinite)
                               2333             123 :         *flags |= RANGE_UB_INF;
                               2334                 : 
                               2335            1174 :     if (*ptr == ']')
                               2336                 :     {
                               2337             313 :         *flags |= RANGE_UB_INC;
                               2338             313 :         ptr++;
                               2339                 :     }
                               2340             861 :     else if (*ptr == ')')
                               2341             855 :         ptr++;
                               2342                 :     else                        /* must be a comma */
  115 tgl                      2343 GNC           6 :         ereturn(escontext, false,
                               2344                 :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                               2345                 :                  errmsg("malformed range literal: \"%s\"",
                               2346                 :                         string),
                               2347                 :                  errdetail("Too many commas.")));
                               2348                 : 
                               2349                 :     /* consume whitespace */
 4163 tgl                      2350 GIC        1183 :     while (*ptr != '\0' && isspace((unsigned char) *ptr))
 4175 heikki.linnakangas       2351              15 :         ptr++;
                               2352                 : 
                               2353            1168 :     if (*ptr != '\0')
  115 tgl                      2354 GNC           9 :         ereturn(escontext, false,
 4175 heikki.linnakangas       2355 ECB             :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                               2356                 :                  errmsg("malformed range literal: \"%s\"",
                               2357                 :                         string),
                               2358                 :                  errdetail("Junk after right parenthesis or bracket.")));
                               2359                 : 
  115 tgl                      2360 GNC        1159 :     return true;
                               2361                 : }
                               2362                 : 
 4156 tgl                      2363 ECB             : /*
                               2364                 :  * Helper for range_parse: parse and de-quote one bound string.
                               2365                 :  *
                               2366                 :  * We scan until finding comma, right parenthesis, or right bracket.
                               2367                 :  *
                               2368                 :  * Input parameters:
                               2369                 :  *  string: entire input string (used only for error reports)
                               2370                 :  *  ptr: where to start parsing bound
                               2371                 :  * Output parameters:
                               2372                 :  *  *bound_str: receives palloc'd bound string, or NULL if none
                               2373                 :  *  *infinite: set true if no bound, else false
                               2374                 :  *
                               2375                 :  * The return value is the scan ptr, advanced past the bound string.
                               2376                 :  * However, if escontext is an ErrorSaveContext, we return NULL on failure.
                               2377                 :  */
                               2378                 : static const char *
 4156 tgl                      2379 GIC        2375 : range_parse_bound(const char *string, const char *ptr,
                               2380                 :                   char **bound_str, bool *infinite, Node *escontext)
 4175 heikki.linnakangas       2381 ECB             : {
 4164 bruce                    2382                 :     StringInfoData buf;
                               2383                 : 
                               2384                 :     /* Check for null: completely empty input means null */
 4175 heikki.linnakangas       2385 CBC        2375 :     if (*ptr == ',' || *ptr == ')' || *ptr == ']')
 4175 heikki.linnakangas       2386 EUB             :     {
 4175 heikki.linnakangas       2387 GIC         204 :         *bound_str = NULL;
 4164 bruce                    2388             204 :         *infinite = true;
                               2389                 :     }
                               2390                 :     else
                               2391                 :     {
 4156 tgl                      2392 ECB             :         /* Extract string for this bound */
 4175 heikki.linnakangas       2393 GIC        2171 :         bool        inquote = false;
                               2394                 : 
 4175 heikki.linnakangas       2395 CBC        2171 :         initStringInfo(&buf);
 4175 heikki.linnakangas       2396 GIC        7868 :         while (inquote || !(*ptr == ',' || *ptr == ')' || *ptr == ']'))
 4175 heikki.linnakangas       2397 ECB             :         {
 4175 heikki.linnakangas       2398 CBC        5706 :             char        ch = *ptr++;
                               2399                 : 
                               2400            5706 :             if (ch == '\0')
  115 tgl                      2401 GNC           9 :                 ereturn(escontext, NULL,
                               2402                 :                         (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 4175 heikki.linnakangas       2403 ECB             :                          errmsg("malformed range literal: \"%s\"",
                               2404                 :                                 string),
                               2405                 :                          errdetail("Unexpected end of input.")));
 4175 heikki.linnakangas       2406 GIC        5697 :             if (ch == '\\')
                               2407                 :             {
                               2408              21 :                 if (*ptr == '\0')
  115 tgl                      2409 UNC           0 :                     ereturn(escontext, NULL,
 4175 heikki.linnakangas       2410 ECB             :                             (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 4175 heikki.linnakangas       2411 EUB             :                              errmsg("malformed range literal: \"%s\"",
 4175 heikki.linnakangas       2412 ECB             :                                     string),
                               2413                 :                              errdetail("Unexpected end of input.")));
 4175 heikki.linnakangas       2414 GIC          21 :                 appendStringInfoChar(&buf, *ptr++);
 4175 heikki.linnakangas       2415 ECB             :             }
 2665 peter_e                  2416 CBC        5676 :             else if (ch == '"')
                               2417                 :             {
 4175 heikki.linnakangas       2418             200 :                 if (!inquote)
 4175 heikki.linnakangas       2419 GIC         100 :                     inquote = true;
 2665 peter_e                  2420             100 :                 else if (*ptr == '"')
                               2421                 :                 {
                               2422                 :                     /* doubled quote within quote sequence */
 4175 heikki.linnakangas       2423               3 :                     appendStringInfoChar(&buf, *ptr++);
 4175 heikki.linnakangas       2424 ECB             :                 }
                               2425                 :                 else
 4175 heikki.linnakangas       2426 CBC          97 :                     inquote = false;
 4175 heikki.linnakangas       2427 ECB             :             }
                               2428                 :             else
 4175 heikki.linnakangas       2429 GIC        5476 :                 appendStringInfoChar(&buf, ch);
 4175 heikki.linnakangas       2430 ECB             :         }
                               2431                 : 
 4175 heikki.linnakangas       2432 CBC        2162 :         *bound_str = buf.data;
 4164 bruce                    2433            2162 :         *infinite = false;
                               2434                 :     }
 4175 heikki.linnakangas       2435 ECB             : 
 4175 heikki.linnakangas       2436 CBC        2366 :     return ptr;
                               2437                 : }
 4175 heikki.linnakangas       2438 ECB             : 
                               2439                 : /*
                               2440                 :  * Convert a deserialized range value to text form
                               2441                 :  *
                               2442                 :  * Inputs are the flags byte, and the two bound values already converted to
                               2443                 :  * text (but not yet quoted).  If no bound value, pass NULL.
                               2444                 :  *
 4163 tgl                      2445                 :  * Result is a palloc'd string
                               2446                 :  */
                               2447                 : static char *
 4156 tgl                      2448 CBC       52061 : range_deparse(char flags, const char *lbound_str, const char *ubound_str)
 4175 heikki.linnakangas       2449 ECB             : {
                               2450                 :     StringInfoData buf;
                               2451                 : 
 4175 heikki.linnakangas       2452 GIC       52061 :     if (flags & RANGE_EMPTY)
                               2453            8452 :         return pstrdup(RANGE_EMPTY_LITERAL);
                               2454                 : 
 4163 tgl                      2455 CBC       43609 :     initStringInfo(&buf);
                               2456                 : 
 4156 tgl                      2457 GIC       43609 :     appendStringInfoChar(&buf, (flags & RANGE_LB_INC) ? '[' : '(');
                               2458                 : 
 4175 heikki.linnakangas       2459           43609 :     if (RANGE_HAS_LBOUND(flags))
                               2460           42382 :         appendStringInfoString(&buf, range_bound_escape(lbound_str));
                               2461                 : 
 4156 tgl                      2462           43609 :     appendStringInfoChar(&buf, ',');
                               2463                 : 
 4175 heikki.linnakangas       2464           43609 :     if (RANGE_HAS_UBOUND(flags))
                               2465           42349 :         appendStringInfoString(&buf, range_bound_escape(ubound_str));
                               2466                 : 
 4156 tgl                      2467           43609 :     appendStringInfoChar(&buf, (flags & RANGE_UB_INC) ? ']' : ')');
                               2468                 : 
 4175 heikki.linnakangas       2469           43609 :     return buf.data;
                               2470                 : }
                               2471                 : 
                               2472                 : /*
                               2473                 :  * Helper for range_deparse: quote a bound value as needed
 4163 tgl                      2474 ECB             :  *
                               2475                 :  * Result is a palloc'd string
                               2476                 :  */
                               2477                 : static char *
 4156 tgl                      2478 GIC       84731 : range_bound_escape(const char *value)
                               2479                 : {
 4164 bruce                    2480 ECB             :     bool        nq;
                               2481                 :     const char *ptr;
                               2482                 :     StringInfoData buf;
 4175 heikki.linnakangas       2483                 : 
 4175 heikki.linnakangas       2484 GIC       84731 :     initStringInfo(&buf);
                               2485                 : 
                               2486                 :     /* Detect whether we need double quotes for this value */
                               2487           84731 :     nq = (value[0] == '\0');    /* force quotes for empty string */
 4156 tgl                      2488 CBC      383970 :     for (ptr = value; *ptr; ptr++)
                               2489                 :     {
                               2490          299488 :         char        ch = *ptr;
 4175 heikki.linnakangas       2491 ECB             : 
 4175 heikki.linnakangas       2492 GIC      299488 :         if (ch == '"' || ch == '\\' ||
 4175 heikki.linnakangas       2493 CBC      299419 :             ch == '(' || ch == ')' ||
 4175 heikki.linnakangas       2494 GIC      299407 :             ch == '[' || ch == ']' ||
 4175 heikki.linnakangas       2495 CBC      299383 :             ch == ',' ||
                               2496          299383 :             isspace((unsigned char) ch))
                               2497                 :         {
 4175 heikki.linnakangas       2498 GIC         249 :             nq = true;
                               2499             249 :             break;
                               2500                 :         }
 4175 heikki.linnakangas       2501 ECB             :     }
                               2502                 : 
                               2503                 :     /* And emit the string */
 4175 heikki.linnakangas       2504 GBC       84731 :     if (nq)
 4175 heikki.linnakangas       2505 GIC         261 :         appendStringInfoChar(&buf, '"');
 4156 tgl                      2506          385917 :     for (ptr = value; *ptr; ptr++)
                               2507                 :     {
                               2508          301186 :         char        ch = *ptr;
 4175 heikki.linnakangas       2509 ECB             : 
 4175 heikki.linnakangas       2510 GIC      301186 :         if (ch == '"' || ch == '\\')
 4175 heikki.linnakangas       2511 CBC          60 :             appendStringInfoChar(&buf, ch);
 4175 heikki.linnakangas       2512 GIC      301186 :         appendStringInfoChar(&buf, ch);
 4175 heikki.linnakangas       2513 ECB             :     }
 4175 heikki.linnakangas       2514 CBC       84731 :     if (nq)
                               2515             261 :         appendStringInfoChar(&buf, '"');
                               2516                 : 
 4175 heikki.linnakangas       2517 GIC       84731 :     return buf.data;
 4175 heikki.linnakangas       2518 ECB             : }
                               2519                 : 
                               2520                 : /*
 4156 tgl                      2521                 :  * Test whether range r1 contains range r2.
                               2522                 :  *
                               2523                 :  * Caller has already checked that they are the same range type, and looked up
                               2524                 :  * the necessary typcache entry.
                               2525                 :  */
                               2526                 : bool
 1256 peter                    2527 CBC      243953 : range_contains_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
 4175 heikki.linnakangas       2528 ECB             : {
                               2529                 :     RangeBound  lower1;
                               2530                 :     RangeBound  upper1;
                               2531                 :     bool        empty1;
                               2532                 :     RangeBound  lower2;
                               2533                 :     RangeBound  upper2;
                               2534                 :     bool        empty2;
                               2535                 : 
                               2536                 :     /* Different types should be prevented by ANYRANGE matching rules */
 3917 heikki.linnakangas       2537 GIC      243953 :     if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
 3917 heikki.linnakangas       2538 UIC           0 :         elog(ERROR, "range types do not match");
                               2539                 : 
 4163 tgl                      2540 GIC      243953 :     range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
                               2541          243953 :     range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
                               2542                 : 
 4156 tgl                      2543 ECB             :     /* If either range is empty, the answer is easy */
 4175 heikki.linnakangas       2544 GIC      243953 :     if (empty2)
                               2545          157373 :         return true;
                               2546           86580 :     else if (empty1)
 4175 heikki.linnakangas       2547 CBC        6783 :         return false;
 4175 heikki.linnakangas       2548 ECB             : 
                               2549                 :     /* Else we must have lower1 <= lower2 and upper1 >= upper2 */
 4163 tgl                      2550 CBC       79797 :     if (range_cmp_bounds(typcache, &lower1, &lower2) > 0)
 4175 heikki.linnakangas       2551 GIC       38018 :         return false;
 4163 tgl                      2552 CBC       41779 :     if (range_cmp_bounds(typcache, &upper1, &upper2) < 0)
 4175 heikki.linnakangas       2553 GIC       37646 :         return false;
 4175 heikki.linnakangas       2554 ECB             : 
 4156 tgl                      2555 CBC        4133 :     return true;
                               2556                 : }
 4156 tgl                      2557 ECB             : 
                               2558                 : bool
 1256 peter                    2559 CBC       62345 : range_contained_by_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
 3917 heikki.linnakangas       2560 ECB             : {
 3917 heikki.linnakangas       2561 GIC       62345 :     return range_contains_internal(typcache, r2, r1);
 3917 heikki.linnakangas       2562 ECB             : }
                               2563                 : 
 4156 tgl                      2564                 : /*
                               2565                 :  * Test whether range r contains a specific element value.
                               2566                 :  */
                               2567                 : bool
 1256 peter                    2568 GIC       45578 : range_contains_elem_internal(TypeCacheEntry *typcache, const RangeType *r, Datum val)
                               2569                 : {
                               2570                 :     RangeBound  lower;
                               2571                 :     RangeBound  upper;
                               2572                 :     bool        empty;
 4156 tgl                      2573 ECB             :     int32       cmp;
                               2574                 : 
 4156 tgl                      2575 GIC       45578 :     range_deserialize(typcache, r, &lower, &upper, &empty);
                               2576                 : 
                               2577           45578 :     if (empty)
                               2578            6432 :         return false;
 4156 tgl                      2579 ECB             : 
 4156 tgl                      2580 GIC       39146 :     if (!lower.infinite)
                               2581                 :     {
 4156 tgl                      2582 CBC       37019 :         cmp = DatumGetInt32(FunctionCall2Coll(&typcache->rng_cmp_proc_finfo,
 4156 tgl                      2583 ECB             :                                               typcache->rng_collation,
                               2584                 :                                               lower.val, val));
 4156 tgl                      2585 CBC       37019 :         if (cmp > 0)
 4156 tgl                      2586 GIC       35691 :             return false;
 4156 tgl                      2587 CBC        1328 :         if (cmp == 0 && !lower.inclusive)
 4156 tgl                      2588 LBC           0 :             return false;
 4156 tgl                      2589 ECB             :     }
                               2590                 : 
 4156 tgl                      2591 CBC        3455 :     if (!upper.infinite)
                               2592                 :     {
                               2593            3437 :         cmp = DatumGetInt32(FunctionCall2Coll(&typcache->rng_cmp_proc_finfo,
 4156 tgl                      2594 ECB             :                                               typcache->rng_collation,
                               2595                 :                                               upper.val, val));
 4156 tgl                      2596 GIC        3437 :         if (cmp < 0)
                               2597             357 :             return false;
                               2598            3080 :         if (cmp == 0 && !upper.inclusive)
 4156 tgl                      2599 CBC           3 :             return false;
 4156 tgl                      2600 ECB             :     }
                               2601                 : 
 4175 heikki.linnakangas       2602 GIC        3095 :     return true;
 4175 heikki.linnakangas       2603 ECB             : }
                               2604                 : 
 4164 tgl                      2605                 : 
 4175 heikki.linnakangas       2606                 : /*
 4164 tgl                      2607                 :  * datum_compute_size() and datum_write() are used to insert the bound
                               2608                 :  * values into a range object.  They are modeled after heaptuple.c's
                               2609                 :  * heap_compute_data_size() and heap_fill_tuple(), but we need not handle
                               2610                 :  * null values here.  TYPE_IS_PACKABLE must test the same conditions as
                               2611                 :  * heaptuple.c's ATT_IS_PACKABLE macro.
 4175 heikki.linnakangas       2612                 :  */
                               2613                 : 
                               2614                 : /* Does datatype allow packing into the 1-byte-header varlena format? */
                               2615                 : #define TYPE_IS_PACKABLE(typlen, typstorage) \
                               2616                 :     ((typlen) == -1 && (typstorage) != TYPSTORAGE_PLAIN)
                               2617                 : 
                               2618                 : /*
                               2619                 :  * Increment data_length by the space needed by the datum, including any
                               2620                 :  * preceding alignment padding.
                               2621                 :  */
                               2622                 : static Size
 4175 heikki.linnakangas       2623 GIC      927320 : datum_compute_size(Size data_length, Datum val, bool typbyval, char typalign,
                               2624                 :                    int16 typlen, char typstorage)
                               2625                 : {
                               2626          927320 :     if (TYPE_IS_PACKABLE(typlen, typstorage) &&
                               2627            4704 :         VARATT_CAN_MAKE_SHORT(DatumGetPointer(val)))
                               2628                 :     {
                               2629                 :         /*
                               2630                 :          * we're anticipating converting to a short varlena header, so adjust
                               2631                 :          * length and don't count any alignment
 4175 heikki.linnakangas       2632 ECB             :          */
 4175 heikki.linnakangas       2633 GBC        4245 :         data_length += VARATT_CONVERTED_SHORT_SIZE(DatumGetPointer(val));
                               2634                 :     }
 4175 heikki.linnakangas       2635 ECB             :     else
                               2636                 :     {
 4175 heikki.linnakangas       2637 GIC      923075 :         data_length = att_align_datum(data_length, typalign, typlen, val);
                               2638          923075 :         data_length = att_addlength_datum(data_length, typlen, val);
 4175 heikki.linnakangas       2639 ECB             :     }
                               2640                 : 
 4175 heikki.linnakangas       2641 CBC      927320 :     return data_length;
 4175 heikki.linnakangas       2642 ECB             : }
                               2643                 : 
                               2644                 : /*
 4164 tgl                      2645                 :  * Write the given datum beginning at ptr (after advancing to correct
                               2646                 :  * alignment, if needed).  Return the pointer incremented by space used.
 4175 heikki.linnakangas       2647                 :  */
                               2648                 : static Pointer
 4175 heikki.linnakangas       2649 GIC      927320 : datum_write(Pointer ptr, Datum datum, bool typbyval, char typalign,
 4175 heikki.linnakangas       2650 ECB             :             int16 typlen, char typstorage)
                               2651                 : {
                               2652                 :     Size        data_length;
                               2653                 : 
 4175 heikki.linnakangas       2654 CBC      927320 :     if (typbyval)
                               2655                 :     {
 4175 heikki.linnakangas       2656 ECB             :         /* pass-by-value */
 4175 heikki.linnakangas       2657 GIC      922616 :         ptr = (char *) att_align_nominal(ptr, typalign);
                               2658          922616 :         store_att_byval(ptr, datum, typlen);
                               2659          922616 :         data_length = typlen;
                               2660                 :     }
                               2661            4704 :     else if (typlen == -1)
                               2662                 :     {
 4175 heikki.linnakangas       2663 ECB             :         /* varlena */
 4175 heikki.linnakangas       2664 GIC        4704 :         Pointer     val = DatumGetPointer(datum);
                               2665                 : 
                               2666            4704 :         if (VARATT_IS_EXTERNAL(val))
                               2667                 :         {
                               2668                 :             /*
                               2669                 :              * Throw error, because we must never put a toast pointer inside a
 4164 tgl                      2670 ECB             :              * range object.  Caller should have detoasted it.
                               2671                 :              */
 4164 tgl                      2672 LBC           0 :             elog(ERROR, "cannot store a toast pointer inside a range");
 4164 tgl                      2673 ECB             :             data_length = 0;    /* keep compiler quiet */
                               2674                 :         }
 4175 heikki.linnakangas       2675 CBC        4704 :         else if (VARATT_IS_SHORT(val))
                               2676                 :         {
 4175 heikki.linnakangas       2677 ECB             :             /* no alignment for short varlenas */
 4175 heikki.linnakangas       2678 GIC         441 :             data_length = VARSIZE_SHORT(val);
                               2679             441 :             memcpy(ptr, val, data_length);
 4175 heikki.linnakangas       2680 ECB             :         }
 4175 heikki.linnakangas       2681 CBC        4263 :         else if (TYPE_IS_PACKABLE(typlen, typstorage) &&
                               2682            4263 :                  VARATT_CAN_MAKE_SHORT(val))
 4175 heikki.linnakangas       2683 EUB             :         {
                               2684                 :             /* convert to short varlena -- no alignment */
 4175 heikki.linnakangas       2685 GIC        4245 :             data_length = VARATT_CONVERTED_SHORT_SIZE(val);
 4175 heikki.linnakangas       2686 CBC        4245 :             SET_VARSIZE_SHORT(ptr, data_length);
 4175 heikki.linnakangas       2687 GIC        4245 :             memcpy(ptr + 1, VARDATA(val), data_length - 1);
 4175 heikki.linnakangas       2688 ECB             :         }
                               2689                 :         else
                               2690                 :         {
                               2691                 :             /* full 4-byte header varlena */
 4175 heikki.linnakangas       2692 CBC          18 :             ptr = (char *) att_align_nominal(ptr, typalign);
                               2693              18 :             data_length = VARSIZE(val);
                               2694              18 :             memcpy(ptr, val, data_length);
                               2695                 :         }
                               2696                 :     }
 4175 heikki.linnakangas       2697 LBC           0 :     else if (typlen == -2)
                               2698                 :     {
                               2699                 :         /* cstring ... never needs alignment */
 1131 tgl                      2700 UIC           0 :         Assert(typalign == TYPALIGN_CHAR);
 4175 heikki.linnakangas       2701               0 :         data_length = strlen(DatumGetCString(datum)) + 1;
                               2702               0 :         memcpy(ptr, DatumGetPointer(datum), data_length);
                               2703                 :     }
                               2704                 :     else
                               2705                 :     {
                               2706                 :         /* fixed-length pass-by-reference */
                               2707               0 :         ptr = (char *) att_align_nominal(ptr, typalign);
                               2708               0 :         Assert(typlen > 0);
                               2709               0 :         data_length = typlen;
                               2710               0 :         memcpy(ptr, DatumGetPointer(datum), data_length);
                               2711                 :     }
                               2712                 : 
 4175 heikki.linnakangas       2713 GIC      927320 :     ptr += data_length;
                               2714                 : 
                               2715          927320 :     return ptr;
                               2716                 : }
        

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