PostgreSQL Source Code git master
Loading...
Searching...
No Matches
multirangetypes.c File Reference
#include "postgres.h"
#include "access/tupmacs.h"
#include "common/hashfn.h"
#include "funcapi.h"
#include "lib/stringinfo.h"
#include "libpq/pqformat.h"
#include "nodes/nodes.h"
#include "port/pg_bitutils.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/multirangetypes.h"
#include "utils/rangetypes.h"
Include dependency graph for multirangetypes.c:

Go to the source code of this file.

Data Structures

struct  MultirangeIOData
 

Macros

#define MultirangeGetItemsPtr(mr)
 
#define MultirangeGetFlagsPtr(mr)
 
#define MultirangeGetBoundariesPtr(mr, align)
 
#define MULTIRANGE_ITEM_OFF_BIT   0x80000000
 
#define MULTIRANGE_ITEM_GET_OFFLEN(item)   ((item) & 0x7FFFFFFF)
 
#define MULTIRANGE_ITEM_HAS_OFF(item)   ((item) & MULTIRANGE_ITEM_OFF_BIT)
 
#define MULTIRANGE_ITEM_OFFSET_STRIDE   4
 

Typedefs

typedef struct MultirangeIOData MultirangeIOData
 
typedef int(* multirange_bsearch_comparison) (TypeCacheEntry *typcache, RangeBound *lower, RangeBound *upper, void *key, bool *match)
 

Enumerations

enum  MultirangeParseState {
  MULTIRANGE_BEFORE_RANGE , MULTIRANGE_IN_RANGE , MULTIRANGE_IN_RANGE_ESCAPED , MULTIRANGE_IN_RANGE_QUOTED ,
  MULTIRANGE_IN_RANGE_QUOTED_ESCAPED , MULTIRANGE_AFTER_RANGE , MULTIRANGE_FINISHED
}
 

Functions

static MultirangeIODataget_multirange_io_data (FunctionCallInfo fcinfo, Oid mltrngtypid, IOFuncSelector func)
 
static int32 multirange_canonicalize (TypeCacheEntry *rangetyp, int32 input_range_count, RangeType **ranges)
 
Datum multirange_in (PG_FUNCTION_ARGS)
 
Datum multirange_out (PG_FUNCTION_ARGS)
 
Datum multirange_recv (PG_FUNCTION_ARGS)
 
Datum multirange_send (PG_FUNCTION_ARGS)
 
TypeCacheEntrymultirange_get_typcache (FunctionCallInfo fcinfo, Oid mltrngtypid)
 
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)
 
MultirangeTypemake_multirange (Oid mltrngtypoid, TypeCacheEntry *rangetyp, int32 range_count, RangeType **ranges)
 
static uint32 multirange_get_bounds_offset (const MultirangeType *multirange, int32 i)
 
RangeTypemultirange_get_range (TypeCacheEntry *rangetyp, const MultirangeType *multirange, int i)
 
void multirange_get_bounds (TypeCacheEntry *rangetyp, const MultirangeType *multirange, uint32 i, RangeBound *lower, RangeBound *upper)
 
RangeTypemultirange_get_union_range (TypeCacheEntry *rangetyp, const MultirangeType *mr)
 
void multirange_deserialize (TypeCacheEntry *rangetyp, const MultirangeType *multirange, int32 *range_count, RangeType ***ranges)
 
MultirangeTypemake_empty_multirange (Oid mltrngtypoid, TypeCacheEntry *rangetyp)
 
static bool range_bounds_overlaps (TypeCacheEntry *typcache, RangeBound *lower1, RangeBound *upper1, RangeBound *lower2, RangeBound *upper2)
 
static bool range_bounds_contains (TypeCacheEntry *typcache, RangeBound *lower1, RangeBound *upper1, RangeBound *lower2, RangeBound *upper2)
 
static bool multirange_bsearch_match (TypeCacheEntry *typcache, const MultirangeType *mr, void *key, multirange_bsearch_comparison cmp_func)
 
Datum multirange_constructor2 (PG_FUNCTION_ARGS)
 
Datum multirange_constructor1 (PG_FUNCTION_ARGS)
 
Datum multirange_constructor0 (PG_FUNCTION_ARGS)
 
Datum multirange_union (PG_FUNCTION_ARGS)
 
Datum multirange_minus (PG_FUNCTION_ARGS)
 
MultirangeTypemultirange_minus_internal (Oid mltrngtypoid, TypeCacheEntry *rangetyp, int32 range_count1, RangeType **ranges1, int32 range_count2, RangeType **ranges2)
 
Datum multirange_minus_multi (PG_FUNCTION_ARGS)
 
Datum multirange_intersect (PG_FUNCTION_ARGS)
 
MultirangeTypemultirange_intersect_internal (Oid mltrngtypoid, TypeCacheEntry *rangetyp, int32 range_count1, RangeType **ranges1, int32 range_count2, RangeType **ranges2)
 
Datum range_agg_transfn (PG_FUNCTION_ARGS)
 
Datum range_agg_finalfn (PG_FUNCTION_ARGS)
 
Datum multirange_agg_transfn (PG_FUNCTION_ARGS)
 
Datum multirange_intersect_agg_transfn (PG_FUNCTION_ARGS)
 
Datum multirange_lower (PG_FUNCTION_ARGS)
 
Datum multirange_upper (PG_FUNCTION_ARGS)
 
Datum multirange_empty (PG_FUNCTION_ARGS)
 
Datum multirange_lower_inc (PG_FUNCTION_ARGS)
 
Datum multirange_upper_inc (PG_FUNCTION_ARGS)
 
Datum multirange_lower_inf (PG_FUNCTION_ARGS)
 
Datum multirange_upper_inf (PG_FUNCTION_ARGS)
 
Datum multirange_contains_elem (PG_FUNCTION_ARGS)
 
Datum elem_contained_by_multirange (PG_FUNCTION_ARGS)
 
static int multirange_elem_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_contains_range (PG_FUNCTION_ARGS)
 
Datum range_contains_multirange (PG_FUNCTION_ARGS)
 
Datum range_contained_by_multirange (PG_FUNCTION_ARGS)
 
Datum multirange_contained_by_range (PG_FUNCTION_ARGS)
 
static int multirange_range_contains_bsearch_comparison (TypeCacheEntry *typcache, RangeBound *lower, RangeBound *upper, void *key, bool *match)
 
bool multirange_contains_range_internal (TypeCacheEntry *rangetyp, const MultirangeType *mr, const RangeType *r)
 
bool range_contains_multirange_internal (TypeCacheEntry *rangetyp, const RangeType *r, const MultirangeType *mr)
 
bool multirange_eq_internal (TypeCacheEntry *rangetyp, const MultirangeType *mr1, const MultirangeType *mr2)
 
Datum multirange_eq (PG_FUNCTION_ARGS)
 
bool multirange_ne_internal (TypeCacheEntry *rangetyp, const MultirangeType *mr1, const MultirangeType *mr2)
 
Datum multirange_ne (PG_FUNCTION_ARGS)
 
Datum range_overlaps_multirange (PG_FUNCTION_ARGS)
 
Datum multirange_overlaps_range (PG_FUNCTION_ARGS)
 
Datum multirange_overlaps_multirange (PG_FUNCTION_ARGS)
 
static int multirange_range_overlaps_bsearch_comparison (TypeCacheEntry *typcache, RangeBound *lower, RangeBound *upper, void *key, bool *match)
 
bool range_overlaps_multirange_internal (TypeCacheEntry *rangetyp, const RangeType *r, const MultirangeType *mr)
 
bool multirange_overlaps_multirange_internal (TypeCacheEntry *rangetyp, const MultirangeType *mr1, const MultirangeType *mr2)
 
bool range_overleft_multirange_internal (TypeCacheEntry *rangetyp, const RangeType *r, const MultirangeType *mr)
 
Datum range_overleft_multirange (PG_FUNCTION_ARGS)
 
Datum multirange_overleft_range (PG_FUNCTION_ARGS)
 
Datum multirange_overleft_multirange (PG_FUNCTION_ARGS)
 
bool range_overright_multirange_internal (TypeCacheEntry *rangetyp, const RangeType *r, const MultirangeType *mr)
 
Datum range_overright_multirange (PG_FUNCTION_ARGS)
 
Datum multirange_overright_range (PG_FUNCTION_ARGS)
 
Datum multirange_overright_multirange (PG_FUNCTION_ARGS)
 
Datum multirange_contains_multirange (PG_FUNCTION_ARGS)
 
Datum multirange_contained_by_multirange (PG_FUNCTION_ARGS)
 
bool multirange_contains_multirange_internal (TypeCacheEntry *rangetyp, const MultirangeType *mr1, const MultirangeType *mr2)
 
Datum range_before_multirange (PG_FUNCTION_ARGS)
 
Datum multirange_before_range (PG_FUNCTION_ARGS)
 
Datum multirange_before_multirange (PG_FUNCTION_ARGS)
 
Datum range_after_multirange (PG_FUNCTION_ARGS)
 
Datum multirange_after_range (PG_FUNCTION_ARGS)
 
Datum multirange_after_multirange (PG_FUNCTION_ARGS)
 
bool range_before_multirange_internal (TypeCacheEntry *rangetyp, const RangeType *r, const MultirangeType *mr)
 
bool multirange_before_multirange_internal (TypeCacheEntry *rangetyp, const MultirangeType *mr1, const MultirangeType *mr2)
 
bool range_after_multirange_internal (TypeCacheEntry *rangetyp, const RangeType *r, const MultirangeType *mr)
 
bool range_adjacent_multirange_internal (TypeCacheEntry *rangetyp, const RangeType *r, const MultirangeType *mr)
 
Datum range_adjacent_multirange (PG_FUNCTION_ARGS)
 
Datum multirange_adjacent_range (PG_FUNCTION_ARGS)
 
Datum multirange_adjacent_multirange (PG_FUNCTION_ARGS)
 
Datum multirange_cmp (PG_FUNCTION_ARGS)
 
Datum multirange_lt (PG_FUNCTION_ARGS)
 
Datum multirange_le (PG_FUNCTION_ARGS)
 
Datum multirange_ge (PG_FUNCTION_ARGS)
 
Datum multirange_gt (PG_FUNCTION_ARGS)
 
Datum range_merge_from_multirange (PG_FUNCTION_ARGS)
 
Datum multirange_unnest (PG_FUNCTION_ARGS)
 
Datum hash_multirange (PG_FUNCTION_ARGS)
 
Datum hash_multirange_extended (PG_FUNCTION_ARGS)
 

Macro Definition Documentation

◆ MULTIRANGE_ITEM_GET_OFFLEN

#define MULTIRANGE_ITEM_GET_OFFLEN (   item)    ((item) & 0x7FFFFFFF)

Definition at line 81 of file multirangetypes.c.

◆ MULTIRANGE_ITEM_HAS_OFF

#define MULTIRANGE_ITEM_HAS_OFF (   item)    ((item) & MULTIRANGE_ITEM_OFF_BIT)

Definition at line 82 of file multirangetypes.c.

◆ MULTIRANGE_ITEM_OFF_BIT

#define MULTIRANGE_ITEM_OFF_BIT   0x80000000

Definition at line 80 of file multirangetypes.c.

◆ MULTIRANGE_ITEM_OFFSET_STRIDE

#define MULTIRANGE_ITEM_OFFSET_STRIDE   4

Definition at line 83 of file multirangetypes.c.

◆ MultirangeGetBoundariesPtr

#define MultirangeGetBoundariesPtr (   mr,
  align 
)
Value:
((char *) (mr) + \
((mr)->rangeCount - 1) * sizeof(uint32) + \
(mr)->rangeCount * sizeof(uint8), (align)))
uint8_t uint8
Definition c.h:544
uint32_t uint32
Definition c.h:546
static int fb(int x)

Definition at line 75 of file multirangetypes.c.

