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

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

420{
421 MultirangeIOData *cache = (MultirangeIOData *) fcinfo->flinfo->fn_extra;
422
423 if (cache == NULL || cache->typcache->type_id != mltrngtypid)
424 {
425 Oid typiofunc;
426 int16 typlen;
427 bool typbyval;
428 char typalign;
429 char typdelim;
430
432 sizeof(MultirangeIOData));
434 if (cache->typcache->rngtype == NULL)
435 elog(ERROR, "type %u is not a multirange type", mltrngtypid);
436
437 /* get_type_io_data does more than we need, but is convenient */
438 get_type_io_data(cache->typcache->rngtype->type_id,
439 func,
440 &typlen,
441 &typbyval,
442 &typalign,
443 &typdelim,
444 &cache->typioparam,
445 &typiofunc);
446
447 if (!OidIsValid(typiofunc))
448 {
449 /* this could only happen for receive or send */
450 if (func == IOFunc_receive)
453 errmsg("no binary input function available for type %s",
454 format_type_be(cache->typcache->rngtype->type_id))));
455 else
458 errmsg("no binary output function available for type %s",
459 format_type_be(cache->typcache->rngtype->type_id))));
460 }
461 fmgr_info_cxt(typiofunc, &cache->typioproc,
462 fcinfo->flinfo->fn_mcxt);
463
464 fcinfo->flinfo->fn_extra = cache;
465 }
466
467 return cache;
468}

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

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

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, result, 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 2934 of file multirangetypes.c.

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

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, result, 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 854 of file multirangetypes.c.

855{
857}

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

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

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

2611{
2614 TypeCacheEntry *typcache;
2618 upper1,
2619 lower2,
2620 upper2;
2621
2623 PG_RETURN_BOOL(false);
2624
2626
2627 range_count1 = mr1->rangeCount;
2628 range_count2 = mr2->rangeCount;
2630 &lower1, &upper1);
2631 multirange_get_bounds(typcache->rngtype, mr2, 0,
2632 &lower2, &upper2);
2633 if (bounds_adjacent(typcache->rngtype, upper1, lower2))
2634 PG_RETURN_BOOL(true);
2635
2636 if (range_count1 > 1)
2637 multirange_get_bounds(typcache->rngtype, mr1, 0,
2638 &lower1, &upper1);
2639 if (range_count2 > 1)
2641 &lower2, &upper2);
2642 if (bounds_adjacent(typcache->rngtype, upper2, lower1))
2643 PG_RETURN_BOOL(true);
2644 PG_RETURN_BOOL(false);
2645}

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

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

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

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

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

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

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

482{
485 int32 i;
487
488 /* Sort the ranges so we can find the ones that overlap/meet. */
489 if (ranges != NULL)
490 qsort_arg(ranges, input_range_count, sizeof(RangeType *),
492
493 /* Now merge where possible: */
494 for (i = 0; i < input_range_count; i++)
495 {
496 currentRange = ranges[i];
498 continue;
499
500 if (lastRange == NULL)
501 {
503 continue;
504 }
505
506 /*
507 * range_adjacent_internal gives true if *either* A meets B or B meets
508 * A, which is not quite want we want, but we rely on the sorting
509 * above to rule out B meets A ever happening.
510 */
512 {
513 /* The two ranges touch (without overlap), so merge them: */
514 ranges[output_range_count - 1] = lastRange =
516 }
518 {
519 /* There's a gap, so make a new entry: */
522 }
523 else
524 {
525 /* They must overlap, so merge them: */
526 ranges[output_range_count - 1] = lastRange =
528 }
529 }
530
531 return output_range_count;
532}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

References Assert, att_addlength_pointer, att_align_pointer, fb(), i, len, memcpy(), 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 552 of file multirangetypes.c.

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

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

810{
812 upper,
813 tmp;
814
817
819 multirange_get_bounds(rangetyp, mr, mr->rangeCount - 1, &tmp, &upper);
820
821 return make_range(rangetyp, &lower, &upper, false, NULL);
822}

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

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

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

1543{
1546 TypeCacheEntry *typcache;
1548 MultirangeType *current;
1553
1554 if (!AggCheckCallContext(fcinfo, &aggContext))
1555 elog(ERROR, "multirange_intersect_agg_transfn called in non-aggregate context");
1556
1557 mltrngtypoid = get_fn_expr_argtype(fcinfo->flinfo, 1);
1559 elog(ERROR, "range_intersect_agg must be called with a multirange");
1560
1561 typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
1562
1563 /* strictness ensures these are non-null */
1565 current = PG_GETARG_MULTIRANGE_P(1);
1566
1568 multirange_deserialize(typcache->rngtype, current, &range_count2, &ranges2);
1569
1571 typcache->rngtype,
1573 ranges1,
1575 ranges2);
1577}

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, result, 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 1337 of file multirangetypes.c.

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

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

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

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

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

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

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

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

