@@ -305,6 +305,16 @@ spg_range_quad_inner_consistent(PG_FUNCTION_ARGS)
305305int which ;
306306int i ;
307307
308+ /*
309+ * For adjacent search we need also previous centroid (if any) to improve
310+ * the precision of the consistent check. In this case needPrevious flag is
311+ * set and centroid is passed into reconstructedValues. This is not the
312+ * intended purpose of reconstructedValues (because we already have the
313+ * full value available at the leaf), but it's a convenient place to store
314+ * state while traversing the tree.
315+ */
316+ bool needPrevious = false;
317+
308318if (in -> allTheSame )
309319{
310320/* Report that all nodes should be visited */
@@ -351,6 +361,7 @@ spg_range_quad_inner_consistent(PG_FUNCTION_ARGS)
351361case RANGESTRAT_OVERLAPS :
352362case RANGESTRAT_OVERRIGHT :
353363case RANGESTRAT_AFTER :
364+ case RANGESTRAT_ADJACENT :
354365/* These strategies return false if any argument is empty */
355366if (empty )
356367which = 0 ;
@@ -435,6 +446,9 @@ spg_range_quad_inner_consistent(PG_FUNCTION_ARGS)
435446/* Are the restrictions on range bounds inclusive? */
436447bool inclusive = true;
437448bool strictEmpty = true;
449+ int cmp ,
450+ which1 ,
451+ which2 ;
438452
439453strategy = in -> scankeys [i ].sk_strategy ;
440454
@@ -522,6 +536,118 @@ spg_range_quad_inner_consistent(PG_FUNCTION_ARGS)
522536inclusive = false;
523537break ;
524538
539+ case RANGESTRAT_ADJACENT :
540+ if (empty )
541+ break ;/* Skip to strictEmpty check. */
542+
543+ /*
544+ * which1 is bitmask for possibility to be adjacent with
545+ * lower bound of argument. which2 is bitmask for
546+ * possibility to be adjacent with upper bound of argument.
547+ */
548+ which1 = which2 = (1 <<1 ) | (1 <<2 ) | (1 <<3 ) | (1 <<4 );
549+
550+ /*
551+ * Previously selected quadrant could exclude possibility
552+ * for lower or upper bounds to be adjacent. Deserialize
553+ * previous centroid range if present for checking this.
554+ */
555+ if (in -> reconstructedValue != (Datum )0 )
556+ {
557+ RangeType * prevCentroid ;
558+ RangeBound prevLower ,
559+ prevUpper ;
560+ bool prevEmpty ;
561+ int cmp1 ,
562+ cmp2 ;
563+
564+ prevCentroid = DatumGetRangeType (in -> reconstructedValue );
565+ range_deserialize (typcache ,prevCentroid ,
566+ & prevLower ,& prevUpper ,& prevEmpty );
567+
568+ /*
569+ * Check if lower bound of argument is not in a
570+ * quadrant we visited in the previous step.
571+ */
572+ cmp1 = range_cmp_bounds (typcache ,& lower ,& prevUpper );
573+ cmp2 = range_cmp_bounds (typcache ,& centroidUpper ,
574+ & prevUpper );
575+ if ((cmp2 < 0 && cmp1 > 0 )|| (cmp2 > 0 && cmp1 < 0 ))
576+ which1 = 0 ;
577+
578+ /*
579+ * Check if upper bound of argument is not in a
580+ * quadrant we visited in the previous step.
581+ */
582+ cmp1 = range_cmp_bounds (typcache ,& upper ,& prevLower );
583+ cmp2 = range_cmp_bounds (typcache ,& centroidLower ,
584+ & prevLower );
585+ if ((cmp2 < 0 && cmp1 > 0 )|| (cmp2 > 0 && cmp1 < 0 ))
586+ which2 = 0 ;
587+ }
588+
589+ if (which1 )
590+ {
591+ /*
592+ * For a range's upper bound to be adjacent to the
593+ * argument's lower bound, it will be found along the
594+ * line adjacent to (and just below) Y=lower.
595+ * Therefore, if the argument's lower bound is less
596+ * than the centroid's upper bound, the line falls in
597+ * quadrants 2 and 3; if greater, the line falls in
598+ * quadrants 1 and 4.
599+ *
600+ * The above is true even when the argument's lower
601+ * bound is greater and adjacent to the centroid's
602+ * upper bound. If the argument's lower bound is
603+ * greater than the centroid's upper bound, then the
604+ * lowest value that an adjacent range could have is
605+ * that of the centroid's upper bound, which still
606+ * falls in quadrants 1 and 4.
607+ *
608+ * In the edge case, where the argument's lower bound
609+ * is equal to the cetroid's upper bound, there may be
610+ * adjacent ranges in any quadrant.
611+ */
612+ cmp = range_cmp_bounds (typcache ,& lower ,
613+ & centroidUpper );
614+ if (cmp < 0 )
615+ which1 &= (1 <<2 ) | (1 <<3 );
616+ else if (cmp > 0 )
617+ which1 &= (1 <<1 ) | (1 <<4 );
618+ }
619+
620+ if (which2 )
621+ {
622+ /*
623+ * For a range's lower bound to be adjacent to the
624+ * argument's upper bound, it will be found along the
625+ * line adjacent to (and just right of)
626+ * X=upper. Therefore, if the argument's upper bound is
627+ * less than (and not adjacent to) the centroid's upper
628+ * bound, the line falls in quadrants 3 and 4; if
629+ * greater or equal to, the line falls in quadrants 1
630+ * and 2.
631+ *
632+ * The edge case is when the argument's upper bound is
633+ * less than and adjacent to the centroid's lower
634+ * bound. In that case, adjacent ranges may be in any
635+ * quadrant.
636+ */
637+ cmp = range_cmp_bounds (typcache ,& lower ,
638+ & centroidUpper );
639+ if (cmp < 0 &&
640+ !bounds_adjacent (typcache ,upper ,centroidLower ))
641+ which1 &= (1 <<3 ) | (1 <<4 );
642+ else if (cmp > 0 )
643+ which1 &= (1 <<1 ) | (1 <<2 );
644+ }
645+
646+ which &=which1 |which2 ;
647+
648+ needPrevious = true;
649+ break ;
650+
525651case RANGESTRAT_CONTAINS :
526652/*
527653 * Non-empty range A contains non-empty range B if lower
@@ -652,11 +778,18 @@ spg_range_quad_inner_consistent(PG_FUNCTION_ARGS)
652778
653779/* We must descend into the quadrant(s) identified by 'which' */
654780out -> nodeNumbers = (int * )palloc (sizeof (int )* in -> nNodes );
781+ if (needPrevious )
782+ out -> reconstructedValues = (Datum * )palloc (sizeof (Datum )* in -> nNodes );
655783out -> nNodes = 0 ;
656784for (i = 1 ;i <=in -> nNodes ;i ++ )
657785{
658786if (which & (1 <<i ))
787+ {
788+ /* Save previous prefix if needed */
789+ if (needPrevious )
790+ out -> reconstructedValues [out -> nNodes ]= in -> prefixDatum ;
659791out -> nodeNumbers [out -> nNodes ++ ]= i - 1 ;
792+ }
660793}
661794
662795PG_RETURN_VOID ();
@@ -713,6 +846,10 @@ spg_range_quad_leaf_consistent(PG_FUNCTION_ARGS)
713846res = range_after_internal (typcache ,leafRange ,
714847DatumGetRangeType (keyDatum ));
715848break ;
849+ case RANGESTRAT_ADJACENT :
850+ res = range_adjacent_internal (typcache ,leafRange ,
851+ DatumGetRangeType (keyDatum ));
852+ break ;
716853case RANGESTRAT_CONTAINS :
717854res = range_contains_internal (typcache ,leafRange ,
718855DatumGetRangeType (keyDatum ));