PostgreSQL Source Code git master
Loading...
Searching...
No Matches
rangetypes_spgist.c File Reference
#include "postgres.h"
#include "access/spgist.h"
#include "access/stratnum.h"
#include "catalog/pg_type.h"
#include "utils/datum.h"
#include "utils/fmgrprotos.h"
#include "utils/rangetypes.h"
Include dependency graph for rangetypes_spgist.c:

Go to the source code of this file.

Functions

static int16 getQuadrant (TypeCacheEntry *typcache, const RangeType *centroid, const RangeType *tst)
 
static int bound_cmp (const void *a, const void *b, void *arg)
 
static int adjacent_inner_consistent (TypeCacheEntry *typcache, const RangeBound *arg, const RangeBound *centroid, const RangeBound *prev)
 
static int adjacent_cmp_bounds (TypeCacheEntry *typcache, const RangeBound *arg, const RangeBound *centroid)
 
Datum spg_range_quad_config (PG_FUNCTION_ARGS)
 
Datum spg_range_quad_choose (PG_FUNCTION_ARGS)
 
Datum spg_range_quad_picksplit (PG_FUNCTION_ARGS)
 
Datum spg_range_quad_inner_consistent (PG_FUNCTION_ARGS)
 
Datum spg_range_quad_leaf_consistent (PG_FUNCTION_ARGS)
 

Function Documentation

◆ adjacent_cmp_bounds()

static int adjacent_cmp_bounds ( TypeCacheEntry typcache,
const RangeBound arg,
const RangeBound centroid 
)
static

Definition at line 787 of file rangetypes_spgist.c.

789{
790 int cmp;
791
792 Assert(arg->lower != centroid->lower);
793
794 cmp = range_cmp_bounds(typcache, arg, centroid);
795
796 if (centroid->lower)
797 {
798 /*------
799 * The argument is an upper bound, we are searching for adjacent lower
800 * bounds. A matching adjacent lower bound must be *larger* than the
801 * argument, but only just.
802 *
803 * The following table illustrates the desired result with a fixed
804 * argument bound, and different centroids. The CMP column shows
805 * the value of 'cmp' variable, and ADJ shows whether the argument
806 * and centroid are adjacent, per bounds_adjacent(). (N) means we
807 * don't need to check for that case, because it's implied by CMP.
808 * With the argument range [..., 500), the adjacent range we're
809 * searching for is [500, ...):
810 *
811 * ARGUMENT CENTROID CMP ADJ
812 * [..., 500) [498, ...) > (N) [500, ...) is to the right
813 * [..., 500) [499, ...) = (N) [500, ...) is to the right
814 * [..., 500) [500, ...) < Y [500, ...) is to the right
815 * [..., 500) [501, ...) < N [500, ...) is to the left
816 *
817 * So, we must search left when the argument is smaller than, and not
818 * adjacent, to the centroid. Otherwise search right.
819 *------
820 */
821 if (cmp < 0 && !bounds_adjacent(typcache, *arg, *centroid))
822 return -1;
823 else
824 return 1;
825 }
826 else
827 {
828 /*------
829 * The argument is a lower bound, we are searching for adjacent upper
830 * bounds. A matching adjacent upper bound must be *smaller* than the
831 * argument, but only just.
832 *
833 * ARGUMENT CENTROID CMP ADJ
834 * [500, ...) [..., 499) > (N) [..., 500) is to the right
835 * [500, ...) [..., 500) > (Y) [..., 500) is to the right
836 * [500, ...) [..., 501) = (N) [..., 500) is to the left
837 * [500, ...) [..., 502) < (N) [..., 500) is to the left
838 *
839 * We must search left when the argument is smaller than or equal to
840 * the centroid. Otherwise search right. We don't need to check
841 * whether the argument is adjacent with the centroid, because it
842 * doesn't matter.
843 *------
844 */
845 if (cmp <= 0)
846 return -1;
847 else
848 return 1;
849 }
850}
#define Assert(condition)
Definition c.h:873
void * arg
static int fb(int x)
int range_cmp_bounds(TypeCacheEntry *typcache, const RangeBound *b1, const RangeBound *b2)
bool bounds_adjacent(TypeCacheEntry *typcache, RangeBound boundA, RangeBound boundB)
Definition rangetypes.c:761
static int cmp(const chr *x, const chr *y, size_t len)