1240{
1242 MemoryContext oldcontext;
1243
1244 if (!SRF_IS_FIRSTCALL())
1245 {
1246 /* We never have more than one result */
1249 }
1250 else
1251 {
1255 TypeCacheEntry *typcache;
1262
1264
1265 /*
1266 * switch to memory context appropriate for multiple function calls
1267 */
1268 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
1269
1270 /* get args, detoasting into multi-call memory context */
1273
1276 if (typcache->rngtype == NULL)
1277 elog(ERROR, "type %u is not a multirange type", mltrngtypoid);
1278 rangetyp = typcache->rngtype;
1279
1281 mr = mr1;
1282 else
1283 {
1286
1288 rangetyp,
1290 ranges1,
1292 ranges2);
1293 }
1294
1295 MemoryContextSwitchTo(oldcontext);
1296
1298 if (MultirangeIsEmpty(mr))
1300 else
1302 }
1303}

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

1994{
1996}

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

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

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

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

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

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

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

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

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
351 /* palloc_array will enforce a more-or-less-sane range_count value */
353
355 for (int i = 0; i < range_count; i++)
356 {
358 const char *range_data = pq_getmsgbytes(buf, range_len);
359
362
364 &tmpbuf,
365 cache->typioparam,
366 typmod));
367 }
369
371
373 range_count, ranges);
375}

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

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

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

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

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

1608{
1610 TypeCacheEntry *typcache;
1613
1614 if (MultirangeIsEmpty(mr))
1616
1617 typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
1618
1619 multirange_get_bounds(typcache->rngtype, mr, mr->rangeCount - 1,
1620 &lower, &upper);
1621
1622 if (!upper.infinite)
1624 else
1626}

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

2550{
2552 upper1,
2553 lower2,
2554 upper2;
2555 bool empty;
2557
2559 return false;
2560
2561 range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
2562 Assert(!empty);
2563
2564 range_count = mr->rangeCount;
2566 &lower2, &upper2);
2567
2569 return true;
2570
2571 if (range_count > 1)
2573 &lower2, &upper2);
2574
2576 return true;
2577
2578 return false;
2579}

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

2525{
2527 upper1,
2528 lower2,
2529 upper2;
2530 bool empty;
2532
2534 return false;
2535
2536 range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
2537 Assert(!empty);
2538
2539 range_count = mr->rangeCount;
2541 &lower2, &upper2);
2542
2543 return (range_cmp_bounds(rangetyp, &lower1, &upper2) > 0);
2544}

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

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

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

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

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

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

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

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

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

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

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

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

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

2752{
2755 TypeCacheEntry *typcache;
2757
2758 typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
2759
2760 if (MultirangeIsEmpty(mr))
2761 {
2762 result = make_empty_range(typcache->rngtype);
2763 }
2764 else if (mr->rangeCount == 1)
2765 {
2766 result = multirange_get_range(typcache->rngtype, mr, 0);
2767 }
2768 else
2769 {
2771 firstUpper,
2772 lastLower,
2773 lastUpper;
2774
2775 multirange_get_bounds(typcache->rngtype, mr, 0,
2777 multirange_get_bounds(typcache->rngtype, mr, mr->rangeCount - 1,
2778 &lastLower, &lastUpper);
2779
2781 false, NULL);
2782 }
2783
2785}

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, result, 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 2070 of file multirangetypes.c.

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

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

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

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

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

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

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

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

Referenced by make_multirange().