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