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. */
487 if (ranges != NULL)
488 qsort_arg(ranges, input_range_count, sizeof(RangeType *),
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}
531
532/*
533 *----------------------------------------------------------
534 * SUPPORT FUNCTIONS
535 *
536 * These functions aren't in pg_proc, but are useful for
537 * defining new generic multirange functions in C.
538 *----------------------------------------------------------
539 */
540
541/*
542 * multirange_get_typcache: get cached information about a multirange type
543 *
544 * This is for use by multirange-related functions that follow the convention
545 * of using the fn_extra field as a pointer to the type cache entry for
546 * the multirange type. Functions that need to cache more information than
547 * that must fend for themselves.
548 */
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}
565
566
567/*
568 * Estimate size occupied by serialized multirange.
569 */
570static Size
572 RangeType **ranges)
573{
574 char elemalign = rangetyp->rngelemtype->typalign;
576 Size size;
577 int32 i;
578
579 /*
580 * Count space for MultirangeType struct, items and flags.
581 */
582 size = att_nominal_alignby(sizeof(MultirangeType) +
583 Max(range_count - 1, 0) * sizeof(uint32) +
584 range_count * sizeof(uint8), elemalignby);
585
586 /* Count space for range bounds */
587 for (i = 0; i < range_count; i++)
588 size += att_nominal_alignby(VARSIZE(ranges[i]) -
589 sizeof(RangeType) -
590 sizeof(char), elemalignby);
591
592 return size;
593}
594
595/*
596 * Write multirange data into pre-allocated space.
597 */
598static void
600 int32 range_count, RangeType **ranges)
601{
602 uint32 *items;
604 uint8 *flags;
605 int32 i;
606 const char *begin;
607 char *ptr;
608 char elemalign = rangetyp->rngelemtype->typalign;
610
613 begin = ptr = MultirangeGetBoundariesPtr(multirange, elemalign);
614 for (i = 0; i < range_count; i++)
615 {
616 uint32 len;
617
618 if (i > 0)
619 {
620 /*
621 * Every range, except the first one, has an item. Every
622 * MULTIRANGE_ITEM_OFFSET_STRIDE item contains an offset, others
623 * contain lengths.
624 */
625 items[i - 1] = ptr - begin;
626 if ((i % MULTIRANGE_ITEM_OFFSET_STRIDE) != 0)
627 items[i - 1] -= prev_offset;
628 else
630 prev_offset = ptr - begin;
631 }
632 flags[i] = *((char *) ranges[i] + VARSIZE(ranges[i]) - sizeof(char));
633 len = VARSIZE(ranges[i]) - sizeof(RangeType) - sizeof(char);
634 memcpy(ptr, ranges[i] + 1, len);
636 }
637}
638
639
640/*
641 * This serializes the multirange from a list of non-null ranges. It also
642 * sorts the ranges and merges any that touch. The ranges should already be
643 * detoasted, and there should be no NULLs. This should be used by most
644 * callers.
645 *
646 * Note that we may change the `ranges` parameter (the pointers, but not
647 * any already-existing RangeType contents).
648 */
651 RangeType **ranges)
652{
654 Size size;
655
656 /* Sort and merge input ranges. */
658
659 /* Note: zero-fill is required here, just as in heap tuples */
661 multirange = palloc0(size);
662 SET_VARSIZE(multirange, size);
663
664 /* Now fill in the datum */
665 multirange->multirangetypid = mltrngtypoid;
666 multirange->rangeCount = range_count;
667
669
670 return multirange;
671}
672
673/*
674 * Get offset of bounds values of the i'th range in the multirange.
675 */
676static uint32
678{
680 uint32 offset = 0;
681
682 /*
683 * Summarize lengths till we meet an offset.
684 */
685 while (i > 0)
686 {
687 offset += MULTIRANGE_ITEM_GET_OFFLEN(items[i - 1]);
689 break;
690 i--;
691 }
692 return offset;
693}
694
695/*
696 * Fetch the i'th range from the multirange.
697 */
698RangeType *
700 const MultirangeType *multirange, int i)
701{
702 uint32 offset;
703 uint8 flags;
704 const char *begin;
705 char *ptr;
706 int16 typlen = rangetyp->rngelemtype->typlen;
707 char typalign = rangetyp->rngelemtype->typalign;
708 uint32 len;
710
711 Assert(i < multirange->rangeCount);
712
715 begin = ptr = MultirangeGetBoundariesPtr(multirange, typalign) + offset;
716
717 /*
718 * Calculate the size of bound values. In principle, we could get offset
719 * of the next range bound values and calculate accordingly. But range
720 * bound values are aligned, so we have to walk the values to get the
721 * exact size.
722 */
723 if (RANGE_HAS_LBOUND(flags))
724 ptr = (char *) att_addlength_pointer(ptr, typlen, ptr);
725 if (RANGE_HAS_UBOUND(flags))
726 {
727 ptr = (char *) att_align_pointer(ptr, typalign, typlen, ptr);
728 ptr = (char *) att_addlength_pointer(ptr, typlen, ptr);
729 }
730 len = (ptr - begin) + sizeof(RangeType) + sizeof(uint8);
731
732 range = palloc0(len);
734 range->rangetypid = rangetyp->type_id;
735
736 memcpy(range + 1, begin, ptr - begin);
737 *((uint8 *) (range + 1) + (ptr - begin)) = flags;
738
739 return range;
740}
741
742/*
743 * Fetch bounds from the i'th range of the multirange. This is the shortcut for
744 * doing the same thing as multirange_get_range() + range_deserialize(), but
745 * performing fewer operations.
746 */
747void
751{
752 uint32 offset;
753 uint8 flags;
754 const char *ptr;
755 int16 typlen = rangetyp->rngelemtype->typlen;
756 char typalign = rangetyp->rngelemtype->typalign;
757 bool typbyval = rangetyp->rngelemtype->typbyval;
758 Datum lbound;
760
761 Assert(i < multirange->rangeCount);
762
766
767 /* multirange can't contain empty ranges */
768 Assert((flags & RANGE_EMPTY) == 0);
769
770 /* fetch lower bound, if any */
771 if (RANGE_HAS_LBOUND(flags))
772 {
773 /* att_align_pointer cannot be necessary here */
774 lbound = fetch_att(ptr, typbyval, typlen);
775 ptr = (char *) att_addlength_pointer(ptr, typlen, ptr);
776 }
777 else
778 lbound = (Datum) 0;
779
780 /* fetch upper bound, if any */
781 if (RANGE_HAS_UBOUND(flags))
782 {
783 ptr = (char *) att_align_pointer(ptr, typalign, typlen, ptr);
784 ubound = fetch_att(ptr, typbyval, typlen);
785 /* no need for att_addlength_pointer */
786 }
787 else
788 ubound = (Datum) 0;
789
790 /* emit results */
791 lower->val = lbound;
792 lower->infinite = (flags & RANGE_LB_INF) != 0;
793 lower->inclusive = (flags & RANGE_LB_INC) != 0;
794 lower->lower = true;
795
796 upper->val = ubound;
797 upper->infinite = (flags & RANGE_UB_INF) != 0;
798 upper->inclusive = (flags & RANGE_UB_INC) != 0;
799 upper->lower = false;
800}
801
802/*
803 * Construct union range from the multirange.
804 */
805RangeType *
807 const MultirangeType *mr)
808{
810 upper,
811 tmp;
812
815
817 multirange_get_bounds(rangetyp, mr, mr->rangeCount - 1, &tmp, &upper);
818
819 return make_range(rangetyp, &lower, &upper, false, NULL);
820}
821
822
823/*
824 * multirange_deserialize: deconstruct a multirange value
825 *
826 * NB: the given multirange object must be fully detoasted; it cannot have a
827 * short varlena header.
828 */
829void
832 RangeType ***ranges)
833{
834 *range_count = multirange->rangeCount;
835
836 /* Convert each ShortRangeType into a RangeType */
837 if (*range_count > 0)
838 {
839 int i;
840
841 *ranges = palloc_array(RangeType *, *range_count);
842 for (i = 0; i < *range_count; i++)
844 }
845 else
846 {
847 *ranges = NULL;
848 }
849}
850
853{
855}
856
857/*
858 * Similar to range_overlaps_internal(), but takes range bounds instead of
859 * ranges as arguments.
860 */
861static bool
865{
866 if (range_cmp_bounds(typcache, lower1, lower2) >= 0 &&
867 range_cmp_bounds(typcache, lower1, upper2) <= 0)
868 return true;
869
870 if (range_cmp_bounds(typcache, lower2, lower1) >= 0 &&
871 range_cmp_bounds(typcache, lower2, upper1) <= 0)
872 return true;
873
874 return false;
875}
876
877/*
878 * Similar to range_contains_internal(), but takes range bounds instead of
879 * ranges as arguments.
880 */
881static bool
885{
886 if (range_cmp_bounds(typcache, lower1, lower2) <= 0 &&
887 range_cmp_bounds(typcache, upper1, upper2) >= 0)
888 return true;
889
890 return false;
891}
892
893/*
894 * Check if the given key matches any range in multirange using binary search.
895 * If the required range isn't found, that counts as a mismatch. When the
896 * required range is found, the comparison function can still report this as
897 * either match or mismatch. For instance, if we search for containment, we can
898 * found a range, which is overlapping but not containing the key range, and
899 * that would count as a mismatch.
900 */
901static bool
904{
905 uint32 l,
906 u,
907 idx;
908 int comparison;
909 bool match = false;
910
911 l = 0;
912 u = mr->rangeCount;
913 while (l < u)
914 {
916 upper;
917
918 idx = (l + u) / 2;
919 multirange_get_bounds(typcache, mr, idx, &lower, &upper);
920 comparison = (*cmp_func) (typcache, &lower, &upper, key, &match);
921
922 if (comparison < 0)
923 u = idx;
924 else if (comparison > 0)
925 l = idx + 1;
926 else
927 return match;
928 }
929
930 return false;
931}
932
933/*
934 *----------------------------------------------------------
935 * GENERIC FUNCTIONS
936 *----------------------------------------------------------
937 */
938
939/*
940 * Construct multirange value from zero or more ranges. Since this is a
941 * variadic function we get passed an array. The array must contain ranges
942 * that match our return value, and there must be no NULLs.
943 */
944Datum
946{
947 Oid mltrngtypid = get_fn_expr_rettype(fcinfo->flinfo);
949 TypeCacheEntry *typcache;
952 int range_count;
953 Datum *elements;
954 bool *nulls;
955 RangeType **ranges;
956 int dims;
957 int i;
958
959 typcache = multirange_get_typcache(fcinfo, mltrngtypid);
960 rangetyp = typcache->rngtype;
961
962 /*
963 * A no-arg invocation should call multirange_constructor0 instead, but
964 * returning an empty range is what that does.
965 */
966
967 if (PG_NARGS() == 0)
969
970 /*
971 * This check should be guaranteed by our signature, but let's do it just
972 * in case.
973 */
974
975 if (PG_ARGISNULL(0))
976 elog(ERROR,
977 "multirange values cannot contain null members");
978
980
981 dims = ARR_NDIM(rangeArray);
982 if (dims > 1)
985 errmsg("multiranges cannot be constructed from multidimensional arrays")));
986
988 if (rngtypid != rangetyp->type_id)
989 elog(ERROR, "type %u does not match constructor type", rngtypid);
990
991 /*
992 * Be careful: we can still be called with zero ranges, like this:
993 * `int4multirange(variadic '{}'::int4range[])
994 */
995 if (dims == 0)
996 {
997 range_count = 0;
998 ranges = NULL;
999 }
1000 else
1001 {
1003 rangetyp->typalign, &elements, &nulls, &range_count);
1004
1005 ranges = palloc0(range_count * sizeof(RangeType *));
1006 for (i = 0; i < range_count; i++)
1007 {
1008 if (nulls[i])
1009 ereport(ERROR,
1011 errmsg("multirange values cannot contain null members")));
1012
1013 /* make_multirange will do its own copy */
1014 ranges[i] = DatumGetRangeTypeP(elements[i]);
1015 }
1016 }
1017
1019}
1020
1021/*
1022 * Construct multirange value from a single range. It'd be nice if we could
1023 * just use multirange_constructor2 for this case, but we need a non-variadic
1024 * single-arg function to let us define a CAST from a range to its multirange.
1025 */
1026Datum
1028{
1029 Oid mltrngtypid = get_fn_expr_rettype(fcinfo->flinfo);
1030 Oid rngtypid;
1031 TypeCacheEntry *typcache;
1034
1035 typcache = multirange_get_typcache(fcinfo, mltrngtypid);
1036 rangetyp = typcache->rngtype;
1037
1038 /*
1039 * This check should be guaranteed by our signature, but let's do it just
1040 * in case.
1041 */
1042
1043 if (PG_ARGISNULL(0))
1044 elog(ERROR,
1045 "multirange values cannot contain null members");
1046
1048
1049 /* Make sure the range type matches. */
1051 if (rngtypid != rangetyp->type_id)
1052 elog(ERROR, "type %u does not match constructor type", rngtypid);
1053
1055}
1056
1057/*
1058 * Constructor just like multirange_constructor1, but opr_sanity gets angry
1059 * if the same internal function handles multiple functions with different arg
1060 * counts.
1061 */
1062Datum
1064{
1066 TypeCacheEntry *typcache;
1068
1069 /* This should always be called without arguments */
1070 if (PG_NARGS() != 0)
1071 elog(ERROR,
1072 "niladic multirange constructor must not receive arguments");
1073
1074 mltrngtypid = get_fn_expr_rettype(fcinfo->flinfo);
1075 typcache = multirange_get_typcache(fcinfo, mltrngtypid);
1076 rangetyp = typcache->rngtype;
1077
1079}
1080
1081
1082/* multirange, multirange -> multirange type functions */
1083
1084/* multirange union */
1085Datum
1087{
1090 TypeCacheEntry *typcache;
1097
1102
1104
1107
1109 ranges3 = palloc0(range_count3 * sizeof(RangeType *));
1114}
1115
1116/* multirange minus */
1117Datum
1119{
1123 TypeCacheEntry *typcache;
1129
1130 typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
1131 rangetyp = typcache->rngtype;
1132
1135
1138
1140 rangetyp,
1142 ranges1,
1144 ranges2));
1145}
1146
1151{
1152 RangeType *r1;
1153 RangeType *r2;
1156 int32 i1;
1157 int32 i2;
1158
1159 /*
1160 * Worst case: every range in ranges1 makes a different cut to some range
1161 * in ranges2.
1162 */
1164 range_count3 = 0;
1165
1166 /*
1167 * For each range in mr1, keep subtracting until it's gone or the ranges
1168 * in mr2 have passed it. After a subtraction we assign what's left back
1169 * to r1. The parallel progress through mr1 and mr2 is similar to
1170 * multirange_overlaps_multirange_internal.
1171 */
1172 r2 = ranges2[0];
1173 for (i1 = 0, i2 = 0; i1 < range_count1; i1++)
1174 {
1175 r1 = ranges1[i1];
1176
1177 /* Discard r2s while r2 << r1 */
1178 while (r2 != NULL && range_before_internal(rangetyp, r2, r1))
1179 {
1180 r2 = ++i2 >= range_count2 ? NULL : ranges2[i2];
1181 }
1182
1183 while (r2 != NULL)
1184 {
1186 {
1187 /*
1188 * If r2 takes a bite out of the middle of r1, we need two
1189 * outputs
1190 */
1191 range_count3++;
1192 r2 = ++i2 >= range_count2 ? NULL : ranges2[i2];
1193 }
1195 {
1196 /*
1197 * If r2 overlaps r1, replace r1 with r1 - r2.
1198 */
1200
1201 /*
1202 * If r2 goes past r1, then we need to stay with it, in case
1203 * it hits future r1s. Otherwise we need to keep r1, in case
1204 * future r2s hit it. Since we already subtracted, there's no
1205 * point in using the overright/overleft calls.
1206 */
1208 break;
1209 else
1210 r2 = ++i2 >= range_count2 ? NULL : ranges2[i2];
1211 }
1212 else
1213 {
1214 /*
1215 * This and all future r2s are past r1, so keep them. Also
1216 * assign whatever is left of r1 to the result.
1217 */
1218 break;
1219 }
1220 }
1221
1222 /*
1223 * Nothing else can remove anything from r1, so keep it. Even if r1 is
1224 * empty here, make_multirange will remove it.
1225 */
1226 ranges3[range_count3++] = r1;
1227 }
1228
1230}
1231
1232/*
1233 * multirange_minus_multi - like multirange_minus but returning the result as a
1234 * SRF, with no rows if the result would be empty.
1235 */
1236Datum
1238{
1240 MemoryContext oldcontext;
1241
1242 if (!SRF_IS_FIRSTCALL())
1243 {
1244 /* We never have more than one result */
1247 }
1248 else
1249 {
1253 TypeCacheEntry *typcache;
1260
1262
1263 /*
1264 * switch to memory context appropriate for multiple function calls
1265 */
1266 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
1267
1268 /* get args, detoasting into multi-call memory context */
1271
1274 if (typcache->rngtype == NULL)
1275 elog(ERROR, "type %u is not a multirange type", mltrngtypoid);
1276 rangetyp = typcache->rngtype;
1277
1279 mr = mr1;
1280 else
1281 {
1284
1286 rangetyp,
1288 ranges1,
1290 ranges2);
1291 }
1292
1293 MemoryContextSwitchTo(oldcontext);
1294
1296 if (MultirangeIsEmpty(mr))
1298 else
1300 }
1301}
1302
1303/* multirange intersection */
1304Datum
1306{
1310 TypeCacheEntry *typcache;
1316
1317 typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
1318 rangetyp = typcache->rngtype;
1319
1322
1325
1327 rangetyp,
1329 ranges1,
1331 ranges2));
1332}
1333
1338{
1339 RangeType *r1;
1340 RangeType *r2;
1343 int32 i1;
1344 int32 i2;
1345
1346 if (range_count1 == 0 || range_count2 == 0)
1348
1349 /*-----------------------------------------------
1350 * Worst case is a stitching pattern like this:
1351 *
1352 * mr1: --- --- --- ---
1353 * mr2: --- --- ---
1354 * mr3: - - - - - -
1355 *
1356 * That seems to be range_count1 + range_count2 - 1,
1357 * but one extra won't hurt.
1358 *-----------------------------------------------
1359 */
1361 range_count3 = 0;
1362
1363 /*
1364 * For each range in mr1, keep intersecting until the ranges in mr2 have
1365 * passed it. The parallel progress through mr1 and mr2 is similar to
1366 * multirange_minus_multirange_internal, but we don't have to assign back
1367 * to r1.
1368 */
1369 r2 = ranges2[0];
1370 for (i1 = 0, i2 = 0; i1 < range_count1; i1++)
1371 {
1372 r1 = ranges1[i1];
1373
1374 /* Discard r2s while r2 << r1 */
1375 while (r2 != NULL && range_before_internal(rangetyp, r2, r1))
1376 {
1377 r2 = ++i2 >= range_count2 ? NULL : ranges2[i2];
1378 }
1379
1380 while (r2 != NULL)
1381 {
1383 {
1384 /* Keep the overlapping part */
1386
1387 /* If we "used up" all of r2, go to the next one... */
1389 r2 = ++i2 >= range_count2 ? NULL : ranges2[i2];
1390
1391 /* ...otherwise go to the next r1 */
1392 else
1393 break;
1394 }
1395 else
1396 /* We're past r1, so move to the next one */
1397 break;
1398 }
1399
1400 /* If we're out of r2s, there can be no more intersections */
1401 if (r2 == NULL)
1402 break;
1403 }
1404
1406}
1407
1408/*
1409 * range_agg_transfn: combine adjacent/overlapping ranges.
1410 *
1411 * All we do here is gather the input ranges into an array
1412 * so that the finalfn can sort and combine them.
1413 */
1414Datum
1416{
1418 Oid rngtypoid;
1420
1421 if (!AggCheckCallContext(fcinfo, &aggContext))
1422 elog(ERROR, "range_agg_transfn called in non-aggregate context");
1423
1424 rngtypoid = get_fn_expr_argtype(fcinfo->flinfo, 1);
1426 elog(ERROR, "range_agg must be called with a range");
1427
1428 if (PG_ARGISNULL(0))
1430 else
1432
1433 /* skip NULLs */
1434 if (!PG_ARGISNULL(1))
1436
1438}
1439
1440/*
1441 * range_agg_finalfn: use our internal array to merge touching ranges.
1442 *
1443 * Shared by range_agg_finalfn(anyrange) and
1444 * multirange_agg_finalfn(anymultirange).
1445 */
1446Datum
1448{
1451 TypeCacheEntry *typcache;
1454 RangeType **ranges;
1455 int i;
1456
1457 if (!AggCheckCallContext(fcinfo, &aggContext))
1458 elog(ERROR, "range_agg_finalfn called in non-aggregate context");
1459
1461 if (state == NULL)
1462 /* This shouldn't be possible, but just in case.... */
1464
1465 /* Also return NULL if we had zero inputs, like other aggregates */
1466 range_count = state->nelems;
1467 if (range_count == 0)
1469
1470 mltrngtypoid = get_fn_expr_rettype(fcinfo->flinfo);
1471 typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
1472
1473 ranges = palloc0(range_count * sizeof(RangeType *));
1474 for (i = 0; i < range_count; i++)
1475 ranges[i] = DatumGetRangeTypeP(state->dvalues[i]);
1476
1478}
1479
1480/*
1481 * multirange_agg_transfn: combine adjacent/overlapping multiranges.
1482 *
1483 * All we do here is gather the input multiranges' ranges into an array so
1484 * that the finalfn can sort and combine them.
1485 */
1486Datum
1488{
1491 TypeCacheEntry *typcache;
1494
1495 if (!AggCheckCallContext(fcinfo, &aggContext))
1496 elog(ERROR, "multirange_agg_transfn called in non-aggregate context");
1497
1498 mltrngtypoid = get_fn_expr_argtype(fcinfo->flinfo, 1);
1500 elog(ERROR, "range_agg must be called with a multirange");
1501
1502 typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
1503 rngtypcache = typcache->rngtype;
1504
1505 if (PG_ARGISNULL(0))
1506 state = initArrayResult(rngtypcache->type_id, aggContext, false);
1507 else
1509
1510 /* skip NULLs */
1511 if (!PG_ARGISNULL(1))
1512 {
1513 MultirangeType *current;
1515 RangeType **ranges;
1516
1517 current = PG_GETARG_MULTIRANGE_P(1);
1518 multirange_deserialize(rngtypcache, current, &range_count, &ranges);
1519 if (range_count == 0)
1520 {
1521 /*
1522 * Add an empty range so we get an empty result (not a null
1523 * result).
1524 */
1527 false, rngtypcache->type_id, aggContext);
1528 }
1529 else
1530 {
1531 for (int32 i = 0; i < range_count; i++)
1532 accumArrayResult(state, RangeTypePGetDatum(ranges[i]), false, rngtypcache->type_id, aggContext);
1533 }
1534 }
1535
1537}
1538
1539Datum
1541{
1544 TypeCacheEntry *typcache;
1545 MultirangeType *result;
1546 MultirangeType *current;
1551
1552 if (!AggCheckCallContext(fcinfo, &aggContext))
1553 elog(ERROR, "multirange_intersect_agg_transfn called in non-aggregate context");
1554
1555 mltrngtypoid = get_fn_expr_argtype(fcinfo->flinfo, 1);
1557 elog(ERROR, "range_intersect_agg must be called with a multirange");
1558
1559 typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
1560
1561 /* strictness ensures these are non-null */
1562 result = PG_GETARG_MULTIRANGE_P(0);
1563 current = PG_GETARG_MULTIRANGE_P(1);
1564
1565 multirange_deserialize(typcache->rngtype, result, &range_count1, &ranges1);
1566 multirange_deserialize(typcache->rngtype, current, &range_count2, &ranges2);
1567
1569 typcache->rngtype,
1571 ranges1,
1573 ranges2);
1574 PG_RETURN_MULTIRANGE_P(result);
1575}
1576
1577
1578/* multirange -> element type functions */
1579
1580/* extract lower bound value */
1581Datum
1583{
1585 TypeCacheEntry *typcache;
1588
1589 if (MultirangeIsEmpty(mr))
1591
1592 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1593
1594 multirange_get_bounds(typcache->rngtype, mr, 0,
1595 &lower, &upper);
1596
1597 if (!lower.infinite)
1599 else
1601}
1602
1603/* extract upper bound value */
1604Datum
1606{
1608 TypeCacheEntry *typcache;
1611
1612 if (MultirangeIsEmpty(mr))
1614
1615 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1616
1617 multirange_get_bounds(typcache->rngtype, mr, mr->rangeCount - 1,
1618 &lower, &upper);
1619
1620 if (!upper.infinite)
1622 else
1624}
1625
1626
1627/* multirange -> bool functions */
1628
1629/* is multirange empty? */
1630Datum
1632{
1634
1636}
1637
1638/* is lower bound inclusive? */
1639Datum
1641{
1643 TypeCacheEntry *typcache;
1646
1647 if (MultirangeIsEmpty(mr))
1648 PG_RETURN_BOOL(false);
1649
1650 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1651 multirange_get_bounds(typcache->rngtype, mr, 0,
1652 &lower, &upper);
1653
1654 PG_RETURN_BOOL(lower.inclusive);
1655}
1656
1657/* is upper bound inclusive? */
1658Datum
1660{
1662 TypeCacheEntry *typcache;
1665
1666 if (MultirangeIsEmpty(mr))
1667 PG_RETURN_BOOL(false);
1668
1669 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1670 multirange_get_bounds(typcache->rngtype, mr, mr->rangeCount - 1,
1671 &lower, &upper);
1672
1673 PG_RETURN_BOOL(upper.inclusive);
1674}
1675
1676/* is lower bound infinite? */
1677Datum
1679{
1681 TypeCacheEntry *typcache;
1684
1685 if (MultirangeIsEmpty(mr))
1686 PG_RETURN_BOOL(false);
1687
1688 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1689 multirange_get_bounds(typcache->rngtype, mr, 0,
1690 &lower, &upper);
1691
1692 PG_RETURN_BOOL(lower.infinite);
1693}
1694
1695/* is upper bound infinite? */
1696Datum
1698{
1700 TypeCacheEntry *typcache;
1703
1704 if (MultirangeIsEmpty(mr))
1705 PG_RETURN_BOOL(false);
1706
1707 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1708 multirange_get_bounds(typcache->rngtype, mr, mr->rangeCount - 1,
1709 &lower, &upper);
1710
1711 PG_RETURN_BOOL(upper.infinite);
1712}
1713
1714
1715
1716/* multirange, element -> bool functions */
1717
1718/* contains? */
1719Datum
1721{
1724 TypeCacheEntry *typcache;
1725
1726 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1727
1729}
1730
1731/* contained by? */
1732Datum
1734{
1737 TypeCacheEntry *typcache;
1738
1739 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1740
1742}
1743
1744/*
1745 * Comparison function for checking if any range of multirange contains given
1746 * key element using binary search.
1747 */
1748static int
1751 void *key, bool *match)
1752{
1753 Datum val = *((Datum *) key);
1754 int cmp;
1755
1756 if (!lower->infinite)
1757 {
1759 typcache->rng_collation,
1760 lower->val, val));
1761 if (cmp > 0 || (cmp == 0 && !lower->inclusive))
1762 return -1;
1763 }
1764
1765 if (!upper->infinite)
1766 {
1768 typcache->rng_collation,
1769 upper->val, val));
1770 if (cmp < 0 || (cmp == 0 && !upper->inclusive))
1771 return 1;
1772 }
1773
1774 *match = true;
1775 return 0;
1776}
1777
1778/*
1779 * Test whether multirange mr contains a specific element value.
1780 */
1781bool
1783 const MultirangeType *mr, Datum val)
1784{
1785 if (MultirangeIsEmpty(mr))
1786 return false;
1787
1790}
1791
1792/* multirange, range -> bool functions */
1793
1794/* contains? */
1795Datum
1797{
1800 TypeCacheEntry *typcache;
1801
1802 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1803
1805}
1806
1807Datum
1809{
1812 TypeCacheEntry *typcache;
1813
1814 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1815
1817}
1818
1819/* contained by? */
1820Datum
1822{
1825 TypeCacheEntry *typcache;
1826
1827 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1828
1830}
1831
1832Datum
1834{
1837 TypeCacheEntry *typcache;
1838
1839 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1840
1842}
1843
1844/*
1845 * Comparison function for checking if any range of multirange contains given
1846 * key range using binary search.
1847 */
1848static int
1851 void *key, bool *match)
1852{
1853 RangeBound *keyLower = (RangeBound *) key;
1854 RangeBound *keyUpper = (RangeBound *) key + 1;
1855
1856 /* Check if key range is strictly in the left or in the right */
1857 if (range_cmp_bounds(typcache, keyUpper, lower) < 0)
1858 return -1;
1859 if (range_cmp_bounds(typcache, keyLower, upper) > 0)
1860 return 1;
1861
1862 /*
1863 * At this point we found overlapping range. But we have to check if it
1864 * really contains the key range. Anyway, we have to stop our search
1865 * here, because multirange contains only non-overlapping ranges.
1866 */
1867 *match = range_bounds_contains(typcache, lower, upper, keyLower, keyUpper);
1868
1869 return 0;
1870}
1871
1872/*
1873 * Test whether multirange mr contains a specific range r.
1874 */
1875bool
1877 const MultirangeType *mr,
1878 const RangeType *r)
1879{
1880 RangeBound bounds[2];
1881 bool empty;
1882
1883 /*
1884 * Every multirange contains an infinite number of empty ranges, even an
1885 * empty one.
1886 */
1887 if (RangeIsEmpty(r))
1888 return true;
1889
1890 if (MultirangeIsEmpty(mr))
1891 return false;
1892
1893 range_deserialize(rangetyp, r, &bounds[0], &bounds[1], &empty);
1894 Assert(!empty);
1895
1898}
1899
1900/*
1901 * Test whether range r contains a multirange mr.
1902 */
1903bool
1905 const RangeType *r,
1906 const MultirangeType *mr)
1907{
1909 upper1,
1910 lower2,
1911 upper2,
1912 tmp;
1913 bool empty;
1914
1915 /*
1916 * Every range contains an infinite number of empty multiranges, even an
1917 * empty one.
1918 */
1919 if (MultirangeIsEmpty(mr))
1920 return true;
1921
1922 if (RangeIsEmpty(r))
1923 return false;
1924
1925 /* Range contains multirange iff it contains its union range. */
1926 range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
1927 Assert(!empty);
1929 multirange_get_bounds(rangetyp, mr, mr->rangeCount - 1, &tmp, &upper2);
1930
1932}
1933
1934
1935/* multirange, multirange -> bool functions */
1936
1937/* equality (internal version) */
1938bool
1940 const MultirangeType *mr1,
1941 const MultirangeType *mr2)
1942{
1945 int32 i;
1947 upper1,
1948 lower2,
1949 upper2;
1950
1951 /* Different types should be prevented by ANYMULTIRANGE matching rules */
1953 elog(ERROR, "multirange types do not match");
1954
1955 range_count_1 = mr1->rangeCount;
1956 range_count_2 = mr2->rangeCount;
1957
1959 return false;
1960
1961 for (i = 0; i < range_count_1; i++)
1962 {
1965
1966 if (range_cmp_bounds(rangetyp, &lower1, &lower2) != 0 ||
1968 return false;
1969 }
1970
1971 return true;
1972}
1973
1974/* equality */
1975Datum
1977{
1980 TypeCacheEntry *typcache;
1981
1983
1985}
1986
1987/* inequality (internal version) */
1988bool
1990 const MultirangeType *mr1,
1991 const MultirangeType *mr2)
1992{
1994}
1995
1996/* inequality */
1997Datum
1999{
2002 TypeCacheEntry *typcache;
2003
2005
2007}
2008
2009/* overlaps? */
2010Datum
2012{
2015 TypeCacheEntry *typcache;
2016
2017 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2018
2020}
2021
2022Datum
2024{
2027 TypeCacheEntry *typcache;
2028
2029 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2030
2032}
2033
2034Datum
2036{
2039 TypeCacheEntry *typcache;
2040
2042
2044}
2045
2046/*
2047 * Comparison function for checking if any range of multirange overlaps given
2048 * key range using binary search.
2049 */
2050static int
2053 void *key, bool *match)
2054{
2055 RangeBound *keyLower = (RangeBound *) key;
2056 RangeBound *keyUpper = (RangeBound *) key + 1;
2057
2058 if (range_cmp_bounds(typcache, keyUpper, lower) < 0)
2059 return -1;
2060 if (range_cmp_bounds(typcache, keyLower, upper) > 0)
2061 return 1;
2062
2063 *match = true;
2064 return 0;
2065}
2066
2067bool
2069 const RangeType *r,
2070 const MultirangeType *mr)
2071{
2072 RangeBound bounds[2];
2073 bool empty;
2074
2075 /*
2076 * Empties never overlap, even with empties. (This seems strange since
2077 * they *do* contain each other, but we want to follow how ranges work.)
2078 */
2080 return false;
2081
2082 range_deserialize(rangetyp, r, &bounds[0], &bounds[1], &empty);
2083 Assert(!empty);
2084
2087}
2088
2089bool
2091 const MultirangeType *mr1,
2092 const MultirangeType *mr2)
2093{
2096 int32 i1;
2097 int32 i2;
2099 upper1,
2100 lower2,
2101 upper2;
2102
2103 /*
2104 * Empties never overlap, even with empties. (This seems strange since
2105 * they *do* contain each other, but we want to follow how ranges work.)
2106 */
2108 return false;
2109
2110 range_count1 = mr1->rangeCount;
2111 range_count2 = mr2->rangeCount;
2112
2113 /*
2114 * Every range in mr1 gets a chance to overlap with the ranges in mr2, but
2115 * we can use their ordering to avoid O(n^2). This is similar to
2116 * range_overlaps_multirange where r1 : r2 :: mrr : r, but there if we
2117 * don't find an overlap with r we're done, and here if we don't find an
2118 * overlap with r2 we try the next r2.
2119 */
2120 i1 = 0;
2122 for (i1 = 0, i2 = 0; i2 < range_count2; i2++)
2123 {
2125
2126 /* Discard r1s while r1 << r2 */
2127 while (range_cmp_bounds(rangetyp, &upper1, &lower2) < 0)
2128 {
2129 if (++i1 >= range_count1)
2130 return false;
2132 }
2133
2134 /*
2135 * If r1 && r2, we're done, otherwise we failed to find an overlap for
2136 * r2, so go to the next one.
2137 */
2139 return true;
2140 }
2141
2142 /* We looked through all of mr2 without finding an overlap */
2143 return false;
2144}
2145
2146/* does not extend to right of? */
2147bool
2149 const RangeType *r,
2150 const MultirangeType *mr)
2151{
2153 upper1,
2154 lower2,
2155 upper2;
2156 bool empty;
2157
2159 return false;
2160
2161 range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
2162 Assert(!empty);
2163 multirange_get_bounds(rangetyp, mr, mr->rangeCount - 1,
2164 &lower2, &upper2);
2165
2166 return (range_cmp_bounds(rangetyp, &upper1, &upper2) <= 0);
2167}
2168
2169Datum
2171{
2174 TypeCacheEntry *typcache;
2175
2176 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2177
2179}
2180
2181Datum
2183{
2186 TypeCacheEntry *typcache;
2188 upper1,
2189 lower2,
2190 upper2;
2191 bool empty;
2192
2194 PG_RETURN_BOOL(false);
2195
2196 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2197
2198 multirange_get_bounds(typcache->rngtype, mr, mr->rangeCount - 1,
2199 &lower1, &upper1);
2200 range_deserialize(typcache->rngtype, r, &lower2, &upper2, &empty);
2201 Assert(!empty);
2202
2204}
2205
2206Datum
2208{
2211 TypeCacheEntry *typcache;
2213 upper1,
2214 lower2,
2215 upper2;
2216
2218 PG_RETURN_BOOL(false);
2219
2221
2222 multirange_get_bounds(typcache->rngtype, mr1, mr1->rangeCount - 1,
2223 &lower1, &upper1);
2224 multirange_get_bounds(typcache->rngtype, mr2, mr2->rangeCount - 1,
2225 &lower2, &upper2);
2226
2228}
2229
2230/* does not extend to left of? */
2231bool
2233 const RangeType *r,
2234 const MultirangeType *mr)
2235{
2237 upper1,
2238 lower2,
2239 upper2;
2240 bool empty;
2241
2243 return false;
2244
2245 range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
2246 Assert(!empty);
2248
2249 return (range_cmp_bounds(rangetyp, &lower1, &lower2) >= 0);
2250}
2251
2252Datum
2254{
2257 TypeCacheEntry *typcache;
2258
2259 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2260
2262}
2263
2264Datum
2266{
2269 TypeCacheEntry *typcache;
2271 upper1,
2272 lower2,
2273 upper2;
2274 bool empty;
2275
2277 PG_RETURN_BOOL(false);
2278
2279 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2280
2281 multirange_get_bounds(typcache->rngtype, mr, 0, &lower1, &upper1);
2282 range_deserialize(typcache->rngtype, r, &lower2, &upper2, &empty);
2283 Assert(!empty);
2284
2286}
2287
2288Datum
2290{
2293 TypeCacheEntry *typcache;
2295 upper1,
2296 lower2,
2297 upper2;
2298
2300 PG_RETURN_BOOL(false);
2301
2303
2304 multirange_get_bounds(typcache->rngtype, mr1, 0, &lower1, &upper1);
2305 multirange_get_bounds(typcache->rngtype, mr2, 0, &lower2, &upper2);
2306
2308}
2309
2310/* contains? */
2311Datum
2313{
2316 TypeCacheEntry *typcache;
2317
2319
2321}
2322
2323/* contained by? */
2324Datum
2326{
2329 TypeCacheEntry *typcache;
2330
2332
2334}
2335
2336/*
2337 * Test whether multirange mr1 contains every range from another multirange mr2.
2338 */
2339bool
2341 const MultirangeType *mr1,
2342 const MultirangeType *mr2)
2343{
2344 int32 range_count1 = mr1->rangeCount;
2345 int32 range_count2 = mr2->rangeCount;
2346 int i1,
2347 i2;
2349 upper1,
2350 lower2,
2351 upper2;
2352
2353 /*
2354 * We follow the same logic for empties as ranges: - an empty multirange
2355 * contains an empty range/multirange. - an empty multirange can't contain
2356 * any other range/multirange. - an empty multirange is contained by any
2357 * other range/multirange.
2358 */
2359
2360 if (range_count2 == 0)
2361 return true;
2362 if (range_count1 == 0)
2363 return false;
2364
2365 /*
2366 * Every range in mr2 must be contained by some range in mr1. To avoid
2367 * O(n^2) we walk through both ranges in tandem.
2368 */
2369 i1 = 0;
2371 for (i2 = 0; i2 < range_count2; i2++)
2372 {
2374
2375 /* Discard r1s while r1 << r2 */
2376 while (range_cmp_bounds(rangetyp, &upper1, &lower2) < 0)
2377 {
2378 if (++i1 >= range_count1)
2379 return false;
2381 }
2382
2383 /*
2384 * If r1 @> r2, go to the next r2, otherwise return false (since every
2385 * r1[n] and r1[n+1] must have a gap). Note this will give weird
2386 * answers if you don't canonicalize, e.g. with a custom
2387 * int2multirange {[1,1], [2,2]} there is a "gap". But that is
2388 * consistent with other range operators, e.g. '[1,1]'::int2range -|-
2389 * '[2,2]'::int2range is false.
2390 */
2392 &lower2, &upper2))
2393 return false;
2394 }
2395
2396 /* All ranges in mr2 are satisfied */
2397 return true;
2398}
2399
2400/* strictly left of? */
2401Datum
2403{
2406 TypeCacheEntry *typcache;
2407
2408 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2409
2411}
2412
2413Datum
2415{
2418 TypeCacheEntry *typcache;
2419
2420 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2421
2423}
2424
2425Datum
2427{
2430 TypeCacheEntry *typcache;
2431
2433
2435}
2436
2437/* strictly right of? */
2438Datum
2440{
2443 TypeCacheEntry *typcache;
2444
2445 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2446
2448}
2449
2450Datum
2452{
2455 TypeCacheEntry *typcache;
2456
2457 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2458
2460}
2461
2462Datum
2464{
2467 TypeCacheEntry *typcache;
2468
2470
2472}
2473
2474/* strictly left of? (internal version) */
2475bool
2477 const RangeType *r,
2478 const MultirangeType *mr)
2479{
2481 upper1,
2482 lower2,
2483 upper2;
2484 bool empty;
2485
2487 return false;
2488
2489 range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
2490 Assert(!empty);
2491
2493
2494 return (range_cmp_bounds(rangetyp, &upper1, &lower2) < 0);
2495}
2496
2497bool
2499 const MultirangeType *mr1,
2500 const MultirangeType *mr2)
2501{
2503 upper1,
2504 lower2,
2505 upper2;
2506
2508 return false;
2509
2510 multirange_get_bounds(rangetyp, mr1, mr1->rangeCount - 1,
2511 &lower1, &upper1);
2513 &lower2, &upper2);
2514
2515 return (range_cmp_bounds(rangetyp, &upper1, &lower2) < 0);
2516}
2517
2518/* strictly right of? (internal version) */
2519bool
2521 const RangeType *r,
2522 const MultirangeType *mr)
2523{
2525 upper1,
2526 lower2,
2527 upper2;
2528 bool empty;
2530
2532 return false;
2533
2534 range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
2535 Assert(!empty);
2536
2537 range_count = mr->rangeCount;
2539 &lower2, &upper2);
2540
2541 return (range_cmp_bounds(rangetyp, &lower1, &upper2) > 0);
2542}
2543
2544bool
2546 const RangeType *r,
2547 const MultirangeType *mr)
2548{
2550 upper1,
2551 lower2,
2552 upper2;
2553 bool empty;
2555
2557 return false;
2558
2559 range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
2560 Assert(!empty);
2561
2562 range_count = mr->rangeCount;
2564 &lower2, &upper2);
2565
2567 return true;
2568
2569 if (range_count > 1)
2571 &lower2, &upper2);
2572
2574 return true;
2575
2576 return false;
2577}
2578
2579/* adjacent to? */
2580Datum
2582{
2585 TypeCacheEntry *typcache;
2586
2587 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2588
2590}
2591
2592Datum
2594{
2597 TypeCacheEntry *typcache;
2598
2600 PG_RETURN_BOOL(false);
2601
2602 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2603
2605}
2606
2607Datum
2609{
2612 TypeCacheEntry *typcache;
2616 upper1,
2617 lower2,
2618 upper2;
2619
2621 PG_RETURN_BOOL(false);
2622
2624
2625 range_count1 = mr1->rangeCount;
2626 range_count2 = mr2->rangeCount;
2628 &lower1, &upper1);
2629 multirange_get_bounds(typcache->rngtype, mr2, 0,
2630 &lower2, &upper2);
2631 if (bounds_adjacent(typcache->rngtype, upper1, lower2))
2632 PG_RETURN_BOOL(true);
2633
2634 if (range_count1 > 1)
2635 multirange_get_bounds(typcache->rngtype, mr1, 0,
2636 &lower1, &upper1);
2637 if (range_count2 > 1)
2639 &lower2, &upper2);
2640 if (bounds_adjacent(typcache->rngtype, upper2, lower1))
2641 PG_RETURN_BOOL(true);
2642 PG_RETURN_BOOL(false);
2643}
2644
2645/* Btree support */
2646
2647/* btree comparator */
2648Datum
2650{
2656 int32 i;
2657 TypeCacheEntry *typcache;
2658 int cmp = 0; /* If both are empty we'll use this. */
2659
2660 /* Different types should be prevented by ANYMULTIRANGE matching rules */
2662 elog(ERROR, "multirange types do not match");
2663
2665
2666 range_count_1 = mr1->rangeCount;
2667 range_count_2 = mr2->rangeCount;
2668
2669 /* Loop over source data */
2671 for (i = 0; i < range_count_max; i++)
2672 {
2674 upper1,
2675 lower2,
2676 upper2;
2677
2678 /*
2679 * If one multirange is shorter, it's as if it had empty ranges at the
2680 * end to extend its length. An empty range compares earlier than any
2681 * other range, so the shorter multirange comes before the longer.
2682 * This is the same behavior as in other types, e.g. in strings 'aaa'
2683 * < 'aaaaaa'.
2684 */
2685 if (i >= range_count_1)
2686 {
2687 cmp = -1;
2688 break;
2689 }
2690 if (i >= range_count_2)
2691 {
2692 cmp = 1;
2693 break;
2694 }
2695
2698
2699 cmp = range_cmp_bounds(typcache->rngtype, &lower1, &lower2);
2700 if (cmp == 0)
2701 cmp = range_cmp_bounds(typcache->rngtype, &upper1, &upper2);
2702 if (cmp != 0)
2703 break;
2704 }
2705
2706 PG_FREE_IF_COPY(mr1, 0);
2707 PG_FREE_IF_COPY(mr2, 1);
2708
2710}
2711
2712/* inequality operators using the multirange_cmp function */
2713Datum
2715{
2716 int cmp = DatumGetInt32(multirange_cmp(fcinfo));
2717
2718 PG_RETURN_BOOL(cmp < 0);
2719}
2720
2721Datum
2723{
2724 int cmp = DatumGetInt32(multirange_cmp(fcinfo));
2725
2726 PG_RETURN_BOOL(cmp <= 0);
2727}
2728
2729Datum
2731{
2732 int cmp = DatumGetInt32(multirange_cmp(fcinfo));
2733
2734 PG_RETURN_BOOL(cmp >= 0);
2735}
2736
2737Datum
2739{
2740 int cmp = DatumGetInt32(multirange_cmp(fcinfo));
2741
2742 PG_RETURN_BOOL(cmp > 0);
2743}
2744
2745/* multirange -> range functions */
2746
2747/* Find the smallest range that includes everything in the multirange */
2748Datum
2750{
2753 TypeCacheEntry *typcache;
2754 RangeType *result;
2755
2756 typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
2757
2758 if (MultirangeIsEmpty(mr))
2759 {
2760 result = make_empty_range(typcache->rngtype);
2761 }
2762 else if (mr->rangeCount == 1)
2763 {
2764 result = multirange_get_range(typcache->rngtype, mr, 0);
2765 }
2766 else
2767 {
2769 firstUpper,
2770 lastLower,
2771 lastUpper;
2772
2773 multirange_get_bounds(typcache->rngtype, mr, 0,
2775 multirange_get_bounds(typcache->rngtype, mr, mr->rangeCount - 1,
2776 &lastLower, &lastUpper);
2777
2778 result = make_range(typcache->rngtype, &firstLower, &lastUpper,
2779 false, NULL);
2780 }
2781
2782 PG_RETURN_RANGE_P(result);
2783}
2784
2785/* Turn multirange into a set of ranges */
2786Datum
2788{
2789 typedef struct
2790 {
2792 TypeCacheEntry *typcache;
2793 int index;
2795
2798 MemoryContext oldcontext;
2799
2800 /* stuff done only on the first call of the function */
2801 if (SRF_IS_FIRSTCALL())
2802 {
2804
2805 /* create a function context for cross-call persistence */
2807
2808 /*
2809 * switch to memory context appropriate for multiple function calls
2810 */
2811 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
2812
2813 /*
2814 * Get the multirange value and detoast if needed. We can't do this
2815 * earlier because if we have to detoast, we want the detoasted copy
2816 * to be in multi_call_memory_ctx, so it will go away when we're done
2817 * and not before. (If no detoast happens, we assume the originally
2818 * passed multirange will stick around till then.)
2819 */
2821
2822 /* allocate memory for user context */
2824
2825 /* initialize state */
2826 fctx->mr = mr;
2827 fctx->index = 0;
2830
2831 funcctx->user_fctx = fctx;
2832 MemoryContextSwitchTo(oldcontext);
2833 }
2834
2835 /* stuff done on every call of the function */
2837 fctx = funcctx->user_fctx;
2838
2839 if (fctx->index < fctx->mr->rangeCount)
2840 {
2842
2843 range = multirange_get_range(fctx->typcache->rngtype,
2844 fctx->mr,
2845 fctx->index);
2846 fctx->index++;
2847
2849 }
2850 else
2851 {
2852 /* do when there is no more left */
2854 }
2855}
2856
2857/* Hash support */
2858
2859/* hash a multirange value */
2860Datum
2862{
2864 uint32 result = 1;
2865 TypeCacheEntry *typcache,
2866 *scache;
2868 i;
2869
2870 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2871 scache = typcache->rngtype->rngelemtype;
2872 if (!OidIsValid(scache->hash_proc_finfo.fn_oid))
2873 {
2874 scache = lookup_type_cache(scache->type_id,
2876 if (!OidIsValid(scache->hash_proc_finfo.fn_oid))
2877 ereport(ERROR,
2879 errmsg("could not identify a hash function for type %s",
2880 format_type_be(scache->type_id))));
2881 }
2882
2883 range_count = mr->rangeCount;
2884 for (i = 0; i < range_count; i++)
2885 {
2887 upper;
2888 uint8 flags = MultirangeGetFlagsPtr(mr)[i];
2892
2893 multirange_get_bounds(typcache->rngtype, mr, i, &lower, &upper);
2894
2895 if (RANGE_HAS_LBOUND(flags))
2897 typcache->rngtype->rng_collation,
2898 lower.val));
2899 else
2900 lower_hash = 0;
2901
2902 if (RANGE_HAS_UBOUND(flags))
2904 typcache->rngtype->rng_collation,
2905 upper.val));
2906 else
2907 upper_hash = 0;
2908
2909 /* Merge hashes of flags and bounds */
2914
2915 /*
2916 * Use the same approach as hash_array to combine the individual
2917 * elements' hash values:
2918 */
2919 result = (result << 5) - result + range_hash;
2920 }
2921
2922 PG_FREE_IF_COPY(mr, 0);
2923
2924 PG_RETURN_UINT32(result);
2925}
2926
2927/*
2928 * Returns 64-bit value by hashing a value to a 64-bit value, with a seed.
2929 * Otherwise, similar to hash_multirange.
2930 */
2931Datum
2933{
2935 Datum seed = PG_GETARG_DATUM(1);
2936 uint64 result = 1;
2937 TypeCacheEntry *typcache,
2938 *scache;
2940 i;
2941
2942 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
2943 scache = typcache->rngtype->rngelemtype;
2944 if (!OidIsValid(scache->hash_extended_proc_finfo.fn_oid))
2945 {
2946 scache = lookup_type_cache(scache->type_id,
2948 if (!OidIsValid(scache->hash_extended_proc_finfo.fn_oid))
2949 ereport(ERROR,
2951 errmsg("could not identify a hash function for type %s",
2952 format_type_be(scache->type_id))));
2953 }
2954
2955 range_count = mr->rangeCount;
2956 for (i = 0; i < range_count; i++)
2957 {
2959 upper;
2960 uint8 flags = MultirangeGetFlagsPtr(mr)[i];
2964
2965 multirange_get_bounds(typcache->rngtype, mr, i, &lower, &upper);
2966
2967 if (RANGE_HAS_LBOUND(flags))
2968 lower_hash = DatumGetUInt64(FunctionCall2Coll(&scache->hash_extended_proc_finfo,
2969 typcache->rngtype->rng_collation,
2970 lower.val,
2971 seed));
2972 else
2973 lower_hash = 0;
2974
2975 if (RANGE_HAS_UBOUND(flags))
2976 upper_hash = DatumGetUInt64(FunctionCall2Coll(&scache->hash_extended_proc_finfo,
2977 typcache->rngtype->rng_collation,
2978 upper.val,
2979 seed));
2980 else
2981 upper_hash = 0;
2982
2983 /* Merge hashes of flags and bounds */
2985 DatumGetInt64(seed)));
2989
2990 /*
2991 * Use the same approach as hash_array to combine the individual
2992 * elements' hash values:
2993 */
2994 result = (result << 5) - result + range_hash;
2995 }
2996
2997 PG_FREE_IF_COPY(mr, 0);
2998
2999 PG_RETURN_UINT64(result);
3000}
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:150
#define att_nominal_alignby(cur_offset, attalignby)
Definition tupmacs.h:189
#define att_addlength_pointer(cur_offset, attlen, attptr)
Definition tupmacs.h:209
static uint8 typalign_to_alignby(char typalign)
Definition tupmacs.h:80
static Datum fetch_att(const void *T, bool attbyval, int attlen)
Definition tupmacs.h:50
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition typcache.c:386
#define TYPECACHE_HASH_PROC_FINFO
Definition typcache.h:145
#define TYPECACHE_MULTIRANGE_INFO
Definition typcache.h:154
#define TYPECACHE_HASH_EXTENDED_PROC_FINFO
Definition typcache.h:153
static Size VARSIZE(const void *PTR)
Definition varatt.h:298
static char * VARDATA(const void *PTR)
Definition varatt.h:305
static void SET_VARSIZE(void *PTR, Size len)
Definition varatt.h:432
static StringInfoData tmpbuf
Definition walsender.c:178