117{
118 char *input_str = PG_GETARG_CSTRING(0);
120 Oid typmod = PG_GETARG_INT32(2);
121 Node *escontext = fcinfo->context;
123 int32 ranges_seen = 0;
124 int32 range_count = 0;
128 MultirangeIOData *cache;
129 MultirangeType *ret;
131 const char *ptr = input_str;
132 const char *range_str_begin = NULL;
134 char *range_str;
136
138 rangetyp = cache->typcache->rngtype;
139
140 /* consume whitespace */
141 while (*ptr != '\0' && isspace((unsigned char) *ptr))
142 ptr++;
143
144 if (*ptr == '{')
145 ptr++;
146 else
147 ereturn(escontext, (Datum) 0,
149 errmsg("malformed multirange literal: \"%s\"",
150 input_str),
151 errdetail("Missing left brace.")));
152
153 /* consume ranges */
155 for (; parse_state != MULTIRANGE_FINISHED; ptr++)
156 {
157 char ch = *ptr;
158
159 if (ch == '\0')
160 ereturn(escontext, (Datum) 0,
162 errmsg("malformed multirange literal: \"%s\"",
163 input_str),
164 errdetail("Unexpected end of input.")));
165
166 /* skip whitespace */
167 if (isspace((unsigned char) ch))
168 continue;
169
170 switch (parse_state)
171 {
173 if (ch == '[' || ch == '(')
174 {
175 range_str_begin = ptr;
177 }
178 else if (ch == '}' && ranges_seen == 0)
182 {
183 ranges_seen++;
184 /* nothing to do with an empty range */
185 ptr += strlen(RANGE_EMPTY_LITERAL) - 1;
187 }
188 else
189 ereturn(escontext, (Datum) 0,
191 errmsg("malformed multirange literal: \"%s\"",
192 input_str),
193 errdetail("Expected range start.")));
194 break;
196 if (ch == ']' || ch == ')')
197 {
198 range_str_len = ptr - range_str_begin + 1;
201 {
202 range_capacity *= 2;
203 ranges = (RangeType **)
204 repalloc(ranges, range_capacity * sizeof(RangeType *));
205 }
206 ranges_seen++;
207 if (!InputFunctionCallSafe(&cache->typioproc,
208 range_str,
209 cache->typioparam,
210 typmod,
211 escontext,
212 &range_datum))
215 if (!RangeIsEmpty(range))
216 ranges[range_count++] = range;
218 }
219 else
220 {
221 if (ch == '"')
223 else if (ch == '\\')
225
226 /*
227 * We will include this character into range_str once we
228 * find the end of the range value.
229 */
230 }
231 break;
233
234 /*
235 * We will include this character into range_str once we find
236 * the end of the range value.
237 */
239 break;
241 if (ch == '"')
242 if (*(ptr + 1) == '"')
243 {
244 /* two quote marks means an escaped quote mark */
245 ptr++;
246 }
247 else
249 else if (ch == '\\')
251
252 /*
253 * We will include this character into range_str once we find
254 * the end of the range value.
255 */
256 break;
258 if (ch == ',')
260 else if (ch == '}')
262 else
263 ereturn(escontext, (Datum) 0,
265 errmsg("malformed multirange literal: \"%s\"",
266 input_str),
267 errdetail("Expected comma or end of multirange.")));
268 break;
270
271 /*
272 * We will include this character into range_str once we find
273 * the end of the range value.
274 */
276 break;
277 default:
278 elog(ERROR, "unknown parse state: %d", parse_state);
279 }
280 }
281
282 /* consume whitespace */
283 while (*ptr != '\0' && isspace((unsigned char) *ptr))
284 ptr++;
285
286 if (*ptr != '\0')
287 ereturn(escontext, (Datum) 0,
289 errmsg("malformed multirange literal: \"%s\"",
290 input_str),
291 errdetail("Junk after closing right brace.")));
292
295}
296
297Datum
299{
302 MultirangeIOData *cache;
305 char *rangeStr;
307 int32 i;
308 RangeType **ranges;
309
311
313
315
317 for (i = 0; i < range_count; i++)
318 {
319 if (i > 0)
321 range = ranges[i];
324 }
325
327
329}
330
331/*
332 * Binary representation: First an int32-sized count of ranges, followed by
333 * ranges in their native binary representation.
334 */
335Datum
337{
340 int32 typmod = PG_GETARG_INT32(2);
341 MultirangeIOData *cache;
343 RangeType **ranges;
344 MultirangeType *ret;
346
348
351
353 for (int i = 0; i < range_count; i++)
354 {
356 const char *range_data = pq_getmsgbytes(buf, range_len);
357
360
362 &tmpbuf,
363 cache->typioparam,
364 typmod));
365 }
367
369
371 range_count, ranges);
373}
374
375Datum
377{
381 RangeType **ranges;
383 MultirangeIOData *cache;
384
387
388 /* construct output */
390
391 pq_sendint32(&buf, multirange->rangeCount);
392
394 for (int i = 0; i < range_count; i++)
395 {
396 Datum range;
398
399 range = RangeTypePGetDatum(ranges[i]);
401
404 }
405
407}
408
409/*
410 * get_multirange_io_data: get cached information needed for multirange type I/O
411 *
412 * The multirange I/O functions need a bit more cached info than other multirange
413 * functions, so they store a MultirangeIOData struct in fn_extra, not just a
414 * pointer to a type cache entry.
415 */
416static MultirangeIOData *
418{
419 MultirangeIOData *cache = (MultirangeIOData *) fcinfo->flinfo->fn_extra;
420
421 if (cache == NULL || cache->typcache->type_id != mltrngtypid)
422 {
423 Oid typiofunc;
424 int16 typlen;
425 bool typbyval;
426 char typalign;
427 char typdelim;
428
429 cache = (MultirangeIOData *) MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
430 sizeof(MultirangeIOData));
432 if (cache->typcache->rngtype == NULL)
433 elog(ERROR, "type %u is not a multirange type", mltrngtypid);
434
435 /* get_type_io_data does more than we need, but is convenient */
437 func,
438 &typlen,
439 &typbyval,
440 &typalign,
441 &typdelim,
442 &cache->typioparam,
443 &typiofunc);
444
445 if (!OidIsValid(typiofunc))
446 {
447 /* this could only happen for receive or send */
448 if (func == IOFunc_receive)
451 errmsg("no binary input function available for type %s",
453 else
456 errmsg("no binary output function available for type %s",
458 }
459 fmgr_info_cxt(typiofunc, &cache->typioproc,
460 fcinfo->flinfo->fn_mcxt);
461
462 fcinfo->flinfo->fn_extra = cache;
463 }
464
465 return cache;
466}
467
468/*
469 * Converts a list of arbitrary ranges into a list that is sorted and merged.
470 * Changes the contents of `ranges`.
471 *
472 * Returns the number of slots actually used, which may be less than
473 * input_range_count but never more.
474 *
475 * We assume that no input ranges are null, but empties are okay.
476 */
477static int32
479 RangeType **ranges)
480{
483 int32 i;
485
486 /* Sort the ranges so we can find the ones that overlap/meet. */
488 rangetyp);
489
490 /* Now merge where possible: */
491 for (i = 0; i < input_range_count; i++)
492 {
493 currentRange = ranges[i];
495 continue;
496
497 if (lastRange == NULL)
498 {
500 continue;
501 }
502
503 /*
504 * range_adjacent_internal gives true if *either* A meets B or B meets
505 * A, which is not quite want we want, but we rely on the sorting
506 * above to rule out B meets A ever happening.
507 */
509 {
510 /* The two ranges touch (without overlap), so merge them: */
511 ranges[output_range_count - 1] = lastRange =
513 }
515 {
516 /* There's a gap, so make a new entry: */
519 }
520 else
521 {
522 /* They must overlap, so merge them: */
523 ranges[output_range_count - 1] = lastRange =
525 }
526 }
527
528 return output_range_count;
529}
530
531/*
532 *----------------------------------------------------------
533 * SUPPORT FUNCTIONS
534 *
535 * These functions aren't in pg_proc, but are useful for
536 * defining new generic multirange functions in C.
537 *----------------------------------------------------------
538 */
539
540/*
541 * multirange_get_typcache: get cached information about a multirange type
542 *
543 * This is for use by multirange-related functions that follow the convention
544 * of using the fn_extra field as a pointer to the type cache entry for
545 * the multirange type. Functions that need to cache more information than
546 * that must fend for themselves.
547 */
550{
551 TypeCacheEntry *typcache = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
552
553 if (typcache == NULL ||
554 typcache->type_id != mltrngtypid)
555 {
557 if (typcache->rngtype == NULL)
558 elog(ERROR, "type %u is not a multirange type", mltrngtypid);
559 fcinfo->flinfo->fn_extra = typcache;
560 }
561
562 return typcache;
563}
564
565
566/*
567 * Estimate size occupied by serialized multirange.
568 */
569static Size
571 RangeType **ranges)
572{
573 char elemalign = rangetyp->rngelemtype->typalign;
574 Size size;
575 int32 i;
576
577 /*
578 * Count space for MultirangeType struct, items and flags.
579 */
580 size = att_align_nominal(sizeof(MultirangeType) +
581 Max(range_count - 1, 0) * sizeof(uint32) +
582 range_count * sizeof(uint8), elemalign);
583
584 /* Count space for range bounds */
585 for (i = 0; i < range_count; i++)
586 size += att_align_nominal(VARSIZE(ranges[i]) -
587 sizeof(RangeType) -
588 sizeof(char), elemalign);
589
590 return size;
591}
592
593/*
594 * Write multirange data into pre-allocated space.
595 */
596static void
598 int32 range_count, RangeType **ranges)
599{
600 uint32 *items;
602 uint8 *flags;
603 int32 i;
604 const char *begin;
605 char *ptr;
606 char elemalign = rangetyp->rngelemtype->typalign;
607
610 begin = ptr = MultirangeGetBoundariesPtr(multirange, elemalign);
611 for (i = 0; i < range_count; i++)
612 {
613 uint32 len;
614
615 if (i > 0)
616 {
617 /*
618 * Every range, except the first one, has an item. Every
619 * MULTIRANGE_ITEM_OFFSET_STRIDE item contains an offset, others
620 * contain lengths.
621 */
622 items[i - 1] = ptr - begin;
623 if ((i % MULTIRANGE_ITEM_OFFSET_STRIDE) != 0)
624 items[i - 1] -= prev_offset;
625 else
627 prev_offset = ptr - begin;
628 }
629 flags[i] = *((char *) ranges[i] + VARSIZE(ranges[i]) - sizeof(char));
630 len = VARSIZE(ranges[i]) - sizeof(RangeType) - sizeof(char);
631 memcpy(ptr, ranges[i] + 1, len);
632 ptr += att_align_nominal(len, elemalign);
633 }
634}
635
636
637/*
638 * This serializes the multirange from a list of non-null ranges. It also
639 * sorts the ranges and merges any that touch. The ranges should already be
640 * detoasted, and there should be no NULLs. This should be used by most
641 * callers.
642 *
643 * Note that we may change the `ranges` parameter (the pointers, but not
644 * any already-existing RangeType contents).
645 */
648 RangeType **ranges)
649{
651 Size size;
652
653 /* Sort and merge input ranges. */
655
656 /* Note: zero-fill is required here, just as in heap tuples */
658 multirange = palloc0(size);
659 SET_VARSIZE(multirange, size);
660
661 /* Now fill in the datum */
662 multirange->multirangetypid = mltrngtypoid;
663 multirange->rangeCount = range_count;
664
666
667 return multirange;
668}
669
670/*
671 * Get offset of bounds values of the i'th range in the multirange.
672 */
673static uint32
675{
677 uint32 offset = 0;
678
679 /*
680 * Summarize lengths till we meet an offset.
681 */
682 while (i > 0)
683 {
684 offset += MULTIRANGE_ITEM_GET_OFFLEN(items[i - 1]);
686 break;
687 i--;
688 }
689 return offset;
690}
691
692/*
693 * Fetch the i'th range from the multirange.
694 */
695RangeType *
697 const MultirangeType *multirange, int i)
698{
699 uint32 offset;
700 uint8 flags;
701 const char *begin;
702 char *ptr;
703 int16 typlen = rangetyp->rngelemtype->typlen;
704 char typalign = rangetyp->rngelemtype->typalign;
705 uint32 len;
707
708 Assert(i < multirange->rangeCount);
709
712 begin = ptr = MultirangeGetBoundariesPtr(multirange, typalign) + offset;
713
714 /*
715 * Calculate the size of bound values. In principle, we could get offset
716 * of the next range bound values and calculate accordingly. But range
717 * bound values are aligned, so we have to walk the values to get the
718 * exact size.
719 */
720 if (RANGE_HAS_LBOUND(flags))
721 ptr = (char *) att_addlength_pointer(ptr, typlen, ptr);
722 if (RANGE_HAS_UBOUND(flags))
723 {
724 ptr = (char *) att_align_pointer(ptr, typalign, typlen, ptr);
725 ptr = (char *) att_addlength_pointer(ptr, typlen, ptr);
726 }
727 len = (ptr - begin) + sizeof(RangeType) + sizeof(uint8);
728
729 range = palloc0(len);
731 range->rangetypid = rangetyp->type_id;
732
733 memcpy(range + 1, begin, ptr - begin);
734 *((uint8 *) (range + 1) + (ptr - begin)) = flags;
735
736 return range;
737}
738
739/*
740 * Fetch bounds from the i'th range of the multirange. This is the shortcut for
741 * doing the same thing as multirange_get_range() + range_deserialize(), but
742 * performing fewer operations.
743 */
744void
748{
749 uint32 offset;
750 uint8 flags;
751 const char *ptr;
752 int16 typlen = rangetyp->rngelemtype->typlen;
753 char typalign = rangetyp->rngelemtype->typalign;
754 bool typbyval = rangetyp->rngelemtype->typbyval;
755 Datum lbound;
757
758 Assert(i < multirange->rangeCount);
759
763
764 /* multirange can't contain empty ranges */
765 Assert((flags & RANGE_EMPTY) == 0);
766
767 /* fetch lower bound, if any */
768 if (RANGE_HAS_LBOUND(flags))
769 {
770 /* att_align_pointer cannot be necessary here */
771 lbound = fetch_att(ptr, typbyval, typlen);
772 ptr = (char *) att_addlength_pointer(ptr, typlen, ptr);
773 }
774 else
775 lbound = (Datum) 0;
776
777 /* fetch upper bound, if any */
778 if (RANGE_HAS_UBOUND(flags))
779 {
780 ptr = (char *) att_align_pointer(ptr, typalign, typlen, ptr);
781 ubound = fetch_att(ptr, typbyval, typlen);
782 /* no need for att_addlength_pointer */
783 }
784 else
785 ubound = (Datum) 0;
786
787 /* emit results */
788 lower->val = lbound;
789 lower->infinite = (flags & RANGE_LB_INF) != 0;
790 lower->inclusive = (flags & RANGE_LB_INC) != 0;
791 lower->lower = true;
792
793 upper->val = ubound;
794 upper->infinite = (flags & RANGE_UB_INF) != 0;
795 upper->inclusive = (flags & RANGE_UB_INC) != 0;
796 upper->lower = false;
797}
798
799/*
800 * Construct union range from the multirange.
801 */
802RangeType *
804 const MultirangeType *mr)
805{
807 upper,
808 tmp;
809
812
814 multirange_get_bounds(rangetyp, mr, mr->rangeCount - 1, &tmp, &upper);
815
816 return make_range(rangetyp, &lower, &upper, false, NULL);
817}
818
819
820/*
821 * multirange_deserialize: deconstruct a multirange value
822 *
823 * NB: the given multirange object must be fully detoasted; it cannot have a
824 * short varlena header.
825 */
826void
829 RangeType ***ranges)
830{
831 *range_count = multirange->rangeCount;
832
833 /* Convert each ShortRangeType into a RangeType */
834 if (*range_count > 0)
835 {
836 int i;
837
838 *ranges = palloc_array(RangeType *, *range_count);
839 for (i = 0; i < *range_count; i++)
841 }
842 else
843 {
844 *ranges = NULL;
845 }
846}
847
850{
852}
853
854/*
855 * Similar to range_overlaps_internal(), but takes range bounds instead of
856 * ranges as arguments.
857 */
858static bool
862{
863 if (range_cmp_bounds(typcache, lower1, lower2) >= 0 &&
864 range_cmp_bounds(typcache, lower1, upper2) <= 0)
865 return true;
866
867 if (range_cmp_bounds(typcache, lower2, lower1) >= 0 &&
868 range_cmp_bounds(typcache, lower2, upper1) <= 0)
869 return true;
870
871 return false;
872}
873
874/*
875 * Similar to range_contains_internal(), but takes range bounds instead of
876 * ranges as arguments.
877 */
878static bool
882{
883 if (range_cmp_bounds(typcache, lower1, lower2) <= 0 &&
884 range_cmp_bounds(typcache, upper1, upper2) >= 0)
885 return true;
886
887 return false;
888}
889
890/*
891 * Check if the given key matches any range in multirange using binary search.
892 * If the required range isn't found, that counts as a mismatch. When the
893 * required range is found, the comparison function can still report this as
894 * either match or mismatch. For instance, if we search for containment, we can
895 * found a range, which is overlapping but not containing the key range, and
896 * that would count as a mismatch.
897 */
898static bool
901{
902 uint32 l,
903 u,
904 idx;
905 int comparison;
906 bool match = false;
907
908 l = 0;
909 u = mr->rangeCount;
910 while (l < u)
911 {
913 upper;
914
915 idx = (l + u) / 2;
916 multirange_get_bounds(typcache, mr, idx, &lower, &upper);
917 comparison = (*cmp_func) (typcache, &lower, &upper, key, &match);
918
919 if (comparison < 0)
920 u = idx;
921 else if (comparison > 0)
922 l = idx + 1;
923 else
924 return match;
925 }
926
927 return false;
928}
929
930/*
931 *----------------------------------------------------------
932 * GENERIC FUNCTIONS
933 *----------------------------------------------------------
934 */
935
936/*
937 * Construct multirange value from zero or more ranges. Since this is a
938 * variadic function we get passed an array. The array must contain ranges
939 * that match our return value, and there must be no NULLs.
940 */
941Datum
943{
944 Oid mltrngtypid = get_fn_expr_rettype(fcinfo->flinfo);
946 TypeCacheEntry *typcache;
949 int range_count;
950 Datum *elements;
951 bool *nulls;
952 RangeType **ranges;
953 int dims;
954 int i;
955
956 typcache = multirange_get_typcache(fcinfo, mltrngtypid);
957 rangetyp = typcache->rngtype;
958
959 /*
960 * A no-arg invocation should call multirange_constructor0 instead, but
961 * returning an empty range is what that does.
962 */
963
964 if (PG_NARGS() == 0)
966
967 /*
968 * This check should be guaranteed by our signature, but let's do it just
969 * in case.
970 */
971
972 if (PG_ARGISNULL(0))
973 elog(ERROR,
974 "multirange values cannot contain null members");
975
977
978 dims = ARR_NDIM(rangeArray);
979 if (dims > 1)
982 errmsg("multiranges cannot be constructed from multidimensional arrays")));
983
985 if (rngtypid != rangetyp->type_id)
986 elog(ERROR, "type %u does not match constructor type", rngtypid);
987
988 /*
989 * Be careful: we can still be called with zero ranges, like this:
990 * `int4multirange(variadic '{}'::int4range[])
991 */
992 if (dims == 0)
993 {
994 range_count = 0;
995 ranges = NULL;
996 }
997 else
998 {
1000 rangetyp->typalign, &elements, &nulls, &range_count);
1001
1002 ranges = palloc0(range_count * sizeof(RangeType *));
1003 for (i = 0; i < range_count; i++)
1004 {
1005 if (nulls[i])
1006 ereport(ERROR,
1008 errmsg("multirange values cannot contain null members")));
1009
1010 /* make_multirange will do its own copy */
1011 ranges[i] = DatumGetRangeTypeP(elements[i]);
1012 }
1013 }
1014
1016}
1017
1018/*
1019 * Construct multirange value from a single range. It'd be nice if we could
1020 * just use multirange_constructor2 for this case, but we need a non-variadic
1021 * single-arg function to let us define a CAST from a range to its multirange.
1022 */
1023Datum
1025{
1026 Oid mltrngtypid = get_fn_expr_rettype(fcinfo->flinfo);
1027 Oid rngtypid;
1028 TypeCacheEntry *typcache;
1031
1032 typcache = multirange_get_typcache(fcinfo, mltrngtypid);
1033 rangetyp = typcache->rngtype;
1034
1035 /*
1036 * This check should be guaranteed by our signature, but let's do it just
1037 * in case.
1038 */
1039
1040 if (PG_ARGISNULL(0))
1041 elog(ERROR,
1042 "multirange values cannot contain null members");
1043
1045
1046 /* Make sure the range type matches. */
1048 if (rngtypid != rangetyp->type_id)
1049 elog(ERROR, "type %u does not match constructor type", rngtypid);
1050
1052}
1053
1054/*
1055 * Constructor just like multirange_constructor1, but opr_sanity gets angry
1056 * if the same internal function handles multiple functions with different arg
1057 * counts.
1058 */
1059Datum
1061{
1063 TypeCacheEntry *typcache;
1065
1066 /* This should always be called without arguments */
1067 if (PG_NARGS() != 0)
1068 elog(ERROR,
1069 "niladic multirange constructor must not receive arguments");
1070
1071 mltrngtypid = get_fn_expr_rettype(fcinfo->flinfo);
1072 typcache = multirange_get_typcache(fcinfo, mltrngtypid);
1073 rangetyp = typcache->rngtype;
1074
1076}
1077
1078
1079/* multirange, multirange -> multirange type functions */
1080
1081/* multirange union */
1082Datum
1084{
1087 TypeCacheEntry *typcache;
1094
1099
1101
1104
1106 ranges3 = palloc0(range_count3 * sizeof(RangeType *));
1111}
1112
1113/* multirange minus */
1114Datum
1116{
1120 TypeCacheEntry *typcache;
1126
1127 typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
1128 rangetyp = typcache->rngtype;
1129
1132
1135
1137 rangetyp,
1139 ranges1,
1141 ranges2));
1142}
1143
1148{
1149 RangeType *r1;
1150 RangeType *r2;
1153 int32 i1;
1154 int32 i2;
1155
1156 /*
1157 * Worst case: every range in ranges1 makes a different cut to some range
1158 * in ranges2.
1159 */
1161 range_count3 = 0;
1162
1163 /*
1164 * For each range in mr1, keep subtracting until it's gone or the ranges
1165 * in mr2 have passed it. After a subtraction we assign what's left back
1166 * to r1. The parallel progress through mr1 and mr2 is similar to
1167 * multirange_overlaps_multirange_internal.
1168 */
1169 r2 = ranges2[0];
1170 for (i1 = 0, i2 = 0; i1 < range_count1; i1++)
1171 {
1172 r1 = ranges1[i1];
1173
1174 /* Discard r2s while r2 << r1 */
1175 while (r2 != NULL && range_before_internal(rangetyp, r2, r1))
1176 {
1177 r2 = ++i2 >= range_count2 ? NULL : ranges2[i2];
1178 }
1179
1180 while (r2 != NULL)
1181 {
1183 {
1184 /*
1185 * If r2 takes a bite out of the middle of r1, we need two
1186 * outputs
1187 */
1188 range_count3++;
1189 r2 = ++i2 >= range_count2 ? NULL : ranges2[i2];
1190 }
1192 {
1193 /*
1194 * If r2 overlaps r1, replace r1 with r1 - r2.
1195 */
1197
1198 /*
1199 * If r2 goes past r1, then we need to stay with it, in case
1200 * it hits future r1s. Otherwise we need to keep r1, in case
1201 * future r2s hit it. Since we already subtracted, there's no
1202 * point in using the overright/overleft calls.
1203 */
1205 break;
1206 else
1207 r2 = ++i2 >= range_count2 ? NULL : ranges2[i2];
1208 }
1209 else
1210 {
1211 /*
1212 * This and all future r2s are past r1, so keep them. Also
1213 * assign whatever is left of r1 to the result.
1214 */
1215 break;
1216 }
1217 }
1218
1219 /*
1220 * Nothing else can remove anything from r1, so keep it. Even if r1 is
1221 * empty here, make_multirange will remove it.
1222 */
1223 ranges3[range_count3++] = r1;
1224 }
1225
1227}
1228
1229/*
1230 * multirange_minus_multi - like multirange_minus but returning the result as a
1231 * SRF, with no rows if the result would be empty.
1232 */
1233Datum
1235{
1237 MemoryContext oldcontext;
1238
1239 if (!SRF_IS_FIRSTCALL())
1240 {
1241 /* We never have more than one result */
1244 }
1245 else
1246 {
1250 TypeCacheEntry *typcache;
1257
1259
1260 /*
1261 * switch to memory context appropriate for multiple function calls
1262 */
1263 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
1264
1265 /* get args, detoasting into multi-call memory context */
1268
1271 if (typcache->rngtype == NULL)
1272 elog(ERROR, "type %u is not a multirange type", mltrngtypoid);
1273 rangetyp = typcache->rngtype;
1274
1276 mr = mr1;
1277 else
1278 {
1281
1283 rangetyp,
1285 ranges1,
1287 ranges2);
1288 }
1289
1290 MemoryContextSwitchTo(oldcontext);
1291
1293 if (MultirangeIsEmpty(mr))
1295 else
1297 }
1298}
1299
1300/* multirange intersection */
1301Datum
1303{
1307 TypeCacheEntry *typcache;
1313
1314 typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
1315 rangetyp = typcache->rngtype;
1316
1319
1322
1324 rangetyp,
1326 ranges1,
1328 ranges2));
1329}
1330
1335{
1336 RangeType *r1;
1337 RangeType *r2;
1340 int32 i1;
1341 int32 i2;
1342
1343 if (range_count1 == 0 || range_count2 == 0)
1345
1346 /*-----------------------------------------------
1347 * Worst case is a stitching pattern like this:
1348 *
1349 * mr1: --- --- --- ---
1350 * mr2: --- --- ---
1351 * mr3: - - - - - -
1352 *
1353 * That seems to be range_count1 + range_count2 - 1,
1354 * but one extra won't hurt.
1355 *-----------------------------------------------
1356 */
1358 range_count3 = 0;
1359
1360 /*
1361 * For each range in mr1, keep intersecting until the ranges in mr2 have
1362 * passed it. The parallel progress through mr1 and mr2 is similar to
1363 * multirange_minus_multirange_internal, but we don't have to assign back
1364 * to r1.
1365 */
1366 r2 = ranges2[0];
1367 for (i1 = 0, i2 = 0; i1 < range_count1; i1++)
1368 {
1369 r1 = ranges1[i1];
1370
1371 /* Discard r2s while r2 << r1 */
1372 while (r2 != NULL && range_before_internal(rangetyp, r2, r1))
1373 {
1374 r2 = ++i2 >= range_count2 ? NULL : ranges2[i2];
1375 }
1376
1377 while (r2 != NULL)
1378 {
1380 {
1381 /* Keep the overlapping part */
1383
1384 /* If we "used up" all of r2, go to the next one... */
1386 r2 = ++i2 >= range_count2 ? NULL : ranges2[i2];
1387
1388 /* ...otherwise go to the next r1 */
1389 else
1390 break;
1391 }
1392 else
1393 /* We're past r1, so move to the next one */
1394 break;
1395 }
1396
1397 /* If we're out of r2s, there can be no more intersections */
1398 if (r2 == NULL)
1399 break;
1400 }
1401
1403}
1404
1405/*
1406 * range_agg_transfn: combine adjacent/overlapping ranges.
1407 *
1408 * All we do here is gather the input ranges into an array
1409 * so that the finalfn can sort and combine them.
1410 */
1411Datum
1413{
1415 Oid rngtypoid;
1417
1418 if (!AggCheckCallContext(fcinfo, &aggContext))
1419 elog(ERROR, "range_agg_transfn called in non-aggregate context");
1420
1421 rngtypoid = get_fn_expr_argtype(fcinfo->flinfo, 1);
1423 elog(ERROR, "range_agg must be called with a range");
1424
1425 if (PG_ARGISNULL(0))
1427 else
1429
1430 /* skip NULLs */
1431 if (!PG_ARGISNULL(1))
1433
1435}
1436
1437/*
1438 * range_agg_finalfn: use our internal array to merge touching ranges.
1439 *
1440 * Shared by range_agg_finalfn(anyrange) and
1441 * multirange_agg_finalfn(anymultirange).
1442 */
1443Datum
1445{
1448 TypeCacheEntry *typcache;
1451 RangeType **ranges;
1452 int i;
1453
1454 if (!AggCheckCallContext(fcinfo, &aggContext))
1455 elog(ERROR, "range_agg_finalfn called in non-aggregate context");
1456
1458 if (state == NULL)
1459 /* This shouldn't be possible, but just in case.... */
1461
1462 /* Also return NULL if we had zero inputs, like other aggregates */
1463 range_count = state->nelems;
1464 if (range_count == 0)
1466
1467 mltrngtypoid = get_fn_expr_rettype(fcinfo->flinfo);
1468 typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
1469
1470 ranges = palloc0(range_count * sizeof(RangeType *));
1471 for (i = 0; i < range_count; i++)
1472 ranges[i] = DatumGetRangeTypeP(state->dvalues[i]);
1473
1475}
1476
1477/*
1478 * multirange_agg_transfn: combine adjacent/overlapping multiranges.
1479 *
1480 * All we do here is gather the input multiranges' ranges into an array so
1481 * that the finalfn can sort and combine them.
1482 */
1483Datum
1485{
1488 TypeCacheEntry *typcache;
1491
1492 if (!AggCheckCallContext(fcinfo, &aggContext))
1493 elog(ERROR, "multirange_agg_transfn called in non-aggregate context");
1494
1495 mltrngtypoid = get_fn_expr_argtype(fcinfo->flinfo, 1);
1497 elog(ERROR, "range_agg must be called with a multirange");
1498
1499 typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
1500 rngtypcache = typcache->rngtype;
1501
1502 if (PG_ARGISNULL(0))
1503 state = initArrayResult(rngtypcache->type_id, aggContext, false);
1504 else
1506
1507 /* skip NULLs */
1508 if (!PG_ARGISNULL(1))
1509 {
1510 MultirangeType *current;
1512 RangeType **ranges;
1513
1514 current = PG_GETARG_MULTIRANGE_P(1);
1515 multirange_deserialize(rngtypcache, current, &range_count, &ranges);
1516 if (range_count == 0)
1517 {
1518 /*
1519 * Add an empty range so we get an empty result (not a null
1520 * result).
1521 */
1524 false, rngtypcache->type_id, aggContext);
1525 }
1526 else
1527 {
1528 for (int32 i = 0; i < range_count; i++)
1529 accumArrayResult(state, RangeTypePGetDatum(ranges[i]), false, rngtypcache->type_id, aggContext);
1530 }
1531 }
1532
1534}
1535
1536Datum
1538{
1541 TypeCacheEntry *typcache;
1542 MultirangeType *result;
1543 MultirangeType *current;
1548
1549 if (!AggCheckCallContext(fcinfo, &aggContext))
1550 elog(ERROR, "multirange_intersect_agg_transfn called in non-aggregate context");
1551
1552 mltrngtypoid = get_fn_expr_argtype(fcinfo->flinfo, 1);
1554 elog(ERROR, "range_intersect_agg must be called with a multirange");
1555
1556 typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
1557
1558 /* strictness ensures these are non-null */
1559 result = PG_GETARG_MULTIRANGE_P(0);
1560 current = PG_GETARG_MULTIRANGE_P(1);
1561
1562 multirange_deserialize(typcache->rngtype, result, &range_count1, &ranges1);
1563 multirange_deserialize(typcache->rngtype, current, &range_count2, &ranges2);
1564
1566 typcache->rngtype,
1568 ranges1,
1570 ranges2);
1571 PG_RETURN_MULTIRANGE_P(result);
1572}
1573
1574
1575/* multirange -> element type functions */
1576
1577/* extract lower bound value */
1578Datum
1580{
1582 TypeCacheEntry *typcache;
1585
1586 if (MultirangeIsEmpty(mr))
1588
1589 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1590
1591 multirange_get_bounds(typcache->rngtype, mr, 0,
1592 &lower, &upper);
1593
1594 if (!lower.infinite)
1596 else
1598}
1599
1600/* extract upper bound value */
1601Datum
1603{
1605 TypeCacheEntry *typcache;
1608
1609 if (MultirangeIsEmpty(mr))
1611
1612 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1613
1614 multirange_get_bounds(typcache->rngtype, mr, mr->rangeCount - 1,
1615 &lower, &upper);
1616
1617 if (!upper.infinite)
1619 else
1621}
1622
1623
1624/* multirange -> bool functions */
1625
1626/* is multirange empty? */
1627Datum
1629{
1631
1633}
1634
1635/* is lower bound inclusive? */
1636Datum
1638{
1640 TypeCacheEntry *typcache;
1643
1644 if (MultirangeIsEmpty(mr))
1645 PG_RETURN_BOOL(false);
1646
1647 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1648 multirange_get_bounds(typcache->rngtype, mr, 0,
1649 &lower, &upper);
1650
1651 PG_RETURN_BOOL(lower.inclusive);
1652}
1653
1654/* is upper bound inclusive? */
1655Datum
1657{
1659 TypeCacheEntry *typcache;
1662
1663 if (MultirangeIsEmpty(mr))
1664 PG_RETURN_BOOL(false);
1665
1666 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1667 multirange_get_bounds(typcache->rngtype, mr, mr->rangeCount - 1,
1668 &lower, &upper);
1669
1670 PG_RETURN_BOOL(upper.inclusive);
1671}
1672
1673/* is lower bound infinite? */
1674Datum
1676{
1678 TypeCacheEntry *typcache;
1681
1682 if (MultirangeIsEmpty(mr))
1683 PG_RETURN_BOOL(false);
1684
1685 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1686 multirange_get_bounds(typcache->rngtype, mr, 0,
1687 &lower, &upper);
1688
1689 PG_RETURN_BOOL(lower.infinite);
1690}
1691
1692/* is upper bound infinite? */
1693Datum
1695{
1697 TypeCacheEntry *typcache;
1700
1701 if (MultirangeIsEmpty(mr))
1702 PG_RETURN_BOOL(false);
1703
1704 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1705 multirange_get_bounds(typcache->rngtype, mr, mr->rangeCount - 1,
1706 &lower, &upper);
1707
1708 PG_RETURN_BOOL(upper.infinite);
1709}
1710
1711
1712
1713/* multirange, element -> bool functions */
1714
1715/* contains? */
1716Datum
1718{
1721 TypeCacheEntry *typcache;
1722
1723 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1724
1726}
1727
1728/* contained by? */
1729Datum
1731{
1734 TypeCacheEntry *typcache;
1735
1736 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1737
1739}
1740
1741/*
1742 * Comparison function for checking if any range of multirange contains given
1743 * key element using binary search.
1744 */
1745static int
1748 void *key, bool *match)
1749{
1750 Datum val = *((Datum *) key);
1751 int cmp;
1752
1753 if (!lower->infinite)
1754 {
1756 typcache->rng_collation,
1757 lower->val, val));
1758 if (cmp > 0 || (cmp == 0 && !lower->inclusive))
1759 return -1;
1760 }
1761
1762 if (!upper->infinite)
1763 {
1765 typcache->rng_collation,
1766 upper->val, val));
1767 if (cmp < 0 || (cmp == 0 && !upper->inclusive))
1768 return 1;
1769 }
1770
1771 *match = true;
1772 return 0;
1773}
1774
1775/*
1776 * Test whether multirange mr contains a specific element value.
1777 */
1778bool
1780 const MultirangeType *mr, Datum val)
1781{
1782 if (MultirangeIsEmpty(mr))
1783 return false;
1784
1787}
1788
1789/* multirange, range -> bool functions */
1790
1791/* contains? */
1792Datum
1794{
1797 TypeCacheEntry *typcache;
1798
1799 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1800
1802}
1803
1804Datum
1806{
1809 TypeCacheEntry *typcache;
1810
1811 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1812
1814}
1815
1816/* contained by? */
1817Datum
1819{
1822 TypeCacheEntry *typcache;
1823
1824 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1825
1827}
1828
1829Datum
1831{
1834 TypeCacheEntry *typcache;
1835
1836 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1837
1839}
1840
1841/*
1842 * Comparison function for checking if any range of multirange contains given
1843 * key range using binary search.
1844 */
1845static int
1848 void *key, bool *match)
1849{
1850 RangeBound *keyLower = (RangeBound *) key;
1851 RangeBound *keyUpper = (RangeBound *) key + 1;
1852
1853 /* Check if key range is strictly in the left or in the right */
1854 if (range_cmp_bounds(typcache, keyUpper, lower) < 0)
1855 return -1;
1856 if (range_cmp_bounds(typcache, keyLower, upper) > 0)
1857 return 1;
1858
1859 /*
1860 * At this point we found overlapping range. But we have to check if it
1861 * really contains the key range. Anyway, we have to stop our search
1862 * here, because multirange contains only non-overlapping ranges.
1863 */
1864 *match = range_bounds_contains(typcache, lower, upper, keyLower, keyUpper);
1865
1866 return 0;
1867}
1868
1869/*
1870 * Test whether multirange mr contains a specific range r.
1871 */
1872bool
1874 const MultirangeType *mr,
1875 const RangeType *r)
1876{
1877 RangeBound bounds[2];
1878 bool empty;
1879
1880 /*
1881 * Every multirange contains an infinite number of empty ranges, even an
1882 * empty one.
1883 */
1884 if (RangeIsEmpty(r))
1885 return true;
1886
1887 if (MultirangeIsEmpty(mr))
1888 return false;
1889
1890 range_deserialize(rangetyp, r, &bounds[0], &bounds[1], &empty);
1891 Assert(!empty);
1892
1895}
1896
1897/*
1898 * Test whether range r contains a multirange mr.
1899 */
1900bool
1902 const RangeType *r,
1903 const MultirangeType *mr)
1904{
1906 upper1,
1907 lower2,
1908 upper2,
1909 tmp;
1910 bool empty;
1911
1912 /*
1913 * Every range contains an infinite number of empty multiranges, even an
1914 * empty one.
1915 */
1916 if (MultirangeIsEmpty(mr))
1917 return true;
1918
1919 if (RangeIsEmpty(r))
1920 return false;
1921
1922 /* Range contains multirange iff it contains its union range. */
1923 range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
1924 Assert(!empty);
1926 multirange_get_bounds(rangetyp, mr, mr->rangeCount - 1, &tmp, &upper2);
1927
1929}
1930
1931
1932/* multirange, multirange -> bool functions */
1933
1934/* equality (internal version) */
1935bool
1937 const MultirangeType *mr1,
1938 const MultirangeType *mr2)
1939{
1942 int32 i;
1944 upper1,
1945 lower2,
1946 upper2;
1947
1948 /* Different types should be prevented by ANYMULTIRANGE matching rules */
1950 elog(ERROR, "multirange types do not match");
1951
1952 range_count_1 = mr1->rangeCount;
1953 range_count_2 = mr2->rangeCount;
1954
1956 return false;
1957
1958 for (i = 0; i < range_count_1; i++)
1959 {
1962
1963 if (range_cmp_bounds(rangetyp, &lower1, &lower2) != 0 ||
1965 return false;
1966 }
1967
1968 return true;
1969}
1970
1971/* equality */
1972Datum
1974{
1977 TypeCacheEntry *typcache;
1978
1980
1982}
1983
1984/* inequality (internal version) */
1985bool
1987 const MultirangeType *mr1,
1988 const MultirangeType *mr2)
1989{
1991}
1992
1993/* inequality */
1994Datum
1996{
1999 TypeCacheEntry *typcache;
2000
2002
2004}
2005
2006/* overlaps? */
2007Datum
2009{
2012 TypeCacheEntry *typcache;
2013
2014 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2015
2017}
2018
2019Datum
2021{
2024 TypeCacheEntry *typcache;
2025
2026 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2027
2029}
2030
2031Datum
2033{
2036 TypeCacheEntry *typcache;
2037
2039
2041}
2042
2043/*
2044 * Comparison function for checking if any range of multirange overlaps given
2045 * key range using binary search.
2046 */
2047static int
2050 void *key, bool *match)
2051{
2052 RangeBound *keyLower = (RangeBound *) key;
2053 RangeBound *keyUpper = (RangeBound *) key + 1;
2054
2055 if (range_cmp_bounds(typcache, keyUpper, lower) < 0)
2056 return -1;
2057 if (range_cmp_bounds(typcache, keyLower, upper) > 0)
2058 return 1;
2059
2060 *match = true;
2061 return 0;
2062}
2063
2064bool
2066 const RangeType *r,
2067 const MultirangeType *mr)
2068{
2069 RangeBound bounds[2];
2070 bool empty;
2071
2072 /*
2073 * Empties never overlap, even with empties. (This seems strange since
2074 * they *do* contain each other, but we want to follow how ranges work.)
2075 */
2077 return false;
2078
2079 range_deserialize(rangetyp, r, &bounds[0], &bounds[1], &empty);
2080 Assert(!empty);
2081
2084}
2085
2086bool
2088 const MultirangeType *mr1,
2089 const MultirangeType *mr2)
2090{
2093 int32 i1;
2094 int32 i2;
2096 upper1,
2097 lower2,
2098 upper2;
2099
2100 /*
2101 * Empties never overlap, even with empties. (This seems strange since
2102 * they *do* contain each other, but we want to follow how ranges work.)
2103 */
2105 return false;
2106
2107 range_count1 = mr1->rangeCount;
2108 range_count2 = mr2->rangeCount;
2109
2110 /*
2111 * Every range in mr1 gets a chance to overlap with the ranges in mr2, but
2112 * we can use their ordering to avoid O(n^2). This is similar to
2113 * range_overlaps_multirange where r1 : r2 :: mrr : r, but there if we
2114 * don't find an overlap with r we're done, and here if we don't find an
2115 * overlap with r2 we try the next r2.
2116 */
2117 i1 = 0;
2119 for (i1 = 0, i2 = 0; i2 < range_count2; i2++)
2120 {
2122
2123 /* Discard r1s while r1 << r2 */
2124 while (range_cmp_bounds(rangetyp, &upper1, &lower2) < 0)
2125 {
2126 if (++i1 >= range_count1)
2127 return false;
2129 }
2130
2131 /*
2132 * If r1 && r2, we're done, otherwise we failed to find an overlap for
2133 * r2, so go to the next one.
2134 */
2136 return true;
2137 }
2138
2139 /* We looked through all of mr2 without finding an overlap */
2140 return false;
2141}
2142
2143/* does not extend to right of? */
2144bool
2146 const RangeType *r,
2147 const MultirangeType *mr)
2148{
2150 upper1,
2151 lower2,
2152 upper2;
2153 bool empty;
2154
2156 return false;
2157
2158 range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
2159 Assert(!empty);
2160 multirange_get_bounds(rangetyp, mr, mr->rangeCount - 1,
2161 &lower2, &upper2);
2162
2163 return (range_cmp_bounds(rangetyp, &upper1, &upper2) <= 0);
2164}
2165
2166Datum
2168{
2171 TypeCacheEntry *typcache;
2172
2173 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2174
2176}
2177
2178Datum
2180{
2183 TypeCacheEntry *typcache;
2185 upper1,
2186 lower2,
2187 upper2;
2188 bool empty;
2189
2191 PG_RETURN_BOOL(false);
2192
2193 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2194
2195 multirange_get_bounds(typcache->rngtype, mr, mr->rangeCount - 1,
2196 &lower1, &upper1);
2197 range_deserialize(typcache->rngtype, r, &lower2, &upper2, &empty);
2198 Assert(!empty);
2199
2201}
2202
2203Datum
2205{
2208 TypeCacheEntry *typcache;
2210 upper1,
2211 lower2,
2212 upper2;
2213
2215 PG_RETURN_BOOL(false);
2216
2218
2219 multirange_get_bounds(typcache->rngtype, mr1, mr1->rangeCount - 1,
2220 &lower1, &upper1);
2221 multirange_get_bounds(typcache->rngtype, mr2, mr2->rangeCount - 1,
2222 &lower2, &upper2);
2223
2225}
2226
2227/* does not extend to left of? */
2228bool
2230 const RangeType *r,
2231 const MultirangeType *mr)
2232{
2234 upper1,
2235 lower2,
2236 upper2;
2237 bool empty;
2238
2240 return false;
2241
2242 range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
2243 Assert(!empty);
2245
2246 return (range_cmp_bounds(rangetyp, &lower1, &lower2) >= 0);
2247}
2248
2249Datum
2251{
2254 TypeCacheEntry *typcache;
2255
2256 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2257
2259}
2260
2261Datum
2263{
2266 TypeCacheEntry *typcache;
2268 upper1,
2269 lower2,
2270 upper2;
2271 bool empty;
2272
2274 PG_RETURN_BOOL(false);
2275
2276 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2277
2278 multirange_get_bounds(typcache->rngtype, mr, 0, &lower1, &upper1);
2279 range_deserialize(typcache->rngtype, r, &lower2, &upper2, &empty);
2280 Assert(!empty);
2281
2283}
2284
2285Datum
2287{
2290 TypeCacheEntry *typcache;
2292 upper1,
2293 lower2,
2294 upper2;
2295
2297 PG_RETURN_BOOL(false);
2298
2300
2301 multirange_get_bounds(typcache->rngtype, mr1, 0, &lower1, &upper1);
2302 multirange_get_bounds(typcache->rngtype, mr2, 0, &lower2, &upper2);
2303
2305}
2306
2307/* contains? */
2308Datum
2310{
2313 TypeCacheEntry *typcache;
2314
2316
2318}
2319
2320/* contained by? */
2321Datum
2323{
2326 TypeCacheEntry *typcache;
2327
2329
2331}
2332
2333/*
2334 * Test whether multirange mr1 contains every range from another multirange mr2.
2335 */
2336bool
2338 const MultirangeType *mr1,
2339 const MultirangeType *mr2)
2340{
2341 int32 range_count1 = mr1->rangeCount;
2342 int32 range_count2 = mr2->rangeCount;
2343 int i1,
2344 i2;
2346 upper1,
2347 lower2,
2348 upper2;
2349
2350 /*
2351 * We follow the same logic for empties as ranges: - an empty multirange
2352 * contains an empty range/multirange. - an empty multirange can't contain
2353 * any other range/multirange. - an empty multirange is contained by any
2354 * other range/multirange.
2355 */
2356
2357 if (range_count2 == 0)
2358 return true;
2359 if (range_count1 == 0)
2360 return false;
2361
2362 /*
2363 * Every range in mr2 must be contained by some range in mr1. To avoid
2364 * O(n^2) we walk through both ranges in tandem.
2365 */
2366 i1 = 0;
2368 for (i2 = 0; i2 < range_count2; i2++)
2369 {
2371
2372 /* Discard r1s while r1 << r2 */
2373 while (range_cmp_bounds(rangetyp, &upper1, &lower2) < 0)
2374 {
2375 if (++i1 >= range_count1)
2376 return false;
2378 }
2379
2380 /*
2381 * If r1 @> r2, go to the next r2, otherwise return false (since every
2382 * r1[n] and r1[n+1] must have a gap). Note this will give weird
2383 * answers if you don't canonicalize, e.g. with a custom
2384 * int2multirange {[1,1], [2,2]} there is a "gap". But that is
2385 * consistent with other range operators, e.g. '[1,1]'::int2range -|-
2386 * '[2,2]'::int2range is false.
2387 */
2389 &lower2, &upper2))
2390 return false;
2391 }
2392
2393 /* All ranges in mr2 are satisfied */
2394 return true;
2395}
2396
2397/* strictly left of? */
2398Datum
2400{
2403 TypeCacheEntry *typcache;
2404
2405 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2406
2408}
2409
2410Datum
2412{
2415 TypeCacheEntry *typcache;
2416
2417 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2418
2420}
2421
2422Datum
2424{
2427 TypeCacheEntry *typcache;
2428
2430
2432}
2433
2434/* strictly right of? */
2435Datum
2437{
2440 TypeCacheEntry *typcache;
2441
2442 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2443
2445}
2446
2447Datum
2449{
2452 TypeCacheEntry *typcache;
2453
2454 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2455
2457}
2458
2459Datum
2461{
2464 TypeCacheEntry *typcache;
2465
2467
2469}
2470
2471/* strictly left of? (internal version) */
2472bool
2474 const RangeType *r,
2475 const MultirangeType *mr)
2476{
2478 upper1,
2479 lower2,
2480 upper2;
2481 bool empty;
2482
2484 return false;
2485
2486 range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
2487 Assert(!empty);
2488
2490
2491 return (range_cmp_bounds(rangetyp, &upper1, &lower2) < 0);
2492}
2493
2494bool
2496 const MultirangeType *mr1,
2497 const MultirangeType *mr2)
2498{
2500 upper1,
2501 lower2,
2502 upper2;
2503
2505 return false;
2506
2507 multirange_get_bounds(rangetyp, mr1, mr1->rangeCount - 1,
2508 &lower1, &upper1);
2510 &lower2, &upper2);
2511
2512 return (range_cmp_bounds(rangetyp, &upper1, &lower2) < 0);
2513}
2514
2515/* strictly right of? (internal version) */
2516bool
2518 const RangeType *r,
2519 const MultirangeType *mr)
2520{
2522 upper1,
2523 lower2,
2524 upper2;
2525 bool empty;
2527
2529 return false;
2530
2531 range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
2532 Assert(!empty);
2533
2534 range_count = mr->rangeCount;
2536 &lower2, &upper2);
2537
2538 return (range_cmp_bounds(rangetyp, &lower1, &upper2) > 0);
2539}
2540
2541bool
2543 const RangeType *r,
2544 const MultirangeType *mr)
2545{
2547 upper1,
2548 lower2,
2549 upper2;
2550 bool empty;
2552
2554 return false;
2555
2556 range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
2557 Assert(!empty);
2558
2559 range_count = mr->rangeCount;
2561 &lower2, &upper2);
2562
2564 return true;
2565
2566 if (range_count > 1)
2568 &lower2, &upper2);
2569
2571 return true;
2572
2573 return false;
2574}
2575
2576/* adjacent to? */
2577Datum
2579{
2582 TypeCacheEntry *typcache;
2583
2584 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2585
2587}
2588
2589Datum
2591{
2594 TypeCacheEntry *typcache;
2595
2597 PG_RETURN_BOOL(false);
2598
2599 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2600
2602}
2603
2604Datum
2606{
2609 TypeCacheEntry *typcache;
2613 upper1,
2614 lower2,
2615 upper2;
2616
2618 PG_RETURN_BOOL(false);
2619
2621
2622 range_count1 = mr1->rangeCount;
2623 range_count2 = mr2->rangeCount;
2625 &lower1, &upper1);
2626 multirange_get_bounds(typcache->rngtype, mr2, 0,
2627 &lower2, &upper2);
2628 if (bounds_adjacent(typcache->rngtype, upper1, lower2))
2629 PG_RETURN_BOOL(true);
2630
2631 if (range_count1 > 1)
2632 multirange_get_bounds(typcache->rngtype, mr1, 0,
2633 &lower1, &upper1);
2634 if (range_count2 > 1)
2636 &lower2, &upper2);
2637 if (bounds_adjacent(typcache->rngtype, upper2, lower1))
2638 PG_RETURN_BOOL(true);
2639 PG_RETURN_BOOL(false);
2640}
2641
2642/* Btree support */
2643
2644/* btree comparator */
2645Datum
2647{
2653 int32 i;
2654 TypeCacheEntry *typcache;
2655 int cmp = 0; /* If both are empty we'll use this. */
2656
2657 /* Different types should be prevented by ANYMULTIRANGE matching rules */
2659 elog(ERROR, "multirange types do not match");
2660
2662
2663 range_count_1 = mr1->rangeCount;
2664 range_count_2 = mr2->rangeCount;
2665
2666 /* Loop over source data */
2668 for (i = 0; i < range_count_max; i++)
2669 {
2671 upper1,
2672 lower2,
2673 upper2;
2674
2675 /*
2676 * If one multirange is shorter, it's as if it had empty ranges at the
2677 * end to extend its length. An empty range compares earlier than any
2678 * other range, so the shorter multirange comes before the longer.
2679 * This is the same behavior as in other types, e.g. in strings 'aaa'
2680 * < 'aaaaaa'.
2681 */
2682 if (i >= range_count_1)
2683 {
2684 cmp = -1;
2685 break;
2686 }
2687 if (i >= range_count_2)
2688 {
2689 cmp = 1;
2690 break;
2691 }
2692
2695
2696 cmp = range_cmp_bounds(typcache->rngtype, &lower1, &lower2);
2697 if (cmp == 0)
2698 cmp = range_cmp_bounds(typcache->rngtype, &upper1, &upper2);
2699 if (cmp != 0)
2700 break;
2701 }
2702
2703 PG_FREE_IF_COPY(mr1, 0);
2704 PG_FREE_IF_COPY(mr2, 1);
2705
2707}
2708
2709/* inequality operators using the multirange_cmp function */
2710Datum
2712{
2713 int cmp = DatumGetInt32(multirange_cmp(fcinfo));
2714
2715 PG_RETURN_BOOL(cmp < 0);
2716}
2717
2718Datum
2720{
2721 int cmp = DatumGetInt32(multirange_cmp(fcinfo));
2722
2723 PG_RETURN_BOOL(cmp <= 0);
2724}
2725
2726Datum
2728{
2729 int cmp = DatumGetInt32(multirange_cmp(fcinfo));
2730
2731 PG_RETURN_BOOL(cmp >= 0);
2732}
2733
2734Datum
2736{
2737 int cmp = DatumGetInt32(multirange_cmp(fcinfo));
2738
2739 PG_RETURN_BOOL(cmp > 0);
2740}
2741
2742/* multirange -> range functions */
2743
2744/* Find the smallest range that includes everything in the multirange */
2745Datum
2747{
2750 TypeCacheEntry *typcache;
2751 RangeType *result;
2752
2753 typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
2754
2755 if (MultirangeIsEmpty(mr))
2756 {
2757 result = make_empty_range(typcache->rngtype);
2758 }
2759 else if (mr->rangeCount == 1)
2760 {
2761 result = multirange_get_range(typcache->rngtype, mr, 0);
2762 }
2763 else
2764 {
2766 firstUpper,
2767 lastLower,
2768 lastUpper;
2769
2770 multirange_get_bounds(typcache->rngtype, mr, 0,
2772 multirange_get_bounds(typcache->rngtype, mr, mr->rangeCount - 1,
2773 &lastLower, &lastUpper);
2774
2775 result = make_range(typcache->rngtype, &firstLower, &lastUpper,
2776 false, NULL);
2777 }
2778
2779 PG_RETURN_RANGE_P(result);
2780}
2781
2782/* Turn multirange into a set of ranges */
2783Datum
2785{
2786 typedef struct
2787 {
2789 TypeCacheEntry *typcache;
2790 int index;
2792
2795 MemoryContext oldcontext;
2796
2797 /* stuff done only on the first call of the function */
2798 if (SRF_IS_FIRSTCALL())
2799 {
2801
2802 /* create a function context for cross-call persistence */
2804
2805 /*
2806 * switch to memory context appropriate for multiple function calls
2807 */
2808 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
2809
2810 /*
2811 * Get the multirange value and detoast if needed. We can't do this
2812 * earlier because if we have to detoast, we want the detoasted copy
2813 * to be in multi_call_memory_ctx, so it will go away when we're done
2814 * and not before. (If no detoast happens, we assume the originally
2815 * passed multirange will stick around till then.)
2816 */
2818
2819 /* allocate memory for user context */
2821
2822 /* initialize state */
2823 fctx->mr = mr;
2824 fctx->index = 0;
2827
2828 funcctx->user_fctx = fctx;
2829 MemoryContextSwitchTo(oldcontext);
2830 }
2831
2832 /* stuff done on every call of the function */
2834 fctx = funcctx->user_fctx;
2835
2836 if (fctx->index < fctx->mr->rangeCount)
2837 {
2839
2840 range = multirange_get_range(fctx->typcache->rngtype,
2841 fctx->mr,
2842 fctx->index);
2843 fctx->index++;
2844
2846 }
2847 else
2848 {
2849 /* do when there is no more left */
2851 }
2852}
2853
2854/* Hash support */
2855
2856/* hash a multirange value */
2857Datum
2859{
2861 uint32 result = 1;
2862 TypeCacheEntry *typcache,
2863 *scache;
2865 i;
2866
2867 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2868 scache = typcache->rngtype->rngelemtype;
2869 if (!OidIsValid(scache->hash_proc_finfo.fn_oid))
2870 {
2871 scache = lookup_type_cache(scache->type_id,
2873 if (!OidIsValid(scache->hash_proc_finfo.fn_oid))
2874 ereport(ERROR,
2876 errmsg("could not identify a hash function for type %s",
2877 format_type_be(scache->type_id))));
2878 }
2879
2880 range_count = mr->rangeCount;
2881 for (i = 0; i < range_count; i++)
2882 {
2884 upper;
2885 uint8 flags = MultirangeGetFlagsPtr(mr)[i];
2889
2890 multirange_get_bounds(typcache->rngtype, mr, i, &lower, &upper);
2891
2892 if (RANGE_HAS_LBOUND(flags))
2894 typcache->rngtype->rng_collation,
2895 lower.val));
2896 else
2897 lower_hash = 0;
2898
2899 if (RANGE_HAS_UBOUND(flags))
2901 typcache->rngtype->rng_collation,
2902 upper.val));
2903 else
2904 upper_hash = 0;
2905
2906 /* Merge hashes of flags and bounds */
2911
2912 /*
2913 * Use the same approach as hash_array to combine the individual
2914 * elements' hash values:
2915 */
2916 result = (result << 5) - result + range_hash;
2917 }
2918
2919 PG_FREE_IF_COPY(mr, 0);
2920
2921 PG_RETURN_UINT32(result);
2922}
2923
2924/*
2925 * Returns 64-bit value by hashing a value to a 64-bit value, with a seed.
2926 * Otherwise, similar to hash_multirange.
2927 */
2928Datum
2930{
2932 Datum seed = PG_GETARG_DATUM(1);
2933 uint64 result = 1;
2934 TypeCacheEntry *typcache,
2935 *scache;
2937 i;
2938
2939 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2940 scache = typcache->rngtype->rngelemtype;
2941 if (!OidIsValid(scache->hash_extended_proc_finfo.fn_oid))
2942 {
2943 scache = lookup_type_cache(scache->type_id,
2945 if (!OidIsValid(scache->hash_extended_proc_finfo.fn_oid))
2946 ereport(ERROR,
2948 errmsg("could not identify a hash function for type %s",
2949 format_type_be(scache->type_id))));
2950 }
2951
2952 range_count = mr->rangeCount;
2953 for (i = 0; i < range_count; i++)
2954 {
2956 upper;
2957 uint8 flags = MultirangeGetFlagsPtr(mr)[i];
2961
2962 multirange_get_bounds(typcache->rngtype, mr, i, &lower, &upper);
2963
2964 if (RANGE_HAS_LBOUND(flags))
2965 lower_hash = DatumGetUInt64(FunctionCall2Coll(&scache->hash_extended_proc_finfo,
2966 typcache->rngtype->rng_collation,
2967 lower.val,
2968 seed));
2969 else
2970 lower_hash = 0;
2971
2972 if (RANGE_HAS_UBOUND(flags))
2973 upper_hash = DatumGetUInt64(FunctionCall2Coll(&scache->hash_extended_proc_finfo,
2974 typcache->rngtype->rng_collation,
2975 upper.val,
2976 seed));
2977 else
2978 upper_hash = 0;
2979
2980 /* Merge hashes of flags and bounds */
2982 DatumGetInt64(seed)));
2986
2987 /*
2988 * Use the same approach as hash_array to combine the individual
2989 * elements' hash values:
2990 */
2991 result = (result << 5) - result + range_hash;
2992 }
2993
2994 PG_FREE_IF_COPY(mr, 0);
2995
2996 PG_RETURN_UINT64(result);
2997}
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)
#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
#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_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
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:113
#define att_align_nominal(cur_offset, attalign)
Definition tupmacs.h:145
#define att_addlength_pointer(cur_offset, attlen, attptr)
Definition tupmacs.h:180
static Datum fetch_att(const void *T, bool attbyval, int attlen)
Definition tupmacs.h:50
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition typcache.c:386
#define TYPECACHE_HASH_PROC_FINFO
Definition typcache.h:145
#define TYPECACHE_MULTIRANGE_INFO
Definition typcache.h:154
#define TYPECACHE_HASH_EXTENDED_PROC_FINFO
Definition typcache.h:153
static Size VARSIZE(const void *PTR)
Definition varatt.h:298
static char * VARDATA(const void *PTR)
Definition varatt.h:305
static void SET_VARSIZE(void *PTR, Size len)
Definition varatt.h:432
static StringInfoData tmpbuf
Definition walsender.c:178

