Thanks to visit codestin.com
Credit goes to doxygen.postgresql.org

PostgreSQL Source Code git master
multirangetypes.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * multirangetypes.c
4 * I/O functions, operators, and support functions for multirange types.
5 *
6 * The stored (serialized) format of a multirange value is:
7 *
8 * 12 bytes: MultirangeType struct including varlena header, multirange
9 * type's OID and the number of ranges in the multirange.
10 * 4 * (rangesCount - 1) bytes: 32-bit items pointing to the each range
11 * in the multirange starting from
12 * the second one.
13 * 1 * rangesCount bytes : 8-bit flags for each range in the multirange
14 * The rest of the multirange are range bound values pointed by multirange
15 * items.
16 *
17 * Majority of items contain lengths of corresponding range bound values.
18 * Thanks to that items are typically low numbers. This makes multiranges
19 * compression-friendly. Every MULTIRANGE_ITEM_OFFSET_STRIDE item contains
20 * an offset of the corresponding range bound values. That allows fast lookups
21 * for a particular range index. Offsets are counted starting from the end of
22 * flags aligned to the bound type.
23 *
24 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
25 * Portions Copyright (c) 1994, Regents of the University of California
26 *
27 *
28 * IDENTIFICATION
29 * src/backend/utils/adt/multirangetypes.c
30 *
31 *-------------------------------------------------------------------------
32 */
33#include "postgres.h"
34
35#include "access/tupmacs.h"
36#include "common/hashfn.h"
37#include "funcapi.h"
38#include "lib/stringinfo.h"
39#include "libpq/pqformat.h"
40#include "nodes/nodes.h"
41#include "port/pg_bitutils.h"
42#include "utils/array.h"
43#include "utils/builtins.h"
44#include "utils/lsyscache.h"
46#include "utils/rangetypes.h"
47
48/* fn_extra cache entry for one of the range I/O functions */
49typedef struct MultirangeIOData
50{
51 TypeCacheEntry *typcache; /* multirange type's typcache entry */
52 FmgrInfo typioproc; /* range type's I/O proc */
53 Oid typioparam; /* range type's I/O parameter */
55
56typedef enum
57{
66
67/*
68 * Macros for accessing past MultirangeType parts of multirange: items, flags
69 * and boundaries.
70 */
71#define MultirangeGetItemsPtr(mr) ((uint32 *) ((Pointer) (mr) + \
72 sizeof(MultirangeType)))
73#define MultirangeGetFlagsPtr(mr) ((uint8 *) ((Pointer) (mr) + \
74 sizeof(MultirangeType) + ((mr)->rangeCount - 1) * sizeof(uint32)))
75#define MultirangeGetBoundariesPtr(mr, align) ((Pointer) (mr) + \
76 att_align_nominal(sizeof(MultirangeType) + \
77 ((mr)->rangeCount - 1) * sizeof(uint32) + \
78 (mr)->rangeCount * sizeof(uint8), (align)))
79
80#define MULTIRANGE_ITEM_OFF_BIT 0x80000000
81#define MULTIRANGE_ITEM_GET_OFFLEN(item) ((item) & 0x7FFFFFFF)
82#define MULTIRANGE_ITEM_HAS_OFF(item) ((item) & MULTIRANGE_ITEM_OFF_BIT)
83#define MULTIRANGE_ITEM_OFFSET_STRIDE 4
84
88 void *key,
89 bool *match);
90
92 Oid mltrngtypid,
93 IOFuncSelector func);
95 int32 input_range_count,
96 RangeType **ranges);
97
98/*
99 *----------------------------------------------------------
100 * I/O FUNCTIONS
101 *----------------------------------------------------------
102 */
103
104/*
105 * Converts string to multirange.
106 *
107 * We expect curly brackets to bound the list, with zero or more ranges
108 * separated by commas. We accept whitespace anywhere: before/after our
109 * brackets and around the commas. Ranges can be the empty literal or some
110 * stuff inside parens/brackets. Mostly we delegate parsing the individual
111 * range contents to range_in, but we have to detect quoting and
112 * backslash-escaping which can happen for range bounds. Backslashes can
113 * escape something inside or outside a quoted string, and a quoted string
114 * can escape quote marks with either backslashes or double double-quotes.
115 */
116Datum
118{
119 char *input_str = PG_GETARG_CSTRING(0);
120 Oid mltrngtypoid = PG_GETARG_OID(1);
121 Oid typmod = PG_GETARG_INT32(2);
122 Node *escontext = fcinfo->context;
123 TypeCacheEntry *rangetyp;
124 int32 ranges_seen = 0;
125 int32 range_count = 0;
126 int32 range_capacity = 8;
128 RangeType **ranges = palloc(range_capacity * sizeof(RangeType *));
129 MultirangeIOData *cache;
130 MultirangeType *ret;
131 MultirangeParseState parse_state;
132 const char *ptr = input_str;
133 const char *range_str_begin = NULL;
134 int32 range_str_len;
135 char *range_str;
136 Datum range_datum;
137
138 cache = get_multirange_io_data(fcinfo, mltrngtypoid, IOFunc_input);
139 rangetyp = cache->typcache->rngtype;
140
141 /* consume whitespace */
142 while (*ptr != '\0' && isspace((unsigned char) *ptr))
143 ptr++;
144
145 if (*ptr == '{')
146 ptr++;
147 else
148 ereturn(escontext, (Datum) 0,
149 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
150 errmsg("malformed multirange literal: \"%s\"",
151 input_str),
152 errdetail("Missing left brace.")));
153
154 /* consume ranges */
155 parse_state = MULTIRANGE_BEFORE_RANGE;
156 for (; parse_state != MULTIRANGE_FINISHED; ptr++)
157 {
158 char ch = *ptr;
159
160 if (ch == '\0')
161 ereturn(escontext, (Datum) 0,
162 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
163 errmsg("malformed multirange literal: \"%s\"",
164 input_str),
165 errdetail("Unexpected end of input.")));
166
167 /* skip whitespace */
168 if (isspace((unsigned char) ch))
169 continue;
170
171 switch (parse_state)
172 {
174 if (ch == '[' || ch == '(')
175 {
176 range_str_begin = ptr;
177 parse_state = MULTIRANGE_IN_RANGE;
178 }
179 else if (ch == '}' && ranges_seen == 0)
180 parse_state = MULTIRANGE_FINISHED;
182 strlen(RANGE_EMPTY_LITERAL)) == 0)
183 {
184 ranges_seen++;
185 /* nothing to do with an empty range */
186 ptr += strlen(RANGE_EMPTY_LITERAL) - 1;
187 parse_state = MULTIRANGE_AFTER_RANGE;
188 }
189 else
190 ereturn(escontext, (Datum) 0,
191 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
192 errmsg("malformed multirange literal: \"%s\"",
193 input_str),
194 errdetail("Expected range start.")));
195 break;
197 if (ch == ']' || ch == ')')
198 {
199 range_str_len = ptr - range_str_begin + 1;
200 range_str = pnstrdup(range_str_begin, range_str_len);
201 if (range_capacity == range_count)
202 {
203 range_capacity *= 2;
204 ranges = (RangeType **)
205 repalloc(ranges, range_capacity * sizeof(RangeType *));
206 }
207 ranges_seen++;
208 if (!InputFunctionCallSafe(&cache->typioproc,
209 range_str,
210 cache->typioparam,
211 typmod,
212 escontext,
213 &range_datum))
215 range = DatumGetRangeTypeP(range_datum);
216 if (!RangeIsEmpty(range))
217 ranges[range_count++] = range;
218 parse_state = MULTIRANGE_AFTER_RANGE;
219 }
220 else
221 {
222 if (ch == '"')
223 parse_state = MULTIRANGE_IN_RANGE_QUOTED;
224 else if (ch == '\\')
225 parse_state = MULTIRANGE_IN_RANGE_ESCAPED;
226
227 /*
228 * We will include this character into range_str once we
229 * find the end of the range value.
230 */
231 }
232 break;
234
235 /*
236 * We will include this character into range_str once we find
237 * the end of the range value.
238 */
239 parse_state = MULTIRANGE_IN_RANGE;
240 break;
242 if (ch == '"')
243 if (*(ptr + 1) == '"')
244 {
245 /* two quote marks means an escaped quote mark */
246 ptr++;
247 }
248 else
249 parse_state = MULTIRANGE_IN_RANGE;
250 else if (ch == '\\')
252
253 /*
254 * We will include this character into range_str once we find
255 * the end of the range value.
256 */
257 break;
259 if (ch == ',')
260 parse_state = MULTIRANGE_BEFORE_RANGE;
261 else if (ch == '}')
262 parse_state = MULTIRANGE_FINISHED;
263 else
264 ereturn(escontext, (Datum) 0,
265 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
266 errmsg("malformed multirange literal: \"%s\"",
267 input_str),
268 errdetail("Expected comma or end of multirange.")));
269 break;
271
272 /*
273 * We will include this character into range_str once we find
274 * the end of the range value.
275 */
276 parse_state = MULTIRANGE_IN_RANGE_QUOTED;
277 break;
278 default:
279 elog(ERROR, "unknown parse state: %d", parse_state);
280 }
281 }
282
283 /* consume whitespace */
284 while (*ptr != '\0' && isspace((unsigned char) *ptr))
285 ptr++;
286
287 if (*ptr != '\0')
288 ereturn(escontext, (Datum) 0,
289 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
290 errmsg("malformed multirange literal: \"%s\"",
291 input_str),
292 errdetail("Junk after closing right brace.")));
293
294 ret = make_multirange(mltrngtypoid, rangetyp, range_count, ranges);
296}
297
298Datum
300{
301 MultirangeType *multirange = PG_GETARG_MULTIRANGE_P(0);
302 Oid mltrngtypoid = MultirangeTypeGetOid(multirange);
303 MultirangeIOData *cache;
306 char *rangeStr;
307 int32 range_count;
308 int32 i;
309 RangeType **ranges;
310
311 cache = get_multirange_io_data(fcinfo, mltrngtypoid, IOFunc_output);
312
314
316
317 multirange_deserialize(cache->typcache->rngtype, multirange, &range_count, &ranges);
318 for (i = 0; i < range_count; i++)
319 {
320 if (i > 0)
322 range = ranges[i];
324 appendStringInfoString(&buf, rangeStr);
325 }
326
328
330}
331
332/*
333 * Binary representation: First an int32-sized count of ranges, followed by
334 * ranges in their native binary representation.
335 */
336Datum
338{
340 Oid mltrngtypoid = PG_GETARG_OID(1);
341 int32 typmod = PG_GETARG_INT32(2);
342 MultirangeIOData *cache;
343 uint32 range_count;
344 RangeType **ranges;
345 MultirangeType *ret;
347
348 cache = get_multirange_io_data(fcinfo, mltrngtypoid, IOFunc_receive);
349
350 range_count = pq_getmsgint(buf, 4);
351 ranges = palloc(range_count * sizeof(RangeType *));
352
354 for (int i = 0; i < range_count; i++)
355 {
356 uint32 range_len = pq_getmsgint(buf, 4);
357 const char *range_data = pq_getmsgbytes(buf, range_len);
358
360 appendBinaryStringInfo(&tmpbuf, range_data, range_len);
361
363 &tmpbuf,
364 cache->typioparam,
365 typmod));
366 }
368
370
371 ret = make_multirange(mltrngtypoid, cache->typcache->rngtype,
372 range_count, ranges);
374}
375
376Datum
378{
379 MultirangeType *multirange = PG_GETARG_MULTIRANGE_P(0);
380 Oid mltrngtypoid = MultirangeTypeGetOid(multirange);
382 RangeType **ranges;
383 int32 range_count;
384 MultirangeIOData *cache;
385
386 cache = get_multirange_io_data(fcinfo, mltrngtypoid, IOFunc_send);
387
388 /* construct output */
390
391 pq_sendint32(buf, multirange->rangeCount);
392
393 multirange_deserialize(cache->typcache->rngtype, multirange, &range_count, &ranges);
394 for (int i = 0; i < range_count; i++)
395 {
396 Datum range;
397 bytea *outputbytes;
398
399 range = RangeTypePGetDatum(ranges[i]);
400 outputbytes = SendFunctionCall(&cache->typioproc, range);
401
402 pq_sendint32(buf, VARSIZE(outputbytes) - VARHDRSZ);
403 pq_sendbytes(buf, VARDATA(outputbytes), VARSIZE(outputbytes) - VARHDRSZ);
404 }
405
407}
408
409/*
410 * get_multirange_io_data: get cached information needed for multirange type I/O
411 *
412 * The multirange I/O functions need a bit more cached info than other multirange
413 * functions, so they store a MultirangeIOData struct in fn_extra, not just a
414 * pointer to a type cache entry.
415 */
416static MultirangeIOData *
418{
419 MultirangeIOData *cache = (MultirangeIOData *) fcinfo->flinfo->fn_extra;
420
421 if (cache == NULL || cache->typcache->type_id != mltrngtypid)
422 {
423 Oid typiofunc;
424 int16 typlen;
425 bool typbyval;
426 char typalign;
427 char typdelim;
428
430 sizeof(MultirangeIOData));
432 if (cache->typcache->rngtype == NULL)
433 elog(ERROR, "type %u is not a multirange type", mltrngtypid);
434
435 /* get_type_io_data does more than we need, but is convenient */
437 func,
438 &typlen,
439 &typbyval,
440 &typalign,
441 &typdelim,
442 &cache->typioparam,
443 &typiofunc);
444
445 if (!OidIsValid(typiofunc))
446 {
447 /* this could only happen for receive or send */
448 if (func == IOFunc_receive)
450 (errcode(ERRCODE_UNDEFINED_FUNCTION),
451 errmsg("no binary input function available for type %s",
453 else
455 (errcode(ERRCODE_UNDEFINED_FUNCTION),
456 errmsg("no binary output function available for type %s",
458 }
459 fmgr_info_cxt(typiofunc, &cache->typioproc,
460 fcinfo->flinfo->fn_mcxt);
461
462 fcinfo->flinfo->fn_extra = cache;
463 }
464
465 return cache;
466}
467
468/*
469 * Converts a list of arbitrary ranges into a list that is sorted and merged.
470 * Changes the contents of `ranges`.
471 *
472 * Returns the number of slots actually used, which may be less than
473 * input_range_count but never more.
474 *
475 * We assume that no input ranges are null, but empties are okay.
476 */
477static int32
478multirange_canonicalize(TypeCacheEntry *rangetyp, int32 input_range_count,
479 RangeType **ranges)
480{
481 RangeType *lastRange = NULL;
482 RangeType *currentRange;
483 int32 i;
484 int32 output_range_count = 0;
485
486 /* Sort the ranges so we can find the ones that overlap/meet. */
487 qsort_arg(ranges, input_range_count, sizeof(RangeType *), range_compare,
488 rangetyp);
489
490 /* Now merge where possible: */
491 for (i = 0; i < input_range_count; i++)
492 {
493 currentRange = ranges[i];
494 if (RangeIsEmpty(currentRange))
495 continue;
496
497 if (lastRange == NULL)
498 {
499 ranges[output_range_count++] = lastRange = currentRange;
500 continue;
501 }
502
503 /*
504 * range_adjacent_internal gives true if *either* A meets B or B meets
505 * A, which is not quite want we want, but we rely on the sorting
506 * above to rule out B meets A ever happening.
507 */
508 if (range_adjacent_internal(rangetyp, lastRange, currentRange))
509 {
510 /* The two ranges touch (without overlap), so merge them: */
511 ranges[output_range_count - 1] = lastRange =
512 range_union_internal(rangetyp, lastRange, currentRange, false);
513 }
514 else if (range_before_internal(rangetyp, lastRange, currentRange))
515 {
516 /* There's a gap, so make a new entry: */
517 lastRange = ranges[output_range_count] = currentRange;
518 output_range_count++;
519 }
520 else
521 {
522 /* They must overlap, so merge them: */
523 ranges[output_range_count - 1] = lastRange =
524 range_union_internal(rangetyp, lastRange, currentRange, true);
525 }
526 }
527
528 return output_range_count;
529}
530
531/*
532 *----------------------------------------------------------
533 * SUPPORT FUNCTIONS
534 *
535 * These functions aren't in pg_proc, but are useful for
536 * defining new generic multirange functions in C.
537 *----------------------------------------------------------
538 */
539
540/*
541 * multirange_get_typcache: get cached information about a multirange type
542 *
543 * This is for use by multirange-related functions that follow the convention
544 * of using the fn_extra field as a pointer to the type cache entry for
545 * the multirange type. Functions that need to cache more information than
546 * that must fend for themselves.
547 */
550{
551 TypeCacheEntry *typcache = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
552
553 if (typcache == NULL ||
554 typcache->type_id != mltrngtypid)
555 {
556 typcache = lookup_type_cache(mltrngtypid, TYPECACHE_MULTIRANGE_INFO);
557 if (typcache->rngtype == NULL)
558 elog(ERROR, "type %u is not a multirange type", mltrngtypid);
559 fcinfo->flinfo->fn_extra = typcache;
560 }
561
562 return typcache;
563}
564
565
566/*
567 * Estimate size occupied by serialized multirange.
568 */
569static Size
571 RangeType **ranges)
572{
573 char elemalign = rangetyp->rngelemtype->typalign;
574 Size size;
575 int32 i;
576
577 /*
578 * Count space for MultirangeType struct, items and flags.
579 */
580 size = att_align_nominal(sizeof(MultirangeType) +
581 Max(range_count - 1, 0) * sizeof(uint32) +
582 range_count * sizeof(uint8), elemalign);
583
584 /* Count space for range bounds */
585 for (i = 0; i < range_count; i++)
586 size += att_align_nominal(VARSIZE(ranges[i]) -
587 sizeof(RangeType) -
588 sizeof(char), elemalign);
589
590 return size;
591}
592
593/*
594 * Write multirange data into pre-allocated space.
595 */
596static void
598 int32 range_count, RangeType **ranges)
599{
600 uint32 *items;
601 uint32 prev_offset = 0;
602 uint8 *flags;
603 int32 i;
604 Pointer begin,
605 ptr;
606 char elemalign = rangetyp->rngelemtype->typalign;
607
608 items = MultirangeGetItemsPtr(multirange);
609 flags = MultirangeGetFlagsPtr(multirange);
610 ptr = begin = MultirangeGetBoundariesPtr(multirange, elemalign);
611 for (i = 0; i < range_count; i++)
612 {
613 uint32 len;
614
615 if (i > 0)
616 {
617 /*
618 * Every range, except the first one, has an item. Every
619 * MULTIRANGE_ITEM_OFFSET_STRIDE item contains an offset, others
620 * contain lengths.
621 */
622 items[i - 1] = ptr - begin;
623 if ((i % MULTIRANGE_ITEM_OFFSET_STRIDE) != 0)
624 items[i - 1] -= prev_offset;
625 else
627 prev_offset = ptr - begin;
628 }
629 flags[i] = *((Pointer) ranges[i] + VARSIZE(ranges[i]) - sizeof(char));
630 len = VARSIZE(ranges[i]) - sizeof(RangeType) - sizeof(char);
631 memcpy(ptr, (Pointer) (ranges[i] + 1), len);
632 ptr += att_align_nominal(len, elemalign);
633 }
634}
635
636
637/*
638 * This serializes the multirange from a list of non-null ranges. It also
639 * sorts the ranges and merges any that touch. The ranges should already be
640 * detoasted, and there should be no NULLs. This should be used by most
641 * callers.
642 *
643 * Note that we may change the `ranges` parameter (the pointers, but not
644 * any already-existing RangeType contents).
645 */
647make_multirange(Oid mltrngtypoid, TypeCacheEntry *rangetyp, int32 range_count,
648 RangeType **ranges)
649{
650 MultirangeType *multirange;
651 Size size;
652
653 /* Sort and merge input ranges. */
654 range_count = multirange_canonicalize(rangetyp, range_count, ranges);
655
656 /* Note: zero-fill is required here, just as in heap tuples */
657 size = multirange_size_estimate(rangetyp, range_count, ranges);
658 multirange = palloc0(size);
659 SET_VARSIZE(multirange, size);
660
661 /* Now fill in the datum */
662 multirange->multirangetypid = mltrngtypoid;
663 multirange->rangeCount = range_count;
664
665 write_multirange_data(multirange, rangetyp, range_count, ranges);
666
667 return multirange;
668}
669
670/*
671 * Get offset of bounds values of the i'th range in the multirange.
672 */
673static uint32
675{
676 uint32 *items = MultirangeGetItemsPtr(multirange);
677 uint32 offset = 0;
678
679 /*
680 * Summarize lengths till we meet an offset.
681 */
682 while (i > 0)
683 {
684 offset += MULTIRANGE_ITEM_GET_OFFLEN(items[i - 1]);
686 break;
687 i--;
688 }
689 return offset;
690}
691
692/*
693 * Fetch the i'th range from the multirange.
694 */
695RangeType *
697 const MultirangeType *multirange, int i)
698{
699 uint32 offset;
700 uint8 flags;
701 Pointer begin,
702 ptr;
703 int16 typlen = rangetyp->rngelemtype->typlen;
704 char typalign = rangetyp->rngelemtype->typalign;
705 uint32 len;
707
708 Assert(i < multirange->rangeCount);
709
710 offset = multirange_get_bounds_offset(multirange, i);
711 flags = MultirangeGetFlagsPtr(multirange)[i];
712 ptr = begin = MultirangeGetBoundariesPtr(multirange, typalign) + offset;
713
714 /*
715 * Calculate the size of bound values. In principle, we could get offset
716 * of the next range bound values and calculate accordingly. But range
717 * bound values are aligned, so we have to walk the values to get the
718 * exact size.
719 */
720 if (RANGE_HAS_LBOUND(flags))
721 ptr = (Pointer) att_addlength_pointer(ptr, typlen, ptr);
722 if (RANGE_HAS_UBOUND(flags))
723 {
724 ptr = (Pointer) att_align_pointer(ptr, typalign, typlen, ptr);
725 ptr = (Pointer) att_addlength_pointer(ptr, typlen, ptr);
726 }
727 len = (ptr - begin) + sizeof(RangeType) + sizeof(uint8);
728
729 range = palloc0(len);
731 range->rangetypid = rangetyp->type_id;
732
733 memcpy(range + 1, begin, ptr - begin);
734 *((uint8 *) (range + 1) + (ptr - begin)) = flags;
735
736 return range;
737}
738
739/*
740 * Fetch bounds from the i'th range of the multirange. This is the shortcut for
741 * doing the same thing as multirange_get_range() + range_deserialize(), but
742 * performing fewer operations.
743 */
744void
746 const MultirangeType *multirange,
748{
749 uint32 offset;
750 uint8 flags;
751 Pointer ptr;
752 int16 typlen = rangetyp->rngelemtype->typlen;
753 char typalign = rangetyp->rngelemtype->typalign;
754 bool typbyval = rangetyp->rngelemtype->typbyval;
755 Datum lbound;
756 Datum ubound;
757
758 Assert(i < multirange->rangeCount);
759
760 offset = multirange_get_bounds_offset(multirange, i);
761 flags = MultirangeGetFlagsPtr(multirange)[i];
762 ptr = MultirangeGetBoundariesPtr(multirange, typalign) + offset;
763
764 /* multirange can't contain empty ranges */
765 Assert((flags & RANGE_EMPTY) == 0);
766
767 /* fetch lower bound, if any */
768 if (RANGE_HAS_LBOUND(flags))
769 {
770 /* att_align_pointer cannot be necessary here */
771 lbound = fetch_att(ptr, typbyval, typlen);
772 ptr = (Pointer) att_addlength_pointer(ptr, typlen, ptr);
773 }
774 else
775 lbound = (Datum) 0;
776
777 /* fetch upper bound, if any */
778 if (RANGE_HAS_UBOUND(flags))
779 {
780 ptr = (Pointer) att_align_pointer(ptr, typalign, typlen, ptr);
781 ubound = fetch_att(ptr, typbyval, typlen);
782 /* no need for att_addlength_pointer */
783 }
784 else
785 ubound = (Datum) 0;
786
787 /* emit results */
788 lower->val = lbound;
789 lower->infinite = (flags & RANGE_LB_INF) != 0;
790 lower->inclusive = (flags & RANGE_LB_INC) != 0;
791 lower->lower = true;
792
793 upper->val = ubound;
794 upper->infinite = (flags & RANGE_UB_INF) != 0;
795 upper->inclusive = (flags & RANGE_UB_INC) != 0;
796 upper->lower = false;
797}
798
799/*
800 * Construct union range from the multirange.
801 */
802RangeType *
804 const MultirangeType *mr)
805{
807 upper,
808 tmp;
809
810 if (MultirangeIsEmpty(mr))
811 return make_empty_range(rangetyp);
812
813 multirange_get_bounds(rangetyp, mr, 0, &lower, &tmp);
814 multirange_get_bounds(rangetyp, mr, mr->rangeCount - 1, &tmp, &upper);
815
816 return make_range(rangetyp, &lower, &upper, false, NULL);
817}
818
819
820/*
821 * multirange_deserialize: deconstruct a multirange value
822 *
823 * NB: the given multirange object must be fully detoasted; it cannot have a
824 * short varlena header.
825 */
826void
828 const MultirangeType *multirange, int32 *range_count,
829 RangeType ***ranges)
830{
831 *range_count = multirange->rangeCount;
832
833 /* Convert each ShortRangeType into a RangeType */
834 if (*range_count > 0)
835 {
836 int i;
837
838 *ranges = palloc(*range_count * sizeof(RangeType *));
839 for (i = 0; i < *range_count; i++)
840 (*ranges)[i] = multirange_get_range(rangetyp, multirange, i);
841 }
842 else
843 {
844 *ranges = NULL;
845 }
846}
847
850{
851 return make_multirange(mltrngtypoid, rangetyp, 0, NULL);
852}
853
854/*
855 * Similar to range_overlaps_internal(), but takes range bounds instead of
856 * ranges as arguments.
857 */
858static bool
860 RangeBound *lower1, RangeBound *upper1,
861 RangeBound *lower2, RangeBound *upper2)
862{
863 if (range_cmp_bounds(typcache, lower1, lower2) >= 0 &&
864 range_cmp_bounds(typcache, lower1, upper2) <= 0)
865 return true;
866
867 if (range_cmp_bounds(typcache, lower2, lower1) >= 0 &&
868 range_cmp_bounds(typcache, lower2, upper1) <= 0)
869 return true;
870
871 return false;
872}
873
874/*
875 * Similar to range_contains_internal(), but takes range bounds instead of
876 * ranges as arguments.
877 */
878static bool
880 RangeBound *lower1, RangeBound *upper1,
881 RangeBound *lower2, RangeBound *upper2)
882{
883 if (range_cmp_bounds(typcache, lower1, lower2) <= 0 &&
884 range_cmp_bounds(typcache, upper1, upper2) >= 0)
885 return true;
886
887 return false;
888}
889
890/*
891 * Check if the given key matches any range in multirange using binary search.
892 * If the required range isn't found, that counts as a mismatch. When the
893 * required range is found, the comparison function can still report this as
894 * either match or mismatch. For instance, if we search for containment, we can
895 * found a range, which is overlapping but not containing the key range, and
896 * that would count as a mismatch.
897 */
898static bool
900 void *key, multirange_bsearch_comparison cmp_func)
901{
902 uint32 l,
903 u,
904 idx;
905 int comparison;
906 bool match = false;
907
908 l = 0;
909 u = mr->rangeCount;
910 while (l < u)
911 {
913 upper;
914
915 idx = (l + u) / 2;
916 multirange_get_bounds(typcache, mr, idx, &lower, &upper);
917 comparison = (*cmp_func) (typcache, &lower, &upper, key, &match);
918
919 if (comparison < 0)
920 u = idx;
921 else if (comparison > 0)
922 l = idx + 1;
923 else
924 return match;
925 }
926
927 return false;
928}
929
930/*
931 *----------------------------------------------------------
932 * GENERIC FUNCTIONS
933 *----------------------------------------------------------
934 */
935
936/*
937 * Construct multirange value from zero or more ranges. Since this is a
938 * variadic function we get passed an array. The array must contain ranges
939 * that match our return value, and there must be no NULLs.
940 */
941Datum
943{
944 Oid mltrngtypid = get_fn_expr_rettype(fcinfo->flinfo);
945 Oid rngtypid;
946 TypeCacheEntry *typcache;
947 TypeCacheEntry *rangetyp;
948 ArrayType *rangeArray;
949 int range_count;
950 Datum *elements;
951 bool *nulls;
952 RangeType **ranges;
953 int dims;
954 int i;
955
956 typcache = multirange_get_typcache(fcinfo, mltrngtypid);
957 rangetyp = typcache->rngtype;
958
959 /*
960 * A no-arg invocation should call multirange_constructor0 instead, but
961 * returning an empty range is what that does.
962 */
963
964 if (PG_NARGS() == 0)
965 PG_RETURN_MULTIRANGE_P(make_multirange(mltrngtypid, rangetyp, 0, NULL));
966
967 /*
968 * This check should be guaranteed by our signature, but let's do it just
969 * in case.
970 */
971
972 if (PG_ARGISNULL(0))
973 elog(ERROR,
974 "multirange values cannot contain null members");
975
976 rangeArray = PG_GETARG_ARRAYTYPE_P(0);
977
978 dims = ARR_NDIM(rangeArray);
979 if (dims > 1)
981 (errcode(ERRCODE_CARDINALITY_VIOLATION),
982 errmsg("multiranges cannot be constructed from multidimensional arrays")));
983
984 rngtypid = ARR_ELEMTYPE(rangeArray);
985 if (rngtypid != rangetyp->type_id)
986 elog(ERROR, "type %u does not match constructor type", rngtypid);
987
988 /*
989 * Be careful: we can still be called with zero ranges, like this:
990 * `int4multirange(variadic '{}'::int4range[])
991 */
992 if (dims == 0)
993 {
994 range_count = 0;
995 ranges = NULL;
996 }
997 else
998 {
999 deconstruct_array(rangeArray, rngtypid, rangetyp->typlen, rangetyp->typbyval,
1000 rangetyp->typalign, &elements, &nulls, &range_count);
1001
1002 ranges = palloc0(range_count * sizeof(RangeType *));
1003 for (i = 0; i < range_count; i++)
1004 {
1005 if (nulls[i])
1006 ereport(ERROR,
1007 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
1008 errmsg("multirange values cannot contain null members")));
1009
1010 /* make_multirange will do its own copy */
1011 ranges[i] = DatumGetRangeTypeP(elements[i]);
1012 }
1013 }
1014
1015 PG_RETURN_MULTIRANGE_P(make_multirange(mltrngtypid, rangetyp, range_count, ranges));
1016}
1017
1018/*
1019 * Construct multirange value from a single range. It'd be nice if we could
1020 * just use multirange_constructor2 for this case, but we need a non-variadic
1021 * single-arg function to let us define a CAST from a range to its multirange.
1022 */
1023Datum
1025{
1026 Oid mltrngtypid = get_fn_expr_rettype(fcinfo->flinfo);
1027 Oid rngtypid;
1028 TypeCacheEntry *typcache;
1029 TypeCacheEntry *rangetyp;
1031
1032 typcache = multirange_get_typcache(fcinfo, mltrngtypid);
1033 rangetyp = typcache->rngtype;
1034
1035 /*
1036 * This check should be guaranteed by our signature, but let's do it just
1037 * in case.
1038 */
1039
1040 if (PG_ARGISNULL(0))
1041 elog(ERROR,
1042 "multirange values cannot contain null members");
1043
1045
1046 /* Make sure the range type matches. */
1047 rngtypid = RangeTypeGetOid(range);
1048 if (rngtypid != rangetyp->type_id)
1049 elog(ERROR, "type %u does not match constructor type", rngtypid);
1050
1051 PG_RETURN_MULTIRANGE_P(make_multirange(mltrngtypid, rangetyp, 1, &range));
1052}
1053
1054/*
1055 * Constructor just like multirange_constructor1, but opr_sanity gets angry
1056 * if the same internal function handles multiple functions with different arg
1057 * counts.
1058 */
1059Datum
1061{
1062 Oid mltrngtypid;
1063 TypeCacheEntry *typcache;
1064 TypeCacheEntry *rangetyp;
1065
1066 /* This should always be called without arguments */
1067 if (PG_NARGS() != 0)
1068 elog(ERROR,
1069 "niladic multirange constructor must not receive arguments");
1070
1071 mltrngtypid = get_fn_expr_rettype(fcinfo->flinfo);
1072 typcache = multirange_get_typcache(fcinfo, mltrngtypid);
1073 rangetyp = typcache->rngtype;
1074
1075 PG_RETURN_MULTIRANGE_P(make_multirange(mltrngtypid, rangetyp, 0, NULL));
1076}
1077
1078
1079/* multirange, multirange -> multirange type functions */
1080
1081/* multirange union */
1082Datum
1084{
1087 TypeCacheEntry *typcache;
1088 int32 range_count1;
1089 int32 range_count2;
1090 int32 range_count3;
1091 RangeType **ranges1;
1092 RangeType **ranges2;
1093 RangeType **ranges3;
1094
1095 if (MultirangeIsEmpty(mr1))
1097 if (MultirangeIsEmpty(mr2))
1099
1100 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1));
1101
1102 multirange_deserialize(typcache->rngtype, mr1, &range_count1, &ranges1);
1103 multirange_deserialize(typcache->rngtype, mr2, &range_count2, &ranges2);
1104
1105 range_count3 = range_count1 + range_count2;
1106 ranges3 = palloc0(range_count3 * sizeof(RangeType *));
1107 memcpy(ranges3, ranges1, range_count1 * sizeof(RangeType *));
1108 memcpy(ranges3 + range_count1, ranges2, range_count2 * sizeof(RangeType *));
1110 range_count3, ranges3));
1111}
1112
1113/* multirange minus */
1114Datum
1116{
1119 Oid mltrngtypoid = MultirangeTypeGetOid(mr1);
1120 TypeCacheEntry *typcache;
1121 TypeCacheEntry *rangetyp;
1122 int32 range_count1;
1123 int32 range_count2;
1124 RangeType **ranges1;
1125 RangeType **ranges2;
1126
1127 typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
1128 rangetyp = typcache->rngtype;
1129
1130 if (MultirangeIsEmpty(mr1) || MultirangeIsEmpty(mr2))
1132
1133 multirange_deserialize(typcache->rngtype, mr1, &range_count1, &ranges1);
1134 multirange_deserialize(typcache->rngtype, mr2, &range_count2, &ranges2);
1135
1137 rangetyp,
1138 range_count1,
1139 ranges1,
1140 range_count2,
1141 ranges2));
1142}
1143
1146 int32 range_count1, RangeType **ranges1,
1147 int32 range_count2, RangeType **ranges2)
1148{
1149 RangeType *r1;
1150 RangeType *r2;
1151 RangeType **ranges3;
1152 int32 range_count3;
1153 int32 i1;
1154 int32 i2;
1155
1156 /*
1157 * Worst case: every range in ranges1 makes a different cut to some range
1158 * in ranges2.
1159 */
1160 ranges3 = palloc0((range_count1 + range_count2) * sizeof(RangeType *));
1161 range_count3 = 0;
1162
1163 /*
1164 * For each range in mr1, keep subtracting until it's gone or the ranges
1165 * in mr2 have passed it. After a subtraction we assign what's left back
1166 * to r1. The parallel progress through mr1 and mr2 is similar to
1167 * multirange_overlaps_multirange_internal.
1168 */
1169 r2 = ranges2[0];
1170 for (i1 = 0, i2 = 0; i1 < range_count1; i1++)
1171 {
1172 r1 = ranges1[i1];
1173
1174 /* Discard r2s while r2 << r1 */
1175 while (r2 != NULL && range_before_internal(rangetyp, r2, r1))
1176 {
1177 r2 = ++i2 >= range_count2 ? NULL : ranges2[i2];
1178 }
1179
1180 while (r2 != NULL)
1181 {
1182 if (range_split_internal(rangetyp, r1, r2, &ranges3[range_count3], &r1))
1183 {
1184 /*
1185 * If r2 takes a bite out of the middle of r1, we need two
1186 * outputs
1187 */
1188 range_count3++;
1189 r2 = ++i2 >= range_count2 ? NULL : ranges2[i2];
1190 }
1191 else if (range_overlaps_internal(rangetyp, r1, r2))
1192 {
1193 /*
1194 * If r2 overlaps r1, replace r1 with r1 - r2.
1195 */
1196 r1 = range_minus_internal(rangetyp, r1, r2);
1197
1198 /*
1199 * If r2 goes past r1, then we need to stay with it, in case
1200 * it hits future r1s. Otherwise we need to keep r1, in case
1201 * future r2s hit it. Since we already subtracted, there's no
1202 * point in using the overright/overleft calls.
1203 */
1204 if (RangeIsEmpty(r1) || range_before_internal(rangetyp, r1, r2))
1205 break;
1206 else
1207 r2 = ++i2 >= range_count2 ? NULL : ranges2[i2];
1208 }
1209 else
1210 {
1211 /*
1212 * This and all future r2s are past r1, so keep them. Also
1213 * assign whatever is left of r1 to the result.
1214 */
1215 break;
1216 }
1217 }
1218
1219 /*
1220 * Nothing else can remove anything from r1, so keep it. Even if r1 is
1221 * empty here, make_multirange will remove it.
1222 */
1223 ranges3[range_count3++] = r1;
1224 }
1225
1226 return make_multirange(mltrngtypoid, rangetyp, range_count3, ranges3);
1227}
1228
1229/* multirange intersection */
1230Datum
1232{
1235 Oid mltrngtypoid = MultirangeTypeGetOid(mr1);
1236 TypeCacheEntry *typcache;
1237 TypeCacheEntry *rangetyp;
1238 int32 range_count1;
1239 int32 range_count2;
1240 RangeType **ranges1;
1241 RangeType **ranges2;
1242
1243 typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
1244 rangetyp = typcache->rngtype;
1245
1246 if (MultirangeIsEmpty(mr1) || MultirangeIsEmpty(mr2))
1247 PG_RETURN_MULTIRANGE_P(make_empty_multirange(mltrngtypoid, rangetyp));
1248
1249 multirange_deserialize(rangetyp, mr1, &range_count1, &ranges1);
1250 multirange_deserialize(rangetyp, mr2, &range_count2, &ranges2);
1251
1253 rangetyp,
1254 range_count1,
1255 ranges1,
1256 range_count2,
1257 ranges2));
1258}
1259
1262 int32 range_count1, RangeType **ranges1,
1263 int32 range_count2, RangeType **ranges2)
1264{
1265 RangeType *r1;
1266 RangeType *r2;
1267 RangeType **ranges3;
1268 int32 range_count3;
1269 int32 i1;
1270 int32 i2;
1271
1272 if (range_count1 == 0 || range_count2 == 0)
1273 return make_multirange(mltrngtypoid, rangetyp, 0, NULL);
1274
1275 /*-----------------------------------------------
1276 * Worst case is a stitching pattern like this:
1277 *
1278 * mr1: --- --- --- ---
1279 * mr2: --- --- ---
1280 * mr3: - - - - - -
1281 *
1282 * That seems to be range_count1 + range_count2 - 1,
1283 * but one extra won't hurt.
1284 *-----------------------------------------------
1285 */
1286 ranges3 = palloc0((range_count1 + range_count2) * sizeof(RangeType *));
1287 range_count3 = 0;
1288
1289 /*
1290 * For each range in mr1, keep intersecting until the ranges in mr2 have
1291 * passed it. The parallel progress through mr1 and mr2 is similar to
1292 * multirange_minus_multirange_internal, but we don't have to assign back
1293 * to r1.
1294 */
1295 r2 = ranges2[0];
1296 for (i1 = 0, i2 = 0; i1 < range_count1; i1++)
1297 {
1298 r1 = ranges1[i1];
1299
1300 /* Discard r2s while r2 << r1 */
1301 while (r2 != NULL && range_before_internal(rangetyp, r2, r1))
1302 {
1303 r2 = ++i2 >= range_count2 ? NULL : ranges2[i2];
1304 }
1305
1306 while (r2 != NULL)
1307 {
1308 if (range_overlaps_internal(rangetyp, r1, r2))
1309 {
1310 /* Keep the overlapping part */
1311 ranges3[range_count3++] = range_intersect_internal(rangetyp, r1, r2);
1312
1313 /* If we "used up" all of r2, go to the next one... */
1314 if (range_overleft_internal(rangetyp, r2, r1))
1315 r2 = ++i2 >= range_count2 ? NULL : ranges2[i2];
1316
1317 /* ...otherwise go to the next r1 */
1318 else
1319 break;
1320 }
1321 else
1322 /* We're past r1, so move to the next one */
1323 break;
1324 }
1325
1326 /* If we're out of r2s, there can be no more intersections */
1327 if (r2 == NULL)
1328 break;
1329 }
1330
1331 return make_multirange(mltrngtypoid, rangetyp, range_count3, ranges3);
1332}
1333
1334/*
1335 * range_agg_transfn: combine adjacent/overlapping ranges.
1336 *
1337 * All we do here is gather the input ranges into an array
1338 * so that the finalfn can sort and combine them.
1339 */
1340Datum
1342{
1343 MemoryContext aggContext;
1344 Oid rngtypoid;
1346
1347 if (!AggCheckCallContext(fcinfo, &aggContext))
1348 elog(ERROR, "range_agg_transfn called in non-aggregate context");
1349
1350 rngtypoid = get_fn_expr_argtype(fcinfo->flinfo, 1);
1351 if (!type_is_range(rngtypoid))
1352 elog(ERROR, "range_agg must be called with a range");
1353
1354 if (PG_ARGISNULL(0))
1355 state = initArrayResult(rngtypoid, aggContext, false);
1356 else
1358
1359 /* skip NULLs */
1360 if (!PG_ARGISNULL(1))
1361 accumArrayResult(state, PG_GETARG_DATUM(1), false, rngtypoid, aggContext);
1362
1364}
1365
1366/*
1367 * range_agg_finalfn: use our internal array to merge touching ranges.
1368 *
1369 * Shared by range_agg_finalfn(anyrange) and
1370 * multirange_agg_finalfn(anymultirange).
1371 */
1372Datum
1374{
1375 MemoryContext aggContext;
1376 Oid mltrngtypoid;
1377 TypeCacheEntry *typcache;
1379 int32 range_count;
1380 RangeType **ranges;
1381 int i;
1382
1383 if (!AggCheckCallContext(fcinfo, &aggContext))
1384 elog(ERROR, "range_agg_finalfn called in non-aggregate context");
1385
1387 if (state == NULL)
1388 /* This shouldn't be possible, but just in case.... */
1390
1391 /* Also return NULL if we had zero inputs, like other aggregates */
1392 range_count = state->nelems;
1393 if (range_count == 0)
1395
1396 mltrngtypoid = get_fn_expr_rettype(fcinfo->flinfo);
1397 typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
1398
1399 ranges = palloc0(range_count * sizeof(RangeType *));
1400 for (i = 0; i < range_count; i++)
1401 ranges[i] = DatumGetRangeTypeP(state->dvalues[i]);
1402
1403 PG_RETURN_MULTIRANGE_P(make_multirange(mltrngtypoid, typcache->rngtype, range_count, ranges));
1404}
1405
1406/*
1407 * multirange_agg_transfn: combine adjacent/overlapping multiranges.
1408 *
1409 * All we do here is gather the input multiranges' ranges into an array so
1410 * that the finalfn can sort and combine them.
1411 */
1412Datum
1414{
1415 MemoryContext aggContext;
1416 Oid mltrngtypoid;
1417 TypeCacheEntry *typcache;
1418 TypeCacheEntry *rngtypcache;
1420
1421 if (!AggCheckCallContext(fcinfo, &aggContext))
1422 elog(ERROR, "multirange_agg_transfn called in non-aggregate context");
1423
1424 mltrngtypoid = get_fn_expr_argtype(fcinfo->flinfo, 1);
1425 if (!type_is_multirange(mltrngtypoid))
1426 elog(ERROR, "range_agg must be called with a multirange");
1427
1428 typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
1429 rngtypcache = typcache->rngtype;
1430
1431 if (PG_ARGISNULL(0))
1432 state = initArrayResult(rngtypcache->type_id, aggContext, false);
1433 else
1435
1436 /* skip NULLs */
1437 if (!PG_ARGISNULL(1))
1438 {
1439 MultirangeType *current;
1440 int32 range_count;
1441 RangeType **ranges;
1442
1443 current = PG_GETARG_MULTIRANGE_P(1);
1444 multirange_deserialize(rngtypcache, current, &range_count, &ranges);
1445 if (range_count == 0)
1446 {
1447 /*
1448 * Add an empty range so we get an empty result (not a null
1449 * result).
1450 */
1453 false, rngtypcache->type_id, aggContext);
1454 }
1455 else
1456 {
1457 for (int32 i = 0; i < range_count; i++)
1458 accumArrayResult(state, RangeTypePGetDatum(ranges[i]), false, rngtypcache->type_id, aggContext);
1459 }
1460 }
1461
1463}
1464
1465Datum
1467{
1468 MemoryContext aggContext;
1469 Oid mltrngtypoid;
1470 TypeCacheEntry *typcache;
1471 MultirangeType *result;
1472 MultirangeType *current;
1473 int32 range_count1;
1474 int32 range_count2;
1475 RangeType **ranges1;
1476 RangeType **ranges2;
1477
1478 if (!AggCheckCallContext(fcinfo, &aggContext))
1479 elog(ERROR, "multirange_intersect_agg_transfn called in non-aggregate context");
1480
1481 mltrngtypoid = get_fn_expr_argtype(fcinfo->flinfo, 1);
1482 if (!type_is_multirange(mltrngtypoid))
1483 elog(ERROR, "range_intersect_agg must be called with a multirange");
1484
1485 typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
1486
1487 /* strictness ensures these are non-null */
1488 result = PG_GETARG_MULTIRANGE_P(0);
1489 current = PG_GETARG_MULTIRANGE_P(1);
1490
1491 multirange_deserialize(typcache->rngtype, result, &range_count1, &ranges1);
1492 multirange_deserialize(typcache->rngtype, current, &range_count2, &ranges2);
1493
1494 result = multirange_intersect_internal(mltrngtypoid,
1495 typcache->rngtype,
1496 range_count1,
1497 ranges1,
1498 range_count2,
1499 ranges2);
1500 PG_RETURN_MULTIRANGE_P(result);
1501}
1502
1503
1504/* multirange -> element type functions */
1505
1506/* extract lower bound value */
1507Datum
1509{
1511 TypeCacheEntry *typcache;
1514
1515 if (MultirangeIsEmpty(mr))
1517
1518 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1519
1520 multirange_get_bounds(typcache->rngtype, mr, 0,
1521 &lower, &upper);
1522
1523 if (!lower.infinite)
1525 else
1527}
1528
1529/* extract upper bound value */
1530Datum
1532{
1534 TypeCacheEntry *typcache;
1537
1538 if (MultirangeIsEmpty(mr))
1540
1541 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1542
1543 multirange_get_bounds(typcache->rngtype, mr, mr->rangeCount - 1,
1544 &lower, &upper);
1545
1546 if (!upper.infinite)
1548 else
1550}
1551
1552
1553/* multirange -> bool functions */
1554
1555/* is multirange empty? */
1556Datum
1558{
1560
1562}
1563
1564/* is lower bound inclusive? */
1565Datum
1567{
1569 TypeCacheEntry *typcache;
1572
1573 if (MultirangeIsEmpty(mr))
1574 PG_RETURN_BOOL(false);
1575
1576 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1577 multirange_get_bounds(typcache->rngtype, mr, 0,
1578 &lower, &upper);
1579
1580 PG_RETURN_BOOL(lower.inclusive);
1581}
1582
1583/* is upper bound inclusive? */
1584Datum
1586{
1588 TypeCacheEntry *typcache;
1591
1592 if (MultirangeIsEmpty(mr))
1593 PG_RETURN_BOOL(false);
1594
1595 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1596 multirange_get_bounds(typcache->rngtype, mr, mr->rangeCount - 1,
1597 &lower, &upper);
1598
1599 PG_RETURN_BOOL(upper.inclusive);
1600}
1601
1602/* is lower bound infinite? */
1603Datum
1605{
1607 TypeCacheEntry *typcache;
1610
1611 if (MultirangeIsEmpty(mr))
1612 PG_RETURN_BOOL(false);
1613
1614 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1615 multirange_get_bounds(typcache->rngtype, mr, 0,
1616 &lower, &upper);
1617
1618 PG_RETURN_BOOL(lower.infinite);
1619}
1620
1621/* is upper bound infinite? */
1622Datum
1624{
1626 TypeCacheEntry *typcache;
1629
1630 if (MultirangeIsEmpty(mr))
1631 PG_RETURN_BOOL(false);
1632
1633 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1634 multirange_get_bounds(typcache->rngtype, mr, mr->rangeCount - 1,
1635 &lower, &upper);
1636
1637 PG_RETURN_BOOL(upper.infinite);
1638}
1639
1640
1641
1642/* multirange, element -> bool functions */
1643
1644/* contains? */
1645Datum
1647{
1650 TypeCacheEntry *typcache;
1651
1652 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1653
1655}
1656
1657/* contained by? */
1658Datum
1660{
1663 TypeCacheEntry *typcache;
1664
1665 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1666
1668}
1669
1670/*
1671 * Comparison function for checking if any range of multirange contains given
1672 * key element using binary search.
1673 */
1674static int
1677 void *key, bool *match)
1678{
1679 Datum val = *((Datum *) key);
1680 int cmp;
1681
1682 if (!lower->infinite)
1683 {
1685 typcache->rng_collation,
1686 lower->val, val));
1687 if (cmp > 0 || (cmp == 0 && !lower->inclusive))
1688 return -1;
1689 }
1690
1691 if (!upper->infinite)
1692 {
1694 typcache->rng_collation,
1695 upper->val, val));
1696 if (cmp < 0 || (cmp == 0 && !upper->inclusive))
1697 return 1;
1698 }
1699
1700 *match = true;
1701 return 0;
1702}
1703
1704/*
1705 * Test whether multirange mr contains a specific element value.
1706 */
1707bool
1709 const MultirangeType *mr, Datum val)
1710{
1711 if (MultirangeIsEmpty(mr))
1712 return false;
1713
1714 return multirange_bsearch_match(rangetyp, mr, &val,
1716}
1717
1718/* multirange, range -> bool functions */
1719
1720/* contains? */
1721Datum
1723{
1726 TypeCacheEntry *typcache;
1727
1728 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1729
1731}
1732
1733Datum
1735{
1738 TypeCacheEntry *typcache;
1739
1740 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1741
1743}
1744
1745/* contained by? */
1746Datum
1748{
1751 TypeCacheEntry *typcache;
1752
1753 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1754
1756}
1757
1758Datum
1760{
1763 TypeCacheEntry *typcache;
1764
1765 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1766
1768}
1769
1770/*
1771 * Comparison function for checking if any range of multirange contains given
1772 * key range using binary search.
1773 */
1774static int
1777 void *key, bool *match)
1778{
1779 RangeBound *keyLower = (RangeBound *) key;
1780 RangeBound *keyUpper = (RangeBound *) key + 1;
1781
1782 /* Check if key range is strictly in the left or in the right */
1783 if (range_cmp_bounds(typcache, keyUpper, lower) < 0)
1784 return -1;
1785 if (range_cmp_bounds(typcache, keyLower, upper) > 0)
1786 return 1;
1787
1788 /*
1789 * At this point we found overlapping range. But we have to check if it
1790 * really contains the key range. Anyway, we have to stop our search
1791 * here, because multirange contains only non-overlapping ranges.
1792 */
1793 *match = range_bounds_contains(typcache, lower, upper, keyLower, keyUpper);
1794
1795 return 0;
1796}
1797
1798/*
1799 * Test whether multirange mr contains a specific range r.
1800 */
1801bool
1803 const MultirangeType *mr,
1804 const RangeType *r)
1805{
1806 RangeBound bounds[2];
1807 bool empty;
1808
1809 /*
1810 * Every multirange contains an infinite number of empty ranges, even an
1811 * empty one.
1812 */
1813 if (RangeIsEmpty(r))
1814 return true;
1815
1816 if (MultirangeIsEmpty(mr))
1817 return false;
1818
1819 range_deserialize(rangetyp, r, &bounds[0], &bounds[1], &empty);
1820 Assert(!empty);
1821
1822 return multirange_bsearch_match(rangetyp, mr, bounds,
1824}
1825
1826/*
1827 * Test whether range r contains a multirange mr.
1828 */
1829bool
1831 const RangeType *r,
1832 const MultirangeType *mr)
1833{
1834 RangeBound lower1,
1835 upper1,
1836 lower2,
1837 upper2,
1838 tmp;
1839 bool empty;
1840
1841 /*
1842 * Every range contains an infinite number of empty multiranges, even an
1843 * empty one.
1844 */
1845 if (MultirangeIsEmpty(mr))
1846 return true;
1847
1848 if (RangeIsEmpty(r))
1849 return false;
1850
1851 /* Range contains multirange iff it contains its union range. */
1852 range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
1853 Assert(!empty);
1854 multirange_get_bounds(rangetyp, mr, 0, &lower2, &tmp);
1855 multirange_get_bounds(rangetyp, mr, mr->rangeCount - 1, &tmp, &upper2);
1856
1857 return range_bounds_contains(rangetyp, &lower1, &upper1, &lower2, &upper2);
1858}
1859
1860
1861/* multirange, multirange -> bool functions */
1862
1863/* equality (internal version) */
1864bool
1866 const MultirangeType *mr1,
1867 const MultirangeType *mr2)
1868{
1869 int32 range_count_1;
1870 int32 range_count_2;
1871 int32 i;
1872 RangeBound lower1,
1873 upper1,
1874 lower2,
1875 upper2;
1876
1877 /* Different types should be prevented by ANYMULTIRANGE matching rules */
1879 elog(ERROR, "multirange types do not match");
1880
1881 range_count_1 = mr1->rangeCount;
1882 range_count_2 = mr2->rangeCount;
1883
1884 if (range_count_1 != range_count_2)
1885 return false;
1886
1887 for (i = 0; i < range_count_1; i++)
1888 {
1889 multirange_get_bounds(rangetyp, mr1, i, &lower1, &upper1);
1890 multirange_get_bounds(rangetyp, mr2, i, &lower2, &upper2);
1891
1892 if (range_cmp_bounds(rangetyp, &lower1, &lower2) != 0 ||
1893 range_cmp_bounds(rangetyp, &upper1, &upper2) != 0)
1894 return false;
1895 }
1896
1897 return true;
1898}
1899
1900/* equality */
1901Datum
1903{
1906 TypeCacheEntry *typcache;
1907
1908 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1));
1909
1910 PG_RETURN_BOOL(multirange_eq_internal(typcache->rngtype, mr1, mr2));
1911}
1912
1913/* inequality (internal version) */
1914bool
1916 const MultirangeType *mr1,
1917 const MultirangeType *mr2)
1918{
1919 return (!multirange_eq_internal(rangetyp, mr1, mr2));
1920}
1921
1922/* inequality */
1923Datum
1925{
1928 TypeCacheEntry *typcache;
1929
1930 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1));
1931
1932 PG_RETURN_BOOL(multirange_ne_internal(typcache->rngtype, mr1, mr2));
1933}
1934
1935/* overlaps? */
1936Datum
1938{
1941 TypeCacheEntry *typcache;
1942
1943 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1944
1946}
1947
1948Datum
1950{
1953 TypeCacheEntry *typcache;
1954
1955 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1956
1958}
1959
1960Datum
1962{
1965 TypeCacheEntry *typcache;
1966
1967 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1));
1968
1970}
1971
1972/*
1973 * Comparison function for checking if any range of multirange overlaps given
1974 * key range using binary search.
1975 */
1976static int
1979 void *key, bool *match)
1980{
1981 RangeBound *keyLower = (RangeBound *) key;
1982 RangeBound *keyUpper = (RangeBound *) key + 1;
1983
1984 if (range_cmp_bounds(typcache, keyUpper, lower) < 0)
1985 return -1;
1986 if (range_cmp_bounds(typcache, keyLower, upper) > 0)
1987 return 1;
1988
1989 *match = true;
1990 return 0;
1991}
1992
1993bool
1995 const RangeType *r,
1996 const MultirangeType *mr)
1997{
1998 RangeBound bounds[2];
1999 bool empty;
2000
2001 /*
2002 * Empties never overlap, even with empties. (This seems strange since
2003 * they *do* contain each other, but we want to follow how ranges work.)
2004 */
2005 if (RangeIsEmpty(r) || MultirangeIsEmpty(mr))
2006 return false;
2007
2008 range_deserialize(rangetyp, r, &bounds[0], &bounds[1], &empty);
2009 Assert(!empty);
2010
2011 return multirange_bsearch_match(rangetyp, mr, bounds,
2013}
2014
2015bool
2017 const MultirangeType *mr1,
2018 const MultirangeType *mr2)
2019{
2020 int32 range_count1;
2021 int32 range_count2;
2022 int32 i1;
2023 int32 i2;
2024 RangeBound lower1,
2025 upper1,
2026 lower2,
2027 upper2;
2028
2029 /*
2030 * Empties never overlap, even with empties. (This seems strange since
2031 * they *do* contain each other, but we want to follow how ranges work.)
2032 */
2033 if (MultirangeIsEmpty(mr1) || MultirangeIsEmpty(mr2))
2034 return false;
2035
2036 range_count1 = mr1->rangeCount;
2037 range_count2 = mr2->rangeCount;
2038
2039 /*
2040 * Every range in mr1 gets a chance to overlap with the ranges in mr2, but
2041 * we can use their ordering to avoid O(n^2). This is similar to
2042 * range_overlaps_multirange where r1 : r2 :: mrr : r, but there if we
2043 * don't find an overlap with r we're done, and here if we don't find an
2044 * overlap with r2 we try the next r2.
2045 */
2046 i1 = 0;
2047 multirange_get_bounds(rangetyp, mr1, i1, &lower1, &upper1);
2048 for (i1 = 0, i2 = 0; i2 < range_count2; i2++)
2049 {
2050 multirange_get_bounds(rangetyp, mr2, i2, &lower2, &upper2);
2051
2052 /* Discard r1s while r1 << r2 */
2053 while (range_cmp_bounds(rangetyp, &upper1, &lower2) < 0)
2054 {
2055 if (++i1 >= range_count1)
2056 return false;
2057 multirange_get_bounds(rangetyp, mr1, i1, &lower1, &upper1);
2058 }
2059
2060 /*
2061 * If r1 && r2, we're done, otherwise we failed to find an overlap for
2062 * r2, so go to the next one.
2063 */
2064 if (range_bounds_overlaps(rangetyp, &lower1, &upper1, &lower2, &upper2))
2065 return true;
2066 }
2067
2068 /* We looked through all of mr2 without finding an overlap */
2069 return false;
2070}
2071
2072/* does not extend to right of? */
2073bool
2075 const RangeType *r,
2076 const MultirangeType *mr)
2077{
2078 RangeBound lower1,
2079 upper1,
2080 lower2,
2081 upper2;
2082 bool empty;
2083
2084 if (RangeIsEmpty(r) || MultirangeIsEmpty(mr))
2085 return false;
2086
2087 range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
2088 Assert(!empty);
2089 multirange_get_bounds(rangetyp, mr, mr->rangeCount - 1,
2090 &lower2, &upper2);
2091
2092 return (range_cmp_bounds(rangetyp, &upper1, &upper2) <= 0);
2093}
2094
2095Datum
2097{
2100 TypeCacheEntry *typcache;
2101
2102 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2103
2105}
2106
2107Datum
2109{
2112 TypeCacheEntry *typcache;
2113 RangeBound lower1,
2114 upper1,
2115 lower2,
2116 upper2;
2117 bool empty;
2118
2119 if (MultirangeIsEmpty(mr) || RangeIsEmpty(r))
2120 PG_RETURN_BOOL(false);
2121
2122 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2123
2124 multirange_get_bounds(typcache->rngtype, mr, mr->rangeCount - 1,
2125 &lower1, &upper1);
2126 range_deserialize(typcache->rngtype, r, &lower2, &upper2, &empty);
2127 Assert(!empty);
2128
2129 PG_RETURN_BOOL(range_cmp_bounds(typcache->rngtype, &upper1, &upper2) <= 0);
2130}
2131
2132Datum
2134{
2137 TypeCacheEntry *typcache;
2138 RangeBound lower1,
2139 upper1,
2140 lower2,
2141 upper2;
2142
2143 if (MultirangeIsEmpty(mr1) || MultirangeIsEmpty(mr2))
2144 PG_RETURN_BOOL(false);
2145
2146 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1));
2147
2148 multirange_get_bounds(typcache->rngtype, mr1, mr1->rangeCount - 1,
2149 &lower1, &upper1);
2150 multirange_get_bounds(typcache->rngtype, mr2, mr2->rangeCount - 1,
2151 &lower2, &upper2);
2152
2153 PG_RETURN_BOOL(range_cmp_bounds(typcache->rngtype, &upper1, &upper2) <= 0);
2154}
2155
2156/* does not extend to left of? */
2157bool
2159 const RangeType *r,
2160 const MultirangeType *mr)
2161{
2162 RangeBound lower1,
2163 upper1,
2164 lower2,
2165 upper2;
2166 bool empty;
2167
2168 if (RangeIsEmpty(r) || MultirangeIsEmpty(mr))
2169 return false;
2170
2171 range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
2172 Assert(!empty);
2173 multirange_get_bounds(rangetyp, mr, 0, &lower2, &upper2);
2174
2175 return (range_cmp_bounds(rangetyp, &lower1, &lower2) >= 0);
2176}
2177
2178Datum
2180{
2183 TypeCacheEntry *typcache;
2184
2185 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2186
2188}
2189
2190Datum
2192{
2195 TypeCacheEntry *typcache;
2196 RangeBound lower1,
2197 upper1,
2198 lower2,
2199 upper2;
2200 bool empty;
2201
2202 if (MultirangeIsEmpty(mr) || RangeIsEmpty(r))
2203 PG_RETURN_BOOL(false);
2204
2205 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2206
2207 multirange_get_bounds(typcache->rngtype, mr, 0, &lower1, &upper1);
2208 range_deserialize(typcache->rngtype, r, &lower2, &upper2, &empty);
2209 Assert(!empty);
2210
2211 PG_RETURN_BOOL(range_cmp_bounds(typcache->rngtype, &lower1, &lower2) >= 0);
2212}
2213
2214Datum
2216{
2219 TypeCacheEntry *typcache;
2220 RangeBound lower1,
2221 upper1,
2222 lower2,
2223 upper2;
2224
2225 if (MultirangeIsEmpty(mr1) || MultirangeIsEmpty(mr2))
2226 PG_RETURN_BOOL(false);
2227
2228 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1));
2229
2230 multirange_get_bounds(typcache->rngtype, mr1, 0, &lower1, &upper1);
2231 multirange_get_bounds(typcache->rngtype, mr2, 0, &lower2, &upper2);
2232
2233 PG_RETURN_BOOL(range_cmp_bounds(typcache->rngtype, &lower1, &lower2) >= 0);
2234}
2235
2236/* contains? */
2237Datum
2239{
2242 TypeCacheEntry *typcache;
2243
2244 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1));
2245
2247}
2248
2249/* contained by? */
2250Datum
2252{
2255 TypeCacheEntry *typcache;
2256
2257 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1));
2258
2260}
2261
2262/*
2263 * Test whether multirange mr1 contains every range from another multirange mr2.
2264 */
2265bool
2267 const MultirangeType *mr1,
2268 const MultirangeType *mr2)
2269{
2270 int32 range_count1 = mr1->rangeCount;
2271 int32 range_count2 = mr2->rangeCount;
2272 int i1,
2273 i2;
2274 RangeBound lower1,
2275 upper1,
2276 lower2,
2277 upper2;
2278
2279 /*
2280 * We follow the same logic for empties as ranges: - an empty multirange
2281 * contains an empty range/multirange. - an empty multirange can't contain
2282 * any other range/multirange. - an empty multirange is contained by any
2283 * other range/multirange.
2284 */
2285
2286 if (range_count2 == 0)
2287 return true;
2288 if (range_count1 == 0)
2289 return false;
2290
2291 /*
2292 * Every range in mr2 must be contained by some range in mr1. To avoid
2293 * O(n^2) we walk through both ranges in tandem.
2294 */
2295 i1 = 0;
2296 multirange_get_bounds(rangetyp, mr1, i1, &lower1, &upper1);
2297 for (i2 = 0; i2 < range_count2; i2++)
2298 {
2299 multirange_get_bounds(rangetyp, mr2, i2, &lower2, &upper2);
2300
2301 /* Discard r1s while r1 << r2 */
2302 while (range_cmp_bounds(rangetyp, &upper1, &lower2) < 0)
2303 {
2304 if (++i1 >= range_count1)
2305 return false;
2306 multirange_get_bounds(rangetyp, mr1, i1, &lower1, &upper1);
2307 }
2308
2309 /*
2310 * If r1 @> r2, go to the next r2, otherwise return false (since every
2311 * r1[n] and r1[n+1] must have a gap). Note this will give weird
2312 * answers if you don't canonicalize, e.g. with a custom
2313 * int2multirange {[1,1], [2,2]} there is a "gap". But that is
2314 * consistent with other range operators, e.g. '[1,1]'::int2range -|-
2315 * '[2,2]'::int2range is false.
2316 */
2317 if (!range_bounds_contains(rangetyp, &lower1, &upper1,
2318 &lower2, &upper2))
2319 return false;
2320 }
2321
2322 /* All ranges in mr2 are satisfied */
2323 return true;
2324}
2325
2326/* strictly left of? */
2327Datum
2329{
2332 TypeCacheEntry *typcache;
2333
2334 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2335
2337}
2338
2339Datum
2341{
2344 TypeCacheEntry *typcache;
2345
2346 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2347
2349}
2350
2351Datum
2353{
2356 TypeCacheEntry *typcache;
2357
2358 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1));
2359
2361}
2362
2363/* strictly right of? */
2364Datum
2366{
2369 TypeCacheEntry *typcache;
2370
2371 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2372
2374}
2375
2376Datum
2378{
2381 TypeCacheEntry *typcache;
2382
2383 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2384
2386}
2387
2388Datum
2390{
2393 TypeCacheEntry *typcache;
2394
2395 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1));
2396
2398}
2399
2400/* strictly left of? (internal version) */
2401bool
2403 const RangeType *r,
2404 const MultirangeType *mr)
2405{
2406 RangeBound lower1,
2407 upper1,
2408 lower2,
2409 upper2;
2410 bool empty;
2411
2412 if (RangeIsEmpty(r) || MultirangeIsEmpty(mr))
2413 return false;
2414
2415 range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
2416 Assert(!empty);
2417
2418 multirange_get_bounds(rangetyp, mr, 0, &lower2, &upper2);
2419
2420 return (range_cmp_bounds(rangetyp, &upper1, &lower2) < 0);
2421}
2422
2423bool
2425 const MultirangeType *mr1,
2426 const MultirangeType *mr2)
2427{
2428 RangeBound lower1,
2429 upper1,
2430 lower2,
2431 upper2;
2432
2433 if (MultirangeIsEmpty(mr1) || MultirangeIsEmpty(mr2))
2434 return false;
2435
2436 multirange_get_bounds(rangetyp, mr1, mr1->rangeCount - 1,
2437 &lower1, &upper1);
2438 multirange_get_bounds(rangetyp, mr2, 0,
2439 &lower2, &upper2);
2440
2441 return (range_cmp_bounds(rangetyp, &upper1, &lower2) < 0);
2442}
2443
2444/* strictly right of? (internal version) */
2445bool
2447 const RangeType *r,
2448 const MultirangeType *mr)
2449{
2450 RangeBound lower1,
2451 upper1,
2452 lower2,
2453 upper2;
2454 bool empty;
2455 int32 range_count;
2456
2457 if (RangeIsEmpty(r) || MultirangeIsEmpty(mr))
2458 return false;
2459
2460 range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
2461 Assert(!empty);
2462
2463 range_count = mr->rangeCount;
2464 multirange_get_bounds(rangetyp, mr, range_count - 1,
2465 &lower2, &upper2);
2466
2467 return (range_cmp_bounds(rangetyp, &lower1, &upper2) > 0);
2468}
2469
2470bool
2472 const RangeType *r,
2473 const MultirangeType *mr)
2474{
2475 RangeBound lower1,
2476 upper1,
2477 lower2,
2478 upper2;
2479 bool empty;
2480 int32 range_count;
2481
2482 if (RangeIsEmpty(r) || MultirangeIsEmpty(mr))
2483 return false;
2484
2485 range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
2486 Assert(!empty);
2487
2488 range_count = mr->rangeCount;
2489 multirange_get_bounds(rangetyp, mr, 0,
2490 &lower2, &upper2);
2491
2492 if (bounds_adjacent(rangetyp, upper1, lower2))
2493 return true;
2494
2495 if (range_count > 1)
2496 multirange_get_bounds(rangetyp, mr, range_count - 1,
2497 &lower2, &upper2);
2498
2499 if (bounds_adjacent(rangetyp, upper2, lower1))
2500 return true;
2501
2502 return false;
2503}
2504
2505/* adjacent to? */
2506Datum
2508{
2511 TypeCacheEntry *typcache;
2512
2513 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2514
2516}
2517
2518Datum
2520{
2523 TypeCacheEntry *typcache;
2524
2525 if (RangeIsEmpty(r) || MultirangeIsEmpty(mr))
2526 PG_RETURN_BOOL(false);
2527
2528 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2529
2531}
2532
2533Datum
2535{
2538 TypeCacheEntry *typcache;
2539 int32 range_count1;
2540 int32 range_count2;
2541 RangeBound lower1,
2542 upper1,
2543 lower2,
2544 upper2;
2545
2546 if (MultirangeIsEmpty(mr1) || MultirangeIsEmpty(mr2))
2547 PG_RETURN_BOOL(false);
2548
2549 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1));
2550
2551 range_count1 = mr1->rangeCount;
2552 range_count2 = mr2->rangeCount;
2553 multirange_get_bounds(typcache->rngtype, mr1, range_count1 - 1,
2554 &lower1, &upper1);
2555 multirange_get_bounds(typcache->rngtype, mr2, 0,
2556 &lower2, &upper2);
2557 if (bounds_adjacent(typcache->rngtype, upper1, lower2))
2558 PG_RETURN_BOOL(true);
2559
2560 if (range_count1 > 1)
2561 multirange_get_bounds(typcache->rngtype, mr1, 0,
2562 &lower1, &upper1);
2563 if (range_count2 > 1)
2564 multirange_get_bounds(typcache->rngtype, mr2, range_count2 - 1,
2565 &lower2, &upper2);
2566 if (bounds_adjacent(typcache->rngtype, upper2, lower1))
2567 PG_RETURN_BOOL(true);
2568 PG_RETURN_BOOL(false);
2569}
2570
2571/* Btree support */
2572
2573/* btree comparator */
2574Datum
2576{
2579 int32 range_count_1;
2580 int32 range_count_2;
2581 int32 range_count_max;
2582 int32 i;
2583 TypeCacheEntry *typcache;
2584 int cmp = 0; /* If both are empty we'll use this. */
2585
2586 /* Different types should be prevented by ANYMULTIRANGE matching rules */
2588 elog(ERROR, "multirange types do not match");
2589
2590 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1));
2591
2592 range_count_1 = mr1->rangeCount;
2593 range_count_2 = mr2->rangeCount;
2594
2595 /* Loop over source data */
2596 range_count_max = Max(range_count_1, range_count_2);
2597 for (i = 0; i < range_count_max; i++)
2598 {
2599 RangeBound lower1,
2600 upper1,
2601 lower2,
2602 upper2;
2603
2604 /*
2605 * If one multirange is shorter, it's as if it had empty ranges at the
2606 * end to extend its length. An empty range compares earlier than any
2607 * other range, so the shorter multirange comes before the longer.
2608 * This is the same behavior as in other types, e.g. in strings 'aaa'
2609 * < 'aaaaaa'.
2610 */
2611 if (i >= range_count_1)
2612 {
2613 cmp = -1;
2614 break;
2615 }
2616 if (i >= range_count_2)
2617 {
2618 cmp = 1;
2619 break;
2620 }
2621
2622 multirange_get_bounds(typcache->rngtype, mr1, i, &lower1, &upper1);
2623 multirange_get_bounds(typcache->rngtype, mr2, i, &lower2, &upper2);
2624
2625 cmp = range_cmp_bounds(typcache->rngtype, &lower1, &lower2);
2626 if (cmp == 0)
2627 cmp = range_cmp_bounds(typcache->rngtype, &upper1, &upper2);
2628 if (cmp != 0)
2629 break;
2630 }
2631
2632 PG_FREE_IF_COPY(mr1, 0);
2633 PG_FREE_IF_COPY(mr2, 1);
2634
2636}
2637
2638/* inequality operators using the multirange_cmp function */
2639Datum
2641{
2642 int cmp = DatumGetInt32(multirange_cmp(fcinfo));
2643
2644 PG_RETURN_BOOL(cmp < 0);
2645}
2646
2647Datum
2649{
2650 int cmp = DatumGetInt32(multirange_cmp(fcinfo));
2651
2652 PG_RETURN_BOOL(cmp <= 0);
2653}
2654
2655Datum
2657{
2658 int cmp = DatumGetInt32(multirange_cmp(fcinfo));
2659
2660 PG_RETURN_BOOL(cmp >= 0);
2661}
2662
2663Datum
2665{
2666 int cmp = DatumGetInt32(multirange_cmp(fcinfo));
2667
2668 PG_RETURN_BOOL(cmp > 0);
2669}
2670
2671/* multirange -> range functions */
2672
2673/* Find the smallest range that includes everything in the multirange */
2674Datum
2676{
2678 Oid mltrngtypoid = MultirangeTypeGetOid(mr);
2679 TypeCacheEntry *typcache;
2680 RangeType *result;
2681
2682 typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
2683
2684 if (MultirangeIsEmpty(mr))
2685 {
2686 result = make_empty_range(typcache->rngtype);
2687 }
2688 else if (mr->rangeCount == 1)
2689 {
2690 result = multirange_get_range(typcache->rngtype, mr, 0);
2691 }
2692 else
2693 {
2694 RangeBound firstLower,
2695 firstUpper,
2696 lastLower,
2697 lastUpper;
2698
2699 multirange_get_bounds(typcache->rngtype, mr, 0,
2700 &firstLower, &firstUpper);
2701 multirange_get_bounds(typcache->rngtype, mr, mr->rangeCount - 1,
2702 &lastLower, &lastUpper);
2703
2704 result = make_range(typcache->rngtype, &firstLower, &lastUpper,
2705 false, NULL);
2706 }
2707
2708 PG_RETURN_RANGE_P(result);
2709}
2710
2711/* Turn multirange into a set of ranges */
2712Datum
2714{
2715 typedef struct
2716 {
2717 MultirangeType *mr;
2718 TypeCacheEntry *typcache;
2719 int index;
2720 } multirange_unnest_fctx;
2721
2722 FuncCallContext *funcctx;
2723 multirange_unnest_fctx *fctx;
2724 MemoryContext oldcontext;
2725
2726 /* stuff done only on the first call of the function */
2727 if (SRF_IS_FIRSTCALL())
2728 {
2729 MultirangeType *mr;
2730
2731 /* create a function context for cross-call persistence */
2732 funcctx = SRF_FIRSTCALL_INIT();
2733
2734 /*
2735 * switch to memory context appropriate for multiple function calls
2736 */
2737 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
2738
2739 /*
2740 * Get the multirange value and detoast if needed. We can't do this
2741 * earlier because if we have to detoast, we want the detoasted copy
2742 * to be in multi_call_memory_ctx, so it will go away when we're done
2743 * and not before. (If no detoast happens, we assume the originally
2744 * passed multirange will stick around till then.)
2745 */
2746 mr = PG_GETARG_MULTIRANGE_P(0);
2747
2748 /* allocate memory for user context */
2749 fctx = (multirange_unnest_fctx *) palloc(sizeof(multirange_unnest_fctx));
2750
2751 /* initialize state */
2752 fctx->mr = mr;
2753 fctx->index = 0;
2754 fctx->typcache = lookup_type_cache(MultirangeTypeGetOid(mr),
2756
2757 funcctx->user_fctx = fctx;
2758 MemoryContextSwitchTo(oldcontext);
2759 }
2760
2761 /* stuff done on every call of the function */
2762 funcctx = SRF_PERCALL_SETUP();
2763 fctx = funcctx->user_fctx;
2764
2765 if (fctx->index < fctx->mr->rangeCount)
2766 {
2768
2769 range = multirange_get_range(fctx->typcache->rngtype,
2770 fctx->mr,
2771 fctx->index);
2772 fctx->index++;
2773
2775 }
2776 else
2777 {
2778 /* do when there is no more left */
2779 SRF_RETURN_DONE(funcctx);
2780 }
2781}
2782
2783/* Hash support */
2784
2785/* hash a multirange value */
2786Datum
2788{
2790 uint32 result = 1;
2791 TypeCacheEntry *typcache,
2792 *scache;
2793 int32 range_count,
2794 i;
2795
2796 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2797 scache = typcache->rngtype->rngelemtype;
2798 if (!OidIsValid(scache->hash_proc_finfo.fn_oid))
2799 {
2800 scache = lookup_type_cache(scache->type_id,
2802 if (!OidIsValid(scache->hash_proc_finfo.fn_oid))
2803 ereport(ERROR,
2804 (errcode(ERRCODE_UNDEFINED_FUNCTION),
2805 errmsg("could not identify a hash function for type %s",
2806 format_type_be(scache->type_id))));
2807 }
2808
2809 range_count = mr->rangeCount;
2810 for (i = 0; i < range_count; i++)
2811 {
2813 upper;
2814 uint8 flags = MultirangeGetFlagsPtr(mr)[i];
2815 uint32 lower_hash;
2816 uint32 upper_hash;
2817 uint32 range_hash;
2818
2819 multirange_get_bounds(typcache->rngtype, mr, i, &lower, &upper);
2820
2821 if (RANGE_HAS_LBOUND(flags))
2822 lower_hash = DatumGetUInt32(FunctionCall1Coll(&scache->hash_proc_finfo,
2823 typcache->rngtype->rng_collation,
2824 lower.val));
2825 else
2826 lower_hash = 0;
2827
2828 if (RANGE_HAS_UBOUND(flags))
2829 upper_hash = DatumGetUInt32(FunctionCall1Coll(&scache->hash_proc_finfo,
2830 typcache->rngtype->rng_collation,
2831 upper.val));
2832 else
2833 upper_hash = 0;
2834
2835 /* Merge hashes of flags and bounds */
2836 range_hash = hash_bytes_uint32((uint32) flags);
2837 range_hash ^= lower_hash;
2838 range_hash = pg_rotate_left32(range_hash, 1);
2839 range_hash ^= upper_hash;
2840
2841 /*
2842 * Use the same approach as hash_array to combine the individual
2843 * elements' hash values:
2844 */
2845 result = (result << 5) - result + range_hash;
2846 }
2847
2848 PG_FREE_IF_COPY(mr, 0);
2849
2850 PG_RETURN_UINT32(result);
2851}
2852
2853/*
2854 * Returns 64-bit value by hashing a value to a 64-bit value, with a seed.
2855 * Otherwise, similar to hash_multirange.
2856 */
2857Datum
2859{
2861 Datum seed = PG_GETARG_DATUM(1);
2862 uint64 result = 1;
2863 TypeCacheEntry *typcache,
2864 *scache;
2865 int32 range_count,
2866 i;
2867
2868 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2869 scache = typcache->rngtype->rngelemtype;
2871 {
2872 scache = lookup_type_cache(scache->type_id,
2875 ereport(ERROR,
2876 (errcode(ERRCODE_UNDEFINED_FUNCTION),
2877 errmsg("could not identify a hash function for type %s",
2878 format_type_be(scache->type_id))));
2879 }
2880
2881 range_count = mr->rangeCount;
2882 for (i = 0; i < range_count; i++)
2883 {
2885 upper;
2886 uint8 flags = MultirangeGetFlagsPtr(mr)[i];
2887 uint64 lower_hash;
2888 uint64 upper_hash;
2889 uint64 range_hash;
2890
2891 multirange_get_bounds(typcache->rngtype, mr, i, &lower, &upper);
2892
2893 if (RANGE_HAS_LBOUND(flags))
2895 typcache->rngtype->rng_collation,
2896 lower.val,
2897 seed));
2898 else
2899 lower_hash = 0;
2900
2901 if (RANGE_HAS_UBOUND(flags))
2903 typcache->rngtype->rng_collation,
2904 upper.val,
2905 seed));
2906 else
2907 upper_hash = 0;
2908
2909 /* Merge hashes of flags and bounds */
2910 range_hash = DatumGetUInt64(hash_uint32_extended((uint32) flags,
2911 DatumGetInt64(seed)));
2912 range_hash ^= lower_hash;
2913 range_hash = ROTATE_HIGH_AND_LOW_32BITS(range_hash);
2914 range_hash ^= upper_hash;
2915
2916 /*
2917 * Use the same approach as hash_array to combine the individual
2918 * elements' hash values:
2919 */
2920 result = (result << 5) - result + range_hash;
2921 }
2922
2923 PG_FREE_IF_COPY(mr, 0);
2924
2925 PG_RETURN_UINT64(result);
2926}
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:262
#define ARR_NDIM(a)
Definition: array.h:290
#define PG_GETARG_ARRAYTYPE_P(n)
Definition: array.h:263
#define ARR_ELEMTYPE(a)
Definition: array.h:292
ArrayBuildState * accumArrayResult(ArrayBuildState *astate, Datum dvalue, bool disnull, Oid element_type, MemoryContext rcontext)
Definition: arrayfuncs.c:5350
void deconstruct_array(ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3631
ArrayBuildState * initArrayResult(Oid element_type, MemoryContext rcontext, bool subcontext)
Definition: arrayfuncs.c:5293
uint8_t uint8
Definition: c.h:536
#define Max(x, y)
Definition: c.h:997
char * Pointer
Definition: c.h:529
#define VARHDRSZ
Definition: c.h:697
int16_t int16
Definition: c.h:533
int32_t int32
Definition: c.h:534
uint64_t uint64
Definition: c.h:539
uint32_t uint32
Definition: c.h:538
#define OidIsValid(objectId)
Definition: c.h:774
size_t Size
Definition: c.h:610
int errdetail(const char *fmt,...)
Definition: elog.c:1207
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define ereturn(context, dummy_value,...)
Definition: elog.h:278
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:226
#define ereport(elevel,...)
Definition: elog.h:150
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1149
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:137
bytea * SendFunctionCall(FmgrInfo *flinfo, Datum val)
Definition: fmgr.c:1743
bool InputFunctionCallSafe(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod, Node *escontext, Datum *result)
Definition: fmgr.c:1584
char * OutputFunctionCall(FmgrInfo *flinfo, Datum val)
Definition: fmgr.c:1682
Oid get_fn_expr_argtype(FmgrInfo *flinfo, int argnum)
Definition: fmgr.c:1874
Datum FunctionCall1Coll(FmgrInfo *flinfo, Oid collation, Datum arg1)
Definition: fmgr.c:1129
Oid get_fn_expr_rettype(FmgrInfo *flinfo)
Definition: fmgr.c:1852
Datum ReceiveFunctionCall(FmgrInfo *flinfo, StringInfo buf, Oid typioparam, int32 typmod)
Definition: fmgr.c:1696
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:260
#define PG_GETARG_OID(n)
Definition: fmgr.h:275
#define PG_RETURN_UINT32(x)
Definition: fmgr.h:355
#define PG_RETURN_BYTEA_P(x)
Definition: fmgr.h:371
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
#define PG_RETURN_CSTRING(x)
Definition: fmgr.h:362
#define PG_ARGISNULL(n)
Definition: fmgr.h:209
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:268
#define PG_NARGS()
Definition: fmgr.h:203
#define PG_GETARG_CSTRING(n)
Definition: fmgr.h:277
#define PG_RETURN_NULL()
Definition: fmgr.h:345
#define PG_RETURN_UINT64(x)
Definition: fmgr.h:369
#define PG_RETURN_INT32(x)
Definition: fmgr.h:354
#define PG_GETARG_INT32(n)
Definition: fmgr.h:269
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:353
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:359
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:304
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:308
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:310
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:306
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:328
uint32 hash_bytes_uint32(uint32 k)
Definition: hashfn.c:610
#define ROTATE_HIGH_AND_LOW_32BITS(v)
Definition: hashfn.h:18
static Datum hash_uint32_extended(uint32 k, uint64 seed)
Definition: hashfn.h:49
Assert(PointerIsAligned(start, uint64))
long val
Definition: informix.c:689
int i
Definition: isn.c:77
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:81
bool type_is_range(Oid typid)
Definition: lsyscache.c:2855
void get_type_io_data(Oid typid, IOFuncSelector which_func, int16 *typlen, bool *typbyval, char *typalign, char *typdelim, Oid *typioparam, Oid *func)
Definition: lsyscache.c:2492
bool type_is_multirange(Oid typid)
Definition: lsyscache.c:2865
IOFuncSelector
Definition: lsyscache.h:35
@ IOFunc_output
Definition: lsyscache.h:37
@ IOFunc_input
Definition: lsyscache.h:36
@ IOFunc_send
Definition: lsyscache.h:39
@ IOFunc_receive
Definition: lsyscache.h:38
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1229
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1610
void pfree(void *pointer)
Definition: mcxt.c:1594
void * palloc0(Size size)
Definition: mcxt.c:1395
void * palloc(Size size)
Definition: mcxt.c:1365
char * pnstrdup(const char *in, Size len)
Definition: mcxt.c:1770
struct MultirangeIOData MultirangeIOData
#define MULTIRANGE_ITEM_GET_OFFLEN(item)
MultirangeType * multirange_intersect_internal(Oid mltrngtypoid, TypeCacheEntry *rangetyp, int32 range_count1, RangeType **ranges1, int32 range_count2, RangeType **ranges2)
MultirangeType * multirange_minus_internal(Oid mltrngtypoid, TypeCacheEntry *rangetyp, int32 range_count1, RangeType **ranges1, int32 range_count2, RangeType **ranges2)
Datum multirange_upper(PG_FUNCTION_ARGS)
Datum multirange_adjacent_range(PG_FUNCTION_ARGS)
Datum multirange_before_range(PG_FUNCTION_ARGS)
Datum multirange_send(PG_FUNCTION_ARGS)
Datum multirange_agg_transfn(PG_FUNCTION_ARGS)
static int multirange_range_contains_bsearch_comparison(TypeCacheEntry *typcache, RangeBound *lower, RangeBound *upper, void *key, bool *match)
bool multirange_contains_elem_internal(TypeCacheEntry *rangetyp, const MultirangeType *mr, Datum val)
Datum multirange_upper_inf(PG_FUNCTION_ARGS)
Datum multirange_intersect_agg_transfn(PG_FUNCTION_ARGS)
Datum range_overleft_multirange(PG_FUNCTION_ARGS)
RangeType * multirange_get_range(TypeCacheEntry *rangetyp, const MultirangeType *multirange, int i)
Datum range_after_multirange(PG_FUNCTION_ARGS)
Datum multirange_upper_inc(PG_FUNCTION_ARGS)
Datum elem_contained_by_multirange(PG_FUNCTION_ARGS)
bool multirange_before_multirange_internal(TypeCacheEntry *rangetyp, const MultirangeType *mr1, const MultirangeType *mr2)
Datum multirange_lt(PG_FUNCTION_ARGS)
Datum multirange_overlaps_multirange(PG_FUNCTION_ARGS)
Datum range_contained_by_multirange(PG_FUNCTION_ARGS)
Datum multirange_overright_range(PG_FUNCTION_ARGS)
Datum range_overlaps_multirange(PG_FUNCTION_ARGS)
MultirangeType * make_multirange(Oid mltrngtypoid, TypeCacheEntry *rangetyp, int32 range_count, RangeType **ranges)
bool multirange_eq_internal(TypeCacheEntry *rangetyp, const MultirangeType *mr1, const MultirangeType *mr2)
Datum multirange_ge(PG_FUNCTION_ARGS)
Datum multirange_contained_by_range(PG_FUNCTION_ARGS)
static int32 multirange_canonicalize(TypeCacheEntry *rangetyp, int32 input_range_count, RangeType **ranges)
#define MULTIRANGE_ITEM_HAS_OFF(item)
Datum multirange_gt(PG_FUNCTION_ARGS)
Datum multirange_intersect(PG_FUNCTION_ARGS)
bool multirange_contains_multirange_internal(TypeCacheEntry *rangetyp, const MultirangeType *mr1, const MultirangeType *mr2)
Datum multirange_lower_inc(PG_FUNCTION_ARGS)
MultirangeType * make_empty_multirange(Oid mltrngtypoid, TypeCacheEntry *rangetyp)
void multirange_get_bounds(TypeCacheEntry *rangetyp, const MultirangeType *multirange, uint32 i, RangeBound *lower, RangeBound *upper)
Datum multirange_overlaps_range(PG_FUNCTION_ARGS)
Datum multirange_overright_multirange(PG_FUNCTION_ARGS)
Datum range_adjacent_multirange(PG_FUNCTION_ARGS)
Datum multirange_out(PG_FUNCTION_ARGS)
Datum multirange_constructor1(PG_FUNCTION_ARGS)
Datum multirange_in(PG_FUNCTION_ARGS)
Datum multirange_constructor2(PG_FUNCTION_ARGS)
static Size multirange_size_estimate(TypeCacheEntry *rangetyp, int32 range_count, RangeType **ranges)
static void write_multirange_data(MultirangeType *multirange, TypeCacheEntry *rangetyp, int32 range_count, RangeType **ranges)
Datum multirange_overleft_range(PG_FUNCTION_ARGS)
#define MULTIRANGE_ITEM_OFFSET_STRIDE
static bool multirange_bsearch_match(TypeCacheEntry *typcache, const MultirangeType *mr, void *key, multirange_bsearch_comparison cmp_func)
bool range_adjacent_multirange_internal(TypeCacheEntry *rangetyp, const RangeType *r, const MultirangeType *mr)
Datum multirange_after_multirange(PG_FUNCTION_ARGS)
Datum multirange_contains_elem(PG_FUNCTION_ARGS)
Datum range_agg_finalfn(PG_FUNCTION_ARGS)
bool range_after_multirange_internal(TypeCacheEntry *rangetyp, const RangeType *r, const MultirangeType *mr)
Datum multirange_union(PG_FUNCTION_ARGS)
Datum multirange_adjacent_multirange(PG_FUNCTION_ARGS)
Datum multirange_before_multirange(PG_FUNCTION_ARGS)
static MultirangeIOData * get_multirange_io_data(FunctionCallInfo fcinfo, Oid mltrngtypid, IOFuncSelector func)
Datum range_overright_multirange(PG_FUNCTION_ARGS)
Datum multirange_lower(PG_FUNCTION_ARGS)
Datum multirange_overleft_multirange(PG_FUNCTION_ARGS)
Datum multirange_ne(PG_FUNCTION_ARGS)
bool multirange_contains_range_internal(TypeCacheEntry *rangetyp, const MultirangeType *mr, const RangeType *r)
bool multirange_overlaps_multirange_internal(TypeCacheEntry *rangetyp, const MultirangeType *mr1, const MultirangeType *mr2)
Datum multirange_eq(PG_FUNCTION_ARGS)
int(* multirange_bsearch_comparison)(TypeCacheEntry *typcache, RangeBound *lower, RangeBound *upper, void *key, bool *match)
static bool range_bounds_contains(TypeCacheEntry *typcache, RangeBound *lower1, RangeBound *upper1, RangeBound *lower2, RangeBound *upper2)
void multirange_deserialize(TypeCacheEntry *rangetyp, const MultirangeType *multirange, int32 *range_count, RangeType ***ranges)
static bool range_bounds_overlaps(TypeCacheEntry *typcache, RangeBound *lower1, RangeBound *upper1, RangeBound *lower2, RangeBound *upper2)
MultirangeParseState
@ MULTIRANGE_BEFORE_RANGE
@ MULTIRANGE_IN_RANGE
@ MULTIRANGE_FINISHED
@ MULTIRANGE_AFTER_RANGE
@ MULTIRANGE_IN_RANGE_QUOTED_ESCAPED
@ MULTIRANGE_IN_RANGE_ESCAPED
@ MULTIRANGE_IN_RANGE_QUOTED
Datum multirange_recv(PG_FUNCTION_ARGS)
TypeCacheEntry * multirange_get_typcache(FunctionCallInfo fcinfo, Oid mltrngtypid)
Datum multirange_minus(PG_FUNCTION_ARGS)
Datum multirange_contains_multirange(PG_FUNCTION_ARGS)
#define MultirangeGetItemsPtr(mr)
Datum multirange_le(PG_FUNCTION_ARGS)
#define MultirangeGetFlagsPtr(mr)
Datum hash_multirange(PG_FUNCTION_ARGS)
RangeType * multirange_get_union_range(TypeCacheEntry *rangetyp, const MultirangeType *mr)
Datum hash_multirange_extended(PG_FUNCTION_ARGS)
Datum multirange_constructor0(PG_FUNCTION_ARGS)
Datum multirange_after_range(PG_FUNCTION_ARGS)
Datum multirange_contained_by_multirange(PG_FUNCTION_ARGS)
Datum multirange_empty(PG_FUNCTION_ARGS)
static int multirange_range_overlaps_bsearch_comparison(TypeCacheEntry *typcache, RangeBound *lower, RangeBound *upper, void *key, bool *match)
static int multirange_elem_bsearch_comparison(TypeCacheEntry *typcache, RangeBound *lower, RangeBound *upper, void *key, bool *match)
Datum range_before_multirange(PG_FUNCTION_ARGS)
bool range_before_multirange_internal(TypeCacheEntry *rangetyp, const RangeType *r, const MultirangeType *mr)
bool range_overright_multirange_internal(TypeCacheEntry *rangetyp, const RangeType *r, const MultirangeType *mr)
bool range_contains_multirange_internal(TypeCacheEntry *rangetyp, const RangeType *r, const MultirangeType *mr)
bool multirange_ne_internal(TypeCacheEntry *rangetyp, const MultirangeType *mr1, const MultirangeType *mr2)
Datum multirange_cmp(PG_FUNCTION_ARGS)
static uint32 multirange_get_bounds_offset(const MultirangeType *multirange, int32 i)
bool range_overlaps_multirange_internal(TypeCacheEntry *rangetyp, const RangeType *r, const MultirangeType *mr)
Datum range_merge_from_multirange(PG_FUNCTION_ARGS)
Datum range_agg_transfn(PG_FUNCTION_ARGS)
Datum range_contains_multirange(PG_FUNCTION_ARGS)
#define MULTIRANGE_ITEM_OFF_BIT
Datum multirange_unnest(PG_FUNCTION_ARGS)
Datum multirange_contains_range(PG_FUNCTION_ARGS)
bool range_overleft_multirange_internal(TypeCacheEntry *rangetyp, const RangeType *r, const MultirangeType *mr)
#define MultirangeGetBoundariesPtr(mr, align)
Datum multirange_lower_inf(PG_FUNCTION_ARGS)
#define MultirangeIsEmpty(mr)
#define PG_RETURN_MULTIRANGE_P(x)
#define PG_GETARG_MULTIRANGE_P(n)
#define MultirangeTypeGetOid(mr)
int AggCheckCallContext(FunctionCallInfo fcinfo, MemoryContext *aggcontext)
Definition: nodeAgg.c:4613
Datum lower(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:49
Datum upper(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:80
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
static uint32 pg_rotate_left32(uint32 word, int n)
Definition: pg_bitutils.h:428
const void size_t len
static char * buf
Definition: pg_test_fsync.c:72
char typalign
Definition: pg_type.h:176
void qsort_arg(void *base, size_t nel, size_t elsize, qsort_arg_comparator cmp, void *arg)
int pg_strncasecmp(const char *s1, const char *s2, size_t n)
Definition: pgstrcasecmp.c:69
static uint32 DatumGetUInt32(Datum X)
Definition: postgres.h:232
static uint64 DatumGetUInt64(Datum X)
Definition: postgres.h:413
static int64 DatumGetInt64(Datum X)
Definition: postgres.h:393
uint64_t Datum
Definition: postgres.h:70
static int32 DatumGetInt32(Datum X)
Definition: postgres.h:212
unsigned int Oid
Definition: postgres_ext.h:32
unsigned int pq_getmsgint(StringInfo msg, int b)
Definition: pqformat.c:415
void pq_sendbytes(StringInfo buf, const void *data, int datalen)
Definition: pqformat.c:126
void pq_getmsgend(StringInfo msg)
Definition: pqformat.c:635
void pq_begintypsend(StringInfo buf)
Definition: pqformat.c:326
const char * pq_getmsgbytes(StringInfo msg, int datalen)
Definition: pqformat.c:508
bytea * pq_endtypsend(StringInfo buf)
Definition: pqformat.c:346
static void pq_sendint32(StringInfo buf, uint32 i)
Definition: pqformat.h:144
int range_cmp_bounds(TypeCacheEntry *typcache, const RangeBound *b1, const RangeBound *b2)
Definition: rangetypes.c:2078
bool range_split_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2, RangeType **output1, RangeType **output2)
Definition: rangetypes.c:1182
RangeType * make_range(TypeCacheEntry *typcache, RangeBound *lower, RangeBound *upper, bool empty, struct Node *escontext)
Definition: rangetypes.c:2014
bool bounds_adjacent(TypeCacheEntry *typcache, RangeBound boundA, RangeBound boundB)
Definition: rangetypes.c:757
bool range_overlaps_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
Definition: rangetypes.c:841
bool range_before_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
Definition: rangetypes.c:664
RangeType * range_intersect_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
Definition: rangetypes.c:1143
RangeType * range_minus_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2)
Definition: rangetypes.c:993
void range_deserialize(TypeCacheEntry *typcache, const RangeType *range, RangeBound *lower, RangeBound *upper, bool *empty)
Definition: rangetypes.c:1918
RangeType * range_union_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2, bool strict)
Definition: rangetypes.c:1052
bool range_adjacent_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
Definition: rangetypes.c:798
bool range_overleft_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
Definition: rangetypes.c:887
int range_compare(const void *key1, const void *key2, void *arg)
Definition: rangetypes.c:2191
RangeType * make_empty_range(TypeCacheEntry *typcache)
Definition: rangetypes.c:2227
static RangeType * DatumGetRangeTypeP(Datum X)
Definition: rangetypes.h:73
#define RANGE_HAS_UBOUND(flags)
Definition: rangetypes.h:51
#define RANGE_UB_INC
Definition: rangetypes.h:40
#define RangeIsEmpty(r)
Definition: rangetypes.h:55
static Datum RangeTypePGetDatum(const RangeType *X)
Definition: rangetypes.h:85
#define RANGE_LB_INC
Definition: rangetypes.h:39
#define RANGE_UB_INF
Definition: rangetypes.h:42
#define PG_RETURN_RANGE_P(x)
Definition: rangetypes.h:92
#define RANGE_EMPTY
Definition: rangetypes.h:38
#define RANGE_HAS_LBOUND(flags)
Definition: rangetypes.h:47
#define PG_GETARG_RANGE_P(n)
Definition: rangetypes.h:90
#define RANGE_EMPTY_LITERAL
Definition: rangetypes.h:32
#define RANGE_LB_INF
Definition: rangetypes.h:41
#define RangeTypeGetOid(r)
Definition: rangetypes.h:35
static int cmp(const chr *x, const chr *y, size_t len)
Definition: regc_locale.c:743
static struct cvec * range(struct vars *v, chr a, chr b, int cases)
Definition: regc_locale.c:412
struct StringInfoData * StringInfo
Definition: string.h:15
StringInfo makeStringInfo(void)
Definition: stringinfo.c:72
void resetStringInfo(StringInfo str)
Definition: stringinfo.c:126
void appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
Definition: stringinfo.c:281
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:230
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:242
void initStringInfo(StringInfo str)
Definition: stringinfo.c:97
Definition: fmgr.h:57
void * fn_extra
Definition: fmgr.h:64
MemoryContext fn_mcxt
Definition: fmgr.h:65
Oid fn_oid
Definition: fmgr.h:59
void * user_fctx
Definition: funcapi.h:82
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:101
FmgrInfo * flinfo
Definition: fmgr.h:87
TypeCacheEntry * typcache
Definition: nodes.h:135
FmgrInfo hash_proc_finfo
Definition: typcache.h:78
FmgrInfo rng_cmp_proc_finfo
Definition: typcache.h:102
Oid rng_collation
Definition: typcache.h:101
char typalign
Definition: typcache.h:41
struct TypeCacheEntry * rngelemtype
Definition: typcache.h:99
FmgrInfo hash_extended_proc_finfo
Definition: typcache.h:79
struct TypeCacheEntry * rngtype
Definition: typcache.h:109
bool typbyval
Definition: typcache.h:40
int16 typlen
Definition: typcache.h:39
Definition: type.h:96
Definition: regguts.h:323
Definition: c.h:692
static ItemArray items
Definition: test_tidstore.c:48
#define att_align_pointer(cur_offset, attalign, attlen, attptr)
Definition: tupmacs.h:113
#define att_align_nominal(cur_offset, attalign)
Definition: tupmacs.h:145
#define att_addlength_pointer(cur_offset, attlen, attptr)
Definition: tupmacs.h:180
static Datum fetch_att(const void *T, bool attbyval, int attlen)
Definition: tupmacs.h:50
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:386
#define TYPECACHE_HASH_PROC_FINFO
Definition: typcache.h:145
#define TYPECACHE_MULTIRANGE_INFO
Definition: typcache.h:154
#define TYPECACHE_HASH_EXTENDED_PROC_FINFO
Definition: typcache.h:153
static Size VARSIZE(const void *PTR)
Definition: varatt.h:298
static char * VARDATA(const void *PTR)
Definition: varatt.h:305
static void SET_VARSIZE(void *PTR, Size len)
Definition: varatt.h:432
static StringInfoData tmpbuf
Definition: walsender.c:178