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
351 /* palloc_array will enforce a more-or-less-sane range_count value */
353
355 for (int i = 0; i < range_count; i++)
356 {
358 const char *range_data = pq_getmsgbytes(buf, range_len);
359
362
364 &tmpbuf,
365 cache->typioparam,
366 typmod));
367 }
369
371
373 range_count, ranges);
375}
376
377Datum
410
411/*
412 * get_multirange_io_data: get cached information needed for multirange type I/O
413 *
414 * The multirange I/O functions need a bit more cached info than other multirange
415 * functions, so they store a MultirangeIOData struct in fn_extra, not just a
416 * pointer to a type cache entry.
417 */
418static MultirangeIOData *
420{
421 MultirangeIOData *cache = (MultirangeIOData *) fcinfo->flinfo->fn_extra;
422
423 if (cache == NULL || cache->typcache->type_id != mltrngtypid)
424 {
425 Oid typiofunc;
426 int16 typlen;
427 bool typbyval;
428 char typalign;
429 char typdelim;
430
432 sizeof(MultirangeIOData));
434 if (cache->typcache->rngtype == NULL)
435 elog(ERROR, "type %u is not a multirange type", mltrngtypid);
436
437 /* get_type_io_data does more than we need, but is convenient */
439 func,
440 &typlen,
441 &typbyval,
442 &typalign,
443 &typdelim,
444 &cache->typioparam,
445 &typiofunc);
446
447 if (!OidIsValid(typiofunc))
448 {
449 /* this could only happen for receive or send */
450 if (func == IOFunc_receive)
453 errmsg("no binary input function available for type %s",
455 else
458 errmsg("no binary output function available for type %s",
460 }
461 fmgr_info_cxt(typiofunc, &cache->typioproc,
462 fcinfo->flinfo->fn_mcxt);
463
464 fcinfo->flinfo->fn_extra = cache;
465 }
466
467 return cache;
468}
469
470/*
471 * Converts a list of arbitrary ranges into a list that is sorted and merged.
472 * Changes the contents of `ranges`.
473 *
474 * Returns the number of slots actually used, which may be less than
475 * input_range_count but never more.
476 *
477 * We assume that no input ranges are null, but empties are okay.
478 */
479static int32
481 RangeType **ranges)
482{
485 int32 i;
487
488 /* Sort the ranges so we can find the ones that overlap/meet. */
489 if (ranges != NULL)
490 qsort_arg(ranges, input_range_count, sizeof(RangeType *),
492
493 /* Now merge where possible: */
494 for (i = 0; i < input_range_count; i++)
495 {
496 currentRange = ranges[i];
498 continue;
499
500 if (lastRange == NULL)
501 {
503 continue;
504 }
505
506 /*
507 * range_adjacent_internal gives true if *either* A meets B or B meets
508 * A, which is not quite want we want, but we rely on the sorting
509 * above to rule out B meets A ever happening.
510 */
512 {
513 /* The two ranges touch (without overlap), so merge them: */
514 ranges[output_range_count - 1] = lastRange =
516 }
518 {
519 /* There's a gap, so make a new entry: */
522 }
523 else
524 {
525 /* They must overlap, so merge them: */
526 ranges[output_range_count - 1] = lastRange =
528 }
529 }
530
531 return output_range_count;
532}
533
534/*
535 *----------------------------------------------------------
536 * SUPPORT FUNCTIONS
537 *
538 * These functions aren't in pg_proc, but are useful for
539 * defining new generic multirange functions in C.
540 *----------------------------------------------------------
541 */
542
543/*
544 * multirange_get_typcache: get cached information about a multirange type
545 *
546 * This is for use by multirange-related functions that follow the convention
547 * of using the fn_extra field as a pointer to the type cache entry for
548 * the multirange type. Functions that need to cache more information than
549 * that must fend for themselves.
550 */
553{
554 TypeCacheEntry *typcache = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
555
556 if (typcache == NULL ||
557 typcache->type_id != mltrngtypid)
558 {
560 if (typcache->rngtype == NULL)
561 elog(ERROR, "type %u is not a multirange type", mltrngtypid);
562 fcinfo->flinfo->fn_extra = typcache;
563 }
564
565 return typcache;
566}
567
568
569/*
570 * Estimate size occupied by serialized multirange.
571 */
572static Size
574 RangeType **ranges)
575{
576 char elemalign = rangetyp->rngelemtype->typalign;
578 Size size;
579 int32 i;
580
581 /*
582 * Count space for MultirangeType struct, items and flags.
583 */
584 size = att_nominal_alignby(sizeof(MultirangeType) +
585 Max(range_count - 1, 0) * sizeof(uint32) +
586 range_count * sizeof(uint8), elemalignby);
587
588 /* Count space for range bounds */
589 for (i = 0; i < range_count; i++)
590 size += att_nominal_alignby(VARSIZE(ranges[i]) -
591 sizeof(RangeType) -
592 sizeof(char), elemalignby);
593
594 return size;
595}
596
597/*
598 * Write multirange data into pre-allocated space.
599 */
600static void
602 int32 range_count, RangeType **ranges)
603{
604 uint32 *items;
606 uint8 *flags;
607 int32 i;
608 const char *begin;
609 char *ptr;
610 char elemalign = rangetyp->rngelemtype->typalign;
612
615 begin = ptr = MultirangeGetBoundariesPtr(multirange, elemalign);
616 for (i = 0; i < range_count; i++)
617 {
618 uint32 len;
619
620 if (i > 0)
621 {
622 /*
623 * Every range, except the first one, has an item. Every
624 * MULTIRANGE_ITEM_OFFSET_STRIDE item contains an offset, others
625 * contain lengths.
626 */
627 items[i - 1] = ptr - begin;
628 if ((i % MULTIRANGE_ITEM_OFFSET_STRIDE) != 0)
629 items[i - 1] -= prev_offset;
630 else
632 prev_offset = ptr - begin;
633 }
634 flags[i] = *((char *) ranges[i] + VARSIZE(ranges[i]) - sizeof(char));
635 len = VARSIZE(ranges[i]) - sizeof(RangeType) - sizeof(char);
636 memcpy(ptr, ranges[i] + 1, len);
638 }
639}
640
641
642/*
643 * This serializes the multirange from a list of non-null ranges. It also
644 * sorts the ranges and merges any that touch. The ranges should already be
645 * detoasted, and there should be no NULLs. This should be used by most
646 * callers.
647 *
648 * Note that we may change the `ranges` parameter (the pointers, but not
649 * any already-existing RangeType contents).
650 */
653 RangeType **ranges)
654{
656 Size size;
657
658 /* Sort and merge input ranges. */
660
661 /* Note: zero-fill is required here, just as in heap tuples */
663 multirange = palloc0(size);
664 SET_VARSIZE(multirange, size);
665
666 /* Now fill in the datum */
667 multirange->multirangetypid = mltrngtypoid;
668 multirange->rangeCount = range_count;
669
671
672 return multirange;
673}
674
675/*
676 * Get offset of bounds values of the i'th range in the multirange.
677 */
678static uint32
680{
682 uint32 offset = 0;
683
684 /*
685 * Summarize lengths till we meet an offset.
686 */
687 while (i > 0)
688 {
689 offset += MULTIRANGE_ITEM_GET_OFFLEN(items[i - 1]);
691 break;
692 i--;
693 }
694 return offset;
695}
696
697/*
698 * Fetch the i'th range from the multirange.
699 */
700RangeType *
702 const MultirangeType *multirange, int i)
703{
704 uint32 offset;
705 uint8 flags;
706 const char *begin;
707 char *ptr;
708 int16 typlen = rangetyp->rngelemtype->typlen;
709 char typalign = rangetyp->rngelemtype->typalign;
710 uint32 len;
712
713 Assert(i < multirange->rangeCount);
714
717 begin = ptr = MultirangeGetBoundariesPtr(multirange, typalign) + offset;
718
719 /*
720 * Calculate the size of bound values. In principle, we could get offset
721 * of the next range bound values and calculate accordingly. But range
722 * bound values are aligned, so we have to walk the values to get the
723 * exact size.
724 */
725 if (RANGE_HAS_LBOUND(flags))
726 ptr = (char *) att_addlength_pointer(ptr, typlen, ptr);
727 if (RANGE_HAS_UBOUND(flags))
728 {
729 ptr = (char *) att_align_pointer(ptr, typalign, typlen, ptr);
730 ptr = (char *) att_addlength_pointer(ptr, typlen, ptr);
731 }
732 len = (ptr - begin) + sizeof(RangeType) + sizeof(uint8);
733
734 range = palloc0(len);
736 range->rangetypid = rangetyp->type_id;
737
738 memcpy(range + 1, begin, ptr - begin);
739 *((uint8 *) (range + 1) + (ptr - begin)) = flags;
740
741 return range;
742}
743
744/*
745 * Fetch bounds from the i'th range of the multirange. This is the shortcut for
746 * doing the same thing as multirange_get_range() + range_deserialize(), but
747 * performing fewer operations.
748 */
749void
753{
754 uint32 offset;
755 uint8 flags;
756 const char *ptr;
757 int16 typlen = rangetyp->rngelemtype->typlen;
758 char typalign = rangetyp->rngelemtype->typalign;
759 bool typbyval = rangetyp->rngelemtype->typbyval;
760 Datum lbound;
762
763 Assert(i < multirange->rangeCount);
764
768
769 /* multirange can't contain empty ranges */
770 Assert((flags & RANGE_EMPTY) == 0);
771
772 /* fetch lower bound, if any */
773 if (RANGE_HAS_LBOUND(flags))
774 {
775 /* att_align_pointer cannot be necessary here */
776 lbound = fetch_att(ptr, typbyval, typlen);
777 ptr = (char *) att_addlength_pointer(ptr, typlen, ptr);
778 }
779 else
780 lbound = (Datum) 0;
781
782 /* fetch upper bound, if any */
783 if (RANGE_HAS_UBOUND(flags))
784 {
785 ptr = (char *) att_align_pointer(ptr, typalign, typlen, ptr);
786 ubound = fetch_att(ptr, typbyval, typlen);
787 /* no need for att_addlength_pointer */
788 }
789 else
790 ubound = (Datum) 0;
791
792 /* emit results */
793 lower->val = lbound;
794 lower->infinite = (flags & RANGE_LB_INF) != 0;
795 lower->inclusive = (flags & RANGE_LB_INC) != 0;
796 lower->lower = true;
797
798 upper->val = ubound;
799 upper->infinite = (flags & RANGE_UB_INF) != 0;
800 upper->inclusive = (flags & RANGE_UB_INC) != 0;
801 upper->lower = false;
802}
803
804/*
805 * Construct union range from the multirange.
806 */
807RangeType *
809 const MultirangeType *mr)
810{
812 upper,
813 tmp;
814
817
819 multirange_get_bounds(rangetyp, mr, mr->rangeCount - 1, &tmp, &upper);
820
821 return make_range(rangetyp, &lower, &upper, false, NULL);
822}
823
824
825/*
826 * multirange_deserialize: deconstruct a multirange value
827 *
828 * NB: the given multirange object must be fully detoasted; it cannot have a
829 * short varlena header.
830 */
831void
834 RangeType ***ranges)
835{
836 *range_count = multirange->rangeCount;
837
838 /* Convert each ShortRangeType into a RangeType */
839 if (*range_count > 0)
840 {
841 int i;
842
843 *ranges = palloc_array(RangeType *, *range_count);
844 for (i = 0; i < *range_count; i++)
846 }
847 else
848 {
849 *ranges = NULL;
850 }
851}
852
858
859/*
860 * Similar to range_overlaps_internal(), but takes range bounds instead of
861 * ranges as arguments.
862 */
863static bool
867{
868 if (range_cmp_bounds(typcache, lower1, lower2) >= 0 &&
869 range_cmp_bounds(typcache, lower1, upper2) <= 0)
870 return true;
871
872 if (range_cmp_bounds(typcache, lower2, lower1) >= 0 &&
873 range_cmp_bounds(typcache, lower2, upper1) <= 0)
874 return true;
875
876 return false;
877}
878
879/*
880 * Similar to range_contains_internal(), but takes range bounds instead of
881 * ranges as arguments.
882 */
883static bool
887{
888 if (range_cmp_bounds(typcache, lower1, lower2) <= 0 &&
889 range_cmp_bounds(typcache, upper1, upper2) >= 0)
890 return true;
891
892 return false;
893}
894
895/*
896 * Check if the given key matches any range in multirange using binary search.
897 * If the required range isn't found, that counts as a mismatch. When the
898 * required range is found, the comparison function can still report this as
899 * either match or mismatch. For instance, if we search for containment, we can
900 * found a range, which is overlapping but not containing the key range, and
901 * that would count as a mismatch.
902 */
903static bool
906{
907 uint32 l,
908 u,
909 idx;
910 int comparison;
911 bool match = false;
912
913 l = 0;
914 u = mr->rangeCount;
915 while (l < u)
916 {
918 upper;
919
920 idx = (l + u) / 2;
921 multirange_get_bounds(typcache, mr, idx, &lower, &upper);
922 comparison = (*cmp_func) (typcache, &lower, &upper, key, &match);
923
924 if (comparison < 0)
925 u = idx;
926 else if (comparison > 0)
927 l = idx + 1;
928 else
929 return match;
930 }
931
932 return false;
933}
934
935/*
936 *----------------------------------------------------------
937 * GENERIC FUNCTIONS
938 *----------------------------------------------------------
939 */
940
941/*
942 * Construct multirange value from zero or more ranges. Since this is a
943 * variadic function we get passed an array. The array must contain ranges
944 * that match our return value, and there must be no NULLs.
945 */
946Datum
948{
949 Oid mltrngtypid = get_fn_expr_rettype(fcinfo->flinfo);
951 TypeCacheEntry *typcache;
954 int range_count;
955 Datum *elements;
956 bool *nulls;
957 RangeType **ranges;
958 int dims;
959 int i;
960
961 typcache = multirange_get_typcache(fcinfo, mltrngtypid);
962 rangetyp = typcache->rngtype;
963
964 /*
965 * A no-arg invocation should call multirange_constructor0 instead, but
966 * returning an empty range is what that does.
967 */
968
969 if (PG_NARGS() == 0)
971
972 /*
973 * This check should be guaranteed by our signature, but let's do it just
974 * in case.
975 */
976
977 if (PG_ARGISNULL(0))
978 elog(ERROR,
979 "multirange values cannot contain null members");
980
982
983 dims = ARR_NDIM(rangeArray);
984 if (dims > 1)
987 errmsg("multiranges cannot be constructed from multidimensional arrays")));
988
990 if (rngtypid != rangetyp->type_id)
991 elog(ERROR, "type %u does not match constructor type", rngtypid);
992
993 /*
994 * Be careful: we can still be called with zero ranges, like this:
995 * `int4multirange(variadic '{}'::int4range[])
996 */
997 if (dims == 0)
998 {
999 range_count = 0;
1000 ranges = NULL;
1001 }
1002 else
1003 {
1005 rangetyp->typalign, &elements, &nulls, &range_count);
1006
1007 ranges = palloc0(range_count * sizeof(RangeType *));
1008 for (i = 0; i < range_count; i++)
1009 {
1010 if (nulls[i])
1011 ereport(ERROR,
1013 errmsg("multirange values cannot contain null members")));
1014
1015 /* make_multirange will do its own copy */
1016 ranges[i] = DatumGetRangeTypeP(elements[i]);
1017 }
1018 }
1019
1021}
1022
1023/*
1024 * Construct multirange value from a single range. It'd be nice if we could
1025 * just use multirange_constructor2 for this case, but we need a non-variadic
1026 * single-arg function to let us define a CAST from a range to its multirange.
1027 */
1028Datum
1030{
1031 Oid mltrngtypid = get_fn_expr_rettype(fcinfo->flinfo);
1032 Oid rngtypid;
1033 TypeCacheEntry *typcache;
1036
1037 typcache = multirange_get_typcache(fcinfo, mltrngtypid);
1038 rangetyp = typcache->rngtype;
1039
1040 /*
1041 * This check should be guaranteed by our signature, but let's do it just
1042 * in case.
1043 */
1044
1045 if (PG_ARGISNULL(0))
1046 elog(ERROR,
1047 "multirange values cannot contain null members");
1048
1050
1051 /* Make sure the range type matches. */
1053 if (rngtypid != rangetyp->type_id)
1054 elog(ERROR, "type %u does not match constructor type", rngtypid);
1055
1057}
1058
1059/*
1060 * Constructor just like multirange_constructor1, but opr_sanity gets angry
1061 * if the same internal function handles multiple functions with different arg
1062 * counts.
1063 */
1064Datum
1066{
1068 TypeCacheEntry *typcache;
1070
1071 /* This should always be called without arguments */
1072 if (PG_NARGS() != 0)
1073 elog(ERROR,
1074 "niladic multirange constructor must not receive arguments");
1075
1076 mltrngtypid = get_fn_expr_rettype(fcinfo->flinfo);
1077 typcache = multirange_get_typcache(fcinfo, mltrngtypid);
1078 rangetyp = typcache->rngtype;
1079
1081}
1082
1083
1084/* multirange, multirange -> multirange type functions */
1085
1086/* multirange union */
1087Datum
1117
1118/* multirange minus */
1119Datum
1148
1153{
1154 RangeType *r1;
1155 RangeType *r2;
1158 int32 i1;
1159 int32 i2;
1160
1161 /*
1162 * Worst case: every range in ranges1 makes a different cut to some range
1163 * in ranges2.
1164 */
1166 range_count3 = 0;
1167
1168 /*
1169 * For each range in mr1, keep subtracting until it's gone or the ranges
1170 * in mr2 have passed it. After a subtraction we assign what's left back
1171 * to r1. The parallel progress through mr1 and mr2 is similar to
1172 * multirange_overlaps_multirange_internal.
1173 */
1174 r2 = ranges2[0];
1175 for (i1 = 0, i2 = 0; i1 < range_count1; i1++)
1176 {
1177 r1 = ranges1[i1];
1178
1179 /* Discard r2s while r2 << r1 */
1180 while (r2 != NULL && range_before_internal(rangetyp, r2, r1))
1181 {
1182 r2 = ++i2 >= range_count2 ? NULL : ranges2[i2];
1183 }
1184
1185 while (r2 != NULL)
1186 {
1188 {
1189 /*
1190 * If r2 takes a bite out of the middle of r1, we need two
1191 * outputs
1192 */
1193 range_count3++;
1194 r2 = ++i2 >= range_count2 ? NULL : ranges2[i2];
1195 }
1197 {
1198 /*
1199 * If r2 overlaps r1, replace r1 with r1 - r2.
1200 */
1202
1203 /*
1204 * If r2 goes past r1, then we need to stay with it, in case
1205 * it hits future r1s. Otherwise we need to keep r1, in case
1206 * future r2s hit it. Since we already subtracted, there's no
1207 * point in using the overright/overleft calls.
1208 */
1210 break;
1211 else
1212 r2 = ++i2 >= range_count2 ? NULL : ranges2[i2];
1213 }
1214 else
1215 {
1216 /*
1217 * This and all future r2s are past r1, so keep them. Also
1218 * assign whatever is left of r1 to the result.
1219 */
1220 break;
1221 }
1222 }
1223
1224 /*
1225 * Nothing else can remove anything from r1, so keep it. Even if r1 is
1226 * empty here, make_multirange will remove it.
1227 */
1228 ranges3[range_count3++] = r1;
1229 }
1230
1232}
1233
1234/*
1235 * multirange_minus_multi - like multirange_minus but returning the result as a
1236 * SRF, with no rows if the result would be empty.
1237 */
1238Datum
1240{
1242 MemoryContext oldcontext;
1243
1244 if (!SRF_IS_FIRSTCALL())
1245 {
1246 /* We never have more than one result */
1249 }
1250 else
1251 {
1255 TypeCacheEntry *typcache;
1262
1264
1265 /*
1266 * switch to memory context appropriate for multiple function calls
1267 */
1268 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
1269
1270 /* get args, detoasting into multi-call memory context */
1273
1276 if (typcache->rngtype == NULL)
1277 elog(ERROR, "type %u is not a multirange type", mltrngtypoid);
1278 rangetyp = typcache->rngtype;
1279
1281 mr = mr1;
1282 else
1283 {
1286
1288 rangetyp,
1290 ranges1,
1292 ranges2);
1293 }
1294
1295 MemoryContextSwitchTo(oldcontext);
1296
1298 if (MultirangeIsEmpty(mr))
1300 else
1302 }
1303}
1304
1305/* multirange intersection */
1306Datum
1335
1340{
1341 RangeType *r1;
1342 RangeType *r2;
1345 int32 i1;
1346 int32 i2;
1347
1348 if (range_count1 == 0 || range_count2 == 0)
1350
1351 /*-----------------------------------------------
1352 * Worst case is a stitching pattern like this:
1353 *
1354 * mr1: --- --- --- ---
1355 * mr2: --- --- ---
1356 * mr3: - - - - - -
1357 *
1358 * That seems to be range_count1 + range_count2 - 1,
1359 * but one extra won't hurt.
1360 *-----------------------------------------------
1361 */
1363 range_count3 = 0;
1364
1365 /*
1366 * For each range in mr1, keep intersecting until the ranges in mr2 have
1367 * passed it. The parallel progress through mr1 and mr2 is similar to
1368 * multirange_minus_multirange_internal, but we don't have to assign back
1369 * to r1.
1370 */
1371 r2 = ranges2[0];
1372 for (i1 = 0, i2 = 0; i1 < range_count1; i1++)
1373 {
1374 r1 = ranges1[i1];
1375
1376 /* Discard r2s while r2 << r1 */
1377 while (r2 != NULL && range_before_internal(rangetyp, r2, r1))
1378 {
1379 r2 = ++i2 >= range_count2 ? NULL : ranges2[i2];
1380 }
1381
1382 while (r2 != NULL)
1383 {
1385 {
1386 /* Keep the overlapping part */
1388
1389 /* If we "used up" all of r2, go to the next one... */
1391 r2 = ++i2 >= range_count2 ? NULL : ranges2[i2];
1392
1393 /* ...otherwise go to the next r1 */
1394 else
1395 break;
1396 }
1397 else
1398 /* We're past r1, so move to the next one */
1399 break;
1400 }
1401
1402 /* If we're out of r2s, there can be no more intersections */
1403 if (r2 == NULL)
1404 break;
1405 }
1406
1408}
1409
1410/*
1411 * range_agg_transfn: combine adjacent/overlapping ranges.
1412 *
1413 * All we do here is gather the input ranges into an array
1414 * so that the finalfn can sort and combine them.
1415 */
1416Datum
1418{
1420 Oid rngtypoid;
1422
1423 if (!AggCheckCallContext(fcinfo, &aggContext))
1424 elog(ERROR, "range_agg_transfn called in non-aggregate context");
1425
1426 rngtypoid = get_fn_expr_argtype(fcinfo->flinfo, 1);
1428 elog(ERROR, "range_agg must be called with a range");
1429
1430 if (PG_ARGISNULL(0))
1432 else
1434
1435 /* skip NULLs */
1436 if (!PG_ARGISNULL(1))
1438
1440}
1441
1442/*
1443 * range_agg_finalfn: use our internal array to merge touching ranges.
1444 *
1445 * Shared by range_agg_finalfn(anyrange) and
1446 * multirange_agg_finalfn(anymultirange).
1447 */
1448Datum
1450{
1453 TypeCacheEntry *typcache;
1456 RangeType **ranges;
1457 int i;
1458
1459 if (!AggCheckCallContext(fcinfo, &aggContext))
1460 elog(ERROR, "range_agg_finalfn called in non-aggregate context");
1461
1463 if (state == NULL)
1464 /* This shouldn't be possible, but just in case.... */
1466
1467 /* Also return NULL if we had zero inputs, like other aggregates */
1468 range_count = state->nelems;
1469 if (range_count == 0)
1471
1472 mltrngtypoid = get_fn_expr_rettype(fcinfo->flinfo);
1473 typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
1474
1475 ranges = palloc0(range_count * sizeof(RangeType *));
1476 for (i = 0; i < range_count; i++)
1477 ranges[i] = DatumGetRangeTypeP(state->dvalues[i]);
1478
1480}
1481
1482/*
1483 * multirange_agg_transfn: combine adjacent/overlapping multiranges.
1484 *
1485 * All we do here is gather the input multiranges' ranges into an array so
1486 * that the finalfn can sort and combine them.
1487 */
1488Datum
1490{
1493 TypeCacheEntry *typcache;
1496
1497 if (!AggCheckCallContext(fcinfo, &aggContext))
1498 elog(ERROR, "multirange_agg_transfn called in non-aggregate context");
1499
1500 mltrngtypoid = get_fn_expr_argtype(fcinfo->flinfo, 1);
1502 elog(ERROR, "range_agg must be called with a multirange");
1503
1504 typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
1505 rngtypcache = typcache->rngtype;
1506
1507 if (PG_ARGISNULL(0))
1508 state = initArrayResult(rngtypcache->type_id, aggContext, false);
1509 else
1511
1512 /* skip NULLs */
1513 if (!PG_ARGISNULL(1))
1514 {
1515 MultirangeType *current;
1517 RangeType **ranges;
1518
1519 current = PG_GETARG_MULTIRANGE_P(1);
1520 multirange_deserialize(rngtypcache, current, &range_count, &ranges);
1521 if (range_count == 0)
1522 {
1523 /*
1524 * Add an empty range so we get an empty result (not a null
1525 * result).
1526 */
1529 false, rngtypcache->type_id, aggContext);
1530 }
1531 else
1532 {
1533 for (int32 i = 0; i < range_count; i++)
1534 accumArrayResult(state, RangeTypePGetDatum(ranges[i]), false, rngtypcache->type_id, aggContext);
1535 }
1536 }
1537
1539}
1540
1541Datum
1543{
1546 TypeCacheEntry *typcache;
1548 MultirangeType *current;
1553
1554 if (!AggCheckCallContext(fcinfo, &aggContext))
1555 elog(ERROR, "multirange_intersect_agg_transfn called in non-aggregate context");
1556
1557 mltrngtypoid = get_fn_expr_argtype(fcinfo->flinfo, 1);
1559 elog(ERROR, "range_intersect_agg must be called with a multirange");
1560
1561 typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
1562
1563 /* strictness ensures these are non-null */
1565 current = PG_GETARG_MULTIRANGE_P(1);
1566
1568 multirange_deserialize(typcache->rngtype, current, &range_count2, &ranges2);
1569
1571 typcache->rngtype,
1573 ranges1,
1575 ranges2);
1577}
1578
1579
1580/* multirange -> element type functions */
1581
1582/* extract lower bound value */
1583Datum
1585{
1587 TypeCacheEntry *typcache;
1590
1591 if (MultirangeIsEmpty(mr))
1593
1594 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1595
1596 multirange_get_bounds(typcache->rngtype, mr, 0,
1597 &lower, &upper);
1598
1599 if (!lower.infinite)
1601 else
1603}
1604
1605/* extract upper bound value */
1606Datum
1608{
1610 TypeCacheEntry *typcache;
1613
1614 if (MultirangeIsEmpty(mr))
1616
1617 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1618
1619 multirange_get_bounds(typcache->rngtype, mr, mr->rangeCount - 1,
1620 &lower, &upper);
1621
1622 if (!upper.infinite)
1624 else
1626}
1627
1628
1629/* multirange -> bool functions */
1630
1631/* is multirange empty? */
1632Datum
1639
1640/* is lower bound inclusive? */
1641Datum
1643{
1645 TypeCacheEntry *typcache;
1648
1649 if (MultirangeIsEmpty(mr))
1650 PG_RETURN_BOOL(false);
1651
1652 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1653 multirange_get_bounds(typcache->rngtype, mr, 0,
1654 &lower, &upper);
1655
1656 PG_RETURN_BOOL(lower.inclusive);
1657}
1658
1659/* is upper bound inclusive? */
1660Datum
1662{
1664 TypeCacheEntry *typcache;
1667
1668 if (MultirangeIsEmpty(mr))
1669 PG_RETURN_BOOL(false);
1670
1671 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1672 multirange_get_bounds(typcache->rngtype, mr, mr->rangeCount - 1,
1673 &lower, &upper);
1674
1675 PG_RETURN_BOOL(upper.inclusive);
1676}
1677
1678/* is lower bound infinite? */
1679Datum
1681{
1683 TypeCacheEntry *typcache;
1686
1687 if (MultirangeIsEmpty(mr))
1688 PG_RETURN_BOOL(false);
1689
1690 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1691 multirange_get_bounds(typcache->rngtype, mr, 0,
1692 &lower, &upper);
1693
1694 PG_RETURN_BOOL(lower.infinite);
1695}
1696
1697/* is upper bound infinite? */
1698Datum
1700{
1702 TypeCacheEntry *typcache;
1705
1706 if (MultirangeIsEmpty(mr))
1707 PG_RETURN_BOOL(false);
1708
1709 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1710 multirange_get_bounds(typcache->rngtype, mr, mr->rangeCount - 1,
1711 &lower, &upper);
1712
1713 PG_RETURN_BOOL(upper.infinite);
1714}
1715
1716
1717
1718/* multirange, element -> bool functions */
1719
1720/* contains? */
1721Datum
1732
1733/* contained by? */
1734Datum
1745
1746/*
1747 * Comparison function for checking if any range of multirange contains given
1748 * key element using binary search.
1749 */
1750static int
1753 void *key, bool *match)
1754{
1755 Datum val = *((Datum *) key);
1756 int cmp;
1757
1758 if (!lower->infinite)
1759 {
1761 typcache->rng_collation,
1762 lower->val, val));
1763 if (cmp > 0 || (cmp == 0 && !lower->inclusive))
1764 return -1;
1765 }
1766
1767 if (!upper->infinite)
1768 {
1770 typcache->rng_collation,
1771 upper->val, val));
1772 if (cmp < 0 || (cmp == 0 && !upper->inclusive))
1773 return 1;
1774 }
1775
1776 *match = true;
1777 return 0;
1778}
1779
1780/*
1781 * Test whether multirange mr contains a specific element value.
1782 */
1783bool
1793
1794/* multirange, range -> bool functions */
1795
1796/* contains? */
1797Datum
1808
1809Datum
1820
1821/* contained by? */
1822Datum
1833
1834Datum
1845
1846/*
1847 * Comparison function for checking if any range of multirange contains given
1848 * key range using binary search.
1849 */
1850static int
1853 void *key, bool *match)
1854{
1855 RangeBound *keyLower = (RangeBound *) key;
1856 RangeBound *keyUpper = (RangeBound *) key + 1;
1857
1858 /* Check if key range is strictly in the left or in the right */
1859 if (range_cmp_bounds(typcache, keyUpper, lower) < 0)
1860 return -1;
1861 if (range_cmp_bounds(typcache, keyLower, upper) > 0)
1862 return 1;
1863
1864 /*
1865 * At this point we found overlapping range. But we have to check if it
1866 * really contains the key range. Anyway, we have to stop our search
1867 * here, because multirange contains only non-overlapping ranges.
1868 */
1869 *match = range_bounds_contains(typcache, lower, upper, keyLower, keyUpper);
1870
1871 return 0;
1872}
1873
1874/*
1875 * Test whether multirange mr contains a specific range r.
1876 */
1877bool
1879 const MultirangeType *mr,
1880 const RangeType *r)
1881{
1882 RangeBound bounds[2];
1883 bool empty;
1884
1885 /*
1886 * Every multirange contains an infinite number of empty ranges, even an
1887 * empty one.
1888 */
1889 if (RangeIsEmpty(r))
1890 return true;
1891
1892 if (MultirangeIsEmpty(mr))
1893 return false;
1894
1895 range_deserialize(rangetyp, r, &bounds[0], &bounds[1], &empty);
1896 Assert(!empty);
1897
1900}
1901
1902/*
1903 * Test whether range r contains a multirange mr.
1904 */
1905bool
1907 const RangeType *r,
1908 const MultirangeType *mr)
1909{
1911 upper1,
1912 lower2,
1913 upper2,
1914 tmp;
1915 bool empty;
1916
1917 /*
1918 * Every range contains an infinite number of empty multiranges, even an
1919 * empty one.
1920 */
1921 if (MultirangeIsEmpty(mr))
1922 return true;
1923
1924 if (RangeIsEmpty(r))
1925 return false;
1926
1927 /* Range contains multirange iff it contains its union range. */
1928 range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
1929 Assert(!empty);
1931 multirange_get_bounds(rangetyp, mr, mr->rangeCount - 1, &tmp, &upper2);
1932
1934}
1935
1936
1937/* multirange, multirange -> bool functions */
1938
1939/* equality (internal version) */
1940bool
1942 const MultirangeType *mr1,
1943 const MultirangeType *mr2)
1944{
1947 int32 i;
1949 upper1,
1950 lower2,
1951 upper2;
1952
1953 /* Different types should be prevented by ANYMULTIRANGE matching rules */
1955 elog(ERROR, "multirange types do not match");
1956
1957 range_count_1 = mr1->rangeCount;
1958 range_count_2 = mr2->rangeCount;
1959
1961 return false;
1962
1963 for (i = 0; i < range_count_1; i++)
1964 {
1967
1968 if (range_cmp_bounds(rangetyp, &lower1, &lower2) != 0 ||
1970 return false;
1971 }
1972
1973 return true;
1974}
1975
1976/* equality */
1977Datum
1988
1989/* inequality (internal version) */
1990bool
1997
1998/* inequality */
1999Datum
2010
2011/* overlaps? */
2012Datum
2023
2024Datum
2035
2036Datum
2047
2048/*
2049 * Comparison function for checking if any range of multirange overlaps given
2050 * key range using binary search.
2051 */
2052static int
2055 void *key, bool *match)
2056{
2057 RangeBound *keyLower = (RangeBound *) key;
2058 RangeBound *keyUpper = (RangeBound *) key + 1;
2059
2060 if (range_cmp_bounds(typcache, keyUpper, lower) < 0)
2061 return -1;
2062 if (range_cmp_bounds(typcache, keyLower, upper) > 0)
2063 return 1;
2064
2065 *match = true;
2066 return 0;
2067}
2068
2069bool
2071 const RangeType *r,
2072 const MultirangeType *mr)
2073{
2074 RangeBound bounds[2];
2075 bool empty;
2076
2077 /*
2078 * Empties never overlap, even with empties. (This seems strange since
2079 * they *do* contain each other, but we want to follow how ranges work.)
2080 */
2082 return false;
2083
2084 range_deserialize(rangetyp, r, &bounds[0], &bounds[1], &empty);
2085 Assert(!empty);
2086
2089}
2090
2091bool
2093 const MultirangeType *mr1,
2094 const MultirangeType *mr2)
2095{
2098 int32 i1;
2099 int32 i2;
2101 upper1,
2102 lower2,
2103 upper2;
2104
2105 /*
2106 * Empties never overlap, even with empties. (This seems strange since
2107 * they *do* contain each other, but we want to follow how ranges work.)
2108 */
2110 return false;
2111
2112 range_count1 = mr1->rangeCount;
2113 range_count2 = mr2->rangeCount;
2114
2115 /*
2116 * Every range in mr1 gets a chance to overlap with the ranges in mr2, but
2117 * we can use their ordering to avoid O(n^2). This is similar to
2118 * range_overlaps_multirange where r1 : r2 :: mrr : r, but there if we
2119 * don't find an overlap with r we're done, and here if we don't find an
2120 * overlap with r2 we try the next r2.
2121 */
2122 i1 = 0;
2124 for (i1 = 0, i2 = 0; i2 < range_count2; i2++)
2125 {
2127
2128 /* Discard r1s while r1 << r2 */
2129 while (range_cmp_bounds(rangetyp, &upper1, &lower2) < 0)
2130 {
2131 if (++i1 >= range_count1)
2132 return false;
2134 }
2135
2136 /*
2137 * If r1 && r2, we're done, otherwise we failed to find an overlap for
2138 * r2, so go to the next one.
2139 */
2141 return true;
2142 }
2143
2144 /* We looked through all of mr2 without finding an overlap */
2145 return false;
2146}
2147
2148/* does not extend to right of? */
2149bool
2151 const RangeType *r,
2152 const MultirangeType *mr)
2153{
2155 upper1,
2156 lower2,
2157 upper2;
2158 bool empty;
2159
2161 return false;
2162
2163 range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
2164 Assert(!empty);
2165 multirange_get_bounds(rangetyp, mr, mr->rangeCount - 1,
2166 &lower2, &upper2);
2167
2168 return (range_cmp_bounds(rangetyp, &upper1, &upper2) <= 0);
2169}
2170
2171Datum
2182
2183Datum
2185{
2188 TypeCacheEntry *typcache;
2190 upper1,
2191 lower2,
2192 upper2;
2193 bool empty;
2194
2196 PG_RETURN_BOOL(false);
2197
2198 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2199
2200 multirange_get_bounds(typcache->rngtype, mr, mr->rangeCount - 1,
2201 &lower1, &upper1);
2202 range_deserialize(typcache->rngtype, r, &lower2, &upper2, &empty);
2203 Assert(!empty);
2204
2206}
2207
2208Datum
2210{
2213 TypeCacheEntry *typcache;
2215 upper1,
2216 lower2,
2217 upper2;
2218
2220 PG_RETURN_BOOL(false);
2221
2223
2224 multirange_get_bounds(typcache->rngtype, mr1, mr1->rangeCount - 1,
2225 &lower1, &upper1);
2226 multirange_get_bounds(typcache->rngtype, mr2, mr2->rangeCount - 1,
2227 &lower2, &upper2);
2228
2230}
2231
2232/* does not extend to left of? */
2233bool
2235 const RangeType *r,
2236 const MultirangeType *mr)
2237{
2239 upper1,
2240 lower2,
2241 upper2;
2242 bool empty;
2243
2245 return false;
2246
2247 range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
2248 Assert(!empty);
2250
2251 return (range_cmp_bounds(rangetyp, &lower1, &lower2) >= 0);
2252}
2253
2254Datum
2265
2266Datum
2268{
2271 TypeCacheEntry *typcache;
2273 upper1,
2274 lower2,
2275 upper2;
2276 bool empty;
2277
2279 PG_RETURN_BOOL(false);
2280
2281 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2282
2283 multirange_get_bounds(typcache->rngtype, mr, 0, &lower1, &upper1);
2284 range_deserialize(typcache->rngtype, r, &lower2, &upper2, &empty);
2285 Assert(!empty);
2286
2288}
2289
2290Datum
2311
2312/* contains? */
2313Datum
2324
2325/* contained by? */
2326Datum
2337
2338/*
2339 * Test whether multirange mr1 contains every range from another multirange mr2.
2340 */
2341bool
2343 const MultirangeType *mr1,
2344 const MultirangeType *mr2)
2345{
2346 int32 range_count1 = mr1->rangeCount;
2347 int32 range_count2 = mr2->rangeCount;
2348 int i1,
2349 i2;
2351 upper1,
2352 lower2,
2353 upper2;
2354
2355 /*
2356 * We follow the same logic for empties as ranges: - an empty multirange
2357 * contains an empty range/multirange. - an empty multirange can't contain
2358 * any other range/multirange. - an empty multirange is contained by any
2359 * other range/multirange.
2360 */
2361
2362 if (range_count2 == 0)
2363 return true;
2364 if (range_count1 == 0)
2365 return false;
2366
2367 /*
2368 * Every range in mr2 must be contained by some range in mr1. To avoid
2369 * O(n^2) we walk through both ranges in tandem.
2370 */
2371 i1 = 0;
2373 for (i2 = 0; i2 < range_count2; i2++)
2374 {
2376
2377 /* Discard r1s while r1 << r2 */
2378 while (range_cmp_bounds(rangetyp, &upper1, &lower2) < 0)
2379 {
2380 if (++i1 >= range_count1)
2381 return false;
2383 }
2384
2385 /*
2386 * If r1 @> r2, go to the next r2, otherwise return false (since every
2387 * r1[n] and r1[n+1] must have a gap). Note this will give weird
2388 * answers if you don't canonicalize, e.g. with a custom
2389 * int2multirange {[1,1], [2,2]} there is a "gap". But that is
2390 * consistent with other range operators, e.g. '[1,1]'::int2range -|-
2391 * '[2,2]'::int2range is false.
2392 */
2394 &lower2, &upper2))
2395 return false;
2396 }
2397
2398 /* All ranges in mr2 are satisfied */
2399 return true;
2400}
2401
2402/* strictly left of? */
2403Datum
2414
2415Datum
2426
2427Datum
2438
2439/* strictly right of? */
2440Datum
2451
2452Datum
2463
2464Datum
2475
2476/* strictly left of? (internal version) */
2477bool
2479 const RangeType *r,
2480 const MultirangeType *mr)
2481{
2483 upper1,
2484 lower2,
2485 upper2;
2486 bool empty;
2487
2489 return false;
2490
2491 range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
2492 Assert(!empty);
2493
2495
2496 return (range_cmp_bounds(rangetyp, &upper1, &lower2) < 0);
2497}
2498
2499bool
2501 const MultirangeType *mr1,
2502 const MultirangeType *mr2)
2503{
2505 upper1,
2506 lower2,
2507 upper2;
2508
2510 return false;
2511
2512 multirange_get_bounds(rangetyp, mr1, mr1->rangeCount - 1,
2513 &lower1, &upper1);
2515 &lower2, &upper2);
2516
2517 return (range_cmp_bounds(rangetyp, &upper1, &lower2) < 0);
2518}
2519
2520/* strictly right of? (internal version) */
2521bool
2523 const RangeType *r,
2524 const MultirangeType *mr)
2525{
2527 upper1,
2528 lower2,
2529 upper2;
2530 bool empty;
2532
2534 return false;
2535
2536 range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
2537 Assert(!empty);
2538
2539 range_count = mr->rangeCount;
2541 &lower2, &upper2);
2542
2543 return (range_cmp_bounds(rangetyp, &lower1, &upper2) > 0);
2544}
2545
2546bool
2548 const RangeType *r,
2549 const MultirangeType *mr)
2550{
2552 upper1,
2553 lower2,
2554 upper2;
2555 bool empty;
2557
2559 return false;
2560
2561 range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
2562 Assert(!empty);
2563
2564 range_count = mr->rangeCount;
2566 &lower2, &upper2);
2567
2569 return true;
2570
2571 if (range_count > 1)
2573 &lower2, &upper2);
2574
2576 return true;
2577
2578 return false;
2579}
2580
2581/* adjacent to? */
2582Datum
2593
2594Datum
2608
2609Datum
2611{
2614 TypeCacheEntry *typcache;
2618 upper1,
2619 lower2,
2620 upper2;
2621
2623 PG_RETURN_BOOL(false);
2624
2626
2627 range_count1 = mr1->rangeCount;
2628 range_count2 = mr2->rangeCount;
2630 &lower1, &upper1);
2631 multirange_get_bounds(typcache->rngtype, mr2, 0,
2632 &lower2, &upper2);
2633 if (bounds_adjacent(typcache->rngtype, upper1, lower2))
2634 PG_RETURN_BOOL(true);
2635
2636 if (range_count1 > 1)
2637 multirange_get_bounds(typcache->rngtype, mr1, 0,
2638 &lower1, &upper1);
2639 if (range_count2 > 1)
2641 &lower2, &upper2);
2642 if (bounds_adjacent(typcache->rngtype, upper2, lower1))
2643 PG_RETURN_BOOL(true);
2644 PG_RETURN_BOOL(false);
2645}
2646
2647/* Btree support */
2648
2649/* btree comparator */
2650Datum
2652{
2658 int32 i;
2659 TypeCacheEntry *typcache;
2660 int cmp = 0; /* If both are empty we'll use this. */
2661
2662 /* Different types should be prevented by ANYMULTIRANGE matching rules */
2664 elog(ERROR, "multirange types do not match");
2665
2667
2668 range_count_1 = mr1->rangeCount;
2669 range_count_2 = mr2->rangeCount;
2670
2671 /* Loop over source data */
2673 for (i = 0; i < range_count_max; i++)
2674 {
2676 upper1,
2677 lower2,
2678 upper2;
2679
2680 /*
2681 * If one multirange is shorter, it's as if it had empty ranges at the
2682 * end to extend its length. An empty range compares earlier than any
2683 * other range, so the shorter multirange comes before the longer.
2684 * This is the same behavior as in other types, e.g. in strings 'aaa'
2685 * < 'aaaaaa'.
2686 */
2687 if (i >= range_count_1)
2688 {
2689 cmp = -1;
2690 break;
2691 }
2692 if (i >= range_count_2)
2693 {
2694 cmp = 1;
2695 break;
2696 }
2697
2700
2701 cmp = range_cmp_bounds(typcache->rngtype, &lower1, &lower2);
2702 if (cmp == 0)
2703 cmp = range_cmp_bounds(typcache->rngtype, &upper1, &upper2);
2704 if (cmp != 0)
2705 break;
2706 }
2707
2708 PG_FREE_IF_COPY(mr1, 0);
2709 PG_FREE_IF_COPY(mr2, 1);
2710
2712}
2713
2714/* inequality operators using the multirange_cmp function */
2715Datum
2717{
2718 int cmp = DatumGetInt32(multirange_cmp(fcinfo));
2719
2720 PG_RETURN_BOOL(cmp < 0);
2721}
2722
2723Datum
2725{
2726 int cmp = DatumGetInt32(multirange_cmp(fcinfo));
2727
2728 PG_RETURN_BOOL(cmp <= 0);
2729}
2730
2731Datum
2733{
2734 int cmp = DatumGetInt32(multirange_cmp(fcinfo));
2735
2736 PG_RETURN_BOOL(cmp >= 0);
2737}
2738
2739Datum
2741{
2742 int cmp = DatumGetInt32(multirange_cmp(fcinfo));
2743
2744 PG_RETURN_BOOL(cmp > 0);
2745}
2746
2747/* multirange -> range functions */
2748
2749/* Find the smallest range that includes everything in the multirange */
2750Datum
2752{
2755 TypeCacheEntry *typcache;
2757
2758 typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
2759
2760 if (MultirangeIsEmpty(mr))
2761 {
2762 result = make_empty_range(typcache->rngtype);
2763 }
2764 else if (mr->rangeCount == 1)
2765 {
2766 result = multirange_get_range(typcache->rngtype, mr, 0);
2767 }
2768 else
2769 {
2771 firstUpper,
2772 lastLower,
2773 lastUpper;
2774
2775 multirange_get_bounds(typcache->rngtype, mr, 0,
2777 multirange_get_bounds(typcache->rngtype, mr, mr->rangeCount - 1,
2778 &lastLower, &lastUpper);
2779
2781 false, NULL);
2782 }
2783
2785}
2786
2787/* Turn multirange into a set of ranges */
2788Datum
2790{
2791 typedef struct
2792 {
2794 TypeCacheEntry *typcache;
2795 int index;
2797
2800 MemoryContext oldcontext;
2801
2802 /* stuff done only on the first call of the function */
2803 if (SRF_IS_FIRSTCALL())
2804 {
2806
2807 /* create a function context for cross-call persistence */
2809
2810 /*
2811 * switch to memory context appropriate for multiple function calls
2812 */
2813 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
2814
2815 /*
2816 * Get the multirange value and detoast if needed. We can't do this
2817 * earlier because if we have to detoast, we want the detoasted copy
2818 * to be in multi_call_memory_ctx, so it will go away when we're done
2819 * and not before. (If no detoast happens, we assume the originally
2820 * passed multirange will stick around till then.)
2821 */
2823
2824 /* allocate memory for user context */
2826
2827 /* initialize state */
2828 fctx->mr = mr;
2829 fctx->index = 0;
2832
2833 funcctx->user_fctx = fctx;
2834 MemoryContextSwitchTo(oldcontext);
2835 }
2836
2837 /* stuff done on every call of the function */
2839 fctx = funcctx->user_fctx;
2840
2841 if (fctx->index < fctx->mr->rangeCount)
2842 {
2844
2845 range = multirange_get_range(fctx->typcache->rngtype,
2846 fctx->mr,
2847 fctx->index);
2848 fctx->index++;
2849
2851 }
2852 else
2853 {
2854 /* do when there is no more left */
2856 }
2857}
2858
2859/* Hash support */
2860
2861/* hash a multirange value */
2862Datum
2864{
2866 uint32 result = 1;
2867 TypeCacheEntry *typcache,
2868 *scache;
2870 i;
2871
2872 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2873 scache = typcache->rngtype->rngelemtype;
2874 if (!OidIsValid(scache->hash_proc_finfo.fn_oid))
2875 {
2876 scache = lookup_type_cache(scache->type_id,
2878 if (!OidIsValid(scache->hash_proc_finfo.fn_oid))
2879 ereport(ERROR,
2881 errmsg("could not identify a hash function for type %s",
2882 format_type_be(scache->type_id))));
2883 }
2884
2885 range_count = mr->rangeCount;
2886 for (i = 0; i < range_count; i++)
2887 {
2889 upper;
2890 uint8 flags = MultirangeGetFlagsPtr(mr)[i];
2894
2895 multirange_get_bounds(typcache->rngtype, mr, i, &lower, &upper);
2896
2897 if (RANGE_HAS_LBOUND(flags))
2899 typcache->rngtype->rng_collation,
2900 lower.val));
2901 else
2902 lower_hash = 0;
2903
2904 if (RANGE_HAS_UBOUND(flags))
2906 typcache->rngtype->rng_collation,
2907 upper.val));
2908 else
2909 upper_hash = 0;
2910
2911 /* Merge hashes of flags and bounds */
2916
2917 /*
2918 * Use the same approach as hash_array to combine the individual
2919 * elements' hash values:
2920 */
2921 result = (result << 5) - result + range_hash;
2922 }
2923
2924 PG_FREE_IF_COPY(mr, 0);
2925
2927}
2928
2929/*
2930 * Returns 64-bit value by hashing a value to a 64-bit value, with a seed.
2931 * Otherwise, similar to hash_multirange.
2932 */
2933Datum
2935{
2937 Datum seed = PG_GETARG_DATUM(1);
2938 uint64 result = 1;
2939 TypeCacheEntry *typcache,
2940 *scache;
2942 i;
2943
2944 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2945 scache = typcache->rngtype->rngelemtype;
2946 if (!OidIsValid(scache->hash_extended_proc_finfo.fn_oid))
2947 {
2948 scache = lookup_type_cache(scache->type_id,
2950 if (!OidIsValid(scache->hash_extended_proc_finfo.fn_oid))
2951 ereport(ERROR,
2953 errmsg("could not identify a hash function for type %s",
2954 format_type_be(scache->type_id))));
2955 }
2956
2957 range_count = mr->rangeCount;
2958 for (i = 0; i < range_count; i++)
2959 {
2961 upper;
2962 uint8 flags = MultirangeGetFlagsPtr(mr)[i];
2966
2967 multirange_get_bounds(typcache->rngtype, mr, i, &lower, &upper);
2968
2969 if (RANGE_HAS_LBOUND(flags))
2970 lower_hash = DatumGetUInt64(FunctionCall2Coll(&scache->hash_extended_proc_finfo,
2971 typcache->rngtype->rng_collation,
2972 lower.val,
2973 seed));
2974 else
2975 lower_hash = 0;
2976
2977 if (RANGE_HAS_UBOUND(flags))
2978 upper_hash = DatumGetUInt64(FunctionCall2Coll(&scache->hash_extended_proc_finfo,
2979 typcache->rngtype->rng_collation,
2980 upper.val,
2981 seed));
2982 else
2983 upper_hash = 0;
2984
2985 /* Merge hashes of flags and bounds */
2987 DatumGetInt64(seed)));
2991
2992 /*
2993 * Use the same approach as hash_array to combine the individual
2994 * elements' hash values:
2995 */
2996 result = (result << 5) - result + range_hash;
2997 }
2998
2999 PG_FREE_IF_COPY(mr, 0);
3000
3002}
Datum idx(PG_FUNCTION_ARGS)
Definition _int_op.c:263
#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:622
#define Max(x, y)
Definition c.h:1085
#define VARHDRSZ
Definition c.h:781
#define Assert(condition)
Definition c.h:943
int16_t int16
Definition c.h:619
int32_t int32
Definition c.h:620
uint64_t uint64
Definition c.h:625
uint32_t uint32
Definition c.h:624
#define OidIsValid(objectId)
Definition c.h:858
size_t Size
Definition c.h:689
uint32 result
memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets))
int errcode(int sqlerrcode)
Definition elog.c:875
#define ereturn(context, dummy_value,...)
Definition elog.h:280
int errdetail(const char *fmt,...) pg_attribute_printf(1
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define ereport(elevel,...)
Definition elog.h:152
#define palloc_object(type)
Definition fe_memutils.h:89
#define palloc_array(type, count)
Definition fe_memutils.h:91
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition fmgr.c:1151
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition fmgr.c:139
bytea * SendFunctionCall(FmgrInfo *flinfo, Datum val)
Definition fmgr.c:1745
bool InputFunctionCallSafe(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod, Node *escontext, Datum *result)
Definition fmgr.c:1586
char * OutputFunctionCall(FmgrInfo *flinfo, Datum val)
Definition fmgr.c:1684
Oid get_fn_expr_argtype(FmgrInfo *flinfo, int argnum)
Definition fmgr.c:1876
Datum FunctionCall1Coll(FmgrInfo *flinfo, Oid collation, Datum arg1)
Definition fmgr.c:1131
Oid get_fn_expr_rettype(FmgrInfo *flinfo)
Definition fmgr.c:1854
Datum ReceiveFunctionCall(FmgrInfo *flinfo, StringInfo buf, Oid typioparam, int32 typmod)
Definition fmgr.c:1698
#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:2921
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:2556
bool type_is_multirange(Oid typid)
Definition lsyscache.c:2931
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:1235
void * repalloc(void *pointer, Size size)
Definition mcxt.c:1635
void pfree(void *pointer)
Definition mcxt.c:1619
void * palloc0(Size size)
Definition mcxt.c:1420
char * pnstrdup(const char *in, Size len)
Definition mcxt.c:1921
#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:4609
static char * errmsg
Datum lower(PG_FUNCTION_ARGS)
Datum upper(PG_FUNCTION_ARGS)
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:138
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:178
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:222
static uint64 DatumGetUInt64(Datum X)
Definition postgres.h:436
static int64 DatumGetInt64(Datum X)
Definition postgres.h:416
uint64_t Datum
Definition postgres.h:70
static int32 DatumGetInt32(Datum X)
Definition postgres.h:202
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:763
bool range_overlaps_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
Definition rangetypes.c:847
bool range_before_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
Definition rangetypes.c:670
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:999
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:804
bool range_overleft_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
Definition rangetypes.c:893
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:97
Definition c.h:776
static ItemArray items
#define att_align_pointer(cur_offset, attalign, attlen, attptr)
Definition tupmacs.h:372
#define att_nominal_alignby(cur_offset, attalignby)
Definition tupmacs.h:411
#define att_addlength_pointer(cur_offset, attlen, attptr)
Definition tupmacs.h:431
static uint8 typalign_to_alignby(char typalign)
Definition tupmacs.h:302
static Datum fetch_att(const void *T, bool attbyval, int attlen)
Definition tupmacs.h:108
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition typcache.c:389
#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:195