◆ MultirangeGetFlagsPtr

#define MultirangeGetFlagsPtr (   mr)
Value:
((uint8 *) ((char *) (mr) + \
sizeof(MultirangeType) + ((mr)->rangeCount - 1) * sizeof(uint32)))

Definition at line 73 of file multirangetypes.c.

◆ MultirangeGetItemsPtr

#define MultirangeGetItemsPtr (   mr)
Value:
((uint32 *) ((char *) (mr) + \
sizeof(MultirangeType)))

Definition at line 71 of file multirangetypes.c.

Typedef Documentation

◆ multirange_bsearch_comparison

typedef int(* multirange_bsearch_comparison) (TypeCacheEntry *typcache, RangeBound *lower, RangeBound *upper, void *key, bool *match)

Definition at line 85 of file multirangetypes.c.

◆ MultirangeIOData

Enumeration Type Documentation

◆ MultirangeParseState

Enumerator
MULTIRANGE_BEFORE_RANGE 
MULTIRANGE_IN_RANGE 
MULTIRANGE_IN_RANGE_ESCAPED 
MULTIRANGE_IN_RANGE_QUOTED 
MULTIRANGE_IN_RANGE_QUOTED_ESCAPED 
MULTIRANGE_AFTER_RANGE 
MULTIRANGE_FINISHED 

