@@ -305,6 +305,16 @@ spg_range_quad_inner_consistent(PG_FUNCTION_ARGS)
305
305
int which ;
306
306
int i ;
307
307
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
+
308
318
if (in -> allTheSame )
309
319
{
310
320
/* Report that all nodes should be visited */
@@ -351,6 +361,7 @@ spg_range_quad_inner_consistent(PG_FUNCTION_ARGS)
351
361
case RANGESTRAT_OVERLAPS :
352
362
case RANGESTRAT_OVERRIGHT :
353
363
case RANGESTRAT_AFTER :
364
+ case RANGESTRAT_ADJACENT :
354
365
/* These strategies return false if any argument is empty */
355
366
if (empty )
356
367
which = 0 ;
@@ -435,6 +446,9 @@ spg_range_quad_inner_consistent(PG_FUNCTION_ARGS)
435
446
/* Are the restrictions on range bounds inclusive? */
436
447
bool inclusive = true;
437
448
bool strictEmpty = true;
449
+ int cmp ,
450
+ which1 ,
451
+ which2 ;
438
452
439
453
strategy = in -> scankeys [i ].sk_strategy ;
440
454
@@ -522,6 +536,118 @@ spg_range_quad_inner_consistent(PG_FUNCTION_ARGS)
522
536
inclusive = false;
523
537
break ;
524
538
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
+
525
651
case RANGESTRAT_CONTAINS :
526
652
/*
527
653
* Non-empty range A contains non-empty range B if lower
@@ -652,11 +778,18 @@ spg_range_quad_inner_consistent(PG_FUNCTION_ARGS)
652
778
653
779
/* We must descend into the quadrant(s) identified by 'which' */
654
780
out -> nodeNumbers = (int * ) palloc (sizeof (int ) * in -> nNodes );
781
+ if (needPrevious )
782
+ out -> reconstructedValues = (Datum * ) palloc (sizeof (Datum ) * in -> nNodes );
655
783
out -> nNodes = 0 ;
656
784
for (i = 1 ; i <= in -> nNodes ; i ++ )
657
785
{
658
786
if (which & (1 << i ))
787
+ {
788
+ /* Save previous prefix if needed */
789
+ if (needPrevious )
790
+ out -> reconstructedValues [out -> nNodes ] = in -> prefixDatum ;
659
791
out -> nodeNumbers [out -> nNodes ++ ] = i - 1 ;
792
+ }
660
793
}
661
794
662
795
PG_RETURN_VOID ();
@@ -713,6 +846,10 @@ spg_range_quad_leaf_consistent(PG_FUNCTION_ARGS)
713
846
res = range_after_internal (typcache , leafRange ,
714
847
DatumGetRangeType (keyDatum ));
715
848
break ;
849
+ case RANGESTRAT_ADJACENT :
850
+ res = range_adjacent_internal (typcache , leafRange ,
851
+ DatumGetRangeType (keyDatum ));
852
+ break ;
716
853
case RANGESTRAT_CONTAINS :
717
854
res = range_contains_internal (typcache , leafRange ,
718
855
DatumGetRangeType (keyDatum ));
0 commit comments