◆ 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 2862 of file multirangetypes.c.

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

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 2933 of file multirangetypes.c.

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

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 853 of file multirangetypes.c.

854{
856}

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 651 of file multirangetypes.c.

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

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 2609 of file multirangetypes.c.

2610{
2613 TypeCacheEntry *typcache;
2617 upper1,
2618 lower2,
2619 upper2;
2620
2622 PG_RETURN_BOOL(false);
2623
2625
2626 range_count1 = mr1->rangeCount;
2627 range_count2 = mr2->rangeCount;
2629 &lower1, &upper1);
2630 multirange_get_bounds(typcache->rngtype, mr2, 0,
2631 &lower2, &upper2);
2632 if (bounds_adjacent(typcache->rngtype, upper1, lower2))
2633 PG_RETURN_BOOL(true);
2634
2635 if (range_count1 > 1)
2636 multirange_get_bounds(typcache->rngtype, mr1, 0,
2637 &lower1, &upper1);
2638 if (range_count2 > 1)
2640 &lower2, &upper2);
2641 if (bounds_adjacent(typcache->rngtype, upper2, lower1))
2642 PG_RETURN_BOOL(true);
2643 PG_RETURN_BOOL(false);
2644}

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 1488 of file multirangetypes.c.

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

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 2499 of file multirangetypes.c.

