1 /*-------------------------------------------------------------------------
4 * I/O functions, operators, and support functions for range types.
6 * The stored (serialized) format of a range value is:
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
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.
22 * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
23 * Portions Copyright (c) 1994, Regents of the University of California
27 * src/backend/utils/adt/rangetypes.c
29 *-------------------------------------------------------------------------
33 #include "access/tupmacs.h"
34 #include "common/hashfn.h"
35 #include "lib/stringinfo.h"
36 #include "libpq/pqformat.h"
37 #include "miscadmin.h"
38 #include "nodes/miscnodes.h"
39 #include "port/pg_bitutils.h"
40 #include "utils/builtins.h"
41 #include "utils/date.h"
42 #include "utils/lsyscache.h"
43 #include "utils/rangetypes.h"
44 #include "utils/timestamp.h"
48 /* fn_extra cache entry for one of the range I/O functions */
49 typedef struct RangeIOData
51 TypeCacheEntry
*typcache
; /* range type's typcache entry */
52 FmgrInfo typioproc
; /* element type's I/O function */
53 Oid typioparam
; /* element type's I/O parameter */
57 static RangeIOData
*get_range_io_data(FunctionCallInfo fcinfo
, Oid rngtypid
,
59 static char range_parse_flags(const char *flags_str
);
60 static bool range_parse(const char *string
, char *flags
, char **lbound_str
,
61 char **ubound_str
, Node
*escontext
);
62 static const char *range_parse_bound(const char *string
, const char *ptr
,
63 char **bound_str
, bool *infinite
,
65 static char *range_deparse(char flags
, const char *lbound_str
,
66 const char *ubound_str
);
67 static char *range_bound_escape(const char *value
);
68 static Size
datum_compute_size(Size data_length
, Datum val
, bool typbyval
,
69 char typalign
, int16 typlen
, char typstorage
);
70 static Pointer
datum_write(Pointer ptr
, Datum datum
, bool typbyval
,
71 char typalign
, int16 typlen
, char typstorage
);
75 *----------------------------------------------------------
77 *----------------------------------------------------------
81 range_in(PG_FUNCTION_ARGS
)
83 char *input_str
= PG_GETARG_CSTRING(0);
84 Oid rngtypoid
= PG_GETARG_OID(1);
85 Oid typmod
= PG_GETARG_INT32(2);
86 Node
*escontext
= fcinfo
->context
;
95 check_stack_depth(); /* recurses when subtype is a range type */
97 cache
= get_range_io_data(fcinfo
, rngtypoid
, IOFunc_input
);
100 if (!range_parse(input_str
, &flags
, &lbound_str
, &ubound_str
, escontext
))
103 /* call element type's input function */
104 if (RANGE_HAS_LBOUND(flags
))
105 if (!InputFunctionCallSafe(&cache
->typioproc
, lbound_str
,
106 cache
->typioparam
, typmod
,
107 escontext
, &lower
.val
))
109 if (RANGE_HAS_UBOUND(flags
))
110 if (!InputFunctionCallSafe(&cache
->typioproc
, ubound_str
,
111 cache
->typioparam
, typmod
,
112 escontext
, &upper
.val
))
115 lower
.infinite
= (flags
& RANGE_LB_INF
) != 0;
116 lower
.inclusive
= (flags
& RANGE_LB_INC
) != 0;
118 upper
.infinite
= (flags
& RANGE_UB_INF
) != 0;
119 upper
.inclusive
= (flags
& RANGE_UB_INC
) != 0;
122 /* serialize and canonicalize */
123 range
= make_range(cache
->typcache
, &lower
, &upper
,
124 flags
& RANGE_EMPTY
, escontext
);
126 PG_RETURN_RANGE_P(range
);
130 range_out(PG_FUNCTION_ARGS
)
132 RangeType
*range
= PG_GETARG_RANGE_P(0);
136 char *lbound_str
= NULL
;
137 char *ubound_str
= NULL
;
142 check_stack_depth(); /* recurses when subtype is a range type */
144 cache
= get_range_io_data(fcinfo
, RangeTypeGetOid(range
), IOFunc_output
);
147 range_deserialize(cache
->typcache
, range
, &lower
, &upper
, &empty
);
148 flags
= range_get_flags(range
);
150 /* call element type's output function */
151 if (RANGE_HAS_LBOUND(flags
))
152 lbound_str
= OutputFunctionCall(&cache
->typioproc
, lower
.val
);
153 if (RANGE_HAS_UBOUND(flags
))
154 ubound_str
= OutputFunctionCall(&cache
->typioproc
, upper
.val
);
156 /* construct result string */
157 output_str
= range_deparse(flags
, lbound_str
, ubound_str
);
159 PG_RETURN_CSTRING(output_str
);
163 * Binary representation: The first byte is the flags, then the lower bound
164 * (if present), then the upper bound (if present). Each bound is represented
165 * by a 4-byte length header and the binary representation of that bound (as
166 * returned by a call to the send function for the subtype).
170 range_recv(PG_FUNCTION_ARGS
)
172 StringInfo buf
= (StringInfo
) PG_GETARG_POINTER(0);
173 Oid rngtypoid
= PG_GETARG_OID(1);
174 int32 typmod
= PG_GETARG_INT32(2);
181 check_stack_depth(); /* recurses when subtype is a range type */
183 cache
= get_range_io_data(fcinfo
, rngtypoid
, IOFunc_receive
);
185 /* receive the flags... */
186 flags
= (unsigned char) pq_getmsgbyte(buf
);
189 * Mask out any unsupported flags, particularly RANGE_xB_NULL which would
190 * confuse following tests. Note that range_serialize will take care of
191 * cleaning up any inconsistencies in the remaining flags.
193 flags
&= (RANGE_EMPTY
|
199 /* receive the bounds ... */
200 if (RANGE_HAS_LBOUND(flags
))
202 uint32 bound_len
= pq_getmsgint(buf
, 4);
203 const char *bound_data
= pq_getmsgbytes(buf
, bound_len
);
204 StringInfoData bound_buf
;
206 initStringInfo(&bound_buf
);
207 appendBinaryStringInfo(&bound_buf
, bound_data
, bound_len
);
209 lower
.val
= ReceiveFunctionCall(&cache
->typioproc
,
213 pfree(bound_buf
.data
);
216 lower
.val
= (Datum
) 0;
218 if (RANGE_HAS_UBOUND(flags
))
220 uint32 bound_len
= pq_getmsgint(buf
, 4);
221 const char *bound_data
= pq_getmsgbytes(buf
, bound_len
);
222 StringInfoData bound_buf
;
224 initStringInfo(&bound_buf
);
225 appendBinaryStringInfo(&bound_buf
, bound_data
, bound_len
);
227 upper
.val
= ReceiveFunctionCall(&cache
->typioproc
,
231 pfree(bound_buf
.data
);
234 upper
.val
= (Datum
) 0;
238 /* finish constructing RangeBound representation */
239 lower
.infinite
= (flags
& RANGE_LB_INF
) != 0;
240 lower
.inclusive
= (flags
& RANGE_LB_INC
) != 0;
242 upper
.infinite
= (flags
& RANGE_UB_INF
) != 0;
243 upper
.inclusive
= (flags
& RANGE_UB_INC
) != 0;
246 /* serialize and canonicalize */
247 range
= make_range(cache
->typcache
, &lower
, &upper
,
248 flags
& RANGE_EMPTY
, NULL
);
250 PG_RETURN_RANGE_P(range
);
254 range_send(PG_FUNCTION_ARGS
)
256 RangeType
*range
= PG_GETARG_RANGE_P(0);
257 StringInfo buf
= makeStringInfo();
264 check_stack_depth(); /* recurses when subtype is a range type */
266 cache
= get_range_io_data(fcinfo
, RangeTypeGetOid(range
), IOFunc_send
);
269 range_deserialize(cache
->typcache
, range
, &lower
, &upper
, &empty
);
270 flags
= range_get_flags(range
);
272 /* construct output */
273 pq_begintypsend(buf
);
275 pq_sendbyte(buf
, flags
);
277 if (RANGE_HAS_LBOUND(flags
))
279 Datum bound
= PointerGetDatum(SendFunctionCall(&cache
->typioproc
,
281 uint32 bound_len
= VARSIZE(bound
) - VARHDRSZ
;
282 char *bound_data
= VARDATA(bound
);
284 pq_sendint32(buf
, bound_len
);
285 pq_sendbytes(buf
, bound_data
, bound_len
);
288 if (RANGE_HAS_UBOUND(flags
))
290 Datum bound
= PointerGetDatum(SendFunctionCall(&cache
->typioproc
,
292 uint32 bound_len
= VARSIZE(bound
) - VARHDRSZ
;
293 char *bound_data
= VARDATA(bound
);
295 pq_sendint32(buf
, bound_len
);
296 pq_sendbytes(buf
, bound_data
, bound_len
);
299 PG_RETURN_BYTEA_P(pq_endtypsend(buf
));
303 * get_range_io_data: get cached information needed for range type I/O
305 * The range I/O functions need a bit more cached info than other range
306 * functions, so they store a RangeIOData struct in fn_extra, not just a
307 * pointer to a type cache entry.
310 get_range_io_data(FunctionCallInfo fcinfo
, Oid rngtypid
, IOFuncSelector func
)
312 RangeIOData
*cache
= (RangeIOData
*) fcinfo
->flinfo
->fn_extra
;
314 if (cache
== NULL
|| cache
->typcache
->type_id
!= rngtypid
)
322 cache
= (RangeIOData
*) MemoryContextAlloc(fcinfo
->flinfo
->fn_mcxt
,
323 sizeof(RangeIOData
));
324 cache
->typcache
= lookup_type_cache(rngtypid
, TYPECACHE_RANGE_INFO
);
325 if (cache
->typcache
->rngelemtype
== NULL
)
326 elog(ERROR
, "type %u is not a range type", rngtypid
);
328 /* get_type_io_data does more than we need, but is convenient */
329 get_type_io_data(cache
->typcache
->rngelemtype
->type_id
,
338 if (!OidIsValid(typiofunc
))
340 /* this could only happen for receive or send */
341 if (func
== IOFunc_receive
)
343 (errcode(ERRCODE_UNDEFINED_FUNCTION
),
344 errmsg("no binary input function available for type %s",
345 format_type_be(cache
->typcache
->rngelemtype
->type_id
))));
348 (errcode(ERRCODE_UNDEFINED_FUNCTION
),
349 errmsg("no binary output function available for type %s",
350 format_type_be(cache
->typcache
->rngelemtype
->type_id
))));
352 fmgr_info_cxt(typiofunc
, &cache
->typioproc
,
353 fcinfo
->flinfo
->fn_mcxt
);
355 fcinfo
->flinfo
->fn_extra
= (void *) cache
;
363 *----------------------------------------------------------
365 *----------------------------------------------------------
368 /* Construct standard-form range value from two arguments */
370 range_constructor2(PG_FUNCTION_ARGS
)
372 Datum arg1
= PG_GETARG_DATUM(0);
373 Datum arg2
= PG_GETARG_DATUM(1);
374 Oid rngtypid
= get_fn_expr_rettype(fcinfo
->flinfo
);
376 TypeCacheEntry
*typcache
;
380 typcache
= range_get_typcache(fcinfo
, rngtypid
);
382 lower
.val
= PG_ARGISNULL(0) ? (Datum
) 0 : arg1
;
383 lower
.infinite
= PG_ARGISNULL(0);
384 lower
.inclusive
= true;
387 upper
.val
= PG_ARGISNULL(1) ? (Datum
) 0 : arg2
;
388 upper
.infinite
= PG_ARGISNULL(1);
389 upper
.inclusive
= false;
392 range
= make_range(typcache
, &lower
, &upper
, false, NULL
);
394 PG_RETURN_RANGE_P(range
);
397 /* Construct general range value from three arguments */
399 range_constructor3(PG_FUNCTION_ARGS
)
401 Datum arg1
= PG_GETARG_DATUM(0);
402 Datum arg2
= PG_GETARG_DATUM(1);
403 Oid rngtypid
= get_fn_expr_rettype(fcinfo
->flinfo
);
405 TypeCacheEntry
*typcache
;
410 typcache
= range_get_typcache(fcinfo
, rngtypid
);
414 (errcode(ERRCODE_DATA_EXCEPTION
),
415 errmsg("range constructor flags argument must not be null")));
417 flags
= range_parse_flags(text_to_cstring(PG_GETARG_TEXT_PP(2)));
419 lower
.val
= PG_ARGISNULL(0) ? (Datum
) 0 : arg1
;
420 lower
.infinite
= PG_ARGISNULL(0);
421 lower
.inclusive
= (flags
& RANGE_LB_INC
) != 0;
424 upper
.val
= PG_ARGISNULL(1) ? (Datum
) 0 : arg2
;
425 upper
.infinite
= PG_ARGISNULL(1);
426 upper
.inclusive
= (flags
& RANGE_UB_INC
) != 0;
429 range
= make_range(typcache
, &lower
, &upper
, false, NULL
);
431 PG_RETURN_RANGE_P(range
);
435 /* range -> subtype functions */
437 /* extract lower bound value */
439 range_lower(PG_FUNCTION_ARGS
)
441 RangeType
*r1
= PG_GETARG_RANGE_P(0);
442 TypeCacheEntry
*typcache
;
447 typcache
= range_get_typcache(fcinfo
, RangeTypeGetOid(r1
));
449 range_deserialize(typcache
, r1
, &lower
, &upper
, &empty
);
451 /* Return NULL if there's no finite lower bound */
452 if (empty
|| lower
.infinite
)
455 PG_RETURN_DATUM(lower
.val
);
458 /* extract upper bound value */
460 range_upper(PG_FUNCTION_ARGS
)
462 RangeType
*r1
= PG_GETARG_RANGE_P(0);
463 TypeCacheEntry
*typcache
;
468 typcache
= range_get_typcache(fcinfo
, RangeTypeGetOid(r1
));
470 range_deserialize(typcache
, r1
, &lower
, &upper
, &empty
);
472 /* Return NULL if there's no finite upper bound */
473 if (empty
|| upper
.infinite
)
476 PG_RETURN_DATUM(upper
.val
);
480 /* range -> bool functions */
482 /* is range empty? */
484 range_empty(PG_FUNCTION_ARGS
)
486 RangeType
*r1
= PG_GETARG_RANGE_P(0);
487 char flags
= range_get_flags(r1
);
489 PG_RETURN_BOOL(flags
& RANGE_EMPTY
);
492 /* is lower bound inclusive? */
494 range_lower_inc(PG_FUNCTION_ARGS
)
496 RangeType
*r1
= PG_GETARG_RANGE_P(0);
497 char flags
= range_get_flags(r1
);
499 PG_RETURN_BOOL(flags
& RANGE_LB_INC
);
502 /* is upper bound inclusive? */
504 range_upper_inc(PG_FUNCTION_ARGS
)
506 RangeType
*r1
= PG_GETARG_RANGE_P(0);
507 char flags
= range_get_flags(r1
);
509 PG_RETURN_BOOL(flags
& RANGE_UB_INC
);
512 /* is lower bound infinite? */
514 range_lower_inf(PG_FUNCTION_ARGS
)
516 RangeType
*r1
= PG_GETARG_RANGE_P(0);
517 char flags
= range_get_flags(r1
);
519 PG_RETURN_BOOL(flags
& RANGE_LB_INF
);
522 /* is upper bound infinite? */
524 range_upper_inf(PG_FUNCTION_ARGS
)
526 RangeType
*r1
= PG_GETARG_RANGE_P(0);
527 char flags
= range_get_flags(r1
);
529 PG_RETURN_BOOL(flags
& RANGE_UB_INF
);
533 /* range, element -> bool functions */
537 range_contains_elem(PG_FUNCTION_ARGS
)
539 RangeType
*r
= PG_GETARG_RANGE_P(0);
540 Datum val
= PG_GETARG_DATUM(1);
541 TypeCacheEntry
*typcache
;
543 typcache
= range_get_typcache(fcinfo
, RangeTypeGetOid(r
));
545 PG_RETURN_BOOL(range_contains_elem_internal(typcache
, r
, val
));
550 elem_contained_by_range(PG_FUNCTION_ARGS
)
552 Datum val
= PG_GETARG_DATUM(0);
553 RangeType
*r
= PG_GETARG_RANGE_P(1);
554 TypeCacheEntry
*typcache
;
556 typcache
= range_get_typcache(fcinfo
, RangeTypeGetOid(r
));
558 PG_RETURN_BOOL(range_contains_elem_internal(typcache
, r
, val
));
562 /* range, range -> bool functions */
564 /* equality (internal version) */
566 range_eq_internal(TypeCacheEntry
*typcache
, const RangeType
*r1
, const RangeType
*r2
)
575 /* Different types should be prevented by ANYRANGE matching rules */
576 if (RangeTypeGetOid(r1
) != RangeTypeGetOid(r2
))
577 elog(ERROR
, "range types do not match");
579 range_deserialize(typcache
, r1
, &lower1
, &upper1
, &empty1
);
580 range_deserialize(typcache
, r2
, &lower2
, &upper2
, &empty2
);
582 if (empty1
&& empty2
)
584 if (empty1
!= empty2
)
587 if (range_cmp_bounds(typcache
, &lower1
, &lower2
) != 0)
590 if (range_cmp_bounds(typcache
, &upper1
, &upper2
) != 0)
598 range_eq(PG_FUNCTION_ARGS
)
600 RangeType
*r1
= PG_GETARG_RANGE_P(0);
601 RangeType
*r2
= PG_GETARG_RANGE_P(1);
602 TypeCacheEntry
*typcache
;
604 typcache
= range_get_typcache(fcinfo
, RangeTypeGetOid(r1
));
606 PG_RETURN_BOOL(range_eq_internal(typcache
, r1
, r2
));
609 /* inequality (internal version) */
611 range_ne_internal(TypeCacheEntry
*typcache
, const RangeType
*r1
, const RangeType
*r2
)
613 return (!range_eq_internal(typcache
, r1
, r2
));
618 range_ne(PG_FUNCTION_ARGS
)
620 RangeType
*r1
= PG_GETARG_RANGE_P(0);
621 RangeType
*r2
= PG_GETARG_RANGE_P(1);
622 TypeCacheEntry
*typcache
;
624 typcache
= range_get_typcache(fcinfo
, RangeTypeGetOid(r1
));
626 PG_RETURN_BOOL(range_ne_internal(typcache
, r1
, r2
));
631 range_contains(PG_FUNCTION_ARGS
)
633 RangeType
*r1
= PG_GETARG_RANGE_P(0);
634 RangeType
*r2
= PG_GETARG_RANGE_P(1);
635 TypeCacheEntry
*typcache
;
637 typcache
= range_get_typcache(fcinfo
, RangeTypeGetOid(r1
));
639 PG_RETURN_BOOL(range_contains_internal(typcache
, r1
, r2
));
644 range_contained_by(PG_FUNCTION_ARGS
)
646 RangeType
*r1
= PG_GETARG_RANGE_P(0);
647 RangeType
*r2
= PG_GETARG_RANGE_P(1);
648 TypeCacheEntry
*typcache
;
650 typcache
= range_get_typcache(fcinfo
, RangeTypeGetOid(r1
));
652 PG_RETURN_BOOL(range_contained_by_internal(typcache
, r1
, r2
));
655 /* strictly left of? (internal version) */
657 range_before_internal(TypeCacheEntry
*typcache
, const RangeType
*r1
, const RangeType
*r2
)
666 /* Different types should be prevented by ANYRANGE matching rules */
667 if (RangeTypeGetOid(r1
) != RangeTypeGetOid(r2
))
668 elog(ERROR
, "range types do not match");
670 range_deserialize(typcache
, r1
, &lower1
, &upper1
, &empty1
);
671 range_deserialize(typcache
, r2
, &lower2
, &upper2
, &empty2
);
673 /* An empty range is neither before nor after any other range */
674 if (empty1
|| empty2
)
677 return (range_cmp_bounds(typcache
, &upper1
, &lower2
) < 0);
680 /* strictly left of? */
682 range_before(PG_FUNCTION_ARGS
)
684 RangeType
*r1
= PG_GETARG_RANGE_P(0);
685 RangeType
*r2
= PG_GETARG_RANGE_P(1);
686 TypeCacheEntry
*typcache
;
688 typcache
= range_get_typcache(fcinfo
, RangeTypeGetOid(r1
));
690 PG_RETURN_BOOL(range_before_internal(typcache
, r1
, r2
));
693 /* strictly right of? (internal version) */
695 range_after_internal(TypeCacheEntry
*typcache
, const RangeType
*r1
, const RangeType
*r2
)
704 /* Different types should be prevented by ANYRANGE matching rules */
705 if (RangeTypeGetOid(r1
) != RangeTypeGetOid(r2
))
706 elog(ERROR
, "range types do not match");
708 range_deserialize(typcache
, r1
, &lower1
, &upper1
, &empty1
);
709 range_deserialize(typcache
, r2
, &lower2
, &upper2
, &empty2
);
711 /* An empty range is neither before nor after any other range */
712 if (empty1
|| empty2
)
715 return (range_cmp_bounds(typcache
, &lower1
, &upper2
) > 0);
718 /* strictly right of? */
720 range_after(PG_FUNCTION_ARGS
)
722 RangeType
*r1
= PG_GETARG_RANGE_P(0);
723 RangeType
*r2
= PG_GETARG_RANGE_P(1);
724 TypeCacheEntry
*typcache
;
726 typcache
= range_get_typcache(fcinfo
, RangeTypeGetOid(r1
));
728 PG_RETURN_BOOL(range_after_internal(typcache
, r1
, r2
));
732 * Check if two bounds A and B are "adjacent", where A is an upper bound and B
733 * is a lower bound. For the bounds to be adjacent, each subtype value must
734 * satisfy strictly one of the bounds: there are no values which satisfy both
735 * bounds (i.e. less than A and greater than B); and there are no values which
736 * satisfy neither bound (i.e. greater than A and less than B).
738 * For discrete ranges, we rely on the canonicalization function to see if A..B
739 * normalizes to empty. (If there is no canonicalization function, it's
740 * impossible for such a range to normalize to empty, so we needn't bother to
743 * If A == B, the ranges are adjacent only if the bounds have different
744 * inclusive flags (i.e., exactly one of the ranges includes the common
747 * And if A > B then the ranges are not adjacent in this order.
750 bounds_adjacent(TypeCacheEntry
*typcache
, RangeBound boundA
, RangeBound boundB
)
754 Assert(!boundA
.lower
&& boundB
.lower
);
756 cmp
= range_cmp_bound_values(typcache
, &boundA
, &boundB
);
762 * Bounds do not overlap; see if there are points in between.
765 /* in a continuous subtype, there are assumed to be points between */
766 if (!OidIsValid(typcache
->rng_canonical_finfo
.fn_oid
))
770 * The bounds are of a discrete range type; so make a range A..B and
774 /* flip the inclusion flags */
775 boundA
.inclusive
= !boundA
.inclusive
;
776 boundB
.inclusive
= !boundB
.inclusive
;
777 /* change upper/lower labels to avoid Assert failures */
779 boundB
.lower
= false;
780 r
= make_range(typcache
, &boundA
, &boundB
, false, NULL
);
781 return RangeIsEmpty(r
);
784 return boundA
.inclusive
!= boundB
.inclusive
;
786 return false; /* bounds overlap */
789 /* adjacent to (but not overlapping)? (internal version) */
791 range_adjacent_internal(TypeCacheEntry
*typcache
, const RangeType
*r1
, const RangeType
*r2
)
800 /* Different types should be prevented by ANYRANGE matching rules */
801 if (RangeTypeGetOid(r1
) != RangeTypeGetOid(r2
))
802 elog(ERROR
, "range types do not match");
804 range_deserialize(typcache
, r1
, &lower1
, &upper1
, &empty1
);
805 range_deserialize(typcache
, r2
, &lower2
, &upper2
, &empty2
);
807 /* An empty range is not adjacent to any other range */
808 if (empty1
|| empty2
)
812 * Given two ranges A..B and C..D, the ranges are adjacent if and only if
813 * B is adjacent to C, or D is adjacent to A.
815 return (bounds_adjacent(typcache
, upper1
, lower2
) ||
816 bounds_adjacent(typcache
, upper2
, lower1
));
819 /* adjacent to (but not overlapping)? */
821 range_adjacent(PG_FUNCTION_ARGS
)
823 RangeType
*r1
= PG_GETARG_RANGE_P(0);
824 RangeType
*r2
= PG_GETARG_RANGE_P(1);
825 TypeCacheEntry
*typcache
;
827 typcache
= range_get_typcache(fcinfo
, RangeTypeGetOid(r1
));
829 PG_RETURN_BOOL(range_adjacent_internal(typcache
, r1
, r2
));
832 /* overlaps? (internal version) */
834 range_overlaps_internal(TypeCacheEntry
*typcache
, const RangeType
*r1
, const RangeType
*r2
)
843 /* Different types should be prevented by ANYRANGE matching rules */
844 if (RangeTypeGetOid(r1
) != RangeTypeGetOid(r2
))
845 elog(ERROR
, "range types do not match");
847 range_deserialize(typcache
, r1
, &lower1
, &upper1
, &empty1
);
848 range_deserialize(typcache
, r2
, &lower2
, &upper2
, &empty2
);
850 /* An empty range does not overlap any other range */
851 if (empty1
|| empty2
)
854 if (range_cmp_bounds(typcache
, &lower1
, &lower2
) >= 0 &&
855 range_cmp_bounds(typcache
, &lower1
, &upper2
) <= 0)
858 if (range_cmp_bounds(typcache
, &lower2
, &lower1
) >= 0 &&
859 range_cmp_bounds(typcache
, &lower2
, &upper1
) <= 0)
867 range_overlaps(PG_FUNCTION_ARGS
)
869 RangeType
*r1
= PG_GETARG_RANGE_P(0);
870 RangeType
*r2
= PG_GETARG_RANGE_P(1);
871 TypeCacheEntry
*typcache
;
873 typcache
= range_get_typcache(fcinfo
, RangeTypeGetOid(r1
));
875 PG_RETURN_BOOL(range_overlaps_internal(typcache
, r1
, r2
));
878 /* does not extend to right of? (internal version) */
880 range_overleft_internal(TypeCacheEntry
*typcache
, const RangeType
*r1
, const RangeType
*r2
)
889 /* Different types should be prevented by ANYRANGE matching rules */
890 if (RangeTypeGetOid(r1
) != RangeTypeGetOid(r2
))
891 elog(ERROR
, "range types do not match");
893 range_deserialize(typcache
, r1
, &lower1
, &upper1
, &empty1
);
894 range_deserialize(typcache
, r2
, &lower2
, &upper2
, &empty2
);
896 /* An empty range is neither before nor after any other range */
897 if (empty1
|| empty2
)
900 if (range_cmp_bounds(typcache
, &upper1
, &upper2
) <= 0)
906 /* does not extend to right of? */
908 range_overleft(PG_FUNCTION_ARGS
)
910 RangeType
*r1
= PG_GETARG_RANGE_P(0);
911 RangeType
*r2
= PG_GETARG_RANGE_P(1);
912 TypeCacheEntry
*typcache
;
914 typcache
= range_get_typcache(fcinfo
, RangeTypeGetOid(r1
));
916 PG_RETURN_BOOL(range_overleft_internal(typcache
, r1
, r2
));
919 /* does not extend to left of? (internal version) */
921 range_overright_internal(TypeCacheEntry
*typcache
, const RangeType
*r1
, const RangeType
*r2
)
930 /* Different types should be prevented by ANYRANGE matching rules */
931 if (RangeTypeGetOid(r1
) != RangeTypeGetOid(r2
))
932 elog(ERROR
, "range types do not match");
934 range_deserialize(typcache
, r1
, &lower1
, &upper1
, &empty1
);
935 range_deserialize(typcache
, r2
, &lower2
, &upper2
, &empty2
);
937 /* An empty range is neither before nor after any other range */
938 if (empty1
|| empty2
)
941 if (range_cmp_bounds(typcache
, &lower1
, &lower2
) >= 0)
947 /* does not extend to left of? */
949 range_overright(PG_FUNCTION_ARGS
)
951 RangeType
*r1
= PG_GETARG_RANGE_P(0);
952 RangeType
*r2
= PG_GETARG_RANGE_P(1);
953 TypeCacheEntry
*typcache
;
955 typcache
= range_get_typcache(fcinfo
, RangeTypeGetOid(r1
));
957 PG_RETURN_BOOL(range_overright_internal(typcache
, r1
, r2
));
961 /* range, range -> range functions */
965 range_minus(PG_FUNCTION_ARGS
)
967 RangeType
*r1
= PG_GETARG_RANGE_P(0);
968 RangeType
*r2
= PG_GETARG_RANGE_P(1);
970 TypeCacheEntry
*typcache
;
972 /* Different types should be prevented by ANYRANGE matching rules */
973 if (RangeTypeGetOid(r1
) != RangeTypeGetOid(r2
))
974 elog(ERROR
, "range types do not match");
976 typcache
= range_get_typcache(fcinfo
, RangeTypeGetOid(r1
));
978 ret
= range_minus_internal(typcache
, r1
, r2
);
980 PG_RETURN_RANGE_P(ret
);
986 range_minus_internal(TypeCacheEntry
*typcache
, RangeType
*r1
, RangeType
*r2
)
999 range_deserialize(typcache
, r1
, &lower1
, &upper1
, &empty1
);
1000 range_deserialize(typcache
, r2
, &lower2
, &upper2
, &empty2
);
1002 /* if either is empty, r1 is the correct answer */
1003 if (empty1
|| empty2
)
1006 cmp_l1l2
= range_cmp_bounds(typcache
, &lower1
, &lower2
);
1007 cmp_l1u2
= range_cmp_bounds(typcache
, &lower1
, &upper2
);
1008 cmp_u1l2
= range_cmp_bounds(typcache
, &upper1
, &lower2
);
1009 cmp_u1u2
= range_cmp_bounds(typcache
, &upper1
, &upper2
);
1011 if (cmp_l1l2
< 0 && cmp_u1u2
> 0)
1013 (errcode(ERRCODE_DATA_EXCEPTION
),
1014 errmsg("result of range difference would not be contiguous")));
1016 if (cmp_l1u2
> 0 || cmp_u1l2
< 0)
1019 if (cmp_l1l2
>= 0 && cmp_u1u2
<= 0)
1020 return make_empty_range(typcache
);
1022 if (cmp_l1l2
<= 0 && cmp_u1l2
>= 0 && cmp_u1u2
<= 0)
1024 lower2
.inclusive
= !lower2
.inclusive
;
1025 lower2
.lower
= false; /* it will become the upper bound */
1026 return make_range(typcache
, &lower1
, &lower2
, false, NULL
);
1029 if (cmp_l1l2
>= 0 && cmp_u1u2
>= 0 && cmp_l1u2
<= 0)
1031 upper2
.inclusive
= !upper2
.inclusive
;
1032 upper2
.lower
= true; /* it will become the lower bound */
1033 return make_range(typcache
, &upper2
, &upper1
, false, NULL
);
1036 elog(ERROR
, "unexpected case in range_minus");
1041 * Set union. If strict is true, it is an error that the two input ranges
1042 * are not adjacent or overlapping.
1045 range_union_internal(TypeCacheEntry
*typcache
, RangeType
*r1
, RangeType
*r2
,
1054 RangeBound
*result_lower
;
1055 RangeBound
*result_upper
;
1057 /* Different types should be prevented by ANYRANGE matching rules */
1058 if (RangeTypeGetOid(r1
) != RangeTypeGetOid(r2
))
1059 elog(ERROR
, "range types do not match");
1061 range_deserialize(typcache
, r1
, &lower1
, &upper1
, &empty1
);
1062 range_deserialize(typcache
, r2
, &lower2
, &upper2
, &empty2
);
1064 /* if either is empty, the other is the correct answer */
1071 !DatumGetBool(range_overlaps_internal(typcache
, r1
, r2
)) &&
1072 !DatumGetBool(range_adjacent_internal(typcache
, r1
, r2
)))
1074 (errcode(ERRCODE_DATA_EXCEPTION
),
1075 errmsg("result of range union would not be contiguous")));
1077 if (range_cmp_bounds(typcache
, &lower1
, &lower2
) < 0)
1078 result_lower
= &lower1
;
1080 result_lower
= &lower2
;
1082 if (range_cmp_bounds(typcache
, &upper1
, &upper2
) > 0)
1083 result_upper
= &upper1
;
1085 result_upper
= &upper2
;
1087 return make_range(typcache
, result_lower
, result_upper
, false, NULL
);
1091 range_union(PG_FUNCTION_ARGS
)
1093 RangeType
*r1
= PG_GETARG_RANGE_P(0);
1094 RangeType
*r2
= PG_GETARG_RANGE_P(1);
1095 TypeCacheEntry
*typcache
;
1097 typcache
= range_get_typcache(fcinfo
, RangeTypeGetOid(r1
));
1099 PG_RETURN_RANGE_P(range_union_internal(typcache
, r1
, r2
, true));
1103 * range merge: like set union, except also allow and account for non-adjacent
1107 range_merge(PG_FUNCTION_ARGS
)
1109 RangeType
*r1
= PG_GETARG_RANGE_P(0);
1110 RangeType
*r2
= PG_GETARG_RANGE_P(1);
1111 TypeCacheEntry
*typcache
;
1113 typcache
= range_get_typcache(fcinfo
, RangeTypeGetOid(r1
));
1115 PG_RETURN_RANGE_P(range_union_internal(typcache
, r1
, r2
, false));
1118 /* set intersection */
1120 range_intersect(PG_FUNCTION_ARGS
)
1122 RangeType
*r1
= PG_GETARG_RANGE_P(0);
1123 RangeType
*r2
= PG_GETARG_RANGE_P(1);
1124 TypeCacheEntry
*typcache
;
1126 /* Different types should be prevented by ANYRANGE matching rules */
1127 if (RangeTypeGetOid(r1
) != RangeTypeGetOid(r2
))
1128 elog(ERROR
, "range types do not match");
1130 typcache
= range_get_typcache(fcinfo
, RangeTypeGetOid(r1
));
1132 PG_RETURN_RANGE_P(range_intersect_internal(typcache
, r1
, r2
));
1136 range_intersect_internal(TypeCacheEntry
*typcache
, const RangeType
*r1
, const RangeType
*r2
)
1144 RangeBound
*result_lower
;
1145 RangeBound
*result_upper
;
1147 range_deserialize(typcache
, r1
, &lower1
, &upper1
, &empty1
);
1148 range_deserialize(typcache
, r2
, &lower2
, &upper2
, &empty2
);
1150 if (empty1
|| empty2
|| !range_overlaps_internal(typcache
, r1
, r2
))
1151 return make_empty_range(typcache
);
1153 if (range_cmp_bounds(typcache
, &lower1
, &lower2
) >= 0)
1154 result_lower
= &lower1
;
1156 result_lower
= &lower2
;
1158 if (range_cmp_bounds(typcache
, &upper1
, &upper2
) <= 0)
1159 result_upper
= &upper1
;
1161 result_upper
= &upper2
;
1163 return make_range(typcache
, result_lower
, result_upper
, false, NULL
);
1166 /* range, range -> range, range functions */
1169 * range_split_internal - if r2 intersects the middle of r1, leaving non-empty
1170 * ranges on both sides, then return true and set output1 and output2 to the
1171 * results of r1 - r2 (in order). Otherwise return false and don't set output1
1172 * or output2. Neither input range should be empty.
1175 range_split_internal(TypeCacheEntry
*typcache
, const RangeType
*r1
, const RangeType
*r2
,
1176 RangeType
**output1
, RangeType
**output2
)
1185 range_deserialize(typcache
, r1
, &lower1
, &upper1
, &empty1
);
1186 range_deserialize(typcache
, r2
, &lower2
, &upper2
, &empty2
);
1188 if (range_cmp_bounds(typcache
, &lower1
, &lower2
) < 0 &&
1189 range_cmp_bounds(typcache
, &upper1
, &upper2
) > 0)
1192 * Need to invert inclusive/exclusive for the lower2 and upper2
1193 * points. They can't be infinite though. We're allowed to overwrite
1194 * these RangeBounds since they only exist locally.
1196 lower2
.inclusive
= !lower2
.inclusive
;
1197 lower2
.lower
= false;
1198 upper2
.inclusive
= !upper2
.inclusive
;
1199 upper2
.lower
= true;
1201 *output1
= make_range(typcache
, &lower1
, &lower2
, false, NULL
);
1202 *output2
= make_range(typcache
, &upper2
, &upper1
, false, NULL
);
1209 /* range -> range aggregate functions */
1212 range_intersect_agg_transfn(PG_FUNCTION_ARGS
)
1214 MemoryContext aggContext
;
1216 TypeCacheEntry
*typcache
;
1220 if (!AggCheckCallContext(fcinfo
, &aggContext
))
1221 elog(ERROR
, "range_intersect_agg_transfn called in non-aggregate context");
1223 rngtypoid
= get_fn_expr_argtype(fcinfo
->flinfo
, 1);
1224 if (!type_is_range(rngtypoid
))
1225 elog(ERROR
, "range_intersect_agg must be called with a range");
1227 typcache
= range_get_typcache(fcinfo
, rngtypoid
);
1229 /* strictness ensures these are non-null */
1230 result
= PG_GETARG_RANGE_P(0);
1231 current
= PG_GETARG_RANGE_P(1);
1233 result
= range_intersect_internal(typcache
, result
, current
);
1234 PG_RETURN_RANGE_P(result
);
1240 /* btree comparator */
1242 range_cmp(PG_FUNCTION_ARGS
)
1244 RangeType
*r1
= PG_GETARG_RANGE_P(0);
1245 RangeType
*r2
= PG_GETARG_RANGE_P(1);
1246 TypeCacheEntry
*typcache
;
1255 check_stack_depth(); /* recurses when subtype is a range type */
1257 /* Different types should be prevented by ANYRANGE matching rules */
1258 if (RangeTypeGetOid(r1
) != RangeTypeGetOid(r2
))
1259 elog(ERROR
, "range types do not match");
1261 typcache
= range_get_typcache(fcinfo
, RangeTypeGetOid(r1
));
1263 range_deserialize(typcache
, r1
, &lower1
, &upper1
, &empty1
);
1264 range_deserialize(typcache
, r2
, &lower2
, &upper2
, &empty2
);
1266 /* For b-tree use, empty ranges sort before all else */
1267 if (empty1
&& empty2
)
1275 cmp
= range_cmp_bounds(typcache
, &lower1
, &lower2
);
1277 cmp
= range_cmp_bounds(typcache
, &upper1
, &upper2
);
1280 PG_FREE_IF_COPY(r1
, 0);
1281 PG_FREE_IF_COPY(r2
, 1);
1283 PG_RETURN_INT32(cmp
);
1286 /* inequality operators using the range_cmp function */
1288 range_lt(PG_FUNCTION_ARGS
)
1290 int cmp
= range_cmp(fcinfo
);
1292 PG_RETURN_BOOL(cmp
< 0);
1296 range_le(PG_FUNCTION_ARGS
)
1298 int cmp
= range_cmp(fcinfo
);
1300 PG_RETURN_BOOL(cmp
<= 0);
1304 range_ge(PG_FUNCTION_ARGS
)
1306 int cmp
= range_cmp(fcinfo
);
1308 PG_RETURN_BOOL(cmp
>= 0);
1312 range_gt(PG_FUNCTION_ARGS
)
1314 int cmp
= range_cmp(fcinfo
);
1316 PG_RETURN_BOOL(cmp
> 0);
1321 /* hash a range value */
1323 hash_range(PG_FUNCTION_ARGS
)
1325 RangeType
*r
= PG_GETARG_RANGE_P(0);
1327 TypeCacheEntry
*typcache
;
1328 TypeCacheEntry
*scache
;
1336 check_stack_depth(); /* recurses when subtype is a range type */
1338 typcache
= range_get_typcache(fcinfo
, RangeTypeGetOid(r
));
1341 range_deserialize(typcache
, r
, &lower
, &upper
, &empty
);
1342 flags
= range_get_flags(r
);
1345 * Look up the element type's hash function, if not done already.
1347 scache
= typcache
->rngelemtype
;
1348 if (!OidIsValid(scache
->hash_proc_finfo
.fn_oid
))
1350 scache
= lookup_type_cache(scache
->type_id
, TYPECACHE_HASH_PROC_FINFO
);
1351 if (!OidIsValid(scache
->hash_proc_finfo
.fn_oid
))
1353 (errcode(ERRCODE_UNDEFINED_FUNCTION
),
1354 errmsg("could not identify a hash function for type %s",
1355 format_type_be(scache
->type_id
))));
1359 * Apply the hash function to each bound.
1361 if (RANGE_HAS_LBOUND(flags
))
1362 lower_hash
= DatumGetUInt32(FunctionCall1Coll(&scache
->hash_proc_finfo
,
1363 typcache
->rng_collation
,
1368 if (RANGE_HAS_UBOUND(flags
))
1369 upper_hash
= DatumGetUInt32(FunctionCall1Coll(&scache
->hash_proc_finfo
,
1370 typcache
->rng_collation
,
1375 /* Merge hashes of flags and bounds */
1376 result
= hash_uint32((uint32
) flags
);
1377 result
^= lower_hash
;
1378 result
= pg_rotate_left32(result
, 1);
1379 result
^= upper_hash
;
1381 PG_RETURN_INT32(result
);
1385 * Returns 64-bit value by hashing a value to a 64-bit value, with a seed.
1386 * Otherwise, similar to hash_range.
1389 hash_range_extended(PG_FUNCTION_ARGS
)
1391 RangeType
*r
= PG_GETARG_RANGE_P(0);
1392 Datum seed
= PG_GETARG_DATUM(1);
1394 TypeCacheEntry
*typcache
;
1395 TypeCacheEntry
*scache
;
1403 check_stack_depth();
1405 typcache
= range_get_typcache(fcinfo
, RangeTypeGetOid(r
));
1407 range_deserialize(typcache
, r
, &lower
, &upper
, &empty
);
1408 flags
= range_get_flags(r
);
1410 scache
= typcache
->rngelemtype
;
1411 if (!OidIsValid(scache
->hash_extended_proc_finfo
.fn_oid
))
1413 scache
= lookup_type_cache(scache
->type_id
,
1414 TYPECACHE_HASH_EXTENDED_PROC_FINFO
);
1415 if (!OidIsValid(scache
->hash_extended_proc_finfo
.fn_oid
))
1417 (errcode(ERRCODE_UNDEFINED_FUNCTION
),
1418 errmsg("could not identify a hash function for type %s",
1419 format_type_be(scache
->type_id
))));
1422 if (RANGE_HAS_LBOUND(flags
))
1423 lower_hash
= DatumGetUInt64(FunctionCall2Coll(&scache
->hash_extended_proc_finfo
,
1424 typcache
->rng_collation
,
1430 if (RANGE_HAS_UBOUND(flags
))
1431 upper_hash
= DatumGetUInt64(FunctionCall2Coll(&scache
->hash_extended_proc_finfo
,
1432 typcache
->rng_collation
,
1438 /* Merge hashes of flags and bounds */
1439 result
= DatumGetUInt64(hash_uint32_extended((uint32
) flags
,
1440 DatumGetInt64(seed
)));
1441 result
^= lower_hash
;
1442 result
= ROTATE_HIGH_AND_LOW_32BITS(result
);
1443 result
^= upper_hash
;
1445 PG_RETURN_UINT64(result
);
1449 *----------------------------------------------------------
1450 * CANONICAL FUNCTIONS
1452 * Functions for specific built-in range types.
1453 *----------------------------------------------------------
1457 int4range_canonical(PG_FUNCTION_ARGS
)
1459 RangeType
*r
= PG_GETARG_RANGE_P(0);
1460 Node
*escontext
= fcinfo
->context
;
1461 TypeCacheEntry
*typcache
;
1466 typcache
= range_get_typcache(fcinfo
, RangeTypeGetOid(r
));
1468 range_deserialize(typcache
, r
, &lower
, &upper
, &empty
);
1471 PG_RETURN_RANGE_P(r
);
1473 if (!lower
.infinite
&& !lower
.inclusive
)
1475 int32 bnd
= DatumGetInt32(lower
.val
);
1477 /* Handle possible overflow manually */
1478 if (unlikely(bnd
== PG_INT32_MAX
))
1479 ereturn(escontext
, (Datum
) 0,
1480 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE
),
1481 errmsg("integer out of range")));
1482 lower
.val
= Int32GetDatum(bnd
+ 1);
1483 lower
.inclusive
= true;
1486 if (!upper
.infinite
&& upper
.inclusive
)
1488 int32 bnd
= DatumGetInt32(upper
.val
);
1490 /* Handle possible overflow manually */
1491 if (unlikely(bnd
== PG_INT32_MAX
))
1492 ereturn(escontext
, (Datum
) 0,
1493 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE
),
1494 errmsg("integer out of range")));
1495 upper
.val
= Int32GetDatum(bnd
+ 1);
1496 upper
.inclusive
= false;
1499 PG_RETURN_RANGE_P(range_serialize(typcache
, &lower
, &upper
,
1504 int8range_canonical(PG_FUNCTION_ARGS
)
1506 RangeType
*r
= PG_GETARG_RANGE_P(0);
1507 Node
*escontext
= fcinfo
->context
;
1508 TypeCacheEntry
*typcache
;
1513 typcache
= range_get_typcache(fcinfo
, RangeTypeGetOid(r
));
1515 range_deserialize(typcache
, r
, &lower
, &upper
, &empty
);
1518 PG_RETURN_RANGE_P(r
);
1520 if (!lower
.infinite
&& !lower
.inclusive
)
1522 int64 bnd
= DatumGetInt64(lower
.val
);
1524 /* Handle possible overflow manually */
1525 if (unlikely(bnd
== PG_INT64_MAX
))
1526 ereturn(escontext
, (Datum
) 0,
1527 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE
),
1528 errmsg("bigint out of range")));
1529 lower
.val
= Int64GetDatum(bnd
+ 1);
1530 lower
.inclusive
= true;
1533 if (!upper
.infinite
&& upper
.inclusive
)
1535 int64 bnd
= DatumGetInt64(upper
.val
);
1537 /* Handle possible overflow manually */
1538 if (unlikely(bnd
== PG_INT64_MAX
))
1539 ereturn(escontext
, (Datum
) 0,
1540 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE
),
1541 errmsg("bigint out of range")));
1542 upper
.val
= Int64GetDatum(bnd
+ 1);
1543 upper
.inclusive
= false;
1546 PG_RETURN_RANGE_P(range_serialize(typcache
, &lower
, &upper
,
1551 daterange_canonical(PG_FUNCTION_ARGS
)
1553 RangeType
*r
= PG_GETARG_RANGE_P(0);
1554 Node
*escontext
= fcinfo
->context
;
1555 TypeCacheEntry
*typcache
;
1560 typcache
= range_get_typcache(fcinfo
, RangeTypeGetOid(r
));
1562 range_deserialize(typcache
, r
, &lower
, &upper
, &empty
);
1565 PG_RETURN_RANGE_P(r
);
1567 if (!lower
.infinite
&& !DATE_NOT_FINITE(DatumGetDateADT(lower
.val
)) &&
1570 DateADT bnd
= DatumGetDateADT(lower
.val
);
1572 /* Check for overflow -- note we already eliminated PG_INT32_MAX */
1574 if (unlikely(!IS_VALID_DATE(bnd
)))
1575 ereturn(escontext
, (Datum
) 0,
1576 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE
),
1577 errmsg("date out of range")));
1578 lower
.val
= DateADTGetDatum(bnd
);
1579 lower
.inclusive
= true;
1582 if (!upper
.infinite
&& !DATE_NOT_FINITE(DatumGetDateADT(upper
.val
)) &&
1585 DateADT bnd
= DatumGetDateADT(upper
.val
);
1587 /* Check for overflow -- note we already eliminated PG_INT32_MAX */
1589 if (unlikely(!IS_VALID_DATE(bnd
)))
1590 ereturn(escontext
, (Datum
) 0,
1591 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE
),
1592 errmsg("date out of range")));
1593 upper
.val
= DateADTGetDatum(bnd
);
1594 upper
.inclusive
= false;
1597 PG_RETURN_RANGE_P(range_serialize(typcache
, &lower
, &upper
,
1602 *----------------------------------------------------------
1603 * SUBTYPE_DIFF FUNCTIONS
1605 * Functions for specific built-in range types.
1607 * Note that subtype_diff does return the difference, not the absolute value
1608 * of the difference, and it must take care to avoid overflow.
1609 * (numrange_subdiff is at some risk there ...)
1610 *----------------------------------------------------------
1614 int4range_subdiff(PG_FUNCTION_ARGS
)
1616 int32 v1
= PG_GETARG_INT32(0);
1617 int32 v2
= PG_GETARG_INT32(1);
1619 PG_RETURN_FLOAT8((float8
) v1
- (float8
) v2
);
1623 int8range_subdiff(PG_FUNCTION_ARGS
)
1625 int64 v1
= PG_GETARG_INT64(0);
1626 int64 v2
= PG_GETARG_INT64(1);
1628 PG_RETURN_FLOAT8((float8
) v1
- (float8
) v2
);
1632 numrange_subdiff(PG_FUNCTION_ARGS
)
1634 Datum v1
= PG_GETARG_DATUM(0);
1635 Datum v2
= PG_GETARG_DATUM(1);
1639 numresult
= DirectFunctionCall2(numeric_sub
, v1
, v2
);
1641 floatresult
= DatumGetFloat8(DirectFunctionCall1(numeric_float8
,
1644 PG_RETURN_FLOAT8(floatresult
);
1648 daterange_subdiff(PG_FUNCTION_ARGS
)
1650 int32 v1
= PG_GETARG_INT32(0);
1651 int32 v2
= PG_GETARG_INT32(1);
1653 PG_RETURN_FLOAT8((float8
) v1
- (float8
) v2
);
1657 tsrange_subdiff(PG_FUNCTION_ARGS
)
1659 Timestamp v1
= PG_GETARG_TIMESTAMP(0);
1660 Timestamp v2
= PG_GETARG_TIMESTAMP(1);
1663 result
= ((float8
) v1
- (float8
) v2
) / USECS_PER_SEC
;
1664 PG_RETURN_FLOAT8(result
);
1668 tstzrange_subdiff(PG_FUNCTION_ARGS
)
1670 Timestamp v1
= PG_GETARG_TIMESTAMP(0);
1671 Timestamp v2
= PG_GETARG_TIMESTAMP(1);
1674 result
= ((float8
) v1
- (float8
) v2
) / USECS_PER_SEC
;
1675 PG_RETURN_FLOAT8(result
);
1679 *----------------------------------------------------------
1682 * These functions aren't in pg_proc, but are useful for
1683 * defining new generic range functions in C.
1684 *----------------------------------------------------------
1688 * range_get_typcache: get cached information about a range type
1690 * This is for use by range-related functions that follow the convention
1691 * of using the fn_extra field as a pointer to the type cache entry for
1692 * the range type. Functions that need to cache more information than
1693 * that must fend for themselves.
1696 range_get_typcache(FunctionCallInfo fcinfo
, Oid rngtypid
)
1698 TypeCacheEntry
*typcache
= (TypeCacheEntry
*) fcinfo
->flinfo
->fn_extra
;
1700 if (typcache
== NULL
||
1701 typcache
->type_id
!= rngtypid
)
1703 typcache
= lookup_type_cache(rngtypid
, TYPECACHE_RANGE_INFO
);
1704 if (typcache
->rngelemtype
== NULL
)
1705 elog(ERROR
, "type %u is not a range type", rngtypid
);
1706 fcinfo
->flinfo
->fn_extra
= (void *) typcache
;
1713 * range_serialize: construct a range value from bounds and empty-flag
1715 * This does not force canonicalization of the range value. In most cases,
1716 * external callers should only be canonicalization functions. Note that
1717 * we perform some datatype-independent canonicalization checks anyway.
1720 range_serialize(TypeCacheEntry
*typcache
, RangeBound
*lower
, RangeBound
*upper
,
1721 bool empty
, struct Node
*escontext
)
1734 * Verify range is not invalid on its face, and construct flags value,
1735 * preventing any non-canonical combinations such as infinite+inclusive.
1737 Assert(lower
->lower
);
1738 Assert(!upper
->lower
);
1741 flags
|= RANGE_EMPTY
;
1744 cmp
= range_cmp_bound_values(typcache
, lower
, upper
);
1746 /* error check: if lower bound value is above upper, it's wrong */
1748 ereturn(escontext
, NULL
,
1749 (errcode(ERRCODE_DATA_EXCEPTION
),
1750 errmsg("range lower bound must be less than or equal to range upper bound")));
1752 /* if bounds are equal, and not both inclusive, range is empty */
1753 if (cmp
== 0 && !(lower
->inclusive
&& upper
->inclusive
))
1754 flags
|= RANGE_EMPTY
;
1757 /* infinite boundaries are never inclusive */
1758 if (lower
->infinite
)
1759 flags
|= RANGE_LB_INF
;
1760 else if (lower
->inclusive
)
1761 flags
|= RANGE_LB_INC
;
1762 if (upper
->infinite
)
1763 flags
|= RANGE_UB_INF
;
1764 else if (upper
->inclusive
)
1765 flags
|= RANGE_UB_INC
;
1769 /* Fetch information about range's element type */
1770 typlen
= typcache
->rngelemtype
->typlen
;
1771 typbyval
= typcache
->rngelemtype
->typbyval
;
1772 typalign
= typcache
->rngelemtype
->typalign
;
1773 typstorage
= typcache
->rngelemtype
->typstorage
;
1775 /* Count space for varlena header and range type's OID */
1776 msize
= sizeof(RangeType
);
1777 Assert(msize
== MAXALIGN(msize
));
1779 /* Count space for bounds */
1780 if (RANGE_HAS_LBOUND(flags
))
1783 * Make sure item to be inserted is not toasted. It is essential that
1784 * we not insert an out-of-line toast value pointer into a range
1785 * object, for the same reasons that arrays and records can't contain
1786 * them. It would work to store a compressed-in-line value, but we
1787 * prefer to decompress and then let compression be applied to the
1788 * whole range object if necessary. But, unlike arrays, we do allow
1789 * short-header varlena objects to stay as-is.
1792 lower
->val
= PointerGetDatum(PG_DETOAST_DATUM_PACKED(lower
->val
));
1794 msize
= datum_compute_size(msize
, lower
->val
, typbyval
, typalign
,
1795 typlen
, typstorage
);
1798 if (RANGE_HAS_UBOUND(flags
))
1800 /* Make sure item to be inserted is not toasted */
1802 upper
->val
= PointerGetDatum(PG_DETOAST_DATUM_PACKED(upper
->val
));
1804 msize
= datum_compute_size(msize
, upper
->val
, typbyval
, typalign
,
1805 typlen
, typstorage
);
1808 /* Add space for flag byte */
1809 msize
+= sizeof(char);
1811 /* Note: zero-fill is required here, just as in heap tuples */
1812 range
= (RangeType
*) palloc0(msize
);
1813 SET_VARSIZE(range
, msize
);
1815 /* Now fill in the datum */
1816 range
->rangetypid
= typcache
->type_id
;
1818 ptr
= (char *) (range
+ 1);
1820 if (RANGE_HAS_LBOUND(flags
))
1822 Assert(lower
->lower
);
1823 ptr
= datum_write(ptr
, lower
->val
, typbyval
, typalign
, typlen
,
1827 if (RANGE_HAS_UBOUND(flags
))
1829 Assert(!upper
->lower
);
1830 ptr
= datum_write(ptr
, upper
->val
, typbyval
, typalign
, typlen
,
1834 *((char *) ptr
) = flags
;
1840 * range_deserialize: deconstruct a range value
1842 * NB: the given range object must be fully detoasted; it cannot have a
1843 * short varlena header.
1845 * Note that if the element type is pass-by-reference, the datums in the
1846 * RangeBound structs will be pointers into the given range object.
1849 range_deserialize(TypeCacheEntry
*typcache
, const RangeType
*range
,
1850 RangeBound
*lower
, RangeBound
*upper
, bool *empty
)
1860 /* assert caller passed the right typcache entry */
1861 Assert(RangeTypeGetOid(range
) == typcache
->type_id
);
1863 /* fetch the flag byte from datum's last byte */
1864 flags
= *((const char *) range
+ VARSIZE(range
) - 1);
1866 /* fetch information about range's element type */
1867 typlen
= typcache
->rngelemtype
->typlen
;
1868 typbyval
= typcache
->rngelemtype
->typbyval
;
1869 typalign
= typcache
->rngelemtype
->typalign
;
1871 /* initialize data pointer just after the range OID */
1872 ptr
= (Pointer
) (range
+ 1);
1874 /* fetch lower bound, if any */
1875 if (RANGE_HAS_LBOUND(flags
))
1877 /* att_align_pointer cannot be necessary here */
1878 lbound
= fetch_att(ptr
, typbyval
, typlen
);
1879 ptr
= (Pointer
) att_addlength_pointer(ptr
, typlen
, ptr
);
1884 /* fetch upper bound, if any */
1885 if (RANGE_HAS_UBOUND(flags
))
1887 ptr
= (Pointer
) att_align_pointer(ptr
, typalign
, typlen
, ptr
);
1888 ubound
= fetch_att(ptr
, typbyval
, typlen
);
1889 /* no need for att_addlength_pointer */
1896 *empty
= (flags
& RANGE_EMPTY
) != 0;
1898 lower
->val
= lbound
;
1899 lower
->infinite
= (flags
& RANGE_LB_INF
) != 0;
1900 lower
->inclusive
= (flags
& RANGE_LB_INC
) != 0;
1901 lower
->lower
= true;
1903 upper
->val
= ubound
;
1904 upper
->infinite
= (flags
& RANGE_UB_INF
) != 0;
1905 upper
->inclusive
= (flags
& RANGE_UB_INC
) != 0;
1906 upper
->lower
= false;
1910 * range_get_flags: just get the flags from a RangeType value.
1912 * This is frequently useful in places that only need the flags and not
1913 * the full results of range_deserialize.
1916 range_get_flags(const RangeType
*range
)
1918 /* fetch the flag byte from datum's last byte */
1919 return *((char *) range
+ VARSIZE(range
) - 1);
1923 * range_set_contain_empty: set the RANGE_CONTAIN_EMPTY bit in the value.
1925 * This is only needed in GiST operations, so we don't include a provision
1926 * for setting it in range_serialize; rather, this function must be applied
1930 range_set_contain_empty(RangeType
*range
)
1934 /* flag byte is datum's last byte */
1935 flagsp
= (char *) range
+ VARSIZE(range
) - 1;
1937 *flagsp
|= RANGE_CONTAIN_EMPTY
;
1941 * This both serializes and canonicalizes (if applicable) the range.
1942 * This should be used by most callers.
1945 make_range(TypeCacheEntry
*typcache
, RangeBound
*lower
, RangeBound
*upper
,
1946 bool empty
, struct Node
*escontext
)
1950 range
= range_serialize(typcache
, lower
, upper
, empty
, escontext
);
1952 if (SOFT_ERROR_OCCURRED(escontext
))
1955 /* no need to call canonical on empty ranges ... */
1956 if (OidIsValid(typcache
->rng_canonical_finfo
.fn_oid
) &&
1957 !RangeIsEmpty(range
))
1959 /* Do this the hard way so that we can pass escontext */
1960 LOCAL_FCINFO(fcinfo
, 1);
1963 InitFunctionCallInfoData(*fcinfo
, &typcache
->rng_canonical_finfo
, 1,
1964 InvalidOid
, escontext
, NULL
);
1966 fcinfo
->args
[0].value
= RangeTypePGetDatum(range
);
1967 fcinfo
->args
[0].isnull
= false;
1969 result
= FunctionCallInvoke(fcinfo
);
1971 if (SOFT_ERROR_OCCURRED(escontext
))
1974 /* Should not get a null result if there was no error */
1976 elog(ERROR
, "function %u returned NULL",
1977 typcache
->rng_canonical_finfo
.fn_oid
);
1979 range
= DatumGetRangeTypeP(result
);
1986 * Compare two range boundary points, returning <0, 0, or >0 according to
1987 * whether b1 is less than, equal to, or greater than b2.
1989 * The boundaries can be any combination of upper and lower; so it's useful
1990 * for a variety of operators.
1992 * The simple case is when b1 and b2 are both finite and inclusive, in which
1993 * case the result is just a comparison of the values held in b1 and b2.
1995 * If a bound is exclusive, then we need to know whether it's a lower bound,
1996 * in which case we treat the boundary point as "just greater than" the held
1997 * value; or an upper bound, in which case we treat the boundary point as
1998 * "just less than" the held value.
2000 * If a bound is infinite, it represents minus infinity (less than every other
2001 * point) if it's a lower bound; or plus infinity (greater than every other
2002 * point) if it's an upper bound.
2004 * There is only one case where two boundaries compare equal but are not
2005 * identical: when both bounds are inclusive and hold the same finite value,
2006 * but one is an upper bound and the other a lower bound.
2009 range_cmp_bounds(TypeCacheEntry
*typcache
, const RangeBound
*b1
, const RangeBound
*b2
)
2014 * First, handle cases involving infinity, which don't require invoking
2015 * the comparison proc.
2017 if (b1
->infinite
&& b2
->infinite
)
2020 * Both are infinity, so they are equal unless one is lower and the
2023 if (b1
->lower
== b2
->lower
)
2026 return b1
->lower
? -1 : 1;
2028 else if (b1
->infinite
)
2029 return b1
->lower
? -1 : 1;
2030 else if (b2
->infinite
)
2031 return b2
->lower
? 1 : -1;
2034 * Both boundaries are finite, so compare the held values.
2036 result
= DatumGetInt32(FunctionCall2Coll(&typcache
->rng_cmp_proc_finfo
,
2037 typcache
->rng_collation
,
2041 * If the comparison is anything other than equal, we're done. If they
2042 * compare equal though, we still have to consider whether the boundaries
2043 * are inclusive or exclusive.
2047 if (!b1
->inclusive
&& !b2
->inclusive
)
2049 /* both are exclusive */
2050 if (b1
->lower
== b2
->lower
)
2053 return b1
->lower
? 1 : -1;
2055 else if (!b1
->inclusive
)
2056 return b1
->lower
? 1 : -1;
2057 else if (!b2
->inclusive
)
2058 return b2
->lower
? -1 : 1;
2062 * Both are inclusive and the values held are equal, so they are
2063 * equal regardless of whether they are upper or lower boundaries,
2074 * Compare two range boundary point values, returning <0, 0, or >0 according
2075 * to whether b1 is less than, equal to, or greater than b2.
2077 * This is similar to but simpler than range_cmp_bounds(). We just compare
2078 * the values held in b1 and b2, ignoring inclusive/exclusive flags. The
2079 * lower/upper flags only matter for infinities, where they tell us if the
2080 * infinity is plus or minus.
2083 range_cmp_bound_values(TypeCacheEntry
*typcache
, const RangeBound
*b1
,
2084 const RangeBound
*b2
)
2087 * First, handle cases involving infinity, which don't require invoking
2088 * the comparison proc.
2090 if (b1
->infinite
&& b2
->infinite
)
2093 * Both are infinity, so they are equal unless one is lower and the
2096 if (b1
->lower
== b2
->lower
)
2099 return b1
->lower
? -1 : 1;
2101 else if (b1
->infinite
)
2102 return b1
->lower
? -1 : 1;
2103 else if (b2
->infinite
)
2104 return b2
->lower
? 1 : -1;
2107 * Both boundaries are finite, so compare the held values.
2109 return DatumGetInt32(FunctionCall2Coll(&typcache
->rng_cmp_proc_finfo
,
2110 typcache
->rng_collation
,
2115 * qsort callback for sorting ranges.
2117 * Two empty ranges compare equal; an empty range sorts to the left of any
2118 * non-empty range. Two non-empty ranges are sorted by lower bound first
2119 * and by upper bound next.
2122 range_compare(const void *key1
, const void *key2
, void *arg
)
2124 RangeType
*r1
= *(RangeType
**) key1
;
2125 RangeType
*r2
= *(RangeType
**) key2
;
2126 TypeCacheEntry
*typcache
= (TypeCacheEntry
*) arg
;
2135 range_deserialize(typcache
, r1
, &lower1
, &upper1
, &empty1
);
2136 range_deserialize(typcache
, r2
, &lower2
, &upper2
, &empty2
);
2138 if (empty1
&& empty2
)
2146 cmp
= range_cmp_bounds(typcache
, &lower1
, &lower2
);
2148 cmp
= range_cmp_bounds(typcache
, &upper1
, &upper2
);
2155 * Build an empty range value of the type indicated by the typcache entry.
2158 make_empty_range(TypeCacheEntry
*typcache
)
2163 lower
.val
= (Datum
) 0;
2164 lower
.infinite
= false;
2165 lower
.inclusive
= false;
2168 upper
.val
= (Datum
) 0;
2169 upper
.infinite
= false;
2170 upper
.inclusive
= false;
2171 upper
.lower
= false;
2173 return make_range(typcache
, &lower
, &upper
, true, NULL
);
2178 *----------------------------------------------------------
2180 *----------------------------------------------------------
2184 * Given a string representing the flags for the range type, return the flags
2185 * represented as a char.
2188 range_parse_flags(const char *flags_str
)
2192 if (flags_str
[0] == '\0' ||
2193 flags_str
[1] == '\0' ||
2194 flags_str
[2] != '\0')
2196 (errcode(ERRCODE_SYNTAX_ERROR
),
2197 errmsg("invalid range bound flags"),
2198 errhint("Valid values are \"[]\", \"[)\", \"(]\", and \"()\".")));
2200 switch (flags_str
[0])
2203 flags
|= RANGE_LB_INC
;
2209 (errcode(ERRCODE_SYNTAX_ERROR
),
2210 errmsg("invalid range bound flags"),
2211 errhint("Valid values are \"[]\", \"[)\", \"(]\", and \"()\".")));
2214 switch (flags_str
[1])
2217 flags
|= RANGE_UB_INC
;
2223 (errcode(ERRCODE_SYNTAX_ERROR
),
2224 errmsg("invalid range bound flags"),
2225 errhint("Valid values are \"[]\", \"[)\", \"(]\", and \"()\".")));
2232 * Parse range input.
2235 * string: input string to be parsed
2236 * Output parameters:
2237 * *flags: receives flags bitmask
2238 * *lbound_str: receives palloc'd lower bound string, or NULL if none
2239 * *ubound_str: receives palloc'd upper bound string, or NULL if none
2241 * This is modeled somewhat after record_in in rowtypes.c.
2242 * The input syntax is:
2244 * | <lb-inc> <string>, <string> <ub-inc>
2245 * <lb-inc> := '[' | '('
2246 * <ub-inc> := ']' | ')'
2248 * Whitespace before or after <range> is ignored. Whitespace within a <string>
2249 * is taken literally and becomes part of the input string for that bound.
2251 * A <string> of length zero is taken as "infinite" (i.e. no bound), unless it
2252 * is surrounded by double-quotes, in which case it is the literal empty
2255 * Within a <string>, special characters (such as comma, parenthesis, or
2256 * brackets) can be enclosed in double-quotes or escaped with backslash. Within
2257 * double-quotes, a double-quote can be escaped with double-quote or backslash.
2259 * Returns true on success, false on failure (but failures will return only if
2260 * escontext is an ErrorSaveContext).
2263 range_parse(const char *string
, char *flags
, char **lbound_str
,
2264 char **ubound_str
, Node
*escontext
)
2266 const char *ptr
= string
;
2271 /* consume whitespace */
2272 while (*ptr
!= '\0' && isspace((unsigned char) *ptr
))
2275 /* check for empty range */
2276 if (pg_strncasecmp(ptr
, RANGE_EMPTY_LITERAL
,
2277 strlen(RANGE_EMPTY_LITERAL
)) == 0)
2279 *flags
= RANGE_EMPTY
;
2283 ptr
+= strlen(RANGE_EMPTY_LITERAL
);
2285 /* the rest should be whitespace */
2286 while (*ptr
!= '\0' && isspace((unsigned char) *ptr
))
2289 /* should have consumed everything */
2291 ereturn(escontext
, false,
2292 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION
),
2293 errmsg("malformed range literal: \"%s\"",
2295 errdetail("Junk after \"empty\" key word.")));
2302 *flags
|= RANGE_LB_INC
;
2305 else if (*ptr
== '(')
2308 ereturn(escontext
, false,
2309 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION
),
2310 errmsg("malformed range literal: \"%s\"",
2312 errdetail("Missing left parenthesis or bracket.")));
2314 ptr
= range_parse_bound(string
, ptr
, lbound_str
, &infinite
, escontext
);
2318 *flags
|= RANGE_LB_INF
;
2323 ereturn(escontext
, false,
2324 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION
),
2325 errmsg("malformed range literal: \"%s\"",
2327 errdetail("Missing comma after lower bound.")));
2329 ptr
= range_parse_bound(string
, ptr
, ubound_str
, &infinite
, escontext
);
2333 *flags
|= RANGE_UB_INF
;
2337 *flags
|= RANGE_UB_INC
;
2340 else if (*ptr
== ')')
2342 else /* must be a comma */
2343 ereturn(escontext
, false,
2344 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION
),
2345 errmsg("malformed range literal: \"%s\"",
2347 errdetail("Too many commas.")));
2349 /* consume whitespace */
2350 while (*ptr
!= '\0' && isspace((unsigned char) *ptr
))
2354 ereturn(escontext
, false,
2355 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION
),
2356 errmsg("malformed range literal: \"%s\"",
2358 errdetail("Junk after right parenthesis or bracket.")));
2364 * Helper for range_parse: parse and de-quote one bound string.
2366 * We scan until finding comma, right parenthesis, or right bracket.
2369 * string: entire input string (used only for error reports)
2370 * ptr: where to start parsing bound
2371 * Output parameters:
2372 * *bound_str: receives palloc'd bound string, or NULL if none
2373 * *infinite: set true if no bound, else false
2375 * The return value is the scan ptr, advanced past the bound string.
2376 * However, if escontext is an ErrorSaveContext, we return NULL on failure.
2379 range_parse_bound(const char *string
, const char *ptr
,
2380 char **bound_str
, bool *infinite
, Node
*escontext
)
2384 /* Check for null: completely empty input means null */
2385 if (*ptr
== ',' || *ptr
== ')' || *ptr
== ']')
2392 /* Extract string for this bound */
2393 bool inquote
= false;
2395 initStringInfo(&buf
);
2396 while (inquote
|| !(*ptr
== ',' || *ptr
== ')' || *ptr
== ']'))
2401 ereturn(escontext
, NULL
,
2402 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION
),
2403 errmsg("malformed range literal: \"%s\"",
2405 errdetail("Unexpected end of input.")));
2409 ereturn(escontext
, NULL
,
2410 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION
),
2411 errmsg("malformed range literal: \"%s\"",
2413 errdetail("Unexpected end of input.")));
2414 appendStringInfoChar(&buf
, *ptr
++);
2420 else if (*ptr
== '"')
2422 /* doubled quote within quote sequence */
2423 appendStringInfoChar(&buf
, *ptr
++);
2429 appendStringInfoChar(&buf
, ch
);
2432 *bound_str
= buf
.data
;
2440 * Convert a deserialized range value to text form
2442 * Inputs are the flags byte, and the two bound values already converted to
2443 * text (but not yet quoted). If no bound value, pass NULL.
2445 * Result is a palloc'd string
2448 range_deparse(char flags
, const char *lbound_str
, const char *ubound_str
)
2452 if (flags
& RANGE_EMPTY
)
2453 return pstrdup(RANGE_EMPTY_LITERAL
);
2455 initStringInfo(&buf
);
2457 appendStringInfoChar(&buf
, (flags
& RANGE_LB_INC
) ? '[' : '(');
2459 if (RANGE_HAS_LBOUND(flags
))
2460 appendStringInfoString(&buf
, range_bound_escape(lbound_str
));
2462 appendStringInfoChar(&buf
, ',');
2464 if (RANGE_HAS_UBOUND(flags
))
2465 appendStringInfoString(&buf
, range_bound_escape(ubound_str
));
2467 appendStringInfoChar(&buf
, (flags
& RANGE_UB_INC
) ? ']' : ')');
2473 * Helper for range_deparse: quote a bound value as needed
2475 * Result is a palloc'd string
2478 range_bound_escape(const char *value
)
2484 initStringInfo(&buf
);
2486 /* Detect whether we need double quotes for this value */
2487 nq
= (value
[0] == '\0'); /* force quotes for empty string */
2488 for (ptr
= value
; *ptr
; ptr
++)
2492 if (ch
== '"' || ch
== '\\' ||
2493 ch
== '(' || ch
== ')' ||
2494 ch
== '[' || ch
== ']' ||
2496 isspace((unsigned char) ch
))
2503 /* And emit the string */
2505 appendStringInfoChar(&buf
, '"');
2506 for (ptr
= value
; *ptr
; ptr
++)
2510 if (ch
== '"' || ch
== '\\')
2511 appendStringInfoChar(&buf
, ch
);
2512 appendStringInfoChar(&buf
, ch
);
2515 appendStringInfoChar(&buf
, '"');
2521 * Test whether range r1 contains range r2.
2523 * Caller has already checked that they are the same range type, and looked up
2524 * the necessary typcache entry.
2527 range_contains_internal(TypeCacheEntry
*typcache
, const RangeType
*r1
, const RangeType
*r2
)
2536 /* Different types should be prevented by ANYRANGE matching rules */
2537 if (RangeTypeGetOid(r1
) != RangeTypeGetOid(r2
))
2538 elog(ERROR
, "range types do not match");
2540 range_deserialize(typcache
, r1
, &lower1
, &upper1
, &empty1
);
2541 range_deserialize(typcache
, r2
, &lower2
, &upper2
, &empty2
);
2543 /* If either range is empty, the answer is easy */
2549 /* Else we must have lower1 <= lower2 and upper1 >= upper2 */
2550 if (range_cmp_bounds(typcache
, &lower1
, &lower2
) > 0)
2552 if (range_cmp_bounds(typcache
, &upper1
, &upper2
) < 0)
2559 range_contained_by_internal(TypeCacheEntry
*typcache
, const RangeType
*r1
, const RangeType
*r2
)
2561 return range_contains_internal(typcache
, r2
, r1
);
2565 * Test whether range r contains a specific element value.
2568 range_contains_elem_internal(TypeCacheEntry
*typcache
, const RangeType
*r
, Datum val
)
2575 range_deserialize(typcache
, r
, &lower
, &upper
, &empty
);
2580 if (!lower
.infinite
)
2582 cmp
= DatumGetInt32(FunctionCall2Coll(&typcache
->rng_cmp_proc_finfo
,
2583 typcache
->rng_collation
,
2587 if (cmp
== 0 && !lower
.inclusive
)
2591 if (!upper
.infinite
)
2593 cmp
= DatumGetInt32(FunctionCall2Coll(&typcache
->rng_cmp_proc_finfo
,
2594 typcache
->rng_collation
,
2598 if (cmp
== 0 && !upper
.inclusive
)
2607 * datum_compute_size() and datum_write() are used to insert the bound
2608 * values into a range object. They are modeled after heaptuple.c's
2609 * heap_compute_data_size() and heap_fill_tuple(), but we need not handle
2610 * null values here. TYPE_IS_PACKABLE must test the same conditions as
2611 * heaptuple.c's ATT_IS_PACKABLE macro. See the comments thare for more
2615 /* Does datatype allow packing into the 1-byte-header varlena format? */
2616 #define TYPE_IS_PACKABLE(typlen, typstorage) \
2617 ((typlen) == -1 && (typstorage) != TYPSTORAGE_PLAIN)
2620 * Increment data_length by the space needed by the datum, including any
2621 * preceding alignment padding.
2624 datum_compute_size(Size data_length
, Datum val
, bool typbyval
, char typalign
,
2625 int16 typlen
, char typstorage
)
2627 if (TYPE_IS_PACKABLE(typlen
, typstorage
) &&
2628 VARATT_CAN_MAKE_SHORT(DatumGetPointer(val
)))
2631 * we're anticipating converting to a short varlena header, so adjust
2632 * length and don't count any alignment
2634 data_length
+= VARATT_CONVERTED_SHORT_SIZE(DatumGetPointer(val
));
2638 data_length
= att_align_datum(data_length
, typalign
, typlen
, val
);
2639 data_length
= att_addlength_datum(data_length
, typlen
, val
);
2646 * Write the given datum beginning at ptr (after advancing to correct
2647 * alignment, if needed). Return the pointer incremented by space used.
2650 datum_write(Pointer ptr
, Datum datum
, bool typbyval
, char typalign
,
2651 int16 typlen
, char typstorage
)
2658 ptr
= (char *) att_align_nominal(ptr
, typalign
);
2659 store_att_byval(ptr
, datum
, typlen
);
2660 data_length
= typlen
;
2662 else if (typlen
== -1)
2665 Pointer val
= DatumGetPointer(datum
);
2667 if (VARATT_IS_EXTERNAL(val
))
2670 * Throw error, because we must never put a toast pointer inside a
2671 * range object. Caller should have detoasted it.
2673 elog(ERROR
, "cannot store a toast pointer inside a range");
2674 data_length
= 0; /* keep compiler quiet */
2676 else if (VARATT_IS_SHORT(val
))
2678 /* no alignment for short varlenas */
2679 data_length
= VARSIZE_SHORT(val
);
2680 memcpy(ptr
, val
, data_length
);
2682 else if (TYPE_IS_PACKABLE(typlen
, typstorage
) &&
2683 VARATT_CAN_MAKE_SHORT(val
))
2685 /* convert to short varlena -- no alignment */
2686 data_length
= VARATT_CONVERTED_SHORT_SIZE(val
);
2687 SET_VARSIZE_SHORT(ptr
, data_length
);
2688 memcpy(ptr
+ 1, VARDATA(val
), data_length
- 1);
2692 /* full 4-byte header varlena */
2693 ptr
= (char *) att_align_nominal(ptr
, typalign
);
2694 data_length
= VARSIZE(val
);
2695 memcpy(ptr
, val
, data_length
);
2698 else if (typlen
== -2)
2700 /* cstring ... never needs alignment */
2701 Assert(typalign
== TYPALIGN_CHAR
);
2702 data_length
= strlen(DatumGetCString(datum
)) + 1;
2703 memcpy(ptr
, DatumGetPointer(datum
), data_length
);
2707 /* fixed-length pass-by-reference */
2708 ptr
= (char *) att_align_nominal(ptr
, typalign
);
2710 data_length
= typlen
;
2711 memcpy(ptr
, DatumGetPointer(datum
), data_length
);