Definition at line 56 of file multirangetypes.c.

Function Documentation

◆ elem_contained_by_multirange()

◆ get_multirange_io_data()

static MultirangeIOData * get_multirange_io_data ( FunctionCallInfo  fcinfo,
Oid  mltrngtypid,
IOFuncSelector  func 
)
static

Definition at line 418 of file multirangetypes.c.

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 */
437 get_type_io_data(cache->typcache->rngtype->type_id,
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",
453 format_type_be(cache->typcache->rngtype->type_id))));
454 else
457 errmsg("no binary output function available for type %s",
458 format_type_be(cache->typcache->rngtype->type_id))));
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}

References elog, ereport, errcode(), errmsg(), ERROR, fb(), FunctionCallInfoBaseData::flinfo, fmgr_info_cxt(), FmgrInfo::fn_extra, FmgrInfo::fn_mcxt, format_type_be(), get_type_io_data(), IOFunc_receive, lookup_type_cache(), MemoryContextAlloc(), OidIsValid, TypeCacheEntry::rngtype, typalign, MultirangeIOData::typcache, TypeCacheEntry::type_id, TYPECACHE_MULTIRANGE_INFO, MultirangeIOData::typioparam, and MultirangeIOData::typioproc.

Referenced by multirange_in(), multirange_out(), multirange_recv(), and multirange_send().