2502{
2504 upper1,
2505 lower2,
2506 upper2;
2507
2509 return false;
2510
2511 multirange_get_bounds(rangetyp, mr1, mr1->rangeCount - 1,
2512 &lower1, &upper1);
2514 &lower2, &upper2);
2515
2516 return (range_cmp_bounds(rangetyp, &upper1, &lower2) < 0);
2517}

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 903 of file multirangetypes.c.

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

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. */
488 if (ranges != NULL)
489 qsort_arg(ranges, input_range_count, sizeof(RangeType *),
491
492 /* Now merge where possible: */
493 for (i = 0; i < input_range_count; i++)
494 {
495 currentRange = ranges[i];
497 continue;
498
499 if (lastRange == NULL)
500 {
502 continue;
503 }
504
505 /*
506 * range_adjacent_internal gives true if *either* A meets B or B meets
507 * A, which is not quite want we want, but we rely on the sorting
508 * above to rule out B meets A ever happening.
509 */
511 {
512 /* The two ranges touch (without overlap), so merge them: */
513 ranges[output_range_count - 1] = lastRange =
515 }
517 {
518 /* There's a gap, so make a new entry: */
521 }
522 else
523 {
524 /* They must overlap, so merge them: */
525 ranges[output_range_count - 1] = lastRange =
527 }
528 }
529
530 return output_range_count;
531}

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 2650 of file multirangetypes.c.

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

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 1064 of file multirangetypes.c.

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

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 1028 of file multirangetypes.c.

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

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 946 of file multirangetypes.c.

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

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 2341 of file multirangetypes.c.

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

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 1877 of file multirangetypes.c.

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

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 831 of file multirangetypes.c.

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

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 1750 of file multirangetypes.c.

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

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 1940 of file multirangetypes.c.

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

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 2731 of file multirangetypes.c.