References arg, Assert, bounds_adjacent(), cmp(), fb(), and range_cmp_bounds().

Referenced by adjacent_inner_consistent().

◆ adjacent_inner_consistent()

static int adjacent_inner_consistent ( TypeCacheEntry typcache,
const RangeBound arg,
const RangeBound centroid,
const RangeBound prev 
)
static

Definition at line 889 of file rangetypes_spgist.c.

891{
892 if (prev)
893 {
894 int prevcmp;
895 int cmp;
896
897 /*
898 * Which direction were we supposed to traverse at previous level,
899 * left or right?
900 */
901 prevcmp = adjacent_cmp_bounds(typcache, arg, prev);
902
903 /* and which direction did we actually go? */
904 cmp = range_cmp_bounds(typcache, centroid, prev);
905
906 /* if the two don't agree, there's nothing to see here */
907 if ((prevcmp < 0 && cmp >= 0) || (prevcmp > 0 && cmp < 0))
908 return 0;
909 }
910
911 return adjacent_cmp_bounds(typcache, arg, centroid);
912}
static int adjacent_cmp_bounds(TypeCacheEntry *typcache, const RangeBound *arg, const RangeBound *centroid)

References adjacent_cmp_bounds(), arg, cmp(), fb(), and range_cmp_bounds().

Referenced by spg_range_quad_inner_consistent().

◆ bound_cmp()

static int bound_cmp ( const void a,
const void b,
void arg 
)
static

Definition at line 188 of file rangetypes_spgist.c.

189{
190 const RangeBound *ba = a;
191 const RangeBound *bb = b;
192 TypeCacheEntry *typcache = arg;
193
194 return range_cmp_bounds(typcache, ba, bb);
195}
int b
Definition isn.c:74
int a
Definition isn.c:73

References a, arg, b, fb(), and range_cmp_bounds().

Referenced by spg_range_quad_picksplit().

◆ getQuadrant()

static int16 getQuadrant ( TypeCacheEntry typcache,
const RangeType centroid,
const RangeType tst 
)
static

Definition at line 97 of file rangetypes_spgist.c.

98{
101 bool centroidEmpty;
103 upper;
104 bool empty;
105
108 range_deserialize(typcache, tst, &lower, &upper, &empty);
109
110 if (empty)
111 return 5;
112
113 if (range_cmp_bounds(typcache, &lower, &centroidLower) >= 0)
114 {
115 if (range_cmp_bounds(typcache, &upper, &centroidUpper) >= 0)
116 return 1;
117 else
118 return 2;
119 }
120 else
121 {
122 if (range_cmp_bounds(typcache, &upper, &centroidUpper) >= 0)
123 return 4;
124 else
125 return 3;
126 }
127}
Datum lower(PG_FUNCTION_ARGS)
Datum upper(PG_FUNCTION_ARGS)
void range_deserialize(TypeCacheEntry *typcache, const RangeType *range, RangeBound *lower, RangeBound *upper, bool *empty)

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

Referenced by spg_range_quad_choose(), spg_range_quad_inner_consistent(), and spg_range_quad_picksplit().

◆ spg_range_quad_choose()

Datum spg_range_quad_choose ( PG_FUNCTION_ARGS  )

Definition at line 133 of file rangetypes_spgist.c.

