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