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