2732{
2733 int cmp = DatumGetInt32(multirange_cmp(fcinfo));
2734
2735 PG_RETURN_BOOL(cmp >= 0);
2736}

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 749 of file multirangetypes.c.

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

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 678 of file multirangetypes.c.

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

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 700 of file multirangetypes.c.

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

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 551 of file multirangetypes.c.

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

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 807 of file multirangetypes.c.

809{
811 upper,
812 tmp;
813
816
818 multirange_get_bounds(rangetyp, mr, mr->rangeCount - 1, &tmp, &upper);
819
820 return make_range(rangetyp, &lower, &upper, false, NULL);
821}

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 2739 of file multirangetypes.c.

2740{
2741 int cmp = DatumGetInt32(multirange_cmp(fcinfo));
2742
2743 PG_RETURN_BOOL(cmp > 0);
2744}

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 1541 of file multirangetypes.c.

1542{
1545 TypeCacheEntry *typcache;
1546 MultirangeType *result;
1547 MultirangeType *current;
1552
1553 if (!AggCheckCallContext(fcinfo, &aggContext))
1554 elog(ERROR, "multirange_intersect_agg_transfn called in non-aggregate context");
1555
1556 mltrngtypoid = get_fn_expr_argtype(fcinfo->flinfo, 1);
1558 elog(ERROR, "range_intersect_agg must be called with a multirange");
1559
1560 typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
1561
1562 /* strictness ensures these are non-null */
1563 result = PG_GETARG_MULTIRANGE_P(0);
1564 current = PG_GETARG_MULTIRANGE_P(1);
1565
1566 multirange_deserialize(typcache->rngtype, result, &range_count1, &ranges1);
1567 multirange_deserialize(typcache->rngtype, current, &range_count2, &ranges2);
1568
1570 typcache->rngtype,
1572 ranges1,
1574 ranges2);
1575 PG_RETURN_MULTIRANGE_P(result);
1576}

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 1336 of file multirangetypes.c.

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

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 2723 of file multirangetypes.c.

