Branch data Line data Source code
1 : : /*
2 : : * contrib/btree_gist/btree_utils_num.h
3 : : */
4 : : #ifndef __BTREE_UTILS_NUM_H__
5 : : #define __BTREE_UTILS_NUM_H__
6 : :
7 : : #include <math.h>
8 : : #include <float.h>
9 : :
10 : : #include "access/gist.h"
11 : : #include "btree_gist.h"
12 : : #include "utils/float.h"
13 : :
14 : : typedef char GBT_NUMKEY;
15 : :
16 : : /* Better readable key */
17 : : typedef struct
18 : : {
19 : : const GBT_NUMKEY *lower,
20 : : *upper;
21 : : } GBT_NUMKEY_R;
22 : :
23 : :
24 : : /* for sorting */
25 : : typedef struct
26 : : {
27 : : int i;
28 : : GBT_NUMKEY *t;
29 : : } Nsrt;
30 : :
31 : :
32 : : /* type description */
33 : :
34 : : typedef struct
35 : : {
36 : :
37 : : /* Attribs */
38 : :
39 : : enum gbtree_type t; /* data type */
40 : : int32 size; /* size of type, 0 means variable */
41 : : int32 indexsize; /* size of datums stored in index */
42 : :
43 : : /* Methods */
44 : :
45 : : bool (*f_gt) (const void *, const void *, FmgrInfo *); /* greater than */
46 : : bool (*f_ge) (const void *, const void *, FmgrInfo *); /* greater or equal */
47 : : bool (*f_eq) (const void *, const void *, FmgrInfo *); /* equal */
48 : : bool (*f_le) (const void *, const void *, FmgrInfo *); /* less or equal */
49 : : bool (*f_lt) (const void *, const void *, FmgrInfo *); /* less than */
50 : : int (*f_cmp) (const void *, const void *, FmgrInfo *); /* key compare function */
51 : : float8 (*f_dist) (const void *, const void *, FmgrInfo *); /* key distance function */
52 : : } gbtree_ninfo;
53 : :
54 : :
55 : : /*
56 : : * Numeric btree functions
57 : : */
58 : :
59 : :
60 : :
61 : : /*
62 : : * Compute penalty for expanding a range olower..oupper to nlower..nupper.
63 : : *
64 : : * Although the arguments are declared double, they must not be NaN nor
65 : : * large enough to risk overflows in the calculations herein. We only
66 : : * actually use this for integral data types, so there's no hazard.
67 : : */
68 : : static inline float
69 : 5830 : penalty_num_impl(double olower, double oupper,
70 : : double nlower, double nupper,
71 : : int natts)
72 : : {
73 : 5830 : float result = 0.0F;
74 : 5830 : double tmp = 0.0;
75 : :
76 : : /* Add penalty for expanding upper bound */
77 [ + + ]: 5830 : if (nupper > oupper)
78 : 659 : tmp += nupper - oupper;
79 : : /* Add penalty for expanding lower bound */
80 [ + + ]: 5830 : if (olower > nlower)
81 : 733 : tmp += olower - nlower;
82 [ + + ]: 5830 : if (tmp > 0.0)
83 : : {
84 : : /* Ensure result is non-zero, even if next step underflows to zero */
85 : 1392 : result += FLT_MIN;
86 : : /* Scale penalty to 0 .. 1 */
87 : 1392 : result += (float) (tmp / (tmp + (oupper - olower)));
88 : : /* Scale to 0 .. FLT_MAX / (natts + 1) */
89 : 1392 : result *= FLT_MAX / (natts + 1);
90 : : }
91 : 5830 : return result;
92 : : }
93 : :
94 : : /*
95 : : * As above, but the input values are float4 or float8, so we must cope
96 : : * with NaNs, infinities, and overflows.
97 : : */
98 : : static inline float
99 : 1644 : float_penalty_num_impl(double olower, double oupper,
100 : : double nlower, double nupper,
101 : : int natts)
102 : : {
103 : 1644 : float result = 0.0F;
104 : 1644 : double tmp = 0.0;
105 : :
106 : : /* Add penalty for expanding upper bound */
107 [ + + ]: 1644 : if (float8_gt(nupper, oupper))
108 : : {
109 : 823 : double delta = nupper - oupper;
110 : :
111 [ + + ]: 823 : if (unlikely(isnan(delta)))
112 : : {
113 : : /* oupper couldn't be NaN here, see float8_gt */
114 [ + - ]: 3 : if (isnan(nupper))
115 : 3 : delta = FLT_MAX; /* max penalty for NaN vs non-NaN */
116 : : else
117 : 0 : delta = 0.0; /* must be Inf - Inf case */
118 : : }
119 [ + + ]: 820 : else if (delta > FLT_MAX)
120 : 3 : delta = FLT_MAX; /* clamp to FLT_MAX, esp for infinity */
121 : 823 : tmp += delta;
122 : : }
123 : : /* Add penalty for expanding lower bound */
124 [ + + ]: 1644 : if (float8_gt(olower, nlower))
125 : : {
126 : 821 : double delta = olower - nlower;
127 : :
128 [ - + ]: 821 : if (unlikely(isnan(delta)))
129 : : {
130 : : /* nlower couldn't be NaN here, see float8_gt */
131 [ # # ]: 0 : if (isnan(olower))
132 : 0 : delta = FLT_MAX; /* max penalty for NaN vs non-NaN */
133 : : else
134 : 0 : delta = 0.0; /* must be Inf - Inf case */
135 : : }
136 [ + + ]: 821 : else if (delta > FLT_MAX)
137 : 3 : delta = FLT_MAX; /* clamp to FLT_MAX, esp for infinity */
138 : 821 : tmp += delta;
139 : : }
140 [ + - ]: 1644 : if (tmp > 0.0)
141 : : {
142 : 1644 : double delta = oupper - olower;
143 : :
144 : : /* Clamp delta (the original range size) to 0 .. FLT_MAX */
145 [ + + ]: 1644 : if (unlikely(isnan(delta)))
146 : : {
147 : : /* here, we must deal with olower possibly being NaN */
148 [ + - - + ]: 685 : if (isnan(oupper) && isnan(olower))
149 : 0 : delta = 0.0; /* treat NaNs as equal */
150 [ - + - - ]: 685 : else if (isnan(oupper) || isnan(olower))
151 : 685 : delta = FLT_MAX; /* max penalty for NaN vs non-NaN */
152 : : else
153 : 0 : delta = 0.0; /* must be Inf - Inf case */
154 : : }
155 [ + + ]: 959 : else if (delta > FLT_MAX)
156 : 686 : delta = FLT_MAX; /* clamp to FLT_MAX, esp for infinity */
157 : : /* Ensure result is non-zero, even if next step underflows to zero */
158 : 1644 : result += FLT_MIN;
159 : : /* Scale penalty to 0 .. 1 */
160 : 1644 : result += (float) (tmp / (tmp + delta));
161 : : /* Scale to 0 .. FLT_MAX / (natts + 1) */
162 : 1644 : result *= FLT_MAX / (natts + 1);
163 : : }
164 : 1644 : return result;
165 : : }
166 : :
167 : : /*
168 : : * These macros provide backwards-compatible notation for callers.
169 : : */
170 : : #define penalty_num(result,olower,oupper,nlower,nupper) do { \
171 : : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); \
172 : : *(result) = penalty_num_impl(olower, oupper, nlower, nupper, \
173 : : entry->rel->rd_att->natts); \
174 : : } while (0)
175 : :
176 : : #define float_penalty_num(result,olower,oupper,nlower,nupper) do { \
177 : : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); \
178 : : *(result) = float_penalty_num_impl(olower, oupper, nlower, nupper, \
179 : : entry->rel->rd_att->natts); \
180 : : } while (0)
181 : :
182 : :
183 : : /*
184 : : * Convert an Interval to an approximate equivalent number of seconds
185 : : * (as a double). Here because we need it for time/timetz as well as
186 : : * interval. See interval_cmp_internal for comparison.
187 : : */
188 : : #define INTERVAL_TO_SEC(ivp) \
189 : : (((double) (ivp)->time) / ((double) USECS_PER_SEC) + \
190 : : (ivp)->day * (24.0 * SECS_PER_HOUR) + \
191 : : (ivp)->month * (30.0 * SECS_PER_DAY))
192 : :
193 : : /* This macro is not safe to use with actual float inputs, only integers */
194 : : #define GET_FLOAT_DISTANCE(t, arg1, arg2) fabs( ((float8) *((const t *) (arg1))) - ((float8) *((const t *) (arg2))) )
195 : :
196 : :
197 : : extern Interval *abs_interval(Interval *a);
198 : :
199 : : extern bool gbt_num_consistent(const GBT_NUMKEY_R *key, const void *query,
200 : : StrategyNumber strategy, bool is_leaf,
201 : : const gbtree_ninfo *tinfo, FmgrInfo *flinfo);
202 : :
203 : : extern float8 gbt_num_distance(const GBT_NUMKEY_R *key, const void *query,
204 : : bool is_leaf, const gbtree_ninfo *tinfo, FmgrInfo *flinfo);
205 : :
206 : : extern GIST_SPLITVEC *gbt_num_picksplit(const GistEntryVector *entryvec, GIST_SPLITVEC *v,
207 : : const gbtree_ninfo *tinfo, FmgrInfo *flinfo);
208 : :
209 : : extern GISTENTRY *gbt_num_compress(GISTENTRY *entry, const gbtree_ninfo *tinfo);
210 : :
211 : : extern GISTENTRY *gbt_num_fetch(GISTENTRY *entry, const gbtree_ninfo *tinfo);
212 : :
213 : : extern void *gbt_num_union(GBT_NUMKEY *out, const GistEntryVector *entryvec,
214 : : const gbtree_ninfo *tinfo, FmgrInfo *flinfo);
215 : :
216 : : extern bool gbt_num_same(const GBT_NUMKEY *a, const GBT_NUMKEY *b,
217 : : const gbtree_ninfo *tinfo, FmgrInfo *flinfo);
218 : :
219 : : extern void gbt_num_bin_union(Datum *u, GBT_NUMKEY *e,
220 : : const gbtree_ninfo *tinfo, FmgrInfo *flinfo);
221 : :
222 : : #endif
|