@@ -54,6 +54,12 @@ static int16 getQuadrant(TypeCacheEntry *typcache, RangeType *centroid,
5454 RangeType * tst );
5555static int bound_cmp (const void * a , const void * b , void * arg );
5656
57+ static int adjacent_inner_consistent (TypeCacheEntry * typcache ,
58+ RangeBound * arg , RangeBound * centroid ,
59+ RangeBound * prev );
60+ static int adjacent_cmp_bounds (TypeCacheEntry * typcache , RangeBound * arg ,
61+ RangeBound * centroid );
62+
5763/*
5864 * SP-GiST 'config' interface function.
5965 */
@@ -441,6 +447,11 @@ spg_range_quad_inner_consistent(PG_FUNCTION_ARGS)
441447 bool empty ;
442448 RangeType * range = NULL ;
443449
450+ RangeType * prevCentroid = NULL ;
451+ RangeBound prevLower ,
452+ prevUpper ;
453+ bool prevEmpty ;
454+
444455 /* Restrictions on range bounds according to scan strategy */
445456 RangeBound * minLower = NULL ,
446457 * maxLower = NULL ,
@@ -549,110 +560,54 @@ spg_range_quad_inner_consistent(PG_FUNCTION_ARGS)
549560 if (empty )
550561 break ; /* Skip to strictEmpty check. */
551562
552- /*
553- * which1 is bitmask for possibility to be adjacent with
554- * lower bound of argument. which2 is bitmask for
555- * possibility to be adjacent with upper bound of
556- * argument.
557- */
558- which1 = which2 = (1 << 1 ) | (1 << 2 ) | (1 << 3 ) | (1 << 4 );
559-
560563 /*
561564 * Previously selected quadrant could exclude possibility
562565 * for lower or upper bounds to be adjacent. Deserialize
563566 * previous centroid range if present for checking this.
564567 */
565568 if (in -> reconstructedValue != (Datum ) 0 )
566569 {
567- RangeType * prevCentroid ;
568- RangeBound prevLower ,
569- prevUpper ;
570- bool prevEmpty ;
571- int cmp1 ,
572- cmp2 ;
573-
574570 prevCentroid = DatumGetRangeType (in -> reconstructedValue );
575571 range_deserialize (typcache , prevCentroid ,
576572 & prevLower , & prevUpper , & prevEmpty );
577-
578- /*
579- * Check if lower bound of argument is not in a
580- * quadrant we visited in the previous step.
581- */
582- cmp1 = range_cmp_bounds (typcache , & lower , & prevUpper );
583- cmp2 = range_cmp_bounds (typcache , & centroidUpper ,
584- & prevUpper );
585- if ((cmp2 < 0 && cmp1 > 0 ) || (cmp2 > 0 && cmp1 < 0 ))
586- which1 = 0 ;
587-
588- /*
589- * Check if upper bound of argument is not in a
590- * quadrant we visited in the previous step.
591- */
592- cmp1 = range_cmp_bounds (typcache , & upper , & prevLower );
593- cmp2 = range_cmp_bounds (typcache , & centroidLower ,
594- & prevLower );
595- if ((cmp2 < 0 && cmp1 > 0 ) || (cmp2 > 0 && cmp1 < 0 ))
596- which2 = 0 ;
597573 }
598574
599- if (which1 )
600- {
601- /*
602- * For a range's upper bound to be adjacent to the
603- * argument's lower bound, it will be found along the
604- * line adjacent to (and just below) Y=lower.
605- * Therefore, if the argument's lower bound is less
606- * than the centroid's upper bound, the line falls in
607- * quadrants 2 and 3; if greater, the line falls in
608- * quadrants 1 and 4.
609- *
610- * The above is true even when the argument's lower
611- * bound is greater and adjacent to the centroid's
612- * upper bound. If the argument's lower bound is
613- * greater than the centroid's upper bound, then the
614- * lowest value that an adjacent range could have is
615- * that of the centroid's upper bound, which still
616- * falls in quadrants 1 and 4.
617- *
618- * In the edge case, where the argument's lower bound
619- * is equal to the cetroid's upper bound, there may be
620- * adjacent ranges in any quadrant.
621- */
622- cmp = range_cmp_bounds (typcache , & lower ,
623- & centroidUpper );
624- if (cmp < 0 )
625- which1 &= (1 << 2 ) | (1 << 3 );
626- else if (cmp > 0 )
627- which1 &= (1 << 1 ) | (1 << 4 );
628- }
575+ /*
576+ * For a range's upper bound to be adjacent to the
577+ * argument's lower bound, it will be found along the line
578+ * adjacent to (and just below) Y=lower. Therefore, if the
579+ * argument's lower bound is less than the centroid's
580+ * upper bound, the line falls in quadrants 2 and 3; if
581+ * greater, the line falls in quadrants 1 and 4. (see
582+ * adjacent_cmp_bounds for description of edge cases).
583+ */
584+ cmp = adjacent_inner_consistent (typcache , & lower ,
585+ & centroidUpper ,
586+ prevCentroid ? & prevUpper : NULL );
587+ if (cmp > 0 )
588+ which1 = (1 << 1 ) | (1 << 4 );
589+ else if (cmp < 0 )
590+ which1 = (1 << 2 ) | (1 << 3 );
591+ else
592+ which1 = 0 ;
629593
630- if (which2 )
631- {
632- /*
633- * For a range's lower bound to be adjacent to the
634- * argument's upper bound, it will be found along the
635- * line adjacent to (and just right of) X=upper.
636- * Therefore, if the argument's upper bound is less
637- * than (and not adjacent to) the centroid's upper
638- * bound, the line falls in quadrants 3 and 4; if
639- * greater or equal to, the line falls in quadrants 1
640- * and 2.
641- *
642- * The edge case is when the argument's upper bound is
643- * less than and adjacent to the centroid's lower
644- * bound. In that case, adjacent ranges may be in any
645- * quadrant.
646- */
647- cmp = range_cmp_bounds (typcache , & lower ,
648- & centroidUpper );
649- if (cmp < 0 &&
650- !bounds_adjacent (typcache , upper , centroidLower ))
651- which1 &= (1 << 3 ) | (1 << 4 );
652- else if (cmp > 0 )
653- which1 &= (1 << 1 ) | (1 << 2 );
654- }
594+ /*
595+ * Also search for ranges's adjacent to argument's upper
596+ * bound. They will be found along the line adjacent to
597+ * (and just right of) X=upper, which falls in quadrants
598+ * 3 and 4, or 1 and 2.
599+ */
600+ cmp = adjacent_inner_consistent (typcache , & upper ,
601+ & centroidLower ,
602+ prevCentroid ? & prevLower : NULL );
603+ if (cmp > 0 )
604+ which2 = (1 << 1 ) | (1 << 2 );
605+ else if (cmp < 0 )
606+ which2 = (1 << 3 ) | (1 << 4 );
607+ else
608+ which2 = 0 ;
655609
610+ /* We must chase down ranges adjacent to either bound. */
656611 which &= which1 | which2 ;
657612
658613 needPrevious = true;
@@ -807,6 +762,146 @@ spg_range_quad_inner_consistent(PG_FUNCTION_ARGS)
807762 PG_RETURN_VOID ();
808763}
809764
765+ /*
766+ * adjacent_cmp_bounds
767+ *
768+ * Given an argument and centroid bound, this function determines if any
769+ * bounds that are adjacent to the argument are smaller than, or greater than
770+ * or equal to centroid. For brevity, we call the arg < centroid "left", and
771+ * arg >= centroid case "right". This corresponds to how the quadrants are
772+ * arranged, if you imagine that "left" is equivalent to "down" and "right"
773+ * is equivalent to "up".
774+ *
775+ * For the "left" case, returns -1, and for the "right" case, returns 1.
776+ */
777+ static int
778+ adjacent_cmp_bounds (TypeCacheEntry * typcache , RangeBound * arg ,
779+ RangeBound * centroid )
780+ {
781+ int cmp ;
782+
783+ Assert (arg -> lower != centroid -> lower );
784+
785+ cmp = range_cmp_bounds (typcache , arg , centroid );
786+
787+ if (centroid -> lower )
788+ {
789+ /*------
790+ * The argument is an upper bound, we are searching for adjacent lower
791+ * bounds. A matching adjacent lower bound must be *larger* than the
792+ * argument, but only just.
793+ *
794+ * The following table illustrates the desired result with a fixed
795+ * argument bound, and different centroids. The CMP column shows
796+ * the value of 'cmp' variable, and ADJ shows whether the argument
797+ * and centroid are adjacent, per bounds_adjacent(). (N) means we
798+ * don't need to check for that case, because it's implied by CMP.
799+ * With the argument range [..., 500), the adjacent range we're
800+ * searching for is [500, ...):
801+ *
802+ * ARGUMENT CENTROID CMP ADJ
803+ * [..., 500) [498, ...) > (N) [500, ...) is to the right
804+ * [..., 500) [499, ...) = (N) [500, ...) is to the right
805+ * [..., 500) [500, ...) < Y [500, ...) is to the right
806+ * [..., 500) [501, ...) < N [500, ...) is to the left
807+ *
808+ * So, we must search left when the argument is smaller than, and not
809+ * adjacent, to the centroid. Otherwise search right.
810+ *------
811+ */
812+ if (cmp < 0 && !bounds_adjacent (typcache , * arg , * centroid ))
813+ return -1 ;
814+ else
815+ return 1 ;
816+ }
817+ else
818+ {
819+ /*------
820+ * The argument is a lower bound, we are searching for adjacent upper
821+ * bounds. A matching adjacent upper bound must be *smaller* than the
822+ * argument, but only just.
823+ *
824+ * ARGUMENT CENTROID CMP ADJ
825+ * [500, ...) [..., 499) > (N) [..., 500) is to the right
826+ * [500, ...) [..., 500) > (Y) [..., 500) is to the right
827+ * [500, ...) [..., 501) = (N) [..., 500) is to the left
828+ * [500, ...) [..., 502) < (N) [..., 500) is to the left
829+ *
830+ * We must search left when the argument is smaller than or equal to
831+ * the centroid. Otherwise search right. We don't need to check
832+ * whether the argument is adjacent with the centroid, because it
833+ * doesn't matter.
834+ *------
835+ */
836+ if (cmp <= 0 )
837+ return -1 ;
838+ else
839+ return 1 ;
840+ }
841+ }
842+
843+ /*----------
844+ * adjacent_inner_consistent
845+ *
846+ * Like adjacent_cmp_bounds, but also takes into account the previous
847+ * level's centroid. We might've traversed left (or right) at the previous
848+ * node, in search for ranges adjacent to the other bound, even though we
849+ * already ruled out the possibility for any matches in that direction for
850+ * this bound. By comparing the argument with the previous centroid, and
851+ * the previous centroid with the current centroid, we can determine which
852+ * direction we should've moved in at previous level, and which direction we
853+ * actually moved.
854+ *
855+ * If there can be any matches to the left, returns -1. If to the right,
856+ * returns 1. If there can be no matches below this centroid, because we
857+ * already ruled them out at the previous level, returns 0.
858+ *
859+ * XXX: Comparing just the previous and current level isn't foolproof; we
860+ * might still search some branches unnecessarily. For example, imagine that
861+ * we are searching for value 15, and we traverse the following centroids
862+ * (only considering one bound for the moment):
863+ *
864+ * Level 1: 20
865+ * Level 2: 50
866+ * Level 3: 25
867+ *
868+ * At this point, previous centroid is 50, current centroid is 25, and the
869+ * target value is to the left. But because we already moved right from
870+ * centroid 20 to 50 in the first level, there cannot be any values < 20 in
871+ * the current branch. But we don't know that just by looking at the previous
872+ * and current centroid, so we traverse left, unnecessarily. The reason we are
873+ * down this branch is that we're searching for matches with the *other*
874+ * bound. If we kept track of which bound we are searching for explicitly,
875+ * instead of deducing that from the previous and current centroid, we could
876+ * avoid some unnecessary work.
877+ *----------
878+ */
879+ static int
880+ adjacent_inner_consistent (TypeCacheEntry * typcache , RangeBound * arg ,
881+ RangeBound * centroid , RangeBound * prev )
882+ {
883+ if (prev )
884+ {
885+ int prevcmp ;
886+ int cmp ;
887+
888+ /*
889+ * Which direction were we supposed to traverse at previous level,
890+ * left or right?
891+ */
892+ prevcmp = adjacent_cmp_bounds (typcache , arg , prev );
893+
894+ /* and which direction did we actually go? */
895+ cmp = range_cmp_bounds (typcache , centroid , prev );
896+
897+ /* if the two don't agree, there's nothing to see here */
898+ if ((prevcmp < 0 && cmp >= 0 ) || (prevcmp > 0 && cmp < 0 ))
899+ return 0 ;
900+ }
901+
902+ return adjacent_cmp_bounds (typcache , arg , centroid );
903+ }
904+
810905/*
811906 * SP-GiST consistent function for leaf nodes: check leaf value against query
812907 * using corresponding function.
0 commit comments