134{
138 *centroid;
140 TypeCacheEntry *typcache;
141
142 if (in->allTheSame)
143 {
145 /* nodeN will be set by core */
146 out->result.matchNode.levelAdd = 0;
149 }
150
151 typcache = range_get_typcache(fcinfo, RangeTypeGetOid(inRange));
152
153 /*
154 * A node with no centroid divides ranges purely on whether they're empty
155 * or not. All empty ranges go to child node 0, all non-empty ranges go to
156 * node 1.
157 */
158 if (!in->hasPrefix)
159 {
162 out->result.matchNode.nodeN = 0;
163 else
164 out->result.matchNode.nodeN = 1;
165 out->result.matchNode.levelAdd = 1;
168 }
169
171 quadrant = getQuadrant(typcache, centroid, inRange);
172
174
175 /* Select node matching to quadrant number */
177 out->result.matchNode.nodeN = quadrant - 1;
178 out->result.matchNode.levelAdd = 1;
180
182}
int16_t int16
Definition c.h:541
#define PG_RETURN_VOID()
Definition fmgr.h:350
#define PG_GETARG_POINTER(n)
Definition fmgr.h:277
TypeCacheEntry * range_get_typcache(FunctionCallInfo fcinfo, Oid rngtypid)
static RangeType * DatumGetRangeTypeP(Datum X)
Definition rangetypes.h:73
#define RangeIsEmpty(r)
Definition rangetypes.h:55
static Datum RangeTypePGetDatum(const RangeType *X)
Definition rangetypes.h:85
#define RangeTypeGetOid(r)
Definition rangetypes.h:35
static int16 getQuadrant(TypeCacheEntry *typcache, const RangeType *centroid, const RangeType *tst)
@ spgMatchNode
Definition spgist.h:69
bool hasPrefix
Definition spgist.h:61
Datum prefixDatum
Definition spgist.h:62
Datum datum
Definition spgist.h:55
bool allTheSame
Definition spgist.h:60
spgChooseResultType resultType
Definition spgist.h:76
int levelAdd
Definition spgist.h:82
Datum restDatum
Definition spgist.h:83
int nodeN
Definition spgist.h:81
union spgChooseOut::@54 result
struct spgChooseOut::@54::@55 matchNode

References spgChooseIn::allTheSame, Assert, spgChooseIn::datum, DatumGetRangeTypeP(), fb(), getQuadrant(), spgChooseIn::hasPrefix, spgChooseOut::levelAdd, spgChooseOut::matchNode, spgChooseOut::nodeN, PG_GETARG_POINTER, PG_RETURN_VOID, spgChooseIn::prefixDatum, range_get_typcache(), RangeIsEmpty, RangeTypeGetOid, RangeTypePGetDatum(), spgChooseOut::restDatum, spgChooseOut::result, spgChooseOut::resultType, and spgMatchNode.

◆ spg_range_quad_config()

Datum spg_range_quad_config ( PG_FUNCTION_ARGS  )

Definition at line 60 of file rangetypes_spgist.c.

61{
62#ifdef NOT_USED
64#endif
66
68 cfg->labelType = VOIDOID; /* we don't need node labels */
69 cfg->canReturnData = true;
70 cfg->longValuesOK = false;
72}
bool longValuesOK
Definition spgist.h:47
bool canReturnData
Definition spgist.h:46
Oid labelType
Definition spgist.h:44
Oid prefixType
Definition spgist.h:43

References spgConfigOut::canReturnData, fb(), spgConfigOut::labelType, spgConfigOut::longValuesOK, PG_GETARG_POINTER, PG_RETURN_VOID, and spgConfigOut::prefixType.

◆ spg_range_quad_inner_consistent()

Datum spg_range_quad_inner_consistent ( PG_FUNCTION_ARGS  )

Definition at line 302 of file rangetypes_spgist.c.