2724{
2725 int cmp = DatumGetInt32(multirange_cmp(fcinfo));
2726
2727 PG_RETURN_BOOL(cmp <= 0);
2728}

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 2715 of file multirangetypes.c.

2716{
2717 int cmp = DatumGetInt32(multirange_cmp(fcinfo));
2718
2719 PG_RETURN_BOOL(cmp < 0);
2720}

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 1149 of file multirangetypes.c.

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

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 1238 of file multirangetypes.c.

1239{
1241 MemoryContext oldcontext;
1242
1243 if (!SRF_IS_FIRSTCALL())
1244 {
1245 /* We never have more than one result */
1248 }
1249 else
1250 {
1254 TypeCacheEntry *typcache;
1261
1263
1264 /*
1265 * switch to memory context appropriate for multiple function calls
1266 */
1267 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
1268
1269 /* get args, detoasting into multi-call memory context */
1272
1275 if (typcache->rngtype == NULL)
1276 elog(ERROR, "type %u is not a multirange type", mltrngtypoid);
1277 rangetyp = typcache->rngtype;
1278
1280 mr = mr1;
1281 else
1282 {
1285
1287 rangetyp,
1289 ranges1,
1291 ranges2);
1292 }
1293
1294 MemoryContextSwitchTo(oldcontext);
1295
1297 if (MultirangeIsEmpty(mr))
1299 else
1301 }
1302}

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 1990 of file multirangetypes.c.

