1 /*
2 * contrib/btree_gist/btree_numeric.c
3 */
4 #include "postgres.h"
5
6 #include "btree_gist.h"
7
8 #include <math.h>
9 #include <float.h>
10
11 #include "btree_utils_var.h"
12 #include "utils/builtins.h"
13 #include "utils/numeric.h"
14 #include "utils/rel.h"
15
16 /*
17 ** Bytea ops
18 */
19 PG_FUNCTION_INFO_V1(gbt_numeric_compress);
20 PG_FUNCTION_INFO_V1(gbt_numeric_union);
21 PG_FUNCTION_INFO_V1(gbt_numeric_picksplit);
22 PG_FUNCTION_INFO_V1(gbt_numeric_consistent);
23 PG_FUNCTION_INFO_V1(gbt_numeric_penalty);
24 PG_FUNCTION_INFO_V1(gbt_numeric_same);
25
26
27 /* define for comparison */
28
29 static bool
gbt_numeric_gt(const void * a,const void * b,Oid collation,FmgrInfo * flinfo)30 gbt_numeric_gt(const void *a, const void *b, Oid collation, FmgrInfo *flinfo)
31 {
32 return DatumGetBool(DirectFunctionCall2(numeric_gt,
33 PointerGetDatum(a),
34 PointerGetDatum(b)));
35 }
36
37 static bool
gbt_numeric_ge(const void * a,const void * b,Oid collation,FmgrInfo * flinfo)38 gbt_numeric_ge(const void *a, const void *b, Oid collation, FmgrInfo *flinfo)
39 {
40 return DatumGetBool(DirectFunctionCall2(numeric_ge,
41 PointerGetDatum(a),
42 PointerGetDatum(b)));
43 }
44
45 static bool
gbt_numeric_eq(const void * a,const void * b,Oid collation,FmgrInfo * flinfo)46 gbt_numeric_eq(const void *a, const void *b, Oid collation, FmgrInfo *flinfo)
47 {
48 return DatumGetBool(DirectFunctionCall2(numeric_eq,
49 PointerGetDatum(a),
50 PointerGetDatum(b)));
51 }
52
53 static bool
gbt_numeric_le(const void * a,const void * b,Oid collation,FmgrInfo * flinfo)54 gbt_numeric_le(const void *a, const void *b, Oid collation, FmgrInfo *flinfo)
55 {
56 return DatumGetBool(DirectFunctionCall2(numeric_le,
57 PointerGetDatum(a),
58 PointerGetDatum(b)));
59 }
60
61 static bool
gbt_numeric_lt(const void * a,const void * b,Oid collation,FmgrInfo * flinfo)62 gbt_numeric_lt(const void *a, const void *b, Oid collation, FmgrInfo *flinfo)
63 {
64 return DatumGetBool(DirectFunctionCall2(numeric_lt,
65 PointerGetDatum(a),
66 PointerGetDatum(b)));
67 }
68
69 static int32
gbt_numeric_cmp(const void * a,const void * b,Oid collation,FmgrInfo * flinfo)70 gbt_numeric_cmp(const void *a, const void *b, Oid collation, FmgrInfo *flinfo)
71 {
72 return DatumGetInt32(DirectFunctionCall2(numeric_cmp,
73 PointerGetDatum(a),
74 PointerGetDatum(b)));
75 }
76
77
78 static const gbtree_vinfo tinfo =
79 {
80 gbt_t_numeric,
81 0,
82 false,
83 gbt_numeric_gt,
84 gbt_numeric_ge,
85 gbt_numeric_eq,
86 gbt_numeric_le,
87 gbt_numeric_lt,
88 gbt_numeric_cmp,
89 NULL
90 };
91
92
93 /**************************************************
94 * Text ops
95 **************************************************/
96
97
98 Datum
gbt_numeric_compress(PG_FUNCTION_ARGS)99 gbt_numeric_compress(PG_FUNCTION_ARGS)
100 {
101 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
102
103 PG_RETURN_POINTER(gbt_var_compress(entry, &tinfo));
104 }
105
106
107
108 Datum
gbt_numeric_consistent(PG_FUNCTION_ARGS)109 gbt_numeric_consistent(PG_FUNCTION_ARGS)
110 {
111 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
112 void *query = (void *) DatumGetNumeric(PG_GETARG_DATUM(1));
113 StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
114
115 /* Oid subtype = PG_GETARG_OID(3); */
116 bool *recheck = (bool *) PG_GETARG_POINTER(4);
117 bool retval;
118 GBT_VARKEY *key = (GBT_VARKEY *) DatumGetPointer(entry->key);
119 GBT_VARKEY_R r = gbt_var_key_readable(key);
120
121 /* All cases served by this function are exact */
122 *recheck = false;
123
124 retval = gbt_var_consistent(&r, query, strategy, PG_GET_COLLATION(),
125 GIST_LEAF(entry), &tinfo, fcinfo->flinfo);
126 PG_RETURN_BOOL(retval);
127 }
128
129
130
131 Datum
gbt_numeric_union(PG_FUNCTION_ARGS)132 gbt_numeric_union(PG_FUNCTION_ARGS)
133 {
134 GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
135 int32 *size = (int *) PG_GETARG_POINTER(1);
136
137 PG_RETURN_POINTER(gbt_var_union(entryvec, size, PG_GET_COLLATION(),
138 &tinfo, fcinfo->flinfo));
139 }
140
141
142 Datum
gbt_numeric_same(PG_FUNCTION_ARGS)143 gbt_numeric_same(PG_FUNCTION_ARGS)
144 {
145 Datum d1 = PG_GETARG_DATUM(0);
146 Datum d2 = PG_GETARG_DATUM(1);
147 bool *result = (bool *) PG_GETARG_POINTER(2);
148
149 *result = gbt_var_same(d1, d2, PG_GET_COLLATION(), &tinfo, fcinfo->flinfo);
150 PG_RETURN_POINTER(result);
151 }
152
153
154 Datum
gbt_numeric_penalty(PG_FUNCTION_ARGS)155 gbt_numeric_penalty(PG_FUNCTION_ARGS)
156 {
157 GISTENTRY *o = (GISTENTRY *) PG_GETARG_POINTER(0);
158 GISTENTRY *n = (GISTENTRY *) PG_GETARG_POINTER(1);
159 float *result = (float *) PG_GETARG_POINTER(2);
160
161 Numeric us,
162 os,
163 ds;
164
165 GBT_VARKEY *org = (GBT_VARKEY *) DatumGetPointer(o->key);
166 GBT_VARKEY *newe = (GBT_VARKEY *) DatumGetPointer(n->key);
167 Datum uni;
168 GBT_VARKEY_R rk,
169 ok,
170 uk;
171
172 rk = gbt_var_key_readable(org);
173 uni = PointerGetDatum(gbt_var_key_copy(&rk));
174 gbt_var_bin_union(&uni, newe, PG_GET_COLLATION(), &tinfo, fcinfo->flinfo);
175 ok = gbt_var_key_readable(org);
176 uk = gbt_var_key_readable((GBT_VARKEY *) DatumGetPointer(uni));
177
178 us = DatumGetNumeric(DirectFunctionCall2(
179 numeric_sub,
180 PointerGetDatum(uk.upper),
181 PointerGetDatum(uk.lower)
182 ));
183
184 os = DatumGetNumeric(DirectFunctionCall2(
185 numeric_sub,
186 PointerGetDatum(ok.upper),
187 PointerGetDatum(ok.lower)
188 ));
189
190 ds = DatumGetNumeric(DirectFunctionCall2(
191 numeric_sub,
192 NumericGetDatum(us),
193 NumericGetDatum(os)
194 ));
195
196 if (numeric_is_nan(us))
197 {
198 if (numeric_is_nan(os))
199 *result = 0.0;
200 else
201 *result = 1.0;
202 }
203 else
204 {
205 Numeric nul = DatumGetNumeric(DirectFunctionCall1(int4_numeric, Int32GetDatum(0)));
206
207 *result = 0.0;
208
209 if (DirectFunctionCall2(numeric_gt, NumericGetDatum(ds), NumericGetDatum(nul)))
210 {
211 *result += FLT_MIN;
212 os = DatumGetNumeric(DirectFunctionCall2(
213 numeric_div,
214 NumericGetDatum(ds),
215 NumericGetDatum(us)
216 ));
217 *result += (float4) DatumGetFloat8(DirectFunctionCall1(numeric_float8_no_overflow, NumericGetDatum(os)));
218 }
219 }
220
221 if (*result > 0)
222 *result *= (FLT_MAX / (((GISTENTRY *) PG_GETARG_POINTER(0))->rel->rd_att->natts + 1));
223
224 PG_RETURN_POINTER(result);
225 }
226
227
228
229 Datum
gbt_numeric_picksplit(PG_FUNCTION_ARGS)230 gbt_numeric_picksplit(PG_FUNCTION_ARGS)
231 {
232 GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
233 GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
234
235 gbt_var_picksplit(entryvec, v, PG_GET_COLLATION(),
236 &tinfo, fcinfo->flinfo);
237 PG_RETURN_POINTER(v);
238 }
239