303{
306 int which;
307 int i;
309
310 /*
311 * For adjacent search we need also previous centroid (if any) to improve
312 * the precision of the consistent check. In this case needPrevious flag
313 * is set and centroid is passed into traversalValue.
314 */
315 bool needPrevious = false;
316
317 if (in->allTheSame)
318 {
319 /* Report that all nodes should be visited */
320 out->nNodes = in->nNodes;
321 out->nodeNumbers = palloc_array(int, in->nNodes);
322 for (i = 0; i < in->nNodes; i++)
323 out->nodeNumbers[i] = i;
325 }
326
327 if (!in->hasPrefix)
328 {
329 /*
330 * No centroid on this inner node. Such a node has two child nodes,
331 * the first for empty ranges, and the second for non-empty ones.
332 */
333 Assert(in->nNodes == 2);
334
335 /*
336 * Nth bit of which variable means that (N - 1)th node should be
337 * visited. Initially all bits are set. Bits of nodes which should be
338 * skipped will be unset.
339 */
340 which = (1 << 1) | (1 << 2);
341 for (i = 0; i < in->nkeys; i++)
342 {
343 StrategyNumber strategy = in->scankeys[i].sk_strategy;
344 bool empty;
345
346 /*
347 * The only strategy when second argument of operator is not range
348 * is RANGESTRAT_CONTAINS_ELEM.
349 */
350 if (strategy != RANGESTRAT_CONTAINS_ELEM)
352 else
353 empty = false;
354
355 switch (strategy)
356 {
361 case RANGESTRAT_AFTER:
363 /* These strategies return false if any argument is empty */
364 if (empty)
365 which = 0;
366 else
367 which &= (1 << 2);
368 break;
369
371
372 /*
373 * All ranges contain an empty range. Only non-empty
374 * ranges can contain a non-empty range.
375 */
376 if (!empty)
377 which &= (1 << 2);
378 break;
379
381
382 /*
383 * Only an empty range is contained by an empty range.
384 * Both empty and non-empty ranges can be contained by a
385 * non-empty range.
386 */
387 if (empty)
388 which &= (1 << 1);
389 break;
390
392 which &= (1 << 2);
393 break;
394
395 case RANGESTRAT_EQ:
396 if (empty)
397 which &= (1 << 1);
398 else
399 which &= (1 << 2);
400 break;
401
402 default:
403 elog(ERROR, "unrecognized range strategy: %d", strategy);
404 break;
405 }
406 if (which == 0)
407 break; /* no need to consider remaining conditions */
408 }
409 }
410 else
411 {
414 bool centroidEmpty;
415 TypeCacheEntry *typcache;
417
418 /* This node has a centroid. Fetch it. */
420 typcache = range_get_typcache(fcinfo,
424
425 Assert(in->nNodes == 4 || in->nNodes == 5);
426
427 /*
428 * Nth bit of which variable means that (N - 1)th node (Nth quadrant)
429 * should be visited. Initially all bits are set. Bits of nodes which
430 * can be skipped will be unset.
431 */
432 which = (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5);
433
434 for (i = 0; i < in->nkeys; i++)
435 {
436 StrategyNumber strategy;
438 upper;
439 bool empty;
441
444 prevUpper;
445 bool prevEmpty;
446
447 /* Restrictions on range bounds according to scan strategy */
449 *maxLower = NULL,
450 *minUpper = NULL,
451 *maxUpper = NULL;
452
453 /* Are the restrictions on range bounds inclusive? */
454 bool inclusive = true;
455 bool strictEmpty = true;
456 int cmp,
457 which1,
458 which2;
459
460 strategy = in->scankeys[i].sk_strategy;
461
462 /*
463 * RANGESTRAT_CONTAINS_ELEM is just like RANGESTRAT_CONTAINS, but
464 * the argument is a single element. Expand the single element to
465 * a range containing only the element, and treat it like
466 * RANGESTRAT_CONTAINS.
467 */
468 if (strategy == RANGESTRAT_CONTAINS_ELEM)
469 {
470 lower.inclusive = true;
471 lower.infinite = false;
472 lower.lower = true;
473 lower.val = in->scankeys[i].sk_argument;
474
475 upper.inclusive = true;
476 upper.infinite = false;
477 upper.lower = false;
478 upper.val = in->scankeys[i].sk_argument;
479
480 empty = false;
481
482 strategy = RANGESTRAT_CONTAINS;
483 }
484 else
485 {
487 range_deserialize(typcache, range, &lower, &upper, &empty);
488 }
489
490 /*
491 * Most strategies are handled by forming a bounding box from the
492 * search key, defined by a minLower, maxLower, minUpper,
493 * maxUpper. Some modify 'which' directly, to specify exactly
494 * which quadrants need to be visited.
495 *
496 * For most strategies, nothing matches an empty search key, and
497 * an empty range never matches a non-empty key. If a strategy
498 * does not behave like that wrt. empty ranges, set strictEmpty to
499 * false.
500 */
501 switch (strategy)
502 {
504
505 /*
506 * Range A is before range B if upper bound of A is lower
507 * than lower bound of B.
508 */
509 maxUpper = &lower;
510 inclusive = false;
511 break;
512
514
515 /*
516 * Range A is overleft to range B if upper bound of A is
517 * less than or equal to upper bound of B.
518 */
519 maxUpper = &upper;
520 break;
521
523
524 /*
525 * Non-empty ranges overlap, if lower bound of each range
526 * is lower or equal to upper bound of the other range.
527 */
528 maxLower = &upper;
529 minUpper = &lower;
530 break;
531
533
534 /*
535 * Range A is overright to range B if lower bound of A is
536 * greater than or equal to lower bound of B.
537 */
538 minLower = &lower;
539 break;
540
541 case RANGESTRAT_AFTER:
542
543 /*
544 * Range A is after range B if lower bound of A is greater
545 * than upper bound of B.
546 */
547 minLower = &upper;
548 inclusive = false;
549 break;
550
552 if (empty)
553 break; /* Skip to strictEmpty check. */
554
555 /*
556 * Previously selected quadrant could exclude possibility
557 * for lower or upper bounds to be adjacent. Deserialize
558 * previous centroid range if present for checking this.
559 */
560 if (in->traversalValue)
561 {
565 }
566
567 /*
568 * For a range's upper bound to be adjacent to the
569 * argument's lower bound, it will be found along the line
570 * adjacent to (and just below) Y=lower. Therefore, if the
571 * argument's lower bound is less than the centroid's
572 * upper bound, the line falls in quadrants 2 and 3; if
573 * greater, the line falls in quadrants 1 and 4. (see
574 * adjacent_cmp_bounds for description of edge cases).
575 */
579 if (cmp > 0)
580 which1 = (1 << 1) | (1 << 4);
581 else if (cmp < 0)
582 which1 = (1 << 2) | (1 << 3);
583 else
584 which1 = 0;
585
586 /*
587 * Also search for ranges's adjacent to argument's upper
588 * bound. They will be found along the line adjacent to
589 * (and just right of) X=upper, which falls in quadrants 3
590 * and 4, or 1 and 2.
591 */
595 if (cmp > 0)
596 which2 = (1 << 1) | (1 << 2);
597 else if (cmp < 0)
598 which2 = (1 << 3) | (1 << 4);
599 else
600 which2 = 0;
601
602 /* We must chase down ranges adjacent to either bound. */
603 which &= which1 | which2;
604
605 needPrevious = true;
606 break;
607
609
610 /*
611 * Non-empty range A contains non-empty range B if lower
612 * bound of A is lower or equal to lower bound of range B
613 * and upper bound of range A is greater than or equal to
614 * upper bound of range A.
615 *
616 * All non-empty ranges contain an empty range.
617 */
618 strictEmpty = false;
619 if (!empty)
620 {
621 which &= (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4);
622 maxLower = &lower;
623 minUpper = &upper;
624 }
625 break;
626
628 /* The opposite of contains. */
629 strictEmpty = false;
630 if (empty)
631 {
632 /* An empty range is only contained by an empty range */
633 which &= (1 << 5);
634 }
635 else
636 {
637 minLower = &lower;
638 maxUpper = &upper;
639 }
640 break;
641
642 case RANGESTRAT_EQ:
643
644 /*
645 * Equal range can be only in the same quadrant where
646 * argument would be placed to.
647 */
648 strictEmpty = false;
649 which &= (1 << getQuadrant(typcache, centroid, range));
650 break;
651
652 default:
653 elog(ERROR, "unrecognized range strategy: %d", strategy);
654 break;
655 }
656
657 if (strictEmpty)
658 {
659 if (empty)
660 {
661 /* Scan key is empty, no branches are satisfying */
662 which = 0;
663 break;
664 }
665 else
666 {
667 /* Shouldn't visit tree branch with empty ranges */
668 which &= (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4);
669 }
670 }
671
672 /*
673 * Using the bounding box, see which quadrants we have to descend
674 * into.
675 */
676 if (minLower)
677 {
678 /*
679 * If the centroid's lower bound is less than or equal to the
680 * minimum lower bound, anything in the 3rd and 4th quadrants
681 * will have an even smaller lower bound, and thus can't
682 * match.
683 */
684 if (range_cmp_bounds(typcache, &centroidLower, minLower) <= 0)
685 which &= (1 << 1) | (1 << 2) | (1 << 5);
686 }
687 if (maxLower)
688 {
689 /*
690 * If the centroid's lower bound is greater than the maximum
691 * lower bound, anything in the 1st and 2nd quadrants will
692 * also have a greater than or equal lower bound, and thus
693 * can't match. If the centroid's lower bound is equal to the
694 * maximum lower bound, we can still exclude the 1st and 2nd
695 * quadrants if we're looking for a value strictly greater
696 * than the maximum.
697 */
698
700 if (cmp > 0 || (!inclusive && cmp == 0))
701 which &= (1 << 3) | (1 << 4) | (1 << 5);
702 }
703 if (minUpper)
704 {
705 /*
706 * If the centroid's upper bound is less than or equal to the
707 * minimum upper bound, anything in the 2nd and 3rd quadrants
708 * will have an even smaller upper bound, and thus can't
709 * match.
710 */
711 if (range_cmp_bounds(typcache, &centroidUpper, minUpper) <= 0)
712 which &= (1 << 1) | (1 << 4) | (1 << 5);
713 }
714 if (maxUpper)
715 {
716 /*
717 * If the centroid's upper bound is greater than the maximum
718 * upper bound, anything in the 1st and 4th quadrants will
719 * also have a greater than or equal upper bound, and thus
720 * can't match. If the centroid's upper bound is equal to the
721 * maximum upper bound, we can still exclude the 1st and 4th
722 * quadrants if we're looking for a value strictly greater
723 * than the maximum.
724 */
725
727 if (cmp > 0 || (!inclusive && cmp == 0))
728 which &= (1 << 2) | (1 << 3) | (1 << 5);
729 }
730
731 if (which == 0)
732 break; /* no need to consider remaining conditions */
733 }
734 }
735
736 /* We must descend into the quadrant(s) identified by 'which' */
737 out->nodeNumbers = palloc_array(int, in->nNodes);
738 if (needPrevious)
739 out->traversalValues = palloc_array(void *, in->nNodes);
740 out->nNodes = 0;
741
742 /*
743 * Elements of traversalValues should be allocated in
744 * traversalMemoryContext
745 */
747
748 for (i = 1; i <= in->nNodes; i++)
749 {
750 if (which & (1 << i))
751 {
752 /* Save previous prefix if needed */
753 if (needPrevious)
754 {
756
757 /*
758 * We know, that in->prefixDatum in this place is varlena,
759 * because it's range
760 */
761 previousCentroid = datumCopy(in->prefixDatum, false, -1);
763 }
764 out->nodeNumbers[out->nNodes] = i - 1;
765 out->nNodes++;
766 }
767 }
768
770
772}
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition datum.c:132
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
#define palloc_array(type, count)
Definition fe_memutils.h:76
int i
Definition isn.c:77
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
uint64_t Datum
Definition postgres.h:70
static Pointer DatumGetPointer(Datum X)
Definition postgres.h:342
#define RANGESTRAT_OVERLAPS
Definition rangetypes.h:98
#define RANGESTRAT_AFTER
Definition rangetypes.h:100
#define RANGESTRAT_BEFORE
Definition rangetypes.h:96
#define RANGESTRAT_OVERRIGHT
Definition rangetypes.h:99
#define RANGESTRAT_OVERLEFT
Definition rangetypes.h:97
#define RANGESTRAT_CONTAINED_BY
Definition rangetypes.h:103
#define RANGESTRAT_EQ
Definition rangetypes.h:105
#define RANGESTRAT_ADJACENT
Definition rangetypes.h:101
#define RANGESTRAT_CONTAINS_ELEM
Definition rangetypes.h:104
#define RANGESTRAT_CONTAINS
Definition rangetypes.h:102
static int adjacent_inner_consistent(TypeCacheEntry *typcache, const RangeBound *arg, const RangeBound *centroid, const RangeBound *prev)
static struct cvec * range(struct vars *v, chr a, chr b, int cases)
uint16 StrategyNumber
Definition stratnum.h:22
Datum sk_argument
Definition skey.h:72
StrategyNumber sk_strategy
Definition skey.h:68
void * traversalValue
Definition spgist.h:141
MemoryContext traversalMemoryContext
Definition spgist.h:142
void ** traversalValues
Definition spgist.h:160

References adjacent_inner_consistent(), spgInnerConsistentIn::allTheSame, Assert, cmp(), datumCopy(), DatumGetPointer(), DatumGetRangeTypeP(), elog, ERROR, fb(), getQuadrant(), spgInnerConsistentIn::hasPrefix, i, lower(), MemoryContextSwitchTo(), spgInnerConsistentIn::nkeys, spgInnerConsistentIn::nNodes, spgInnerConsistentOut::nNodes, spgInnerConsistentOut::nodeNumbers, palloc_array, PG_GETARG_POINTER, PG_RETURN_VOID, spgInnerConsistentIn::prefixDatum, range(), range_cmp_bounds(), range_deserialize(), range_get_typcache(), RangeIsEmpty, RANGESTRAT_ADJACENT, RANGESTRAT_AFTER, RANGESTRAT_BEFORE, RANGESTRAT_CONTAINED_BY, RANGESTRAT_CONTAINS, RANGESTRAT_CONTAINS_ELEM, RANGESTRAT_EQ, RANGESTRAT_OVERLAPS, RANGESTRAT_OVERLEFT, RANGESTRAT_OVERRIGHT, RangeTypeGetOid, spgInnerConsistentIn::scankeys, ScanKeyData::sk_argument, ScanKeyData::sk_strategy, spgInnerConsistentIn::traversalMemoryContext, spgInnerConsistentIn::traversalValue, spgInnerConsistentOut::traversalValues, and upper().

◆ spg_range_quad_leaf_consistent()

Datum spg_range_quad_leaf_consistent ( PG_FUNCTION_ARGS  )

Definition at line 919 of file rangetypes_spgist.c.

920{
924 TypeCacheEntry *typcache;
925 bool res;
926 int i;
927
928 /* all tests are exact */
929 out->recheck = false;
930
931 /* leafDatum is what it is... */
932 out->leafValue = in->leafDatum;
933
934 typcache = range_get_typcache(fcinfo, RangeTypeGetOid(leafRange));
935
936 /* Perform the required comparison(s) */
937 res = true;
938 for (i = 0; i < in->nkeys; i++)
939 {
941
942 /* Call the function corresponding to the scan strategy */
943 switch (in->scankeys[i].sk_strategy)
944 {
946 res = range_before_internal(typcache, leafRange,
948 break;
950 res = range_overleft_internal(typcache, leafRange,
952 break;
954 res = range_overlaps_internal(typcache, leafRange,
956 break;
958 res = range_overright_internal(typcache, leafRange,
960 break;
961 case RANGESTRAT_AFTER:
962 res = range_after_internal(typcache, leafRange,
964 break;
966 res = range_adjacent_internal(typcache, leafRange,
968 break;
970 res = range_contains_internal(typcache, leafRange,
972 break;
976 break;
979 keyDatum);
980 break;
981 case RANGESTRAT_EQ:
982 res = range_eq_internal(typcache, leafRange,
984 break;
985 default:
986 elog(ERROR, "unrecognized range strategy: %d",
987 in->scankeys[i].sk_strategy);
988 break;
989 }
990
991 /*
992 * If leaf datum doesn't match to a query key, no need to check
993 * subsequent keys.
994 */
995 if (!res)
996 break;
997 }
998
999 PG_RETURN_BOOL(res);
1000}
#define PG_RETURN_BOOL(x)
Definition fmgr.h:360
bool range_contained_by_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
bool range_contains_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
bool range_after_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
Definition rangetypes.c:706
bool range_overlaps_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
Definition rangetypes.c:845
bool range_before_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
Definition rangetypes.c:668
bool range_overright_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
Definition rangetypes.c:932
bool range_contains_elem_internal(TypeCacheEntry *typcache, const RangeType *r, Datum val)
bool range_eq_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
Definition rangetypes.c:577
bool range_adjacent_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
Definition rangetypes.c:802
bool range_overleft_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
Definition rangetypes.c:891

References DatumGetRangeTypeP(), elog, ERROR, fb(), i, spgLeafConsistentIn::leafDatum, spgLeafConsistentOut::leafValue, spgLeafConsistentIn::nkeys, PG_GETARG_POINTER, PG_RETURN_BOOL, range_adjacent_internal(), range_after_internal(), range_before_internal(), range_contained_by_internal(), range_contains_elem_internal(), range_contains_internal(), range_eq_internal(), range_get_typcache(), range_overlaps_internal(), range_overleft_internal(), range_overright_internal(), RANGESTRAT_ADJACENT, RANGESTRAT_AFTER, RANGESTRAT_BEFORE, RANGESTRAT_CONTAINED_BY, RANGESTRAT_CONTAINS, RANGESTRAT_CONTAINS_ELEM, RANGESTRAT_EQ, RANGESTRAT_OVERLAPS, RANGESTRAT_OVERLEFT, RANGESTRAT_OVERRIGHT, RangeTypeGetOid, spgLeafConsistentOut::recheck, spgLeafConsistentIn::scankeys, ScanKeyData::sk_argument, and ScanKeyData::sk_strategy.

◆ spg_range_quad_picksplit()

Datum spg_range_quad_picksplit ( PG_FUNCTION_ARGS  )

Definition at line 202 of file rangetypes_spgist.c.

203{
206 int i;
207 int j;
208 int nonEmptyCount;
210 bool empty;
211 TypeCacheEntry *typcache;
212
213 /* Use the median values of lower and upper bounds as the centroid range */
216
217 typcache = range_get_typcache(fcinfo,
219
220 /* Allocate memory for bounds */
223 j = 0;
224
225 /* Deserialize bounds of ranges, count non-empty ranges */
226 for (i = 0; i < in->nTuples; i++)
227 {
229 &lowerBounds[j], &upperBounds[j], &empty);
230 if (!empty)
231 j++;
232 }
234
235 /*
236 * All the ranges are empty. The best we can do is to construct an inner
237 * node with no centroid, and put all ranges into node 0. If non-empty
238 * ranges are added later, they will be routed to node 1.
239 */
240 if (nonEmptyCount == 0)
241 {
242 out->nNodes = 2;
243 out->hasPrefix = false;
244 /* Prefix is empty */
246 out->nodeLabels = NULL;
247
248 out->mapTuplesToNodes = palloc_array(int, in->nTuples);
250
251 /* Place all ranges into node 0 */
252 for (i = 0; i < in->nTuples; i++)
253 {
255
257 out->mapTuplesToNodes[i] = 0;
258 }
260 }
261
262 /* Sort range bounds in order to find medians */
264 bound_cmp, typcache);
266 bound_cmp, typcache);
267
268 /* Construct "centroid" range from medians of lower and upper bounds */
270 &upperBounds[nonEmptyCount / 2], false, NULL);
271 out->hasPrefix = true;
273
274 /* Create node for empty ranges only if it is a root node */
275 out->nNodes = (in->level == 0) ? 5 : 4;
276 out->nodeLabels = NULL; /* we don't need node labels */
277
278 out->mapTuplesToNodes = palloc_array(int, in->nTuples);
280
281 /*
282 * Assign ranges to corresponding nodes according to quadrants relative to
283 * "centroid" range.
284 */
285 for (i = 0; i < in->nTuples; i++)
286 {
289
291 out->mapTuplesToNodes[i] = quadrant - 1;
292 }
293
295}
int j
Definition isn.c:78
void qsort_arg(void *base, size_t nel, size_t elsize, qsort_arg_comparator cmp, void *arg)
static Datum PointerGetDatum(const void *X)
Definition postgres.h:352
RangeType * range_serialize(TypeCacheEntry *typcache, RangeBound *lower, RangeBound *upper, bool empty, struct Node *escontext)
static int bound_cmp(const void *a, const void *b, void *arg)
Datum * datums
Definition spgist.h:113
int * mapTuplesToNodes
Definition spgist.h:125
Datum * nodeLabels
Definition spgist.h:123
Datum * leafTupleDatums
Definition spgist.h:126
Datum prefixDatum
Definition spgist.h:120

References bound_cmp(), DatumGetRangeTypeP(), spgPickSplitIn::datums, fb(), getQuadrant(), spgPickSplitOut::hasPrefix, i, j, spgPickSplitOut::leafTupleDatums, spgPickSplitIn::level, spgPickSplitOut::mapTuplesToNodes, spgPickSplitOut::nNodes, spgPickSplitOut::nodeLabels, spgPickSplitIn::nTuples, palloc_array, PG_GETARG_POINTER, PG_RETURN_VOID, PointerGetDatum(), spgPickSplitOut::prefixDatum, qsort_arg(), range(), range_deserialize(), range_get_typcache(), range_serialize(), RangeTypeGetOid, and RangeTypePGetDatum().