LCOV - code coverage report
Current view: top level - src/backend/utils/adt - rangetypes.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 718 860 83.5 %
Date: 2017-09-29 13:40:31 Functions: 66 75 88.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11