◆ hash_multirange()

Datum hash_multirange ( PG_FUNCTION_ARGS  )

Definition at line 2859 of file multirangetypes.c.

2860{
2862 uint32 result = 1;
2863 TypeCacheEntry *typcache,
2864 *scache;
2866 i;
2867
2868 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2869 scache = typcache->rngtype->rngelemtype;
2870 if (!OidIsValid(scache->hash_proc_finfo.fn_oid))
2871 {
2872 scache = lookup_type_cache(scache->type_id,
2874 if (!OidIsValid(scache->hash_proc_finfo.fn_oid))
2875 ereport(ERROR,
2877 errmsg("could not identify a hash function for type %s",
2878 format_type_be(scache->type_id))));
2879 }
2880
2881 range_count = mr->rangeCount;
2882 for (i = 0; i < range_count; i++)
2883 {
2885 upper;
2886 uint8 flags = MultirangeGetFlagsPtr(mr)[i];
2890
2891 multirange_get_bounds(typcache->rngtype, mr, i, &lower, &upper);
2892
2893 if (RANGE_HAS_LBOUND(flags))
2895 typcache->rngtype->rng_collation,
2896 lower.val));
2897 else
2898 lower_hash = 0;
2899
2900 if (RANGE_HAS_UBOUND(flags))
2902 typcache->rngtype->rng_collation,
2903 upper.val));
2904 else
2905 upper_hash = 0;
2906
2907 /* Merge hashes of flags and bounds */
2912
2913 /*
2914 * Use the same approach as hash_array to combine the individual
2915 * elements' hash values:
2916 */
2917 result = (result << 5) - result + range_hash;
2918 }
2919
2920 PG_FREE_IF_COPY(mr, 0);
2921
2922 PG_RETURN_UINT32(result);
2923}

References DatumGetUInt32(), ereport, errcode(), errmsg(), ERROR, fb(), format_type_be(), FunctionCall1Coll(), hash_bytes_uint32(), i, lookup_type_cache(), lower(), multirange_get_bounds(), multirange_get_typcache(), MultirangeGetFlagsPtr, MultirangeTypeGetOid, OidIsValid, PG_FREE_IF_COPY, PG_GETARG_MULTIRANGE_P, PG_RETURN_UINT32, pg_rotate_left32(), RANGE_HAS_LBOUND, RANGE_HAS_UBOUND, TypeCacheEntry::rng_collation, TypeCacheEntry::rngelemtype, TypeCacheEntry::rngtype, TYPECACHE_HASH_PROC_FINFO, and upper().

◆ hash_multirange_extended()

Datum hash_multirange_extended ( PG_FUNCTION_ARGS  )

Definition at line 2930 of file multirangetypes.c.

2931{
2933 Datum seed = PG_GETARG_DATUM(1);
2934 uint64 result = 1;
2935 TypeCacheEntry *typcache,
2936 *scache;
2938 i;
2939
2940 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2941 scache = typcache->rngtype->rngelemtype;
2942 if (!OidIsValid(scache->hash_extended_proc_finfo.fn_oid))
2943 {
2944 scache = lookup_type_cache(scache->type_id,
2946 if (!OidIsValid(scache->hash_extended_proc_finfo.fn_oid))
2947 ereport(ERROR,
2949 errmsg("could not identify a hash function for type %s",
2950 format_type_be(scache->type_id))));
2951 }
2952
2953 range_count = mr->rangeCount;
2954 for (i = 0; i < range_count; i++)
2955 {
2957 upper;
2958 uint8 flags = MultirangeGetFlagsPtr(mr)[i];
2962
2963 multirange_get_bounds(typcache->rngtype, mr, i, &lower, &upper);
2964
2965 if (RANGE_HAS_LBOUND(flags))
2966 lower_hash = DatumGetUInt64(FunctionCall2Coll(&scache->hash_extended_proc_finfo,
2967 typcache->rngtype->rng_collation,
2968 lower.val,
2969 seed));
2970 else
2971 lower_hash = 0;
2972
2973 if (RANGE_HAS_UBOUND(flags))
2974 upper_hash = DatumGetUInt64(FunctionCall2Coll(&scache->hash_extended_proc_finfo,
2975 typcache->rngtype->rng_collation,
2976 upper.val,
2977 seed));
2978 else
2979 upper_hash = 0;
2980
2981 /* Merge hashes of flags and bounds */
2983 DatumGetInt64(seed)));
2987
2988 /*
2989 * Use the same approach as hash_array to combine the individual
2990 * elements' hash values:
2991 */
2992 result = (result << 5) - result + range_hash;
2993 }
2994
2995 PG_FREE_IF_COPY(mr, 0);
2996
2997 PG_RETURN_UINT64(result);
2998}

References DatumGetInt64(), DatumGetUInt64(), ereport, errcode(), errmsg(), ERROR, fb(), format_type_be(), FunctionCall2Coll(), hash_uint32_extended(), i, lookup_type_cache(), lower(), multirange_get_bounds(), multirange_get_typcache(), MultirangeGetFlagsPtr, MultirangeTypeGetOid, OidIsValid, PG_FREE_IF_COPY, PG_GETARG_DATUM, PG_GETARG_MULTIRANGE_P, PG_RETURN_UINT64, RANGE_HAS_LBOUND, RANGE_HAS_UBOUND, TypeCacheEntry::rng_collation, TypeCacheEntry::rngelemtype, TypeCacheEntry::rngtype, ROTATE_HIGH_AND_LOW_32BITS, TYPECACHE_HASH_EXTENDED_PROC_FINFO, and upper().

◆ make_empty_multirange()

MultirangeType * make_empty_multirange ( Oid  mltrngtypoid,
TypeCacheEntry rangetyp 
)

Definition at line 850 of file multirangetypes.c.

851{
853}

References fb(), and make_multirange().

Referenced by multirange_intersect().

◆ make_multirange()

MultirangeType * make_multirange ( Oid  mltrngtypoid,
TypeCacheEntry rangetyp,
int32  range_count,
RangeType **  ranges 
)

Definition at line 648 of file multirangetypes.c.

650{
652 Size size;
653
654 /* Sort and merge input ranges. */
656
657 /* Note: zero-fill is required here, just as in heap tuples */
659 multirange = palloc0(size);
660 SET_VARSIZE(multirange, size);
661
662 /* Now fill in the datum */
663 multirange->multirangetypid = mltrngtypoid;
664 multirange->rangeCount = range_count;
665
667
668 return multirange;
669}

References fb(), multirange_canonicalize(), multirange_size_estimate(), palloc0(), SET_VARSIZE(), and write_multirange_data().

Referenced by make_empty_multirange(), multirange_constructor0(), multirange_constructor1(), multirange_constructor2(), multirange_in(), multirange_intersect_internal(), multirange_minus_internal(), multirange_recv(), multirange_union(), multirangesel(), and range_agg_finalfn().

◆ multirange_adjacent_multirange()

Datum multirange_adjacent_multirange ( PG_FUNCTION_ARGS  )

Definition at line 2606 of file multirangetypes.c.

2607{
2610 TypeCacheEntry *typcache;
2614 upper1,
2615 lower2,
2616 upper2;
2617
2619 PG_RETURN_BOOL(false);
2620
2622
2623 range_count1 = mr1->rangeCount;
2624 range_count2 = mr2->rangeCount;
2626 &lower1, &upper1);
2627 multirange_get_bounds(typcache->rngtype, mr2, 0,
2628 &lower2, &upper2);
2629 if (bounds_adjacent(typcache->rngtype, upper1, lower2))
2630 PG_RETURN_BOOL(true);
2631
2632 if (range_count1 > 1)
2633 multirange_get_bounds(typcache->rngtype, mr1, 0,
2634 &lower1, &upper1);
2635 if (range_count2 > 1)
2637 &lower2, &upper2);
2638 if (bounds_adjacent(typcache->rngtype, upper2, lower1))
2639 PG_RETURN_BOOL(true);
2640 PG_RETURN_BOOL(false);
2641}

References bounds_adjacent(), fb(), multirange_get_bounds(), multirange_get_typcache(), MultirangeIsEmpty, MultirangeTypeGetOid, PG_GETARG_MULTIRANGE_P, PG_RETURN_BOOL, and TypeCacheEntry::rngtype.

◆ multirange_adjacent_range()

◆ multirange_after_multirange()

◆ multirange_after_range()

◆ multirange_agg_transfn()

Datum multirange_agg_transfn ( PG_FUNCTION_ARGS  )

Definition at line 1485 of file multirangetypes.c.

1486{
1489 TypeCacheEntry *typcache;
1492
1493 if (!AggCheckCallContext(fcinfo, &aggContext))
1494 elog(ERROR, "multirange_agg_transfn called in non-aggregate context");
1495
1496 mltrngtypoid = get_fn_expr_argtype(fcinfo->flinfo, 1);
1498 elog(ERROR, "range_agg must be called with a multirange");
1499
1500 typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
1501 rngtypcache = typcache->rngtype;
1502
1503 if (PG_ARGISNULL(0))
1504 state = initArrayResult(rngtypcache->type_id, aggContext, false);
1505 else
1507
1508 /* skip NULLs */
1509 if (!PG_ARGISNULL(1))
1510 {
1511 MultirangeType *current;
1513 RangeType **ranges;
1514
1515 current = PG_GETARG_MULTIRANGE_P(1);
1516 multirange_deserialize(rngtypcache, current, &range_count, &ranges);
1517 if (range_count == 0)
1518 {
1519 /*
1520 * Add an empty range so we get an empty result (not a null
1521 * result).
1522 */
1525 false, rngtypcache->type_id, aggContext);
1526 }
1527 else
1528 {
1529 for (int32 i = 0; i < range_count; i++)
1530 accumArrayResult(state, RangeTypePGetDatum(ranges[i]), false, rngtypcache->type_id, aggContext);
1531 }
1532 }
1533
1535}

References accumArrayResult(), AggCheckCallContext(), elog, ERROR, fb(), get_fn_expr_argtype(), i, initArrayResult(), make_empty_range(), multirange_deserialize(), multirange_get_typcache(), PG_ARGISNULL, PG_GETARG_MULTIRANGE_P, PG_GETARG_POINTER, PG_RETURN_POINTER, RangeTypePGetDatum(), TypeCacheEntry::rngtype, and type_is_multirange().

◆ multirange_before_multirange()

◆ multirange_before_multirange_internal()

bool multirange_before_multirange_internal ( TypeCacheEntry rangetyp,
const MultirangeType mr1,
const MultirangeType mr2 
)

Definition at line 2496 of file multirangetypes.c.

2499{
2501 upper1,
2502 lower2,
2503 upper2;
2504
2506 return false;
2507
2508 multirange_get_bounds(rangetyp, mr1, mr1->rangeCount - 1,
2509 &lower1, &upper1);
2511 &lower2, &upper2);
2512
2513 return (range_cmp_bounds(rangetyp, &upper1, &lower2) < 0);
2514}

References fb(), multirange_get_bounds(), MultirangeIsEmpty, and range_cmp_bounds().

Referenced by multirange_after_multirange(), and multirange_before_multirange().

◆ multirange_before_range()

◆ multirange_bsearch_match()

static bool multirange_bsearch_match ( TypeCacheEntry typcache,
const MultirangeType mr,
void key,
multirange_bsearch_comparison  cmp_func 
)
static

Definition at line 900 of file multirangetypes.c.

902{
903 uint32 l,
904 u,
905 idx;
906 int comparison;
907 bool match = false;
908
909 l = 0;
910 u = mr->rangeCount;
911 while (l < u)
912 {
914 upper;
915
916 idx = (l + u) / 2;
917 multirange_get_bounds(typcache, mr, idx, &lower, &upper);
918 comparison = (*cmp_func) (typcache, &lower, &upper, key, &match);
919
920 if (comparison < 0)
921 u = idx;
922 else if (comparison > 0)
923 l = idx + 1;
924 else
925 return match;
926 }
927
928 return false;
929}

References fb(), idx(), lower(), multirange_get_bounds(), and upper().

Referenced by multirange_contains_elem_internal(), multirange_contains_range_internal(), and range_overlaps_multirange_internal().

◆ multirange_canonicalize()

static int32 multirange_canonicalize ( TypeCacheEntry rangetyp,
int32  input_range_count,
RangeType **  ranges 
)
static

Definition at line 479 of file multirangetypes.c.

481{
484 int32 i;
486
487 /* Sort the ranges so we can find the ones that overlap/meet. */
489 rangetyp);
490
491 /* Now merge where possible: */
492 for (i = 0; i < input_range_count; i++)
493 {
494 currentRange = ranges[i];
496 continue;
497
498 if (lastRange == NULL)
499 {
501 continue;
502 }
503
504 /*
505 * range_adjacent_internal gives true if *either* A meets B or B meets
506 * A, which is not quite want we want, but we rely on the sorting
507 * above to rule out B meets A ever happening.
508 */
510 {
511 /* The two ranges touch (without overlap), so merge them: */
512 ranges[output_range_count - 1] = lastRange =
514 }
516 {
517 /* There's a gap, so make a new entry: */
520 }
521 else
522 {
523 /* They must overlap, so merge them: */
524 ranges[output_range_count - 1] = lastRange =
526 }
527 }
528
529 return output_range_count;
530}

References fb(), i, qsort_arg(), range_adjacent_internal(), range_before_internal(), range_compare(), range_union_internal(), and RangeIsEmpty.

Referenced by make_multirange().

◆ multirange_cmp()

Datum multirange_cmp ( PG_FUNCTION_ARGS  )

Definition at line 2647 of file multirangetypes.c.

2648{
2654 int32 i;
2655 TypeCacheEntry *typcache;
2656 int cmp = 0; /* If both are empty we'll use this. */
2657
2658 /* Different types should be prevented by ANYMULTIRANGE matching rules */
2660 elog(ERROR, "multirange types do not match");
2661
2663
2664 range_count_1 = mr1->rangeCount;
2665 range_count_2 = mr2->rangeCount;
2666
2667 /* Loop over source data */
2669 for (i = 0; i < range_count_max; i++)
2670 {
2672 upper1,
2673 lower2,
2674 upper2;
2675
2676 /*
2677 * If one multirange is shorter, it's as if it had empty ranges at the
2678 * end to extend its length. An empty range compares earlier than any
2679 * other range, so the shorter multirange comes before the longer.
2680 * This is the same behavior as in other types, e.g. in strings 'aaa'
2681 * < 'aaaaaa'.
2682 */
2683 if (i >= range_count_1)
2684 {
2685 cmp = -1;
2686 break;
2687 }
2688 if (i >= range_count_2)
2689 {
2690 cmp = 1;
2691 break;
2692 }
2693
2696
2697 cmp = range_cmp_bounds(typcache->rngtype, &lower1, &lower2);
2698 if (cmp == 0)
2699 cmp = range_cmp_bounds(typcache->rngtype, &upper1, &upper2);
2700 if (cmp != 0)
2701 break;
2702 }
2703
2704 PG_FREE_IF_COPY(mr1, 0);
2705 PG_FREE_IF_COPY(mr2, 1);
2706
2708}

