17
17
*/
18
18
#include "postgres.h"
19
19
20
+ #include <math.h>
21
+
20
22
#include "access/gist.h"
21
23
#include "access/skey.h"
24
+ #include "utils/builtins.h"
22
25
#include "utils/geo_decls.h"
23
26
24
27
25
28
static bool gist_box_leaf_consistent (BOX * key , BOX * query ,
26
29
StrategyNumber strategy );
27
- static double size_box (BOX * box );
28
30
static bool rtree_internal_consistent (BOX * key , BOX * query ,
29
31
StrategyNumber strategy );
30
32
31
33
/* Minimum accepted ratio of split */
32
34
#define LIMIT_RATIO 0.3
33
35
36
+ /* Convenience macros for NaN-aware comparisons */
37
+ #define FLOAT8_EQ (a ,b ) (float8_cmp_internal(a, b) == 0)
38
+ #define FLOAT8_LT (a ,b ) (float8_cmp_internal(a, b) < 0)
39
+ #define FLOAT8_LE (a ,b ) (float8_cmp_internal(a, b) <= 0)
40
+ #define FLOAT8_GT (a ,b ) (float8_cmp_internal(a, b) > 0)
41
+ #define FLOAT8_GE (a ,b ) (float8_cmp_internal(a, b) >= 0)
42
+ #define FLOAT8_MAX (a ,b ) (FLOAT8_GT(a, b) ? (a) : (b))
43
+ #define FLOAT8_MIN (a ,b ) (FLOAT8_LT(a, b) ? (a) : (b))
44
+
34
45
35
46
/**************************************************
36
47
* Box ops
@@ -40,12 +51,53 @@ static bool rtree_internal_consistent(BOX *key, BOX *query,
40
51
* Calculates union of two boxes, a and b. The result is stored in *n.
41
52
*/
42
53
static void
43
- rt_box_union (BOX * n , BOX * a , BOX * b )
54
+ rt_box_union (BOX * n , const BOX * a , const BOX * b )
55
+ {
56
+ n -> high .x = FLOAT8_MAX (a -> high .x , b -> high .x );
57
+ n -> high .y = FLOAT8_MAX (a -> high .y , b -> high .y );
58
+ n -> low .x = FLOAT8_MIN (a -> low .x , b -> low .x );
59
+ n -> low .y = FLOAT8_MIN (a -> low .y , b -> low .y );
60
+ }
61
+
62
+ /*
63
+ * Size of a BOX for penalty-calculation purposes.
64
+ * The result can be +Infinity, but not NaN.
65
+ */
66
+ static double
67
+ size_box (const BOX * box )
68
+ {
69
+ /*
70
+ * Check for zero-width cases. Note that we define the size of a zero-
71
+ * by-infinity box as zero. It's important to special-case this somehow,
72
+ * as naively multiplying infinity by zero will produce NaN.
73
+ *
74
+ * The less-than cases should not happen, but if they do, say "zero".
75
+ */
76
+ if (FLOAT8_LE (box -> high .x , box -> low .x ) ||
77
+ FLOAT8_LE (box -> high .y , box -> low .y ))
78
+ return 0.0 ;
79
+
80
+ /*
81
+ * We treat NaN as larger than +Infinity, so any distance involving a NaN
82
+ * and a non-NaN is infinite. Note the previous check eliminated the
83
+ * possibility that the low fields are NaNs.
84
+ */
85
+ if (isnan (box -> high .x ) || isnan (box -> high .y ))
86
+ return get_float8_infinity ();
87
+ return (box -> high .x - box -> low .x ) * (box -> high .y - box -> low .y );
88
+ }
89
+
90
+ /*
91
+ * Return amount by which the union of the two boxes is larger than
92
+ * the original BOX's area. The result can be +Infinity, but not NaN.
93
+ */
94
+ static double
95
+ box_penalty (const BOX * original , const BOX * new )
44
96
{
45
- n -> high . x = Max ( a -> high . x , b -> high . x ) ;
46
- n -> high . y = Max ( a -> high . y , b -> high . y );
47
- n -> low . x = Min ( a -> low . x , b -> low . x );
48
- n -> low . y = Min ( a -> low . y , b -> low . y );
97
+ BOX unionbox ;
98
+
99
+ rt_box_union ( & unionbox , original , new );
100
+ return size_box ( & unionbox ) - size_box ( original );
49
101
}
50
102
51
103
/*
@@ -85,16 +137,19 @@ gist_box_consistent(PG_FUNCTION_ARGS)
85
137
strategy ));
86
138
}
87
139
140
+ /*
141
+ * Increase BOX b to include addon.
142
+ */
88
143
static void
89
- adjustBox (BOX * b , BOX * addon )
144
+ adjustBox (BOX * b , const BOX * addon )
90
145
{
91
- if (b -> high .x < addon -> high .x )
146
+ if (FLOAT8_LT ( b -> high .x , addon -> high .x ) )
92
147
b -> high .x = addon -> high .x ;
93
- if (b -> low .x > addon -> low .x )
148
+ if (FLOAT8_GT ( b -> low .x , addon -> low .x ) )
94
149
b -> low .x = addon -> low .x ;
95
- if (b -> high .y < addon -> high .y )
150
+ if (FLOAT8_LT ( b -> high .y , addon -> high .y ) )
96
151
b -> high .y = addon -> high .y ;
97
- if (b -> low .y > addon -> low .y )
152
+ if (FLOAT8_GT ( b -> low .y , addon -> low .y ) )
98
153
b -> low .y = addon -> low .y ;
99
154
}
100
155
@@ -164,10 +219,8 @@ gist_box_penalty(PG_FUNCTION_ARGS)
164
219
float * result = (float * ) PG_GETARG_POINTER (2 );
165
220
BOX * origbox = DatumGetBoxP (origentry -> key );
166
221
BOX * newbox = DatumGetBoxP (newentry -> key );
167
- BOX unionbox ;
168
222
169
- rt_box_union (& unionbox , origbox , newbox );
170
- * result = (float ) (size_box (& unionbox ) - size_box (origbox ));
223
+ * result = (float ) box_penalty (origbox , newbox );
171
224
PG_RETURN_POINTER (result );
172
225
}
173
226
@@ -280,12 +333,7 @@ interval_cmp_lower(const void *i1, const void *i2)
280
333
double lower1 = ((const SplitInterval * ) i1 )-> lower ,
281
334
lower2 = ((const SplitInterval * ) i2 )-> lower ;
282
335
283
- if (lower1 < lower2 )
284
- return -1 ;
285
- else if (lower1 > lower2 )
286
- return 1 ;
287
- else
288
- return 0 ;
336
+ return float8_cmp_internal (lower1 , lower2 );
289
337
}
290
338
291
339
/*
@@ -297,16 +345,11 @@ interval_cmp_upper(const void *i1, const void *i2)
297
345
double upper1 = ((const SplitInterval * ) i1 )-> upper ,
298
346
upper2 = ((const SplitInterval * ) i2 )-> upper ;
299
347
300
- if (upper1 < upper2 )
301
- return -1 ;
302
- else if (upper1 > upper2 )
303
- return 1 ;
304
- else
305
- return 0 ;
348
+ return float8_cmp_internal (upper1 , upper2 );
306
349
}
307
350
308
351
/*
309
- * Replace negative value with zero.
352
+ * Replace negative (or NaN) value with zero.
310
353
*/
311
354
static inline float
312
355
non_negative (float val )
@@ -425,25 +468,9 @@ g_box_consider_split(ConsiderSplitContext *context, int dimNum,
425
468
}
426
469
}
427
470
428
- /*
429
- * Return increase of original BOX area by new BOX area insertion.
430
- */
431
- static double
432
- box_penalty (BOX * original , BOX * new )
433
- {
434
- double union_width ,
435
- union_height ;
436
-
437
- union_width = Max (original -> high .x , new -> high .x ) -
438
- Min (original -> low .x , new -> low .x );
439
- union_height = Max (original -> high .y , new -> high .y ) -
440
- Min (original -> low .y , new -> low .y );
441
- return union_width * union_height - (original -> high .x - original -> low .x ) *
442
- (original -> high .y - original -> low .y );
443
- }
444
-
445
471
/*
446
472
* Compare common entries by their deltas.
473
+ * (We assume the deltas can't be NaN.)
447
474
*/
448
475
static int
449
476
common_entry_cmp (const void * i1 , const void * i2 )
@@ -605,9 +632,11 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
605
632
/*
606
633
* Find next lower bound of right group.
607
634
*/
608
- while (i1 < nentries && rightLower == intervalsLower [i1 ].lower )
635
+ while (i1 < nentries &&
636
+ FLOAT8_EQ (rightLower , intervalsLower [i1 ].lower ))
609
637
{
610
- leftUpper = Max (leftUpper , intervalsLower [i1 ].upper );
638
+ if (FLOAT8_LT (leftUpper , intervalsLower [i1 ].upper ))
639
+ leftUpper = intervalsLower [i1 ].upper ;
611
640
i1 ++ ;
612
641
}
613
642
if (i1 >= nentries )
@@ -618,7 +647,8 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
618
647
* Find count of intervals which anyway should be placed to the
619
648
* left group.
620
649
*/
621
- while (i2 < nentries && intervalsUpper [i2 ].upper <= leftUpper )
650
+ while (i2 < nentries &&
651
+ FLOAT8_LE (intervalsUpper [i2 ].upper , leftUpper ))
622
652
i2 ++ ;
623
653
624
654
/*
@@ -640,9 +670,10 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
640
670
/*
641
671
* Find next upper bound of left group.
642
672
*/
643
- while (i2 >= 0 && leftUpper == intervalsUpper [i2 ].upper )
673
+ while (i2 >= 0 && FLOAT8_EQ ( leftUpper , intervalsUpper [i2 ].upper ) )
644
674
{
645
- rightLower = Min (rightLower , intervalsUpper [i2 ].lower );
675
+ if (FLOAT8_GT (rightLower , intervalsUpper [i2 ].lower ))
676
+ rightLower = intervalsUpper [i2 ].lower ;
646
677
i2 -- ;
647
678
}
648
679
if (i2 < 0 )
@@ -653,7 +684,7 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
653
684
* Find count of intervals which anyway should be placed to the
654
685
* right group.
655
686
*/
656
- while (i1 >= 0 && intervalsLower [i1 ].lower >= rightLower )
687
+ while (i1 >= 0 && FLOAT8_GE ( intervalsLower [i1 ].lower , rightLower ) )
657
688
i1 -- ;
658
689
659
690
/*
@@ -741,10 +772,10 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
741
772
upper = box -> high .y ;
742
773
}
743
774
744
- if (upper <= context .leftUpper )
775
+ if (FLOAT8_LE ( upper , context .leftUpper ) )
745
776
{
746
777
/* Fits to the left group */
747
- if (lower >= context .rightLower )
778
+ if (FLOAT8_GE ( lower , context .rightLower ) )
748
779
{
749
780
/* Fits also to the right group, so "common entry" */
750
781
commonEntries [commonEntriesCount ++ ].index = i ;
@@ -762,7 +793,7 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
762
793
* entry didn't fit on the left group, it better fit in the right
763
794
* group.
764
795
*/
765
- Assert (lower >= context .rightLower );
796
+ Assert (FLOAT8_GE ( lower , context .rightLower ) );
766
797
767
798
/* Doesn't fit to the left group, so join to the right group */
768
799
PLACE_RIGHT (box , i );
@@ -846,8 +877,10 @@ gist_box_same(PG_FUNCTION_ARGS)
846
877
bool * result = (bool * ) PG_GETARG_POINTER (2 );
847
878
848
879
if (b1 && b2 )
849
- * result = (b1 -> low .x == b2 -> low .x && b1 -> low .y == b2 -> low .y &&
850
- b1 -> high .x == b2 -> high .x && b1 -> high .y == b2 -> high .y );
880
+ * result = (FLOAT8_EQ (b1 -> low .x , b2 -> low .x ) &&
881
+ FLOAT8_EQ (b1 -> low .y , b2 -> low .y ) &&
882
+ FLOAT8_EQ (b1 -> high .x , b2 -> high .x ) &&
883
+ FLOAT8_EQ (b1 -> high .y , b2 -> high .y ));
851
884
else
852
885
* result = (b1 == NULL && b2 == NULL );
853
886
PG_RETURN_POINTER (result );
@@ -931,14 +964,6 @@ gist_box_leaf_consistent(BOX *key, BOX *query, StrategyNumber strategy)
931
964
return retval ;
932
965
}
933
966
934
- static double
935
- size_box (BOX * box )
936
- {
937
- if (box -> high .x <= box -> low .x || box -> high .y <= box -> low .y )
938
- return 0.0 ;
939
- return (box -> high .x - box -> low .x ) * (box -> high .y - box -> low .y );
940
- }
941
-
942
967
/*****************************************
943
968
* Common rtree functions (for boxes, polygons, and circles)
944
969
*****************************************/
0 commit comments