1993{
1995}

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 2091 of file multirangetypes.c.

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

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 2183 of file multirangetypes.c.

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

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 1850 of file multirangetypes.c.

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

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 2052 of file multirangetypes.c.

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

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 572 of file multirangetypes.c.

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

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

Referenced by make_multirange().

◆ multirange_union()

◆ multirange_unnest()

Datum multirange_unnest ( PG_FUNCTION_ARGS  )

Definition at line 2788 of file multirangetypes.c.

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

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 1606 of file multirangetypes.c.

1607{
1609 TypeCacheEntry *typcache;
1612
1613 if (MultirangeIsEmpty(mr))
1615
1616 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1617
1618 multirange_get_bounds(typcache->rngtype, mr, mr->rangeCount - 1,
1619 &lower, &upper);
1620
1621 if (!upper.infinite)
1623 else
1625}

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 2546 of file multirangetypes.c.

2549{
2551 upper1,
2552 lower2,
2553 upper2;
2554 bool empty;
2556
2558 return false;
2559
2560 range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
2561 Assert(!empty);
2562
2563 range_count = mr->rangeCount;
2565 &lower2, &upper2);
2566
2568 return true;
2569
2570 if (range_count > 1)
2572 &lower2, &upper2);
2573
2575 return true;
2576
2577 return false;
2578}

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 2521 of file multirangetypes.c.