References cmp(), elog, ERROR, fb(), i, Max, multirange_get_bounds(), multirange_get_typcache(), MultirangeTypeGetOid, PG_FREE_IF_COPY, PG_GETARG_MULTIRANGE_P, PG_RETURN_INT32, range_cmp_bounds(), and TypeCacheEntry::rngtype.

Referenced by multirange_ge(), multirange_gt(), multirange_le(), and multirange_lt().

◆ multirange_constructor0()

Datum multirange_constructor0 ( PG_FUNCTION_ARGS  )

Definition at line 1061 of file multirangetypes.c.

1062{
1064 TypeCacheEntry *typcache;
1066
1067 /* This should always be called without arguments */
1068 if (PG_NARGS() != 0)
1069 elog(ERROR,
1070 "niladic multirange constructor must not receive arguments");
1071
1072 mltrngtypid = get_fn_expr_rettype(fcinfo->flinfo);
1073 typcache = multirange_get_typcache(fcinfo, mltrngtypid);
1074 rangetyp = typcache->rngtype;
1075
1077}

References elog, ERROR, fb(), get_fn_expr_rettype(), make_multirange(), multirange_get_typcache(), PG_NARGS, PG_RETURN_MULTIRANGE_P, and TypeCacheEntry::rngtype.

◆ multirange_constructor1()

Datum multirange_constructor1 ( PG_FUNCTION_ARGS  )

Definition at line 1025 of file multirangetypes.c.

1026{
1027 Oid mltrngtypid = get_fn_expr_rettype(fcinfo->flinfo);
1028 Oid rngtypid;
1029 TypeCacheEntry *typcache;
1032
1033 typcache = multirange_get_typcache(fcinfo, mltrngtypid);
1034 rangetyp = typcache->rngtype;
1035
1036 /*
1037 * This check should be guaranteed by our signature, but let's do it just
1038 * in case.
1039 */
1040
1041 if (PG_ARGISNULL(0))
1042 elog(ERROR,
1043 "multirange values cannot contain null members");
1044
1046
1047 /* Make sure the range type matches. */
1049 if (rngtypid != rangetyp->type_id)
1050 elog(ERROR, "type %u does not match constructor type", rngtypid);
1051
1053}

References elog, ERROR, fb(), get_fn_expr_rettype(), make_multirange(), multirange_get_typcache(), PG_ARGISNULL, PG_GETARG_RANGE_P, PG_RETURN_MULTIRANGE_P, range(), RangeTypeGetOid, and TypeCacheEntry::rngtype.

◆ multirange_constructor2()

Datum multirange_constructor2 ( PG_FUNCTION_ARGS  )

Definition at line 943 of file multirangetypes.c.

944{
945 Oid mltrngtypid = get_fn_expr_rettype(fcinfo->flinfo);
947 TypeCacheEntry *typcache;
950 int range_count;
951 Datum *elements;
952 bool *nulls;
953 RangeType **ranges;
954 int dims;
955 int i;
956
957 typcache = multirange_get_typcache(fcinfo, mltrngtypid);
958 rangetyp = typcache->rngtype;
959
960 /*
961 * A no-arg invocation should call multirange_constructor0 instead, but
962 * returning an empty range is what that does.
963 */
964
965 if (PG_NARGS() == 0)
967
968 /*
969 * This check should be guaranteed by our signature, but let's do it just
970 * in case.
971 */
972
973 if (PG_ARGISNULL(0))
974 elog(ERROR,
975 "multirange values cannot contain null members");
976
978
979 dims = ARR_NDIM(rangeArray);
980 if (dims > 1)
983 errmsg("multiranges cannot be constructed from multidimensional arrays")));
984
986 if (rngtypid != rangetyp->type_id)
987 elog(ERROR, "type %u does not match constructor type", rngtypid);
988
989 /*
990 * Be careful: we can still be called with zero ranges, like this:
991 * `int4multirange(variadic '{}'::int4range[])
992 */
993 if (dims == 0)
994 {
995 range_count = 0;
996 ranges = NULL;
997 }
998 else
999 {
1001 rangetyp->typalign, &elements, &nulls, &range_count);
1002
1003 ranges = palloc0(range_count * sizeof(RangeType *));
1004 for (i = 0; i < range_count; i++)
1005 {
1006 if (nulls[i])
1007 ereport(ERROR,
1009 errmsg("multirange values cannot contain null members")));
1010
1011 /* make_multirange will do its own copy */
1012 ranges[i] = DatumGetRangeTypeP(elements[i]);
1013 }
1014 }
1015
1017}

References ARR_ELEMTYPE, ARR_NDIM, DatumGetRangeTypeP(), deconstruct_array(), elog, ereport, errcode(), errmsg(), ERROR, fb(), get_fn_expr_rettype(), i, make_multirange(), multirange_get_typcache(), palloc0(), PG_ARGISNULL, PG_GETARG_ARRAYTYPE_P, PG_NARGS, PG_RETURN_MULTIRANGE_P, and TypeCacheEntry::rngtype.

◆ multirange_contained_by_multirange()

◆ multirange_contained_by_range()

◆ multirange_contains_elem()

◆ multirange_contains_elem_internal()

bool multirange_contains_elem_internal ( TypeCacheEntry rangetyp,
const MultirangeType mr,
Datum  val 
)

◆ multirange_contains_multirange()

◆ multirange_contains_multirange_internal()

bool multirange_contains_multirange_internal ( TypeCacheEntry rangetyp,
const MultirangeType mr1,
const MultirangeType mr2 
)

Definition at line 2338 of file multirangetypes.c.

2341{
2342 int32 range_count1 = mr1->rangeCount;
2343 int32 range_count2 = mr2->rangeCount;
2344 int i1,
2345 i2;
2347 upper1,
2348 lower2,
2349 upper2;
2350
2351 /*
2352 * We follow the same logic for empties as ranges: - an empty multirange
2353 * contains an empty range/multirange. - an empty multirange can't contain
2354 * any other range/multirange. - an empty multirange is contained by any
2355 * other range/multirange.
2356 */
2357
2358 if (range_count2 == 0)
2359 return true;
2360 if (range_count1 == 0)
2361 return false;
2362
2363 /*
2364 * Every range in mr2 must be contained by some range in mr1. To avoid
2365 * O(n^2) we walk through both ranges in tandem.
2366 */
2367 i1 = 0;
2369 for (i2 = 0; i2 < range_count2; i2++)
2370 {
2372
2373 /* Discard r1s while r1 << r2 */
2374 while (range_cmp_bounds(rangetyp, &upper1, &lower2) < 0)
2375 {
2376 if (++i1 >= range_count1)
2377 return false;
2379 }
2380
2381 /*
2382 * If r1 @> r2, go to the next r2, otherwise return false (since every
2383 * r1[n] and r1[n+1] must have a gap). Note this will give weird
2384 * answers if you don't canonicalize, e.g. with a custom
2385 * int2multirange {[1,1], [2,2]} there is a "gap". But that is
2386 * consistent with other range operators, e.g. '[1,1]'::int2range -|-
2387 * '[2,2]'::int2range is false.
2388 */
2390 &lower2, &upper2))
2391 return false;
2392 }
2393
2394 /* All ranges in mr2 are satisfied */
2395 return true;
2396}

References fb(), multirange_get_bounds(), range_bounds_contains(), and range_cmp_bounds().

Referenced by multirange_contained_by_multirange(), and multirange_contains_multirange().

◆ multirange_contains_range()

◆ multirange_contains_range_internal()

bool multirange_contains_range_internal ( TypeCacheEntry rangetyp,
const MultirangeType mr,
const RangeType r 
)

Definition at line 1874 of file multirangetypes.c.

1877{
1878 RangeBound bounds[2];
1879 bool empty;
1880
1881 /*
1882 * Every multirange contains an infinite number of empty ranges, even an
1883 * empty one.
1884 */
1885 if (RangeIsEmpty(r))
1886 return true;
1887
1888 if (MultirangeIsEmpty(mr))
1889 return false;
1890
1891 range_deserialize(rangetyp, r, &bounds[0], &bounds[1], &empty);
1892 Assert(!empty);
1893
1896}

References Assert, fb(), multirange_bsearch_match(), multirange_range_contains_bsearch_comparison(), MultirangeIsEmpty, range_deserialize(), and RangeIsEmpty.

Referenced by multirange_contains_range(), range_contained_by_multirange(), and range_gist_consistent_leaf_multirange().

◆ multirange_deserialize()

void multirange_deserialize ( TypeCacheEntry rangetyp,
const MultirangeType multirange,
int32 range_count,
RangeType ***  ranges 
)

Definition at line 828 of file multirangetypes.c.

831{
832 *range_count = multirange->rangeCount;
833
834 /* Convert each ShortRangeType into a RangeType */
835 if (*range_count > 0)
836 {
837 int i;
838
839 *ranges = palloc_array(RangeType *, *range_count);
840 for (i = 0; i < *range_count; i++)
842 }
843 else
844 {
845 *ranges = NULL;
846 }
847}

References fb(), i, multirange_get_range(), and palloc_array.

Referenced by multirange_agg_transfn(), multirange_intersect(), multirange_intersect_agg_transfn(), multirange_minus(), multirange_minus_multi(), multirange_out(), multirange_send(), and multirange_union().

◆ multirange_elem_bsearch_comparison()

static int multirange_elem_bsearch_comparison ( TypeCacheEntry typcache,
RangeBound lower,
RangeBound upper,
void key,
bool match 
)
static

Definition at line 1747 of file multirangetypes.c.

1750{
1751 Datum val = *((Datum *) key);
1752 int cmp;
1753
1754 if (!lower->infinite)
1755 {
1757 typcache->rng_collation,
1758 lower->val, val));
1759 if (cmp > 0 || (cmp == 0 && !lower->inclusive))
1760 return -1;
1761 }
1762
1763 if (!upper->infinite)
1764 {
1766 typcache->rng_collation,
1767 upper->val, val));
1768 if (cmp < 0 || (cmp == 0 && !upper->inclusive))
1769 return 1;
1770 }
1771
1772 *match = true;
1773 return 0;
1774}

References cmp(), DatumGetInt32(), FunctionCall2Coll(), lower(), TypeCacheEntry::rng_cmp_proc_finfo, TypeCacheEntry::rng_collation, upper(), and val.

Referenced by multirange_contains_elem_internal().

◆ multirange_empty()

Datum multirange_empty ( PG_FUNCTION_ARGS  )

◆ multirange_eq()

◆ multirange_eq_internal()

bool multirange_eq_internal ( TypeCacheEntry rangetyp,
const MultirangeType mr1,
const MultirangeType mr2 
)

Definition at line 1937 of file multirangetypes.c.

1940{
1943 int32 i;
1945 upper1,
1946 lower2,
1947 upper2;
1948
1949 /* Different types should be prevented by ANYMULTIRANGE matching rules */
1951 elog(ERROR, "multirange types do not match");
1952
1953 range_count_1 = mr1->rangeCount;
1954 range_count_2 = mr2->rangeCount;
1955
1957 return false;
1958
1959 for (i = 0; i < range_count_1; i++)
1960 {
1963
1964 if (range_cmp_bounds(rangetyp, &lower1, &lower2) != 0 ||
1966 return false;
1967 }
1968
1969 return true;
1970}

References elog, ERROR, fb(), i, multirange_get_bounds(), MultirangeTypeGetOid, and range_cmp_bounds().

Referenced by multirange_eq(), and multirange_ne_internal().

◆ multirange_ge()

Datum multirange_ge ( PG_FUNCTION_ARGS  )

Definition at line 2728 of file multirangetypes.c.

2729{
2730 int cmp = DatumGetInt32(multirange_cmp(fcinfo));
2731
2732 PG_RETURN_BOOL(cmp >= 0);
2733}

References cmp(), DatumGetInt32(), multirange_cmp(), and PG_RETURN_BOOL.

◆ multirange_get_bounds()

void multirange_get_bounds ( TypeCacheEntry rangetyp,
const MultirangeType multirange,
uint32  i,
RangeBound lower,
RangeBound upper 
)

Definition at line 746 of file multirangetypes.c.

749{
750 uint32 offset;
751 uint8 flags;
752 const char *ptr;
753 int16 typlen = rangetyp->rngelemtype->typlen;
754 char typalign = rangetyp->rngelemtype->typalign;
755 bool typbyval = rangetyp->rngelemtype->typbyval;
756 Datum lbound;
758
759 Assert(i < multirange->rangeCount);
760
764
765 /* multirange can't contain empty ranges */
766 Assert((flags & RANGE_EMPTY) == 0);
767
768 /* fetch lower bound, if any */
769 if (RANGE_HAS_LBOUND(flags))
770 {
771 /* att_align_pointer cannot be necessary here */
772 lbound = fetch_att(ptr, typbyval, typlen);
773 ptr = (char *) att_addlength_pointer(ptr, typlen, ptr);
774 }
775 else
776 lbound = (Datum) 0;
777
778 /* fetch upper bound, if any */
779 if (RANGE_HAS_UBOUND(flags))
780 {
781 ptr = (char *) att_align_pointer(ptr, typalign, typlen, ptr);
782 ubound = fetch_att(ptr, typbyval, typlen);
783 /* no need for att_addlength_pointer */
784 }
785 else
786 ubound = (Datum) 0;
787
788 /* emit results */
789 lower->val = lbound;
790 lower->infinite = (flags & RANGE_LB_INF) != 0;
791 lower->inclusive = (flags & RANGE_LB_INC) != 0;
792 lower->lower = true;
793
794 upper->val = ubound;
795 upper->infinite = (flags & RANGE_UB_INF) != 0;
796 upper->inclusive = (flags & RANGE_UB_INC) != 0;
797 upper->lower = false;
798}

References Assert, att_addlength_pointer, att_align_pointer, fb(), fetch_att(), i, lower(), multirange_get_bounds_offset(), MultirangeGetBoundariesPtr, MultirangeGetFlagsPtr, RANGE_EMPTY, RANGE_HAS_LBOUND, RANGE_HAS_UBOUND, RANGE_LB_INC, RANGE_LB_INF, RANGE_UB_INC, RANGE_UB_INF, typalign, and upper().

Referenced by calc_hist_selectivity(), compute_range_stats(), hash_multirange(), hash_multirange_extended(), multirange_adjacent_multirange(), multirange_before_multirange_internal(), multirange_bsearch_match(), multirange_cmp(), multirange_contains_multirange_internal(), multirange_eq_internal(), multirange_get_union_range(), multirange_lower(), multirange_lower_inc(), multirange_lower_inf(), multirange_overlaps_multirange_internal(), multirange_overleft_multirange(), multirange_overleft_range(), multirange_overright_multirange(), multirange_overright_range(), multirange_union_range_equal(), multirange_upper(), multirange_upper_inc(), multirange_upper_inf(), range_adjacent_multirange_internal(), range_after_multirange_internal(), range_before_multirange_internal(), range_contains_multirange_internal(), range_merge_from_multirange(), range_overleft_multirange_internal(), and range_overright_multirange_internal().

◆ multirange_get_bounds_offset()

static uint32 multirange_get_bounds_offset ( const MultirangeType multirange,
int32  i 
)
static

Definition at line 675 of file multirangetypes.c.

676{
678 uint32 offset = 0;
679
680 /*
681 * Summarize lengths till we meet an offset.
682 */
683 while (i > 0)
684 {
685 offset += MULTIRANGE_ITEM_GET_OFFLEN(items[i - 1]);
687 break;
688 i--;
689 }
690 return offset;
691}

References fb(), i, items, MULTIRANGE_ITEM_GET_OFFLEN, MULTIRANGE_ITEM_HAS_OFF, and MultirangeGetItemsPtr.

Referenced by multirange_get_bounds(), and multirange_get_range().

◆ multirange_get_range()

RangeType * multirange_get_range ( TypeCacheEntry rangetyp,
const MultirangeType multirange,
int  i 
)

Definition at line 697 of file multirangetypes.c.

699{
700 uint32 offset;
701 uint8 flags;
702 const char *begin;
703 char *ptr;
704 int16 typlen = rangetyp->rngelemtype->typlen;
705 char typalign = rangetyp->rngelemtype->typalign;
706 uint32 len;
708
709 Assert(i < multirange->rangeCount);
710
713 begin = ptr = MultirangeGetBoundariesPtr(multirange, typalign) + offset;
714
715 /*
716 * Calculate the size of bound values. In principle, we could get offset
717 * of the next range bound values and calculate accordingly. But range
718 * bound values are aligned, so we have to walk the values to get the
719 * exact size.
720 */
721 if (RANGE_HAS_LBOUND(flags))
722 ptr = (char *) att_addlength_pointer(ptr, typlen, ptr);
723 if (RANGE_HAS_UBOUND(flags))
724 {
725 ptr = (char *) att_align_pointer(ptr, typalign, typlen, ptr);
726 ptr = (char *) att_addlength_pointer(ptr, typlen, ptr);
727 }
728 len = (ptr - begin) + sizeof(RangeType) + sizeof(uint8);
729
730 range = palloc0(len);
732 range->rangetypid = rangetyp->type_id;
733
734 memcpy(range + 1, begin, ptr - begin);
735 *((uint8 *) (range + 1) + (ptr - begin)) = flags;
736
737 return range;
738}

References Assert, att_addlength_pointer, att_align_pointer, fb(), i, len, multirange_get_bounds_offset(), MultirangeGetBoundariesPtr, MultirangeGetFlagsPtr, palloc0(), range(), RANGE_HAS_LBOUND, RANGE_HAS_UBOUND, SET_VARSIZE(), and typalign.

Referenced by multirange_deserialize(), multirange_unnest(), and range_merge_from_multirange().

◆ multirange_get_typcache()

TypeCacheEntry * multirange_get_typcache ( FunctionCallInfo  fcinfo,
Oid  mltrngtypid 
)

Definition at line 550 of file multirangetypes.c.

551{
552 TypeCacheEntry *typcache = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
553
554 if (typcache == NULL ||
555 typcache->type_id != mltrngtypid)
556 {
558 if (typcache->rngtype == NULL)
559 elog(ERROR, "type %u is not a multirange type", mltrngtypid);
560 fcinfo->flinfo->fn_extra = typcache;
561 }
562
563 return typcache;
564}

References elog, ERROR, fb(), FunctionCallInfoBaseData::flinfo, FmgrInfo::fn_extra, lookup_type_cache(), TypeCacheEntry::rngtype, TypeCacheEntry::type_id, and TYPECACHE_MULTIRANGE_INFO.

Referenced by elem_contained_by_multirange(), hash_multirange(), hash_multirange_extended(), multirange_adjacent_multirange(), multirange_adjacent_range(), multirange_after_multirange(), multirange_after_range(), multirange_agg_transfn(), multirange_before_multirange(), multirange_before_range(), multirange_cmp(), multirange_constructor0(), multirange_constructor1(), multirange_constructor2(), multirange_contained_by_multirange(), multirange_contained_by_range(), multirange_contains_elem(), multirange_contains_multirange(), multirange_contains_range(), multirange_eq(), multirange_gist_compress(), multirange_intersect(), multirange_intersect_agg_transfn(), multirange_lower(), multirange_lower_inc(), multirange_lower_inf(), multirange_minus(), multirange_ne(), multirange_overlaps_multirange(), multirange_overlaps_range(), multirange_overleft_multirange(), multirange_overleft_range(), multirange_overright_multirange(), multirange_overright_range(), multirange_typanalyze(), multirange_union(), multirange_upper(), multirange_upper_inc(), multirange_upper_inf(), multirangesel(), range_adjacent_multirange(), range_after_multirange(), range_agg_finalfn(), range_before_multirange(), range_contained_by_multirange(), range_contains_multirange(), range_merge_from_multirange(), range_overlaps_multirange(), range_overleft_multirange(), and range_overright_multirange().

◆ multirange_get_union_range()

RangeType * multirange_get_union_range ( TypeCacheEntry rangetyp,
const MultirangeType mr 
)

Definition at line 804 of file multirangetypes.c.

806{
808 upper,
809 tmp;
810
813
815 multirange_get_bounds(rangetyp, mr, mr->rangeCount - 1, &tmp, &upper);
816
817 return make_range(rangetyp, &lower, &upper, false, NULL);
818}

References fb(), lower(), make_empty_range(), make_range(), multirange_get_bounds(), MultirangeIsEmpty, and upper().

Referenced by multirange_gist_compress().

◆ multirange_gt()

Datum multirange_gt ( PG_FUNCTION_ARGS  )

Definition at line 2736 of file multirangetypes.c.

2737{
2738 int cmp = DatumGetInt32(multirange_cmp(fcinfo));
2739
2740 PG_RETURN_BOOL(cmp > 0);
2741}

References cmp(), DatumGetInt32(), multirange_cmp(), and PG_RETURN_BOOL.

◆ multirange_in()

Datum multirange_in ( PG_FUNCTION_ARGS  )

Definition at line 117 of file multirangetypes.c.

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}

