PostgreSQL Source Code git master
Loading...
Searching...
No Matches
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-2026, 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
66
67/*
68 * Macros for accessing past MultirangeType parts of multirange: items, flags
69 * and boundaries.
70 */
71#define MultirangeGetItemsPtr(mr) ((uint32 *) ((char *) (mr) + \
72 sizeof(MultirangeType)))
73#define MultirangeGetFlagsPtr(mr) ((uint8 *) ((char *) (mr) + \
74 sizeof(MultirangeType) + ((mr)->rangeCount - 1) * sizeof(uint32)))
75#define MultirangeGetBoundariesPtr(mr, align) ((char *) (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
93 IOFuncSelector func);
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);
121 Oid typmod = PG_GETARG_INT32(2);
122 Node *escontext = fcinfo->context;
124 int32 ranges_seen = 0;
125 int32 range_count = 0;
129 MultirangeIOData *cache;
130 MultirangeType *ret;
132 const char *ptr = input_str;
133 const char *range_str_begin = NULL;
135 char *range_str;
137
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,
150 errmsg("malformed multirange literal: \"%s\"",
151 input_str),
152 errdetail("Missing left brace.")));
153
154 /* consume ranges */
156 for (; parse_state != MULTIRANGE_FINISHED; ptr++)
157 {
158 char ch = *ptr;
159
160 if (ch == '\0')
161 ereturn(escontext, (Datum) 0,
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;
178 }
179 else if (ch == '}' && ranges_seen == 0)
183 {
184 ranges_seen++;
185 /* nothing to do with an empty range */
186 ptr += strlen(RANGE_EMPTY_LITERAL) - 1;
188 }
189 else
190 ereturn(escontext, (Datum) 0,
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;
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))
216 if (!RangeIsEmpty(range))
217 ranges[range_count++] = range;
219 }
220 else
221 {
222 if (ch == '"')
224 else if (ch == '\\')
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 */
240 break;
242 if (ch == '"')
243 if (*(ptr + 1) == '"')
244 {
245 /* two quote marks means an escaped quote mark */
246 ptr++;
247 }
248 else
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 == ',')
261 else if (ch == '}')
263 else
264 ereturn(escontext, (Datum) 0,
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 */
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,
290 errmsg("malformed multirange literal: \"%s\"",
291 input_str),
292 errdetail("Junk after closing right brace.")));
293
296}
297
298Datum
331
332/*
333 * Binary representation: First an int32-sized count of ranges, followed by
334 * ranges in their native binary representation.
335 */
336Datum
338{
341 int32 typmod = PG_GETARG_INT32(2);
342 MultirangeIOData *cache;
344 RangeType **ranges;
345 MultirangeType *ret;
347
349
352
354 for (int i = 0; i < range_count; i++)
355 {
357 const char *range_data = pq_getmsgbytes(buf, range_len);
358
361
363 &tmpbuf,
364 cache->typioparam,
365 typmod));
366 }
368
370
372 range_count, ranges);
374}
375
376Datum
409
410/*
411 * get_multirange_io_data: get cached information needed for multirange type I/O
412 *
413 * The multirange I/O functions need a bit more cached info than other multirange
414 * functions, so they store a MultirangeIOData struct in fn_extra, not just a
415 * pointer to a type cache entry.
416 */
417static MultirangeIOData *
419{
420 MultirangeIOData *cache = (MultirangeIOData *) fcinfo->flinfo->fn_extra;
421
422 if (cache == NULL || cache->typcache->type_id != mltrngtypid)
423 {
424 Oid typiofunc;
425 int16 typlen;
426 bool typbyval;
427 char typalign;
428 char typdelim;
429
431 sizeof(MultirangeIOData));
433 if (cache->typcache->rngtype == NULL)
434 elog(ERROR, "type %u is not a multirange type", mltrngtypid);
435
436 /* get_type_io_data does more than we need, but is convenient */
438 func,
439 &typlen,
440 &typbyval,
441 &typalign,
442 &typdelim,
443 &cache->typioparam,
444 &typiofunc);
445
446 if (!OidIsValid(typiofunc))
447 {
448 /* this could only happen for receive or send */
449 if (func == IOFunc_receive)
452 errmsg("no binary input function available for type %s",
454 else
457 errmsg("no binary output function available for type %s",
459 }
460 fmgr_info_cxt(typiofunc, &cache->typioproc,
461 fcinfo->flinfo->fn_mcxt);
462
463 fcinfo->flinfo->fn_extra = cache;
464 }
465
466 return cache;
467}
468
469/*
470 * Converts a list of arbitrary ranges into a list that is sorted and merged.
471 * Changes the contents of `ranges`.
472 *
473 * Returns the number of slots actually used, which may be less than
474 * input_range_count but never more.
475 *
476 * We assume that no input ranges are null, but empties are okay.
477 */
478static int32
480 RangeType **ranges)
481{
484 int32 i;
486
487 /* Sort the ranges so we can find the ones that overlap/meet. */
488 if (ranges != NULL)
489 qsort_arg(ranges, input_range_count, sizeof(RangeType *),
491
492 /* Now merge where possible: */
493 for (i = 0; i < input_range_count; i++)
494 {
495 currentRange = ranges[i];
497 continue;
498
499 if (lastRange == NULL)
500 {
502 continue;
503 }
504
505 /*
506 * range_adjacent_internal gives true if *either* A meets B or B meets
507 * A, which is not quite want we want, but we rely on the sorting
508 * above to rule out B meets A ever happening.
509 */
511 {
512 /* The two ranges touch (without overlap), so merge them: */
513 ranges[output_range_count - 1] = lastRange =
515 }
517 {
518 /* There's a gap, so make a new entry: */
521 }
522 else
523 {
524 /* They must overlap, so merge them: */
525 ranges[output_range_count - 1] = lastRange =
527 }
528 }
529
530 return output_range_count;
531}
532
533/*
534 *----------------------------------------------------------
535 * SUPPORT FUNCTIONS
536 *
537 * These functions aren't in pg_proc, but are useful for
538 * defining new generic multirange functions in C.
539 *----------------------------------------------------------
540 */
541
542/*
543 * multirange_get_typcache: get cached information about a multirange type
544 *
545 * This is for use by multirange-related functions that follow the convention
546 * of using the fn_extra field as a pointer to the type cache entry for
547 * the multirange type. Functions that need to cache more information than
548 * that must fend for themselves.
549 */
552{
553 TypeCacheEntry *typcache = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
554
555 if (typcache == NULL ||
556 typcache->type_id != mltrngtypid)
557 {
559 if (typcache->rngtype == NULL)
560 elog(ERROR, "type %u is not a multirange type", mltrngtypid);
561 fcinfo->flinfo->fn_extra = typcache;
562 }
563
564 return typcache;
565}
566
567
568/*
569 * Estimate size occupied by serialized multirange.
570 */
571static Size
573 RangeType **ranges)
574{
575 char elemalign = rangetyp->rngelemtype->typalign;
577 Size size;
578 int32 i;
579
580 /*
581 * Count space for MultirangeType struct, items and flags.
582 */
583 size = att_nominal_alignby(sizeof(MultirangeType) +
584 Max(range_count - 1, 0) * sizeof(uint32) +
585 range_count * sizeof(uint8), elemalignby);
586
587 /* Count space for range bounds */
588 for (i = 0; i < range_count; i++)
589 size += att_nominal_alignby(VARSIZE(ranges[i]) -
590 sizeof(RangeType) -
591 sizeof(char), elemalignby);
592
593 return size;
594}
595
596/*
597 * Write multirange data into pre-allocated space.
598 */
599static void
601 int32 range_count, RangeType **ranges)
602{
603 uint32 *items;
605 uint8 *flags;
606 int32 i;
607 const char *begin;
608 char *ptr;
609 char elemalign = rangetyp->rngelemtype->typalign;
611
614 begin = ptr = MultirangeGetBoundariesPtr(multirange, elemalign);
615 for (i = 0; i < range_count; i++)
616 {
617 uint32 len;
618
619 if (i > 0)
620 {
621 /*
622 * Every range, except the first one, has an item. Every
623 * MULTIRANGE_ITEM_OFFSET_STRIDE item contains an offset, others
624 * contain lengths.
625 */
626 items[i - 1] = ptr - begin;
627 if ((i % MULTIRANGE_ITEM_OFFSET_STRIDE) != 0)
628 items[i - 1] -= prev_offset;
629 else
631 prev_offset = ptr - begin;
632 }
633 flags[i] = *((char *) ranges[i] + VARSIZE(ranges[i]) - sizeof(char));
634 len = VARSIZE(ranges[i]) - sizeof(RangeType) - sizeof(char);
635 memcpy(ptr, ranges[i] + 1, len);
637 }
638}
639
640
641/*
642 * This serializes the multirange from a list of non-null ranges. It also
643 * sorts the ranges and merges any that touch. The ranges should already be
644 * detoasted, and there should be no NULLs. This should be used by most
645 * callers.
646 *
647 * Note that we may change the `ranges` parameter (the pointers, but not
648 * any already-existing RangeType contents).
649 */
652 RangeType **ranges)
653{
655 Size size;
656
657 /* Sort and merge input ranges. */
659
660 /* Note: zero-fill is required here, just as in heap tuples */
662 multirange = palloc0(size);
663 SET_VARSIZE(multirange, size);
664
665 /* Now fill in the datum */
666 multirange->multirangetypid = mltrngtypoid;
667 multirange->rangeCount = range_count;
668
670
671 return multirange;
672}
673
674/*
675 * Get offset of bounds values of the i'th range in the multirange.
676 */
677static uint32
679{
681 uint32 offset = 0;
682
683 /*
684 * Summarize lengths till we meet an offset.
685 */
686 while (i > 0)
687 {
688 offset += MULTIRANGE_ITEM_GET_OFFLEN(items[i - 1]);
690 break;
691 i--;
692 }
693 return offset;
694}
695
696/*
697 * Fetch the i'th range from the multirange.
698 */
699RangeType *
701 const MultirangeType *multirange, int i)
702{
703 uint32 offset;
704 uint8 flags;
705 const char *begin;
706 char *ptr;
707 int16 typlen = rangetyp->rngelemtype->typlen;
708 char typalign = rangetyp->rngelemtype->typalign;
709 uint32 len;
711
712 Assert(i < multirange->rangeCount);
713
716 begin = ptr = MultirangeGetBoundariesPtr(multirange, typalign) + offset;
717
718 /*
719 * Calculate the size of bound values. In principle, we could get offset
720 * of the next range bound values and calculate accordingly. But range
721 * bound values are aligned, so we have to walk the values to get the
722 * exact size.
723 */
724 if (RANGE_HAS_LBOUND(flags))
725 ptr = (char *) att_addlength_pointer(ptr, typlen, ptr);
726 if (RANGE_HAS_UBOUND(flags))
727 {
728 ptr = (char *) att_align_pointer(ptr, typalign, typlen, ptr);
729 ptr = (char *) att_addlength_pointer(ptr, typlen, ptr);
730 }
731 len = (ptr - begin) + sizeof(RangeType) + sizeof(uint8);
732
733 range = palloc0(len);
735 range->rangetypid = rangetyp->type_id;
736
737 memcpy(range + 1, begin, ptr - begin);
738 *((uint8 *) (range + 1) + (ptr - begin)) = flags;
739
740 return range;
741}
742
743/*
744 * Fetch bounds from the i'th range of the multirange. This is the shortcut for
745 * doing the same thing as multirange_get_range() + range_deserialize(), but
746 * performing fewer operations.
747 */
748void
752{
753 uint32 offset;
754 uint8 flags;
755 const char *ptr;
756 int16 typlen = rangetyp->rngelemtype->typlen;
757 char typalign = rangetyp->rngelemtype->typalign;
758 bool typbyval = rangetyp->rngelemtype->typbyval;
759 Datum lbound;
761
762 Assert(i < multirange->rangeCount);
763
767
768 /* multirange can't contain empty ranges */
769 Assert((flags & RANGE_EMPTY) == 0);
770
771 /* fetch lower bound, if any */
772 if (RANGE_HAS_LBOUND(flags))
773 {
774 /* att_align_pointer cannot be necessary here */
775 lbound = fetch_att(ptr, typbyval, typlen);
776 ptr = (char *) att_addlength_pointer(ptr, typlen, ptr);
777 }
778 else
779 lbound = (Datum) 0;
780
781 /* fetch upper bound, if any */
782 if (RANGE_HAS_UBOUND(flags))
783 {
784 ptr = (char *) att_align_pointer(ptr, typalign, typlen, ptr);
785 ubound = fetch_att(ptr, typbyval, typlen);
786 /* no need for att_addlength_pointer */
787 }
788 else
789 ubound = (Datum) 0;
790
791 /* emit results */
792 lower->val = lbound;
793 lower->infinite = (flags & RANGE_LB_INF) != 0;
794 lower->inclusive = (flags & RANGE_LB_INC) != 0;
795 lower->lower = true;
796
797 upper->val = ubound;
798 upper->infinite = (flags & RANGE_UB_INF) != 0;
799 upper->inclusive = (flags & RANGE_UB_INC) != 0;
800 upper->lower = false;
801}
802
803/*
804 * Construct union range from the multirange.
805 */
806RangeType *
808 const MultirangeType *mr)
809{
811 upper,
812 tmp;
813
816
818 multirange_get_bounds(rangetyp, mr, mr->rangeCount - 1, &tmp, &upper);
819
820 return make_range(rangetyp, &lower, &upper, false, NULL);
821}
822
823
824/*
825 * multirange_deserialize: deconstruct a multirange value
826 *
827 * NB: the given multirange object must be fully detoasted; it cannot have a
828 * short varlena header.
829 */
830void
833 RangeType ***ranges)
834{
835 *range_count = multirange->rangeCount;
836
837 /* Convert each ShortRangeType into a RangeType */
838 if (*range_count > 0)
839 {
840 int i;
841
842 *ranges = palloc_array(RangeType *, *range_count);
843 for (i = 0; i < *range_count; i++)
845 }
846 else
847 {
848 *ranges = NULL;
849 }
850}
851
857
858/*
859 * Similar to range_overlaps_internal(), but takes range bounds instead of
860 * ranges as arguments.
861 */
862static bool
866{
867 if (range_cmp_bounds(typcache, lower1, lower2) >= 0 &&
868 range_cmp_bounds(typcache, lower1, upper2) <= 0)
869 return true;
870
871 if (range_cmp_bounds(typcache, lower2, lower1) >= 0 &&
872 range_cmp_bounds(typcache, lower2, upper1) <= 0)
873 return true;
874
875 return false;
876}
877
878/*
879 * Similar to range_contains_internal(), but takes range bounds instead of
880 * ranges as arguments.
881 */
882static bool
886{
887 if (range_cmp_bounds(typcache, lower1, lower2) <= 0 &&
888 range_cmp_bounds(typcache, upper1, upper2) >= 0)
889 return true;
890
891 return false;
892}
893
894/*
895 * Check if the given key matches any range in multirange using binary search.
896 * If the required range isn't found, that counts as a mismatch. When the
897 * required range is found, the comparison function can still report this as
898 * either match or mismatch. For instance, if we search for containment, we can
899 * found a range, which is overlapping but not containing the key range, and
900 * that would count as a mismatch.
901 */
902static bool
905{
906 uint32 l,
907 u,
908 idx;
909 int comparison;
910 bool match = false;
911
912 l = 0;
913 u = mr->rangeCount;
914 while (l < u)
915 {
917 upper;
918
919 idx = (l + u) / 2;
920 multirange_get_bounds(typcache, mr, idx, &lower, &upper);
921 comparison = (*cmp_func) (typcache, &lower, &upper, key, &match);
922
923 if (comparison < 0)
924 u = idx;
925 else if (comparison > 0)
926 l = idx + 1;
927 else
928 return match;
929 }
930
931 return false;
932}
933
934/*
935 *----------------------------------------------------------
936 * GENERIC FUNCTIONS
937 *----------------------------------------------------------
938 */
939
940/*
941 * Construct multirange value from zero or more ranges. Since this is a
942 * variadic function we get passed an array. The array must contain ranges
943 * that match our return value, and there must be no NULLs.
944 */
945Datum
947{
948 Oid mltrngtypid = get_fn_expr_rettype(fcinfo->flinfo);
950 TypeCacheEntry *typcache;
953 int range_count;
954 Datum *elements;
955 bool *nulls;
956 RangeType **ranges;
957 int dims;
958 int i;
959
960 typcache = multirange_get_typcache(fcinfo, mltrngtypid);
961 rangetyp = typcache->rngtype;
962
963 /*
964 * A no-arg invocation should call multirange_constructor0 instead, but
965 * returning an empty range is what that does.
966 */
967
968 if (PG_NARGS() == 0)
970
971 /*
972 * This check should be guaranteed by our signature, but let's do it just
973 * in case.
974 */
975
976 if (PG_ARGISNULL(0))
977 elog(ERROR,
978 "multirange values cannot contain null members");
979
981
982 dims = ARR_NDIM(rangeArray);
983 if (dims > 1)
986 errmsg("multiranges cannot be constructed from multidimensional arrays")));
987
989 if (rngtypid != rangetyp->type_id)
990 elog(ERROR, "type %u does not match constructor type", rngtypid);
991
992 /*
993 * Be careful: we can still be called with zero ranges, like this:
994 * `int4multirange(variadic '{}'::int4range[])
995 */
996 if (dims == 0)
997 {
998 range_count = 0;
999 ranges = NULL;
1000 }
1001 else
1002 {
1004 rangetyp->typalign, &elements, &nulls, &range_count);
1005
1006 ranges = palloc0(range_count * sizeof(RangeType *));
1007 for (i = 0; i < range_count; i++)
1008 {
1009 if (nulls[i])
1010 ereport(ERROR,
1012 errmsg("multirange values cannot contain null members")));
1013
1014 /* make_multirange will do its own copy */
1015 ranges[i] = DatumGetRangeTypeP(elements[i]);
1016 }
1017 }
1018
1020}
1021
1022/*
1023 * Construct multirange value from a single range. It'd be nice if we could
1024 * just use multirange_constructor2 for this case, but we need a non-variadic
1025 * single-arg function to let us define a CAST from a range to its multirange.
1026 */
1027Datum
1029{
1030 Oid mltrngtypid = get_fn_expr_rettype(fcinfo->flinfo);
1031 Oid rngtypid;
1032 TypeCacheEntry *typcache;
1035
1036 typcache = multirange_get_typcache(fcinfo, mltrngtypid);
1037 rangetyp = typcache->rngtype;
1038
1039 /*
1040 * This check should be guaranteed by our signature, but let's do it just
1041 * in case.
1042 */
1043
1044 if (PG_ARGISNULL(0))
1045 elog(ERROR,
1046 "multirange values cannot contain null members");
1047
1049
1050 /* Make sure the range type matches. */
1052 if (rngtypid != rangetyp->type_id)
1053 elog(ERROR, "type %u does not match constructor type", rngtypid);
1054
1056}
1057
1058/*
1059 * Constructor just like multirange_constructor1, but opr_sanity gets angry
1060 * if the same internal function handles multiple functions with different arg
1061 * counts.
1062 */
1063Datum
1065{
1067 TypeCacheEntry *typcache;
1069
1070 /* This should always be called without arguments */
1071 if (PG_NARGS() != 0)
1072 elog(ERROR,
1073 "niladic multirange constructor must not receive arguments");
1074
1075 mltrngtypid = get_fn_expr_rettype(fcinfo->flinfo);
1076 typcache = multirange_get_typcache(fcinfo, mltrngtypid);
1077 rangetyp = typcache->rngtype;
1078
1080}
1081
1082
1083/* multirange, multirange -> multirange type functions */
1084
1085/* multirange union */
1086Datum
1116
1117/* multirange minus */
1118Datum
1147
1152{
1153 RangeType *r1;
1154 RangeType *r2;
1157 int32 i1;
1158 int32 i2;
1159
1160 /*
1161 * Worst case: every range in ranges1 makes a different cut to some range
1162 * in ranges2.
1163 */
1165 range_count3 = 0;
1166
1167 /*
1168 * For each range in mr1, keep subtracting until it's gone or the ranges
1169 * in mr2 have passed it. After a subtraction we assign what's left back
1170 * to r1. The parallel progress through mr1 and mr2 is similar to
1171 * multirange_overlaps_multirange_internal.
1172 */
1173 r2 = ranges2[0];
1174 for (i1 = 0, i2 = 0; i1 < range_count1; i1++)
1175 {
1176 r1 = ranges1[i1];
1177
1178 /* Discard r2s while r2 << r1 */
1179 while (r2 != NULL && range_before_internal(rangetyp, r2, r1))
1180 {
1181 r2 = ++i2 >= range_count2 ? NULL : ranges2[i2];
1182 }
1183
1184 while (r2 != NULL)
1185 {
1187 {
1188 /*
1189 * If r2 takes a bite out of the middle of r1, we need two
1190 * outputs
1191 */
1192 range_count3++;
1193 r2 = ++i2 >= range_count2 ? NULL : ranges2[i2];
1194 }
1196 {
1197 /*
1198 * If r2 overlaps r1, replace r1 with r1 - r2.
1199 */
1201
1202 /*
1203 * If r2 goes past r1, then we need to stay with it, in case
1204 * it hits future r1s. Otherwise we need to keep r1, in case
1205 * future r2s hit it. Since we already subtracted, there's no
1206 * point in using the overright/overleft calls.
1207 */
1209 break;
1210 else
1211 r2 = ++i2 >= range_count2 ? NULL : ranges2[i2];
1212 }
1213 else
1214 {
1215 /*
1216 * This and all future r2s are past r1, so keep them. Also
1217 * assign whatever is left of r1 to the result.
1218 */
1219 break;
1220 }
1221 }
1222
1223 /*
1224 * Nothing else can remove anything from r1, so keep it. Even if r1 is
1225 * empty here, make_multirange will remove it.
1226 */
1227 ranges3[range_count3++] = r1;
1228 }
1229
1231}
1232
1233/*
1234 * multirange_minus_multi - like multirange_minus but returning the result as a
1235 * SRF, with no rows if the result would be empty.
1236 */
1237Datum
1239{
1241 MemoryContext oldcontext;
1242
1243 if (!SRF_IS_FIRSTCALL())
1244 {
1245 /* We never have more than one result */
1248 }
1249 else
1250 {
1254 TypeCacheEntry *typcache;
1261
1263
1264 /*
1265 * switch to memory context appropriate for multiple function calls
1266 */
1267 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
1268
1269 /* get args, detoasting into multi-call memory context */
1272
1275 if (typcache->rngtype == NULL)
1276 elog(ERROR, "type %u is not a multirange type", mltrngtypoid);
1277 rangetyp = typcache->rngtype;
1278
1280 mr = mr1;
1281 else
1282 {
1285
1287 rangetyp,
1289 ranges1,
1291 ranges2);
1292 }
1293
1294 MemoryContextSwitchTo(oldcontext);
1295
1297 if (MultirangeIsEmpty(mr))
1299 else
1301 }
1302}
1303
1304/* multirange intersection */
1305Datum
1334
1339{
1340 RangeType *r1;
1341 RangeType *r2;
1344 int32 i1;
1345 int32 i2;
1346
1347 if (range_count1 == 0 || range_count2 == 0)
1349
1350 /*-----------------------------------------------
1351 * Worst case is a stitching pattern like this:
1352 *
1353 * mr1: --- --- --- ---
1354 * mr2: --- --- ---
1355 * mr3: - - - - - -
1356 *
1357 * That seems to be range_count1 + range_count2 - 1,
1358 * but one extra won't hurt.
1359 *-----------------------------------------------
1360 */
1362 range_count3 = 0;
1363
1364 /*
1365 * For each range in mr1, keep intersecting until the ranges in mr2 have
1366 * passed it. The parallel progress through mr1 and mr2 is similar to
1367 * multirange_minus_multirange_internal, but we don't have to assign back
1368 * to r1.
1369 */
1370 r2 = ranges2[0];
1371 for (i1 = 0, i2 = 0; i1 < range_count1; i1++)
1372 {
1373 r1 = ranges1[i1];
1374
1375 /* Discard r2s while r2 << r1 */
1376 while (r2 != NULL && range_before_internal(rangetyp, r2, r1))
1377 {
1378 r2 = ++i2 >= range_count2 ? NULL : ranges2[i2];
1379 }
1380
1381 while (r2 != NULL)
1382 {
1384 {
1385 /* Keep the overlapping part */
1387
1388 /* If we "used up" all of r2, go to the next one... */
1390 r2 = ++i2 >= range_count2 ? NULL : ranges2[i2];
1391
1392 /* ...otherwise go to the next r1 */
1393 else
1394 break;
1395 }
1396 else
1397 /* We're past r1, so move to the next one */
1398 break;
1399 }
1400
1401 /* If we're out of r2s, there can be no more intersections */
1402 if (r2 == NULL)
1403 break;
1404 }
1405
1407}
1408
1409/*
1410 * range_agg_transfn: combine adjacent/overlapping ranges.
1411 *
1412 * All we do here is gather the input ranges into an array
1413 * so that the finalfn can sort and combine them.
1414 */
1415Datum
1417{
1419 Oid rngtypoid;
1421
1422 if (!AggCheckCallContext(fcinfo, &aggContext))
1423 elog(ERROR, "range_agg_transfn called in non-aggregate context");
1424
1425 rngtypoid = get_fn_expr_argtype(fcinfo->flinfo, 1);
1427 elog(ERROR, "range_agg must be called with a range");
1428
1429 if (PG_ARGISNULL(0))
1431 else
1433
1434 /* skip NULLs */
1435 if (!PG_ARGISNULL(1))
1437
1439}
1440
1441/*
1442 * range_agg_finalfn: use our internal array to merge touching ranges.
1443 *
1444 * Shared by range_agg_finalfn(anyrange) and
1445 * multirange_agg_finalfn(anymultirange).
1446 */
1447Datum
1449{
1452 TypeCacheEntry *typcache;
1455 RangeType **ranges;
1456 int i;
1457
1458 if (!AggCheckCallContext(fcinfo, &aggContext))
1459 elog(ERROR, "range_agg_finalfn called in non-aggregate context");
1460
1462 if (state == NULL)
1463 /* This shouldn't be possible, but just in case.... */
1465
1466 /* Also return NULL if we had zero inputs, like other aggregates */
1467 range_count = state->nelems;
1468 if (range_count == 0)
1470
1471 mltrngtypoid = get_fn_expr_rettype(fcinfo->flinfo);
1472 typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
1473
1474 ranges = palloc0(range_count * sizeof(RangeType *));
1475 for (i = 0; i < range_count; i++)
1476 ranges[i] = DatumGetRangeTypeP(state->dvalues[i]);
1477
1479}
1480
1481/*
1482 * multirange_agg_transfn: combine adjacent/overlapping multiranges.
1483 *
1484 * All we do here is gather the input multiranges' ranges into an array so
1485 * that the finalfn can sort and combine them.
1486 */
1487Datum
1489{
1492 TypeCacheEntry *typcache;
1495
1496 if (!AggCheckCallContext(fcinfo, &aggContext))
1497 elog(ERROR, "multirange_agg_transfn called in non-aggregate context");
1498
1499 mltrngtypoid = get_fn_expr_argtype(fcinfo->flinfo, 1);
1501 elog(ERROR, "range_agg must be called with a multirange");
1502
1503 typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
1504 rngtypcache = typcache->rngtype;
1505
1506 if (PG_ARGISNULL(0))
1507 state = initArrayResult(rngtypcache->type_id, aggContext, false);
1508 else
1510
1511 /* skip NULLs */
1512 if (!PG_ARGISNULL(1))
1513 {
1514 MultirangeType *current;
1516 RangeType **ranges;
1517
1518 current = PG_GETARG_MULTIRANGE_P(1);
1519 multirange_deserialize(rngtypcache, current, &range_count, &ranges);
1520 if (range_count == 0)
1521 {
1522 /*
1523 * Add an empty range so we get an empty result (not a null
1524 * result).
1525 */
1528 false, rngtypcache->type_id, aggContext);
1529 }
1530 else
1531 {
1532 for (int32 i = 0; i < range_count; i++)
1533 accumArrayResult(state, RangeTypePGetDatum(ranges[i]), false, rngtypcache->type_id, aggContext);
1534 }
1535 }
1536
1538}
1539
1540Datum
1542{
1545 TypeCacheEntry *typcache;
1546 MultirangeType *result;
1547 MultirangeType *current;
1552
1553 if (!AggCheckCallContext(fcinfo, &aggContext))
1554 elog(ERROR, "multirange_intersect_agg_transfn called in non-aggregate context");
1555
1556 mltrngtypoid = get_fn_expr_argtype(fcinfo->flinfo, 1);
1558 elog(ERROR, "range_intersect_agg must be called with a multirange");
1559
1560 typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
1561
1562 /* strictness ensures these are non-null */
1563 result = PG_GETARG_MULTIRANGE_P(0);
1564 current = PG_GETARG_MULTIRANGE_P(1);
1565
1566 multirange_deserialize(typcache->rngtype, result, &range_count1, &ranges1);
1567 multirange_deserialize(typcache->rngtype, current, &range_count2, &ranges2);
1568
1570 typcache->rngtype,
1572 ranges1,
1574 ranges2);
1575 PG_RETURN_MULTIRANGE_P(result);
1576}
1577
1578
1579/* multirange -> element type functions */
1580
1581/* extract lower bound value */
1582Datum
1584{
1586 TypeCacheEntry *typcache;
1589
1590 if (MultirangeIsEmpty(mr))
1592
1593 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1594
1595 multirange_get_bounds(typcache->rngtype, mr, 0,
1596 &lower, &upper);
1597
1598 if (!lower.infinite)
1600 else
1602}
1603
1604/* extract upper bound value */
1605Datum
1607{
1609 TypeCacheEntry *typcache;
1612
1613 if (MultirangeIsEmpty(mr))
1615
1616 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1617
1618 multirange_get_bounds(typcache->rngtype, mr, mr->rangeCount - 1,
1619 &lower, &upper);
1620
1621 if (!upper.infinite)
1623 else
1625}
1626
1627
1628/* multirange -> bool functions */
1629
1630/* is multirange empty? */
1631Datum
1638
1639/* is lower bound inclusive? */
1640Datum
1642{
1644 TypeCacheEntry *typcache;
1647
1648 if (MultirangeIsEmpty(mr))
1649 PG_RETURN_BOOL(false);
1650
1651 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1652 multirange_get_bounds(typcache->rngtype, mr, 0,
1653 &lower, &upper);
1654
1655 PG_RETURN_BOOL(lower.inclusive);
1656}
1657
1658/* is upper bound inclusive? */
1659Datum
1661{
1663 TypeCacheEntry *typcache;
1666
1667 if (MultirangeIsEmpty(mr))
1668 PG_RETURN_BOOL(false);
1669
1670 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1671 multirange_get_bounds(typcache->rngtype, mr, mr->rangeCount - 1,
1672 &lower, &upper);
1673
1674 PG_RETURN_BOOL(upper.inclusive);
1675}
1676
1677/* is lower bound infinite? */
1678Datum
1680{
1682 TypeCacheEntry *typcache;
1685
1686 if (MultirangeIsEmpty(mr))
1687 PG_RETURN_BOOL(false);
1688
1689 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1690 multirange_get_bounds(typcache->rngtype, mr, 0,
1691 &lower, &upper);
1692
1693 PG_RETURN_BOOL(lower.infinite);
1694}
1695
1696/* is upper bound infinite? */
1697Datum
1699{
1701 TypeCacheEntry *typcache;
1704
1705 if (MultirangeIsEmpty(mr))
1706 PG_RETURN_BOOL(false);
1707
1708 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1709 multirange_get_bounds(typcache->rngtype, mr, mr->rangeCount - 1,
1710 &lower, &upper);
1711
1712 PG_RETURN_BOOL(upper.infinite);
1713}
1714
1715
1716
1717/* multirange, element -> bool functions */
1718
1719/* contains? */
1720Datum
1731
1732/* contained by? */
1733Datum
1744
1745/*
1746 * Comparison function for checking if any range of multirange contains given
1747 * key element using binary search.
1748 */
1749static int
1752 void *key, bool *match)
1753{
1754 Datum val = *((Datum *) key);
1755 int cmp;
1756
1757 if (!lower->infinite)
1758 {
1760 typcache->rng_collation,
1761 lower->val, val));
1762 if (cmp > 0 || (cmp == 0 && !lower->inclusive))
1763 return -1;
1764 }
1765
1766 if (!upper->infinite)
1767 {
1769 typcache->rng_collation,
1770 upper->val, val));
1771 if (cmp < 0 || (cmp == 0 && !upper->inclusive))
1772 return 1;
1773 }
1774
1775 *match = true;
1776 return 0;
1777}
1778
1779/*
1780 * Test whether multirange mr contains a specific element value.
1781 */
1782bool
1792
1793/* multirange, range -> bool functions */
1794
1795/* contains? */
1796Datum
1807
1808Datum
1819
1820/* contained by? */
1821Datum
1832
1833Datum
1844
1845/*
1846 * Comparison function for checking if any range of multirange contains given
1847 * key range using binary search.
1848 */
1849static int
1852 void *key, bool *match)
1853{
1854 RangeBound *keyLower = (RangeBound *) key;
1855 RangeBound *keyUpper = (RangeBound *) key + 1;
1856
1857 /* Check if key range is strictly in the left or in the right */
1858 if (range_cmp_bounds(typcache, keyUpper, lower) < 0)
1859 return -1;
1860 if (range_cmp_bounds(typcache, keyLower, upper) > 0)
1861 return 1;
1862
1863 /*
1864 * At this point we found overlapping range. But we have to check if it
1865 * really contains the key range. Anyway, we have to stop our search
1866 * here, because multirange contains only non-overlapping ranges.
1867 */
1868 *match = range_bounds_contains(typcache, lower, upper, keyLower, keyUpper);
1869
1870 return 0;
1871}
1872
1873/*
1874 * Test whether multirange mr contains a specific range r.
1875 */
1876bool
1878 const MultirangeType *mr,
1879 const RangeType *r)
1880{
1881 RangeBound bounds[2];
1882 bool empty;
1883
1884 /*
1885 * Every multirange contains an infinite number of empty ranges, even an
1886 * empty one.
1887 */
1888 if (RangeIsEmpty(r))
1889 return true;
1890
1891 if (MultirangeIsEmpty(mr))
1892 return false;
1893
1894 range_deserialize(rangetyp, r, &bounds[0], &bounds[1], &empty);
1895 Assert(!empty);
1896
1899}
1900
1901/*
1902 * Test whether range r contains a multirange mr.
1903 */
1904bool
1906 const RangeType *r,
1907 const MultirangeType *mr)
1908{
1910 upper1,
1911 lower2,
1912 upper2,
1913 tmp;
1914 bool empty;
1915
1916 /*
1917 * Every range contains an infinite number of empty multiranges, even an
1918 * empty one.
1919 */
1920 if (MultirangeIsEmpty(mr))
1921 return true;
1922
1923 if (RangeIsEmpty(r))
1924 return false;
1925
1926 /* Range contains multirange iff it contains its union range. */
1927 range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
1928 Assert(!empty);
1930 multirange_get_bounds(rangetyp, mr, mr->rangeCount - 1, &tmp, &upper2);
1931
1933}
1934
1935
1936/* multirange, multirange -> bool functions */
1937
1938/* equality (internal version) */
1939bool
1941 const MultirangeType *mr1,
1942 const MultirangeType *mr2)
1943{
1946 int32 i;
1948 upper1,
1949 lower2,
1950 upper2;
1951
1952 /* Different types should be prevented by ANYMULTIRANGE matching rules */
1954 elog(ERROR, "multirange types do not match");
1955
1956 range_count_1 = mr1->rangeCount;
1957 range_count_2 = mr2->rangeCount;
1958
1960 return false;
1961
1962 for (i = 0; i < range_count_1; i++)
1963 {
1966
1967 if (range_cmp_bounds(rangetyp, &lower1, &lower2) != 0 ||
1969 return false;
1970 }
1971
1972 return true;
1973}
1974
1975/* equality */
1976Datum
1987
1988/* inequality (internal version) */
1989bool
1996
1997/* inequality */
1998Datum
2009
2010/* overlaps? */
2011Datum
2022
2023Datum
2034
2035Datum
2046
2047/*
2048 * Comparison function for checking if any range of multirange overlaps given
2049 * key range using binary search.
2050 */
2051static int
2054 void *key, bool *match)
2055{
2056 RangeBound *keyLower = (RangeBound *) key;
2057 RangeBound *keyUpper = (RangeBound *) key + 1;
2058
2059 if (range_cmp_bounds(typcache, keyUpper, lower) < 0)
2060 return -1;
2061 if (range_cmp_bounds(typcache, keyLower, upper) > 0)
2062 return 1;
2063
2064 *match = true;
2065 return 0;
2066}
2067
2068bool
2070 const RangeType *r,
2071 const MultirangeType *mr)
2072{
2073 RangeBound bounds[2];
2074 bool empty;
2075
2076 /*
2077 * Empties never overlap, even with empties. (This seems strange since
2078 * they *do* contain each other, but we want to follow how ranges work.)
2079 */
2081 return false;
2082
2083 range_deserialize(rangetyp, r, &bounds[0], &bounds[1], &empty);
2084 Assert(!empty);
2085
2088}
2089
2090bool
2092 const MultirangeType *mr1,
2093 const MultirangeType *mr2)
2094{
2097 int32 i1;
2098 int32 i2;
2100 upper1,
2101 lower2,
2102 upper2;
2103
2104 /*
2105 * Empties never overlap, even with empties. (This seems strange since
2106 * they *do* contain each other, but we want to follow how ranges work.)
2107 */
2109 return false;
2110
2111 range_count1 = mr1->rangeCount;
2112 range_count2 = mr2->rangeCount;
2113
2114 /*
2115 * Every range in mr1 gets a chance to overlap with the ranges in mr2, but
2116 * we can use their ordering to avoid O(n^2). This is similar to
2117 * range_overlaps_multirange where r1 : r2 :: mrr : r, but there if we
2118 * don't find an overlap with r we're done, and here if we don't find an
2119 * overlap with r2 we try the next r2.
2120 */
2121 i1 = 0;
2123 for (i1 = 0, i2 = 0; i2 < range_count2; i2++)
2124 {
2126
2127 /* Discard r1s while r1 << r2 */
2128 while (range_cmp_bounds(rangetyp, &upper1, &lower2) < 0)
2129 {
2130 if (++i1 >= range_count1)
2131 return false;
2133 }
2134
2135 /*
2136 * If r1 && r2, we're done, otherwise we failed to find an overlap for
2137 * r2, so go to the next one.
2138 */
2140 return true;
2141 }
2142
2143 /* We looked through all of mr2 without finding an overlap */
2144 return false;
2145}
2146
2147/* does not extend to right of? */
2148bool
2150 const RangeType *r,
2151 const MultirangeType *mr)
2152{
2154 upper1,
2155 lower2,
2156 upper2;
2157 bool empty;
2158
2160 return false;
2161
2162 range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
2163 Assert(!empty);
2164 multirange_get_bounds(rangetyp, mr, mr->rangeCount - 1,
2165 &lower2, &upper2);
2166
2167 return (range_cmp_bounds(rangetyp, &upper1, &upper2) <= 0);
2168}
2169
2170Datum
2181
2182Datum
2184{
2187 TypeCacheEntry *typcache;
2189 upper1,
2190 lower2,
2191 upper2;
2192 bool empty;
2193
2195 PG_RETURN_BOOL(false);
2196
2197 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2198
2199 multirange_get_bounds(typcache->rngtype, mr, mr->rangeCount - 1,
2200 &lower1, &upper1);
2201 range_deserialize(typcache->rngtype, r, &lower2, &upper2, &empty);
2202 Assert(!empty);
2203
2205}
2206
2207Datum
2209{
2212 TypeCacheEntry *typcache;
2214 upper1,
2215 lower2,
2216 upper2;
2217
2219 PG_RETURN_BOOL(false);
2220
2222
2223 multirange_get_bounds(typcache->rngtype, mr1, mr1->rangeCount - 1,
2224 &lower1, &upper1);
2225 multirange_get_bounds(typcache->rngtype, mr2, mr2->rangeCount - 1,
2226 &lower2, &upper2);
2227
2229}
2230
2231/* does not extend to left of? */
2232bool
2234 const RangeType *r,
2235 const MultirangeType *mr)
2236{
2238 upper1,
2239 lower2,
2240 upper2;
2241 bool empty;
2242
2244 return false;
2245
2246 range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
2247 Assert(!empty);
2249
2250 return (range_cmp_bounds(rangetyp, &lower1, &lower2) >= 0);
2251}
2252
2253Datum
2264
2265Datum
2267{
2270 TypeCacheEntry *typcache;
2272 upper1,
2273 lower2,
2274 upper2;
2275 bool empty;
2276
2278 PG_RETURN_BOOL(false);
2279
2280 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2281
2282 multirange_get_bounds(typcache->rngtype, mr, 0, &lower1, &upper1);
2283 range_deserialize(typcache->rngtype, r, &lower2, &upper2, &empty);
2284 Assert(!empty);
2285
2287}
2288
2289Datum
2310
2311/* contains? */
2312Datum
2323
2324/* contained by? */
2325Datum
2336
2337/*
2338 * Test whether multirange mr1 contains every range from another multirange mr2.
2339 */
2340bool
2342 const MultirangeType *mr1,
2343 const MultirangeType *mr2)
2344{
2345 int32 range_count1 = mr1->rangeCount;
2346 int32 range_count2 = mr2->rangeCount;
2347 int i1,
2348 i2;
2350 upper1,
2351 lower2,
2352 upper2;
2353
2354 /*
2355 * We follow the same logic for empties as ranges: - an empty multirange
2356 * contains an empty range/multirange. - an empty multirange can't contain
2357 * any other range/multirange. - an empty multirange is contained by any
2358 * other range/multirange.
2359 */
2360
2361 if (range_count2 == 0)
2362 return true;
2363 if (range_count1 == 0)
2364 return false;
2365
2366 /*
2367 * Every range in mr2 must be contained by some range in mr1. To avoid
2368 * O(n^2) we walk through both ranges in tandem.
2369 */
2370 i1 = 0;
2372 for (i2 = 0; i2 < range_count2; i2++)
2373 {
2375
2376 /* Discard r1s while r1 << r2 */
2377 while (range_cmp_bounds(rangetyp, &upper1, &lower2) < 0)
2378 {
2379 if (++i1 >= range_count1)
2380 return false;
2382 }
2383
2384 /*
2385 * If r1 @> r2, go to the next r2, otherwise return false (since every
2386 * r1[n] and r1[n+1] must have a gap). Note this will give weird
2387 * answers if you don't canonicalize, e.g. with a custom
2388 * int2multirange {[1,1], [2,2]} there is a "gap". But that is
2389 * consistent with other range operators, e.g. '[1,1]'::int2range -|-
2390 * '[2,2]'::int2range is false.
2391 */
2393 &lower2, &upper2))
2394 return false;
2395 }
2396
2397 /* All ranges in mr2 are satisfied */
2398 return true;
2399}
2400
2401/* strictly left of? */
2402Datum
2413
2414Datum
2425
2426Datum
2437
2438/* strictly right of? */
2439Datum
2450
2451Datum
2462
2463Datum
2474
2475/* strictly left of? (internal version) */
2476bool
2478 const RangeType *r,
2479 const MultirangeType *mr)
2480{
2482 upper1,
2483 lower2,
2484 upper2;
2485 bool empty;
2486
2488 return false;
2489
2490 range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
2491 Assert(!empty);
2492
2494
2495 return (range_cmp_bounds(rangetyp, &upper1, &lower2) < 0);
2496}
2497
2498bool
2500 const MultirangeType *mr1,
2501 const MultirangeType *mr2)
2502{
2504 upper1,
2505 lower2,
2506 upper2;
2507
2509 return false;
2510
2511 multirange_get_bounds(rangetyp, mr1, mr1->rangeCount - 1,
2512 &lower1, &upper1);
2514 &lower2, &upper2);
2515
2516 return (range_cmp_bounds(rangetyp, &upper1, &lower2) < 0);
2517}
2518
2519/* strictly right of? (internal version) */
2520bool
2522 const RangeType *r,
2523 const MultirangeType *mr)
2524{
2526 upper1,
2527 lower2,
2528 upper2;
2529 bool empty;
2531
2533 return false;
2534
2535 range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
2536 Assert(!empty);
2537
2538 range_count = mr->rangeCount;
2540 &lower2, &upper2);
2541
2542 return (range_cmp_bounds(rangetyp, &lower1, &upper2) > 0);
2543}
2544
2545bool
2547 const RangeType *r,
2548 const MultirangeType *mr)
2549{
2551 upper1,
2552 lower2,
2553 upper2;
2554 bool empty;
2556
2558 return false;
2559
2560 range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
2561 Assert(!empty);
2562
2563 range_count = mr->rangeCount;
2565 &lower2, &upper2);
2566
2568 return true;
2569
2570 if (range_count > 1)
2572 &lower2, &upper2);
2573
2575 return true;
2576
2577 return false;
2578}
2579
2580/* adjacent to? */
2581Datum
2592
2593Datum
2607
2608Datum
2610{
2613 TypeCacheEntry *typcache;
2617 upper1,
2618 lower2,
2619 upper2;
2620
2622 PG_RETURN_BOOL(false);
2623
2625
2626 range_count1 = mr1->rangeCount;
2627 range_count2 = mr2->rangeCount;
2629 &lower1, &upper1);
2630 multirange_get_bounds(typcache->rngtype, mr2, 0,
2631 &lower2, &upper2);
2632 if (bounds_adjacent(typcache->rngtype, upper1, lower2))
2633 PG_RETURN_BOOL(true);
2634
2635 if (range_count1 > 1)
2636 multirange_get_bounds(typcache->rngtype, mr1, 0,
2637 &lower1, &upper1);
2638 if (range_count2 > 1)
2640 &lower2, &upper2);
2641 if (bounds_adjacent(typcache->rngtype, upper2, lower1))
2642 PG_RETURN_BOOL(true);
2643 PG_RETURN_BOOL(false);
2644}
2645
2646/* Btree support */
2647
2648/* btree comparator */
2649Datum
2651{
2657 int32 i;
2658 TypeCacheEntry *typcache;
2659 int cmp = 0; /* If both are empty we'll use this. */
2660
2661 /* Different types should be prevented by ANYMULTIRANGE matching rules */
2663 elog(ERROR, "multirange types do not match");
2664
2666
2667 range_count_1 = mr1->rangeCount;
2668 range_count_2 = mr2->rangeCount;
2669
2670 /* Loop over source data */
2672 for (i = 0; i < range_count_max; i++)
2673 {
2675 upper1,
2676 lower2,
2677 upper2;
2678
2679 /*
2680 * If one multirange is shorter, it's as if it had empty ranges at the
2681 * end to extend its length. An empty range compares earlier than any
2682 * other range, so the shorter multirange comes before the longer.
2683 * This is the same behavior as in other types, e.g. in strings 'aaa'
2684 * < 'aaaaaa'.
2685 */
2686 if (i >= range_count_1)
2687 {
2688 cmp = -1;
2689 break;
2690 }
2691 if (i >= range_count_2)
2692 {
2693 cmp = 1;
2694 break;
2695 }
2696
2699
2700 cmp = range_cmp_bounds(typcache->rngtype, &lower1, &lower2);
2701 if (cmp == 0)
2702 cmp = range_cmp_bounds(typcache->rngtype, &upper1, &upper2);
2703 if (cmp != 0)
2704 break;
2705 }
2706
2707 PG_FREE_IF_COPY(mr1, 0);
2708 PG_FREE_IF_COPY(mr2, 1);
2709
2711}
2712
2713/* inequality operators using the multirange_cmp function */
2714Datum
2716{
2717 int cmp = DatumGetInt32(multirange_cmp(fcinfo));
2718
2719 PG_RETURN_BOOL(cmp < 0);
2720}
2721
2722Datum
2724{
2725 int cmp = DatumGetInt32(multirange_cmp(fcinfo));
2726
2727 PG_RETURN_BOOL(cmp <= 0);
2728}
2729
2730Datum
2732{
2733 int cmp = DatumGetInt32(multirange_cmp(fcinfo));
2734
2735 PG_RETURN_BOOL(cmp >= 0);
2736}
2737
2738Datum
2740{
2741 int cmp = DatumGetInt32(multirange_cmp(fcinfo));
2742
2743 PG_RETURN_BOOL(cmp > 0);
2744}
2745
2746/* multirange -> range functions */
2747
2748/* Find the smallest range that includes everything in the multirange */
2749Datum
2751{
2754 TypeCacheEntry *typcache;
2755 RangeType *result;
2756
2757 typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
2758
2759 if (MultirangeIsEmpty(mr))
2760 {
2761 result = make_empty_range(typcache->rngtype);
2762 }
2763 else if (mr->rangeCount == 1)
2764 {
2765 result = multirange_get_range(typcache->rngtype, mr, 0);
2766 }
2767 else
2768 {
2770 firstUpper,
2771 lastLower,
2772 lastUpper;
2773
2774 multirange_get_bounds(typcache->rngtype, mr, 0,
2776 multirange_get_bounds(typcache->rngtype, mr, mr->rangeCount - 1,
2777 &lastLower, &lastUpper);
2778
2779 result = make_range(typcache->rngtype, &firstLower, &lastUpper,
2780 false, NULL);
2781 }
2782
2783 PG_RETURN_RANGE_P(result);
2784}
2785
2786/* Turn multirange into a set of ranges */
2787Datum
2789{
2790 typedef struct
2791 {
2793 TypeCacheEntry *typcache;
2794 int index;
2796
2799 MemoryContext oldcontext;
2800
2801 /* stuff done only on the first call of the function */
2802 if (SRF_IS_FIRSTCALL())
2803 {
2805
2806 /* create a function context for cross-call persistence */
2808
2809 /*
2810 * switch to memory context appropriate for multiple function calls
2811 */
2812 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
2813
2814 /*
2815 * Get the multirange value and detoast if needed. We can't do this
2816 * earlier because if we have to detoast, we want the detoasted copy
2817 * to be in multi_call_memory_ctx, so it will go away when we're done
2818 * and not before. (If no detoast happens, we assume the originally
2819 * passed multirange will stick around till then.)
2820 */
2822
2823 /* allocate memory for user context */
2825
2826 /* initialize state */
2827 fctx->mr = mr;
2828 fctx->index = 0;
2831
2832 funcctx->user_fctx = fctx;
2833 MemoryContextSwitchTo(oldcontext);
2834 }
2835
2836 /* stuff done on every call of the function */
2838 fctx = funcctx->user_fctx;
2839
2840 if (fctx->index < fctx->mr->rangeCount)
2841 {
2843
2844 range = multirange_get_range(fctx->typcache->rngtype,
2845 fctx->mr,
2846 fctx->index);
2847 fctx->index++;
2848
2850 }
2851 else
2852 {
2853 /* do when there is no more left */
2855 }
2856}
2857
2858/* Hash support */
2859
2860/* hash a multirange value */
2861Datum
2863{
2865 uint32 result = 1;
2866 TypeCacheEntry *typcache,
2867 *scache;
2869 i;
2870
2871 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2872 scache = typcache->rngtype->rngelemtype;
2873 if (!OidIsValid(scache->hash_proc_finfo.fn_oid))
2874 {
2875 scache = lookup_type_cache(scache->type_id,
2877 if (!OidIsValid(scache->hash_proc_finfo.fn_oid))
2878 ereport(ERROR,
2880 errmsg("could not identify a hash function for type %s",
2881 format_type_be(scache->type_id))));
2882 }
2883
2884 range_count = mr->rangeCount;
2885 for (i = 0; i < range_count; i++)
2886 {
2888 upper;
2889 uint8 flags = MultirangeGetFlagsPtr(mr)[i];
2893
2894 multirange_get_bounds(typcache->rngtype, mr, i, &lower, &upper);
2895
2896 if (RANGE_HAS_LBOUND(flags))
2898 typcache->rngtype->rng_collation,
2899 lower.val));
2900 else
2901 lower_hash = 0;
2902
2903 if (RANGE_HAS_UBOUND(flags))
2905 typcache->rngtype->rng_collation,
2906 upper.val));
2907 else
2908 upper_hash = 0;
2909
2910 /* Merge hashes of flags and bounds */
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_UINT32(result);
2926}
2927
2928/*
2929 * Returns 64-bit value by hashing a value to a 64-bit value, with a seed.
2930 * Otherwise, similar to hash_multirange.
2931 */
2932Datum
2934{
2936 Datum seed = PG_GETARG_DATUM(1);
2937 uint64 result = 1;
2938 TypeCacheEntry *typcache,
2939 *scache;
2941 i;
2942
2943 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2944 scache = typcache->rngtype->rngelemtype;
2945 if (!OidIsValid(scache->hash_extended_proc_finfo.fn_oid))
2946 {
2947 scache = lookup_type_cache(scache->type_id,
2949 if (!OidIsValid(scache->hash_extended_proc_finfo.fn_oid))
2950 ereport(ERROR,
2952 errmsg("could not identify a hash function for type %s",
2953 format_type_be(scache->type_id))));
2954 }
2955
2956 range_count = mr->rangeCount;
2957 for (i = 0; i < range_count; i++)
2958 {
2960 upper;
2961 uint8 flags = MultirangeGetFlagsPtr(mr)[i];
2965
2966 multirange_get_bounds(typcache->rngtype, mr, i, &lower, &upper);
2967
2968 if (RANGE_HAS_LBOUND(flags))
2969 lower_hash = DatumGetUInt64(FunctionCall2Coll(&scache->hash_extended_proc_finfo,
2970 typcache->rngtype->rng_collation,
2971 lower.val,
2972 seed));
2973 else
2974 lower_hash = 0;
2975
2976 if (RANGE_HAS_UBOUND(flags))
2977 upper_hash = DatumGetUInt64(FunctionCall2Coll(&scache->hash_extended_proc_finfo,
2978 typcache->rngtype->rng_collation,
2979 upper.val,
2980 seed));
2981 else
2982 upper_hash = 0;
2983
2984 /* Merge hashes of flags and bounds */
2986 DatumGetInt64(seed)));
2990
2991 /*
2992 * Use the same approach as hash_array to combine the individual
2993 * elements' hash values:
2994 */
2995 result = (result << 5) - result + range_hash;
2996 }
2997
2998 PG_FREE_IF_COPY(mr, 0);
2999
3000 PG_RETURN_UINT64(result);
3001}
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)
ArrayBuildState * initArrayResult(Oid element_type, MemoryContext rcontext, bool subcontext)
void deconstruct_array(const ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
uint8_t uint8
Definition c.h:544
#define Max(x, y)
Definition c.h:991
#define VARHDRSZ
Definition c.h:711
#define Assert(condition)
Definition c.h:873
int16_t int16
Definition c.h:541
int32_t int32
Definition c.h:542
uint64_t uint64
Definition c.h:547
uint32_t uint32
Definition c.h:546
#define OidIsValid(objectId)
Definition c.h:788
size_t Size
Definition c.h:619
int errdetail(const char *fmt,...)
Definition elog.c:1216
int errcode(int sqlerrcode)
Definition elog.c:863
int errmsg(const char *fmt,...)
Definition elog.c:1080
#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
#define palloc_object(type)
Definition fe_memutils.h:74
#define palloc_array(type, count)
Definition fe_memutils.h:76
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition fmgr.c:1150
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition fmgr.c:138
bytea * SendFunctionCall(FmgrInfo *flinfo, Datum val)
Definition fmgr.c:1744
bool InputFunctionCallSafe(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod, Node *escontext, Datum *result)
Definition fmgr.c:1585
char * OutputFunctionCall(FmgrInfo *flinfo, Datum val)
Definition fmgr.c:1683
Oid get_fn_expr_argtype(FmgrInfo *flinfo, int argnum)
Definition fmgr.c:1875
Datum FunctionCall1Coll(FmgrInfo *flinfo, Oid collation, Datum arg1)
Definition fmgr.c:1130
Oid get_fn_expr_rettype(FmgrInfo *flinfo)
Definition fmgr.c:1853
Datum ReceiveFunctionCall(FmgrInfo *flinfo, StringInfo buf, Oid typioparam, int32 typmod)
Definition fmgr.c:1697
#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:356
#define PG_RETURN_BYTEA_P(x)
Definition fmgr.h:373
#define PG_GETARG_POINTER(n)
Definition fmgr.h:277
#define PG_RETURN_CSTRING(x)
Definition fmgr.h:364
#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:278
#define PG_RETURN_NULL()
Definition fmgr.h:346
#define PG_RETURN_UINT64(x)
Definition fmgr.h:371
#define PG_RETURN_INT32(x)
Definition fmgr.h:355
#define PG_GETARG_INT32(n)
Definition fmgr.h:269
#define PG_RETURN_DATUM(x)
Definition fmgr.h:354
#define PG_RETURN_POINTER(x)
Definition fmgr.h:363
#define PG_FUNCTION_ARGS
Definition fmgr.h:193
#define PG_RETURN_BOOL(x)
Definition fmgr.h:360
char * format_type_be(Oid type_oid)
#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
long val
Definition informix.c:689
int i
Definition isn.c:77
bool type_is_range(Oid typid)
Definition lsyscache.c:2838
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:2475
bool type_is_multirange(Oid typid)
Definition lsyscache.c:2848
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:1232
void * repalloc(void *pointer, Size size)
Definition mcxt.c:1632
void pfree(void *pointer)
Definition mcxt.c:1616
void * palloc0(Size size)
Definition mcxt.c:1417
char * pnstrdup(const char *in, Size len)
Definition mcxt.c:1792
#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_minus_multi(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)
static Datum MultirangeTypePGetDatum(const MultirangeType *X)
int AggCheckCallContext(FunctionCallInfo fcinfo, MemoryContext *aggcontext)
Definition nodeAgg.c:4607
Datum lower(PG_FUNCTION_ARGS)
Datum upper(PG_FUNCTION_ARGS)
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
static uint32 pg_rotate_left32(uint32 word, int n)
const void size_t len
static char buf[DEFAULT_XLOG_SEG_SIZE]
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)
static uint32 DatumGetUInt32(Datum X)
Definition postgres.h:232
static uint64 DatumGetUInt64(Datum X)
Definition postgres.h:433
static int64 DatumGetInt64(Datum X)
Definition postgres.h:413
uint64_t Datum
Definition postgres.h:70
static int32 DatumGetInt32(Datum X)
Definition postgres.h:212
unsigned int Oid
unsigned int pq_getmsgint(StringInfo msg, int b)
Definition pqformat.c:414
void pq_sendbytes(StringInfo buf, const void *data, int datalen)
Definition pqformat.c:126
void pq_getmsgend(StringInfo msg)
Definition pqformat.c:634
void pq_begintypsend(StringInfo buf)
Definition pqformat.c:325
const char * pq_getmsgbytes(StringInfo msg, int datalen)
Definition pqformat.c:507
bytea * pq_endtypsend(StringInfo buf)
Definition pqformat.c:345
static void pq_sendint32(StringInfo buf, uint32 i)
Definition pqformat.h:144
static int fb(int x)
int range_cmp_bounds(TypeCacheEntry *typcache, const RangeBound *b1, const RangeBound *b2)
bool range_split_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2, RangeType **output1, RangeType **output2)
RangeType * make_range(TypeCacheEntry *typcache, RangeBound *lower, RangeBound *upper, bool empty, struct Node *escontext)
bool bounds_adjacent(TypeCacheEntry *typcache, RangeBound boundA, RangeBound boundB)
Definition rangetypes.c:761
bool range_overlaps_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
Definition rangetypes.c:845
bool range_before_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
Definition rangetypes.c:668
RangeType * range_intersect_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
RangeType * range_minus_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2)
Definition rangetypes.c:997
void range_deserialize(TypeCacheEntry *typcache, const RangeType *range, RangeBound *lower, RangeBound *upper, bool *empty)
RangeType * range_union_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2, bool strict)
bool range_adjacent_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
Definition rangetypes.c:802
bool range_overleft_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
Definition rangetypes.c:891
int range_compare(const void *key1, const void *key2, void *arg)
RangeType * make_empty_range(TypeCacheEntry *typcache)
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)
static struct cvec * range(struct vars *v, chr a, chr b, int cases)
struct StringInfoData * StringInfo
Definition string.h:15
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
void * fn_extra
Definition fmgr.h:64
MemoryContext fn_mcxt
Definition fmgr.h:65
FmgrInfo * flinfo
Definition fmgr.h:87
TypeCacheEntry * typcache
Definition nodes.h:135
FmgrInfo rng_cmp_proc_finfo
Definition typcache.h:102
struct TypeCacheEntry * rngelemtype
Definition typcache.h:99
struct TypeCacheEntry * rngtype
Definition typcache.h:109
Definition type.h:96
Definition c.h:706
static ItemArray items
#define att_align_pointer(cur_offset, attalign, attlen, attptr)
Definition tupmacs.h:150
#define att_nominal_alignby(cur_offset, attalignby)
Definition tupmacs.h:189
#define att_addlength_pointer(cur_offset, attlen, attptr)
Definition tupmacs.h:209
static uint8 typalign_to_alignby(char typalign)
Definition tupmacs.h:80
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