2524{
2526 upper1,
2527 lower2,
2528 upper2;
2529 bool empty;
2531
2533 return false;
2534
2535 range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
2536 Assert(!empty);
2537
2538 range_count = mr->rangeCount;
2540 &lower2, &upper2);
2541
2542 return (range_cmp_bounds(rangetyp, &lower1, &upper2) > 0);
2543}

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 1448 of file multirangetypes.c.

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

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 1416 of file multirangetypes.c.

1417{
1419 Oid rngtypoid;
1421
1422 if (!AggCheckCallContext(fcinfo, &aggContext))
1423 elog(ERROR, "range_agg_transfn called in non-aggregate context");
1424
1425 rngtypoid = get_fn_expr_argtype(fcinfo->flinfo, 1);
1427 elog(ERROR, "range_agg must be called with a range");
1428
1429 if (PG_ARGISNULL(0))
1431 else
1433
1434 /* skip NULLs */
1435 if (!PG_ARGISNULL(1))
1437
1439}

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 2477 of file multirangetypes.c.

2480{
2482 upper1,
2483 lower2,
2484 upper2;
2485 bool empty;
2486
2488 return false;
2489
2490 range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
2491 Assert(!empty);
2492
2494
2495 return (range_cmp_bounds(rangetyp, &upper1, &lower2) < 0);
2496}

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 883 of file multirangetypes.c.

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

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 863 of file multirangetypes.c.

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

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 1905 of file multirangetypes.c.

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

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 2750 of file multirangetypes.c.

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

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 2069 of file multirangetypes.c.

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

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 2149 of file multirangetypes.c.

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

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 2233 of file multirangetypes.c.

2236{
2238 upper1,
2239 lower2,
2240 upper2;
2241 bool empty;
2242
2244 return false;
2245
2246 range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
2247 Assert(!empty);
2249
2250 return (range_cmp_bounds(rangetyp, &lower1, &lower2) >= 0);
2251}

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 600 of file multirangetypes.c.

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

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

Referenced by make_multirange().