References DatumGetRangeTypeP(), elog, ereturn, errcode(), errdetail(), errmsg(), ERROR, fb(), get_multirange_io_data(), InputFunctionCallSafe(), IOFunc_input, make_multirange(), MULTIRANGE_AFTER_RANGE, MULTIRANGE_BEFORE_RANGE, MULTIRANGE_FINISHED, MULTIRANGE_IN_RANGE, MULTIRANGE_IN_RANGE_ESCAPED, MULTIRANGE_IN_RANGE_QUOTED, MULTIRANGE_IN_RANGE_QUOTED_ESCAPED, palloc_array, PG_GETARG_CSTRING, PG_GETARG_INT32, PG_GETARG_OID, PG_RETURN_MULTIRANGE_P, PG_RETURN_NULL, pg_strncasecmp(), pnstrdup(), range(), RANGE_EMPTY_LITERAL, RangeIsEmpty, repalloc(), TypeCacheEntry::rngtype, MultirangeIOData::typcache, MultirangeIOData::typioparam, and MultirangeIOData::typioproc.

◆ multirange_intersect()

◆ multirange_intersect_agg_transfn()

Datum multirange_intersect_agg_transfn ( PG_FUNCTION_ARGS  )

Definition at line 1538 of file multirangetypes.c.

1539{
1542 TypeCacheEntry *typcache;
1543 MultirangeType *result;
1544 MultirangeType *current;
1549
1550 if (!AggCheckCallContext(fcinfo, &aggContext))
1551 elog(ERROR, "multirange_intersect_agg_transfn called in non-aggregate context");
1552
1553 mltrngtypoid = get_fn_expr_argtype(fcinfo->flinfo, 1);
1555 elog(ERROR, "range_intersect_agg must be called with a multirange");
1556
1557 typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
1558
1559 /* strictness ensures these are non-null */
1560 result = PG_GETARG_MULTIRANGE_P(0);
1561 current = PG_GETARG_MULTIRANGE_P(1);
1562
1563 multirange_deserialize(typcache->rngtype, result, &range_count1, &ranges1);
1564 multirange_deserialize(typcache->rngtype, current, &range_count2, &ranges2);
1565
1567 typcache->rngtype,
1569 ranges1,
1571 ranges2);
1572 PG_RETURN_MULTIRANGE_P(result);
1573}

References AggCheckCallContext(), elog, ERROR, fb(), get_fn_expr_argtype(), multirange_deserialize(), multirange_get_typcache(), multirange_intersect_internal(), PG_GETARG_MULTIRANGE_P, PG_RETURN_MULTIRANGE_P, TypeCacheEntry::rngtype, and type_is_multirange().

◆ multirange_intersect_internal()

MultirangeType * multirange_intersect_internal ( Oid  mltrngtypoid,
TypeCacheEntry rangetyp,
int32  range_count1,
RangeType **  ranges1,
int32  range_count2,
RangeType **  ranges2 
)

Definition at line 1333 of file multirangetypes.c.

1336{
1337 RangeType *r1;
1338 RangeType *r2;
1341 int32 i1;
1342 int32 i2;
1343
1344 if (range_count1 == 0 || range_count2 == 0)
1346
1347 /*-----------------------------------------------
1348 * Worst case is a stitching pattern like this:
1349 *
1350 * mr1: --- --- --- ---
1351 * mr2: --- --- ---
1352 * mr3: - - - - - -
1353 *
1354 * That seems to be range_count1 + range_count2 - 1,
1355 * but one extra won't hurt.
1356 *-----------------------------------------------
1357 */
1359 range_count3 = 0;
1360
1361 /*
1362 * For each range in mr1, keep intersecting until the ranges in mr2 have
1363 * passed it. The parallel progress through mr1 and mr2 is similar to
1364 * multirange_minus_multirange_internal, but we don't have to assign back
1365 * to r1.
1366 */
1367 r2 = ranges2[0];
1368 for (i1 = 0, i2 = 0; i1 < range_count1; i1++)
1369 {
1370 r1 = ranges1[i1];
1371
1372 /* Discard r2s while r2 << r1 */
1373 while (r2 != NULL && range_before_internal(rangetyp, r2, r1))
1374 {
1375 r2 = ++i2 >= range_count2 ? NULL : ranges2[i2];
1376 }
1377
1378 while (r2 != NULL)
1379 {
1381 {
1382 /* Keep the overlapping part */
1384
1385 /* If we "used up" all of r2, go to the next one... */
1387 r2 = ++i2 >= range_count2 ? NULL : ranges2[i2];
1388
1389 /* ...otherwise go to the next r1 */
1390 else
1391 break;
1392 }
1393 else
1394 /* We're past r1, so move to the next one */
1395 break;
1396 }
1397
1398 /* If we're out of r2s, there can be no more intersections */
1399 if (r2 == NULL)
1400 break;
1401 }
1402
1404}

References fb(), make_multirange(), palloc0(), range_before_internal(), range_intersect_internal(), range_overlaps_internal(), and range_overleft_internal().

Referenced by multirange_intersect(), and multirange_intersect_agg_transfn().

◆ multirange_le()

Datum multirange_le ( PG_FUNCTION_ARGS  )

Definition at line 2720 of file multirangetypes.c.

2721{
2722 int cmp = DatumGetInt32(multirange_cmp(fcinfo));
2723
2724 PG_RETURN_BOOL(cmp <= 0);
2725}

References cmp(), DatumGetInt32(), multirange_cmp(), and PG_RETURN_BOOL.

◆ multirange_lower()

Datum multirange_lower ( PG_FUNCTION_ARGS  )

◆ multirange_lower_inc()

◆ multirange_lower_inf()

◆ multirange_lt()

Datum multirange_lt ( PG_FUNCTION_ARGS  )

Definition at line 2712 of file multirangetypes.c.

2713{
2714 int cmp = DatumGetInt32(multirange_cmp(fcinfo));
2715
2716 PG_RETURN_BOOL(cmp < 0);
2717}

References cmp(), DatumGetInt32(), multirange_cmp(), and PG_RETURN_BOOL.

◆ multirange_minus()

◆ multirange_minus_internal()

MultirangeType * multirange_minus_internal ( Oid  mltrngtypoid,
TypeCacheEntry rangetyp,
int32  range_count1,
RangeType **  ranges1,
int32  range_count2,
RangeType **  ranges2 
)

Definition at line 1146 of file multirangetypes.c.

1149{
1150 RangeType *r1;
1151 RangeType *r2;
1154 int32 i1;
1155 int32 i2;
1156
1157 /*
1158 * Worst case: every range in ranges1 makes a different cut to some range
1159 * in ranges2.
1160 */
1162 range_count3 = 0;
1163
1164 /*
1165 * For each range in mr1, keep subtracting until it's gone or the ranges
1166 * in mr2 have passed it. After a subtraction we assign what's left back
1167 * to r1. The parallel progress through mr1 and mr2 is similar to
1168 * multirange_overlaps_multirange_internal.
1169 */
1170 r2 = ranges2[0];
1171 for (i1 = 0, i2 = 0; i1 < range_count1; i1++)
1172 {
1173 r1 = ranges1[i1];
1174
1175 /* Discard r2s while r2 << r1 */
1176 while (r2 != NULL && range_before_internal(rangetyp, r2, r1))
1177 {
1178 r2 = ++i2 >= range_count2 ? NULL : ranges2[i2];
1179 }
1180
1181 while (r2 != NULL)
1182 {
1184 {
1185 /*
1186 * If r2 takes a bite out of the middle of r1, we need two
1187 * outputs
1188 */
1189 range_count3++;
1190 r2 = ++i2 >= range_count2 ? NULL : ranges2[i2];
1191 }
1193 {
1194 /*
1195 * If r2 overlaps r1, replace r1 with r1 - r2.
1196 */
1198
1199 /*
1200 * If r2 goes past r1, then we need to stay with it, in case
1201 * it hits future r1s. Otherwise we need to keep r1, in case
1202 * future r2s hit it. Since we already subtracted, there's no
1203 * point in using the overright/overleft calls.
1204 */
1206 break;
1207 else
1208 r2 = ++i2 >= range_count2 ? NULL : ranges2[i2];
1209 }
1210 else
1211 {
1212 /*
1213 * This and all future r2s are past r1, so keep them. Also
1214 * assign whatever is left of r1 to the result.
1215 */
1216 break;
1217 }
1218 }
1219
1220 /*
1221 * Nothing else can remove anything from r1, so keep it. Even if r1 is
1222 * empty here, make_multirange will remove it.
1223 */
1224 ranges3[range_count3++] = r1;
1225 }
1226
1228}

References fb(), make_multirange(), palloc0(), range_before_internal(), range_minus_internal(), range_overlaps_internal(), range_split_internal(), and RangeIsEmpty.

Referenced by multirange_minus(), and multirange_minus_multi().

◆ multirange_minus_multi()

Datum multirange_minus_multi ( PG_FUNCTION_ARGS  )

Definition at line 1235 of file multirangetypes.c.

1236{
1238 MemoryContext oldcontext;
1239
1240 if (!SRF_IS_FIRSTCALL())
1241 {
1242 /* We never have more than one result */
1245 }
1246 else
1247 {
1251 TypeCacheEntry *typcache;
1258
1260
1261 /*
1262 * switch to memory context appropriate for multiple function calls
1263 */
1264 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
1265
1266 /* get args, detoasting into multi-call memory context */
1269
1272 if (typcache->rngtype == NULL)
1273 elog(ERROR, "type %u is not a multirange type", mltrngtypoid);
1274 rangetyp = typcache->rngtype;
1275
1277 mr = mr1;
1278 else
1279 {
1282
1284 rangetyp,
1286 ranges1,
1288 ranges2);
1289 }
1290
1291 MemoryContextSwitchTo(oldcontext);
1292
1294 if (MultirangeIsEmpty(mr))
1296 else
1298 }
1299}

References elog, ERROR, fb(), lookup_type_cache(), MemoryContextSwitchTo(), multirange_deserialize(), multirange_minus_internal(), MultirangeIsEmpty, MultirangeTypeGetOid, MultirangeTypePGetDatum(), PG_GETARG_MULTIRANGE_P, TypeCacheEntry::rngtype, SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, and TYPECACHE_MULTIRANGE_INFO.

◆ multirange_ne()

◆ multirange_ne_internal()

bool multirange_ne_internal ( TypeCacheEntry rangetyp,
const MultirangeType mr1,
const MultirangeType mr2 
)

Definition at line 1987 of file multirangetypes.c.

1990{
1992}

References fb(), and multirange_eq_internal().

Referenced by multirange_ne().

◆ multirange_out()

◆ multirange_overlaps_multirange()

◆ multirange_overlaps_multirange_internal()

bool multirange_overlaps_multirange_internal ( TypeCacheEntry rangetyp,
const MultirangeType mr1,
const MultirangeType mr2 
)

Definition at line 2088 of file multirangetypes.c.

2091{
2094 int32 i1;
2095 int32 i2;
2097 upper1,
2098 lower2,
2099 upper2;
2100
2101 /*
2102 * Empties never overlap, even with empties. (This seems strange since
2103 * they *do* contain each other, but we want to follow how ranges work.)
2104 */
2106 return false;
2107
2108 range_count1 = mr1->rangeCount;
2109 range_count2 = mr2->rangeCount;
2110
2111 /*
2112 * Every range in mr1 gets a chance to overlap with the ranges in mr2, but
2113 * we can use their ordering to avoid O(n^2). This is similar to
2114 * range_overlaps_multirange where r1 : r2 :: mrr : r, but there if we
2115 * don't find an overlap with r we're done, and here if we don't find an
2116 * overlap with r2 we try the next r2.
2117 */
2118 i1 = 0;
2120 for (i1 = 0, i2 = 0; i2 < range_count2; i2++)
2121 {
2123
2124 /* Discard r1s while r1 << r2 */
2125 while (range_cmp_bounds(rangetyp, &upper1, &lower2) < 0)
2126 {
2127 if (++i1 >= range_count1)
2128 return false;
2130 }
2131
2132 /*
2133 * If r1 && r2, we're done, otherwise we failed to find an overlap for
2134 * r2, so go to the next one.
2135 */
2137 return true;
2138 }
2139
2140 /* We looked through all of mr2 without finding an overlap */
2141 return false;
2142}

References fb(), multirange_get_bounds(), MultirangeIsEmpty, range_bounds_overlaps(), and range_cmp_bounds().

Referenced by multirange_overlaps_multirange().

◆ multirange_overlaps_range()

◆ multirange_overleft_multirange()

Datum multirange_overleft_multirange ( PG_FUNCTION_ARGS  )

◆ multirange_overleft_range()

Datum multirange_overleft_range ( PG_FUNCTION_ARGS  )

Definition at line 2180 of file multirangetypes.c.

2181{
2184 TypeCacheEntry *typcache;
2186 upper1,
2187 lower2,
2188 upper2;
2189 bool empty;
2190
2192 PG_RETURN_BOOL(false);
2193
2194 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2195
2196 multirange_get_bounds(typcache->rngtype, mr, mr->rangeCount - 1,
2197 &lower1, &upper1);
2198 range_deserialize(typcache->rngtype, r, &lower2, &upper2, &empty);
2199 Assert(!empty);
2200
2202}

References Assert, fb(), multirange_get_bounds(), multirange_get_typcache(), MultirangeIsEmpty, MultirangeTypeGetOid, PG_GETARG_MULTIRANGE_P, PG_GETARG_RANGE_P, PG_RETURN_BOOL, range_cmp_bounds(), range_deserialize(), RangeIsEmpty, and TypeCacheEntry::rngtype.

◆ multirange_overright_multirange()

◆ multirange_overright_range()

Datum multirange_overright_range ( PG_FUNCTION_ARGS  )

◆ multirange_range_contains_bsearch_comparison()

static int multirange_range_contains_bsearch_comparison ( TypeCacheEntry typcache,
RangeBound lower,
RangeBound upper,
void key,
bool match 
)
static

Definition at line 1847 of file multirangetypes.c.

1850{
1851 RangeBound *keyLower = (RangeBound *) key;
1852 RangeBound *keyUpper = (RangeBound *) key + 1;
1853
1854 /* Check if key range is strictly in the left or in the right */
1855 if (range_cmp_bounds(typcache, keyUpper, lower) < 0)
1856 return -1;
1857 if (range_cmp_bounds(typcache, keyLower, upper) > 0)
1858 return 1;
1859
1860 /*
1861 * At this point we found overlapping range. But we have to check if it
1862 * really contains the key range. Anyway, we have to stop our search
1863 * here, because multirange contains only non-overlapping ranges.
1864 */
1865 *match = range_bounds_contains(typcache, lower, upper, keyLower, keyUpper);
1866
1867 return 0;
1868}

References fb(), lower(), range_bounds_contains(), range_cmp_bounds(), and upper().

Referenced by multirange_contains_range_internal().

◆ multirange_range_overlaps_bsearch_comparison()

static int multirange_range_overlaps_bsearch_comparison ( TypeCacheEntry typcache,
RangeBound lower,
RangeBound upper,
void key,
bool match 
)
static

Definition at line 2049 of file multirangetypes.c.

2052{
2053 RangeBound *keyLower = (RangeBound *) key;
2054 RangeBound *keyUpper = (RangeBound *) key + 1;
2055
2056 if (range_cmp_bounds(typcache, keyUpper, lower) < 0)
2057 return -1;
2058 if (range_cmp_bounds(typcache, keyLower, upper) > 0)
2059 return 1;
2060
2061 *match = true;
2062 return 0;
2063}

References fb(), lower(), range_cmp_bounds(), and upper().

Referenced by range_overlaps_multirange_internal().

◆ multirange_recv()

Datum multirange_recv ( PG_FUNCTION_ARGS  )

Definition at line 337 of file multirangetypes.c.

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}

References appendBinaryStringInfo(), buf, StringInfoData::data, DatumGetRangeTypeP(), fb(), get_multirange_io_data(), i, initStringInfo(), IOFunc_receive, make_multirange(), palloc_array, pfree(), PG_GETARG_INT32, PG_GETARG_OID, PG_GETARG_POINTER, PG_RETURN_MULTIRANGE_P, pq_getmsgbytes(), pq_getmsgend(), pq_getmsgint(), ReceiveFunctionCall(), resetStringInfo(), TypeCacheEntry::rngtype, tmpbuf, MultirangeIOData::typcache, MultirangeIOData::typioparam, and MultirangeIOData::typioproc.

◆ multirange_send()

◆ multirange_size_estimate()

static Size multirange_size_estimate ( TypeCacheEntry rangetyp,
int32  range_count,
RangeType **  ranges 
)
static

Definition at line 571 of file multirangetypes.c.

573{
574 char elemalign = rangetyp->rngelemtype->typalign;
575 Size size;
576 int32 i;
577
578 /*
579 * Count space for MultirangeType struct, items and flags.
580 */
581 size = att_align_nominal(sizeof(MultirangeType) +
582 Max(range_count - 1, 0) * sizeof(uint32) +
583 range_count * sizeof(uint8), elemalign);
584
585 /* Count space for range bounds */
586 for (i = 0; i < range_count; i++)
587 size += att_align_nominal(VARSIZE(ranges[i]) -
588 sizeof(RangeType) -
589 sizeof(char), elemalign);
590
591 return size;
592}

References att_align_nominal, fb(), i, Max, TypeCacheEntry::rngelemtype, TypeCacheEntry::typalign, and VARSIZE().

Referenced by make_multirange().

◆ multirange_union()

◆ multirange_unnest()

Datum multirange_unnest ( PG_FUNCTION_ARGS  )

Definition at line 2785 of file multirangetypes.c.

2786{
2787 typedef struct
2788 {
2790 TypeCacheEntry *typcache;
2791 int index;
2793
2796 MemoryContext oldcontext;
2797
2798 /* stuff done only on the first call of the function */
2799 if (SRF_IS_FIRSTCALL())
2800 {
2802
2803 /* create a function context for cross-call persistence */
2805
2806 /*
2807 * switch to memory context appropriate for multiple function calls
2808 */
2809 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
2810
2811 /*
2812 * Get the multirange value and detoast if needed. We can't do this
2813 * earlier because if we have to detoast, we want the detoasted copy
2814 * to be in multi_call_memory_ctx, so it will go away when we're done
2815 * and not before. (If no detoast happens, we assume the originally
2816 * passed multirange will stick around till then.)
2817 */
2819
2820 /* allocate memory for user context */
2822
2823 /* initialize state */
2824 fctx->mr = mr;
2825 fctx->index = 0;
2828
2829 funcctx->user_fctx = fctx;
2830 MemoryContextSwitchTo(oldcontext);
2831 }
2832
2833 /* stuff done on every call of the function */
2835 fctx = funcctx->user_fctx;
2836
2837 if (fctx->index < fctx->mr->rangeCount)
2838 {
2840
2841 range = multirange_get_range(fctx->typcache->rngtype,
2842 fctx->mr,
2843 fctx->index);
2844 fctx->index++;
2845
2847 }
2848 else
2849 {
2850 /* do when there is no more left */
2852 }
2853}

References fb(), lookup_type_cache(), MemoryContextSwitchTo(), multirange_get_range(), MultirangeTypeGetOid, palloc_object, PG_GETARG_MULTIRANGE_P, range(), RangeTypePGetDatum(), SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, and TYPECACHE_MULTIRANGE_INFO.

◆ multirange_upper()

Datum multirange_upper ( PG_FUNCTION_ARGS  )

Definition at line 1603 of file multirangetypes.c.

1604{
1606 TypeCacheEntry *typcache;
1609
1610 if (MultirangeIsEmpty(mr))
1612
1613 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1614
1615 multirange_get_bounds(typcache->rngtype, mr, mr->rangeCount - 1,
1616 &lower, &upper);
1617
1618 if (!upper.infinite)
1620 else
1622}

References fb(), lower(), multirange_get_bounds(), multirange_get_typcache(), MultirangeIsEmpty, MultirangeTypeGetOid, PG_GETARG_MULTIRANGE_P, PG_RETURN_DATUM, PG_RETURN_NULL, TypeCacheEntry::rngtype, and upper().

◆ multirange_upper_inc()

Datum multirange_upper_inc ( PG_FUNCTION_ARGS  )

◆ multirange_upper_inf()

Datum multirange_upper_inf ( PG_FUNCTION_ARGS  )

◆ range_adjacent_multirange()

◆ range_adjacent_multirange_internal()

bool range_adjacent_multirange_internal ( TypeCacheEntry rangetyp,
const RangeType r,
const MultirangeType mr 
)

Definition at line 2543 of file multirangetypes.c.

2546{
2548 upper1,
2549 lower2,
2550 upper2;
2551 bool empty;
2553
2555 return false;
2556
2557 range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
2558 Assert(!empty);
2559
2560 range_count = mr->rangeCount;
2562 &lower2, &upper2);
2563
2565 return true;
2566
2567 if (range_count > 1)
2569 &lower2, &upper2);
2570
2572 return true;
2573
2574 return false;
2575}

References Assert, bounds_adjacent(), fb(), multirange_get_bounds(), MultirangeIsEmpty, range_deserialize(), and RangeIsEmpty.

Referenced by multirange_adjacent_range(), range_adjacent_multirange(), range_gist_consistent_int_multirange(), and range_gist_consistent_leaf_multirange().

◆ range_after_multirange()

◆ range_after_multirange_internal()

bool range_after_multirange_internal ( TypeCacheEntry rangetyp,
const RangeType r,
const MultirangeType mr 
)

Definition at line 2518 of file multirangetypes.c.

2521{
2523 upper1,
2524 lower2,
2525 upper2;
2526 bool empty;
2528
2530 return false;
2531
2532 range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
2533 Assert(!empty);
2534
2535 range_count = mr->rangeCount;
2537 &lower2, &upper2);
2538
2539 return (range_cmp_bounds(rangetyp, &lower1, &upper2) > 0);
2540}

References Assert, fb(), multirange_get_bounds(), MultirangeIsEmpty, range_cmp_bounds(), range_deserialize(), and RangeIsEmpty.

Referenced by multirange_before_range(), range_after_multirange(), range_gist_consistent_int_multirange(), and range_gist_consistent_leaf_multirange().

◆ range_agg_finalfn()

Datum range_agg_finalfn ( PG_FUNCTION_ARGS  )

Definition at line 1445 of file multirangetypes.c.

1446{
1449 TypeCacheEntry *typcache;
1452 RangeType **ranges;
1453 int i;
1454
1455 if (!AggCheckCallContext(fcinfo, &aggContext))
1456 elog(ERROR, "range_agg_finalfn called in non-aggregate context");
1457
1459 if (state == NULL)
1460 /* This shouldn't be possible, but just in case.... */
1462
1463 /* Also return NULL if we had zero inputs, like other aggregates */
1464 range_count = state->nelems;
1465 if (range_count == 0)
1467
1468 mltrngtypoid = get_fn_expr_rettype(fcinfo->flinfo);
1469 typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
1470
1471 ranges = palloc0(range_count * sizeof(RangeType *));
1472 for (i = 0; i < range_count; i++)
1473 ranges[i] = DatumGetRangeTypeP(state->dvalues[i]);
1474
1476}

References AggCheckCallContext(), DatumGetRangeTypeP(), elog, ERROR, fb(), get_fn_expr_rettype(), i, make_multirange(), multirange_get_typcache(), palloc0(), PG_ARGISNULL, PG_GETARG_POINTER, PG_RETURN_MULTIRANGE_P, PG_RETURN_NULL, and TypeCacheEntry::rngtype.

◆ range_agg_transfn()

Datum range_agg_transfn ( PG_FUNCTION_ARGS  )

Definition at line 1413 of file multirangetypes.c.

1414{
1416 Oid rngtypoid;
1418
1419 if (!AggCheckCallContext(fcinfo, &aggContext))
1420 elog(ERROR, "range_agg_transfn called in non-aggregate context");
1421
1422 rngtypoid = get_fn_expr_argtype(fcinfo->flinfo, 1);
1424 elog(ERROR, "range_agg must be called with a range");
1425
1426 if (PG_ARGISNULL(0))
1428 else
1430
1431 /* skip NULLs */
1432 if (!PG_ARGISNULL(1))
1434
1436}

References accumArrayResult(), AggCheckCallContext(), elog, ERROR, fb(), get_fn_expr_argtype(), initArrayResult(), PG_ARGISNULL, PG_GETARG_DATUM, PG_GETARG_POINTER, PG_RETURN_POINTER, and type_is_range().

◆ range_before_multirange()

◆ range_before_multirange_internal()

bool range_before_multirange_internal ( TypeCacheEntry rangetyp,
const RangeType r,
const MultirangeType mr 
)

Definition at line 2474 of file multirangetypes.c.

2477{
2479 upper1,
2480 lower2,
2481 upper2;
2482 bool empty;
2483
2485 return false;
2486
2487 range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
2488 Assert(!empty);
2489
2491
2492 return (range_cmp_bounds(rangetyp, &upper1, &lower2) < 0);
2493}

References Assert, fb(), multirange_get_bounds(), MultirangeIsEmpty, range_cmp_bounds(), range_deserialize(), and RangeIsEmpty.

Referenced by multirange_after_range(), range_before_multirange(), range_gist_consistent_int_multirange(), and range_gist_consistent_leaf_multirange().

◆ range_bounds_contains()

static bool range_bounds_contains ( TypeCacheEntry typcache,
RangeBound lower1,
RangeBound upper1,
RangeBound lower2,
RangeBound upper2 
)
static

Definition at line 880 of file multirangetypes.c.

883{
884 if (range_cmp_bounds(typcache, lower1, lower2) <= 0 &&
885 range_cmp_bounds(typcache, upper1, upper2) >= 0)
886 return true;
887
888 return false;
889}

References fb(), and range_cmp_bounds().

Referenced by multirange_contains_multirange_internal(), multirange_range_contains_bsearch_comparison(), and range_contains_multirange_internal().

◆ range_bounds_overlaps()

static bool range_bounds_overlaps ( TypeCacheEntry typcache,
RangeBound lower1,
RangeBound upper1,
RangeBound lower2,
RangeBound upper2 
)
static

Definition at line 860 of file multirangetypes.c.

863{
864 if (range_cmp_bounds(typcache, lower1, lower2) >= 0 &&
865 range_cmp_bounds(typcache, lower1, upper2) <= 0)
866 return true;
867
868 if (range_cmp_bounds(typcache, lower2, lower1) >= 0 &&
869 range_cmp_bounds(typcache, lower2, upper1) <= 0)
870 return true;
871
872 return false;
873}

References fb(), and range_cmp_bounds().

Referenced by multirange_overlaps_multirange_internal().

◆ range_contained_by_multirange()

◆ range_contains_multirange()

◆ range_contains_multirange_internal()

bool range_contains_multirange_internal ( TypeCacheEntry rangetyp,
const RangeType r,
const MultirangeType mr 
)

Definition at line 1902 of file multirangetypes.c.

1905{
1907 upper1,
1908 lower2,
1909 upper2,
1910 tmp;
1911 bool empty;
1912
1913 /*
1914 * Every range contains an infinite number of empty multiranges, even an
1915 * empty one.
1916 */
1917 if (MultirangeIsEmpty(mr))
1918 return true;
1919
1920 if (RangeIsEmpty(r))
1921 return false;
1922
1923 /* Range contains multirange iff it contains its union range. */
1924 range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
1925 Assert(!empty);
1927 multirange_get_bounds(rangetyp, mr, mr->rangeCount - 1, &tmp, &upper2);
1928
1930}

References Assert, fb(), multirange_get_bounds(), MultirangeIsEmpty, range_bounds_contains(), range_deserialize(), and RangeIsEmpty.

Referenced by multirange_contained_by_range(), range_contains_multirange(), range_gist_consistent_int_multirange(), and range_gist_consistent_leaf_multirange().

◆ range_merge_from_multirange()

Datum range_merge_from_multirange ( PG_FUNCTION_ARGS  )

Definition at line 2747 of file multirangetypes.c.

2748{
2751 TypeCacheEntry *typcache;
2752 RangeType *result;
2753
2754 typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
2755
2756 if (MultirangeIsEmpty(mr))
2757 {
2758 result = make_empty_range(typcache->rngtype);
2759 }
2760 else if (mr->rangeCount == 1)
2761 {
2762 result = multirange_get_range(typcache->rngtype, mr, 0);
2763 }
2764 else
2765 {
2767 firstUpper,
2768 lastLower,
2769 lastUpper;
2770
2771 multirange_get_bounds(typcache->rngtype, mr, 0,
2773 multirange_get_bounds(typcache->rngtype, mr, mr->rangeCount - 1,
2774 &lastLower, &lastUpper);
2775
2776 result = make_range(typcache->rngtype, &firstLower, &lastUpper,
2777 false, NULL);
2778 }
2779
2780 PG_RETURN_RANGE_P(result);
2781}

References fb(), make_empty_range(), make_range(), multirange_get_bounds(), multirange_get_range(), multirange_get_typcache(), MultirangeIsEmpty, MultirangeTypeGetOid, PG_GETARG_MULTIRANGE_P, PG_RETURN_RANGE_P, and TypeCacheEntry::rngtype.

◆ range_overlaps_multirange()

◆ range_overlaps_multirange_internal()

bool range_overlaps_multirange_internal ( TypeCacheEntry rangetyp,
const RangeType r,
const MultirangeType mr 
)

Definition at line 2066 of file multirangetypes.c.

2069{
2070 RangeBound bounds[2];
2071 bool empty;
2072
2073 /*
2074 * Empties never overlap, even with empties. (This seems strange since
2075 * they *do* contain each other, but we want to follow how ranges work.)
2076 */
2078 return false;
2079
2080 range_deserialize(rangetyp, r, &bounds[0], &bounds[1], &empty);
2081 Assert(!empty);
2082
2085}

References Assert, fb(), multirange_bsearch_match(), multirange_range_overlaps_bsearch_comparison(), MultirangeIsEmpty, range_deserialize(), and RangeIsEmpty.

Referenced by multirange_overlaps_range(), range_gist_consistent_int_multirange(), range_gist_consistent_leaf_multirange(), and range_overlaps_multirange().

◆ range_overleft_multirange()

◆ range_overleft_multirange_internal()

bool range_overleft_multirange_internal ( TypeCacheEntry rangetyp,
const RangeType r,
const MultirangeType mr 
)

Definition at line 2146 of file multirangetypes.c.

2149{
2151 upper1,
2152 lower2,
2153 upper2;
2154 bool empty;
2155
2157 return false;
2158
2159 range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
2160 Assert(!empty);
2161 multirange_get_bounds(rangetyp, mr, mr->rangeCount - 1,
2162 &lower2, &upper2);
2163
2164 return (range_cmp_bounds(rangetyp, &upper1, &upper2) <= 0);
2165}

References Assert, fb(), multirange_get_bounds(), MultirangeIsEmpty, range_cmp_bounds(), range_deserialize(), and RangeIsEmpty.

Referenced by range_gist_consistent_int_multirange(), range_gist_consistent_leaf_multirange(), and range_overleft_multirange().

◆ range_overright_multirange()

◆ range_overright_multirange_internal()

bool range_overright_multirange_internal ( TypeCacheEntry rangetyp,
const RangeType r,
const MultirangeType mr 
)

Definition at line 2230 of file multirangetypes.c.

2233{
2235 upper1,
2236 lower2,
2237 upper2;
2238 bool empty;
2239
2241 return false;
2242
2243 range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
2244 Assert(!empty);
2246
2247 return (range_cmp_bounds(rangetyp, &lower1, &lower2) >= 0);
2248}

References Assert, fb(), multirange_get_bounds(), MultirangeIsEmpty, range_cmp_bounds(), range_deserialize(), and RangeIsEmpty.

Referenced by range_gist_consistent_int_multirange(), range_gist_consistent_leaf_multirange(), and range_overright_multirange().

◆ write_multirange_data()

static void write_multirange_data ( MultirangeType multirange,
TypeCacheEntry rangetyp,
int32  range_count,
RangeType **  ranges 
)
static

Definition at line 598 of file multirangetypes.c.

600{
601 uint32 *items;
603 uint8 *flags;
604 int32 i;
605 const char *begin;
606 char *ptr;
607 char elemalign = rangetyp->rngelemtype->typalign;
608
611 begin = ptr = MultirangeGetBoundariesPtr(multirange, elemalign);
612 for (i = 0; i < range_count; i++)
613 {
614 uint32 len;
615
616 if (i > 0)
617 {
618 /*
619 * Every range, except the first one, has an item. Every
620 * MULTIRANGE_ITEM_OFFSET_STRIDE item contains an offset, others
621 * contain lengths.
622 */
623 items[i - 1] = ptr - begin;
624 if ((i % MULTIRANGE_ITEM_OFFSET_STRIDE) != 0)
625 items[i - 1] -= prev_offset;
626 else
628 prev_offset = ptr - begin;
629 }
630 flags[i] = *((char *) ranges[i] + VARSIZE(ranges[i]) - sizeof(char));
631 len = VARSIZE(ranges[i]) - sizeof(RangeType) - sizeof(char);
632 memcpy(ptr, ranges[i] + 1, len);
633 ptr += att_align_nominal(len, elemalign);
634 }
635}

References att_align_nominal, fb(), i, items, len, MULTIRANGE_ITEM_OFF_BIT, MULTIRANGE_ITEM_OFFSET_STRIDE, MultirangeGetBoundariesPtr, MultirangeGetFlagsPtr, MultirangeGetItemsPtr, and VARSIZE().

Referenced by make_multirange().