1 /*
2  * contrib/btree_gist/btree_time.c
3  */
4 #include "postgres.h"
5 
6 #include "btree_gist.h"
7 #include "btree_utils_num.h"
8 #include "utils/builtins.h"
9 #include "utils/date.h"
10 #include "utils/timestamp.h"
11 
12 typedef struct
13 {
14 	TimeADT		lower;
15 	TimeADT		upper;
16 } timeKEY;
17 
18 /*
19 ** time ops
20 */
21 PG_FUNCTION_INFO_V1(gbt_time_compress);
22 PG_FUNCTION_INFO_V1(gbt_timetz_compress);
23 PG_FUNCTION_INFO_V1(gbt_time_fetch);
24 PG_FUNCTION_INFO_V1(gbt_time_union);
25 PG_FUNCTION_INFO_V1(gbt_time_picksplit);
26 PG_FUNCTION_INFO_V1(gbt_time_consistent);
27 PG_FUNCTION_INFO_V1(gbt_time_distance);
28 PG_FUNCTION_INFO_V1(gbt_timetz_consistent);
29 PG_FUNCTION_INFO_V1(gbt_time_penalty);
30 PG_FUNCTION_INFO_V1(gbt_time_same);
31 
32 
33 #ifdef USE_FLOAT8_BYVAL
34 #define TimeADTGetDatumFast(X) TimeADTGetDatum(X)
35 #else
36 #define TimeADTGetDatumFast(X) PointerGetDatum(&(X))
37 #endif
38 
39 
40 static bool
41 gbt_timegt(const void *a, const void *b, FmgrInfo *flinfo)
42 {
43 	const TimeADT *aa = (const TimeADT *) a;
44 	const TimeADT *bb = (const TimeADT *) b;
45 
46 	return DatumGetBool(DirectFunctionCall2(time_gt,
47 											TimeADTGetDatumFast(*aa),
48 											TimeADTGetDatumFast(*bb)));
49 }
50 
51 static bool
52 gbt_timege(const void *a, const void *b, FmgrInfo *flinfo)
53 {
54 	const TimeADT *aa = (const TimeADT *) a;
55 	const TimeADT *bb = (const TimeADT *) b;
56 
57 	return DatumGetBool(DirectFunctionCall2(time_ge,
58 											TimeADTGetDatumFast(*aa),
59 											TimeADTGetDatumFast(*bb)));
60 }
61 
62 static bool
63 gbt_timeeq(const void *a, const void *b, FmgrInfo *flinfo)
64 {
65 	const TimeADT *aa = (const TimeADT *) a;
66 	const TimeADT *bb = (const TimeADT *) b;
67 
68 	return DatumGetBool(DirectFunctionCall2(time_eq,
69 											TimeADTGetDatumFast(*aa),
70 											TimeADTGetDatumFast(*bb)));
71 }
72 
73 static bool
74 gbt_timele(const void *a, const void *b, FmgrInfo *flinfo)
75 {
76 	const TimeADT *aa = (const TimeADT *) a;
77 	const TimeADT *bb = (const TimeADT *) b;
78 
79 	return DatumGetBool(DirectFunctionCall2(time_le,
80 											TimeADTGetDatumFast(*aa),
81 											TimeADTGetDatumFast(*bb)));
82 }
83 
84 static bool
85 gbt_timelt(const void *a, const void *b, FmgrInfo *flinfo)
86 {
87 	const TimeADT *aa = (const TimeADT *) a;
88 	const TimeADT *bb = (const TimeADT *) b;
89 
90 	return DatumGetBool(DirectFunctionCall2(time_lt,
91 											TimeADTGetDatumFast(*aa),
92 											TimeADTGetDatumFast(*bb)));
93 }
94 
95 
96 
97 static int
98 gbt_timekey_cmp(const void *a, const void *b, FmgrInfo *flinfo)
99 {
100 	timeKEY    *ia = (timeKEY *) (((const Nsrt *) a)->t);
101 	timeKEY    *ib = (timeKEY *) (((const Nsrt *) b)->t);
102 	int			res;
103 
104 	res = DatumGetInt32(DirectFunctionCall2(time_cmp, TimeADTGetDatumFast(ia->lower), TimeADTGetDatumFast(ib->lower)));
105 	if (res == 0)
106 		return DatumGetInt32(DirectFunctionCall2(time_cmp, TimeADTGetDatumFast(ia->upper), TimeADTGetDatumFast(ib->upper)));
107 
108 	return res;
109 }
110 
111 static float8
112 gbt_time_dist(const void *a, const void *b, FmgrInfo *flinfo)
113 {
114 	const TimeADT *aa = (const TimeADT *) a;
115 	const TimeADT *bb = (const TimeADT *) b;
116 	Interval   *i;
117 
118 	i = DatumGetIntervalP(DirectFunctionCall2(time_mi_time,
119 											  TimeADTGetDatumFast(*aa),
120 											  TimeADTGetDatumFast(*bb)));
121 	return (float8) Abs(INTERVAL_TO_SEC(i));
122 }
123 
124 
125 static const gbtree_ninfo tinfo =
126 {
127 	gbt_t_time,
128 	sizeof(TimeADT),
129 	16,							/* sizeof(gbtreekey16) */
130 	gbt_timegt,
131 	gbt_timege,
132 	gbt_timeeq,
133 	gbt_timele,
134 	gbt_timelt,
135 	gbt_timekey_cmp,
136 	gbt_time_dist
137 };
138 
139 
140 PG_FUNCTION_INFO_V1(time_dist);
141 Datum
142 time_dist(PG_FUNCTION_ARGS)
143 {
144 	Datum		diff = DirectFunctionCall2(time_mi_time,
145 										   PG_GETARG_DATUM(0),
146 										   PG_GETARG_DATUM(1));
147 
148 	PG_RETURN_INTERVAL_P(abs_interval(DatumGetIntervalP(diff)));
149 }
150 
151 
152 /**************************************************
153  * time ops
154  **************************************************/
155 
156 
157 
158 Datum
159 gbt_time_compress(PG_FUNCTION_ARGS)
160 {
161 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
162 
163 	PG_RETURN_POINTER(gbt_num_compress(entry, &tinfo));
164 }
165 
166 
167 Datum
168 gbt_timetz_compress(PG_FUNCTION_ARGS)
169 {
170 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
171 	GISTENTRY  *retval;
172 
173 	if (entry->leafkey)
174 	{
175 		timeKEY    *r = (timeKEY *) palloc(sizeof(timeKEY));
176 		TimeTzADT  *tz = DatumGetTimeTzADTP(entry->key);
177 		TimeADT		tmp;
178 
179 		retval = palloc(sizeof(GISTENTRY));
180 
181 		/* We are using the time + zone only to compress */
182 		tmp = tz->time + (tz->zone * INT64CONST(1000000));
183 		r->lower = r->upper = tmp;
184 		gistentryinit(*retval, PointerGetDatum(r),
185 					  entry->rel, entry->page,
186 					  entry->offset, false);
187 	}
188 	else
189 		retval = entry;
190 	PG_RETURN_POINTER(retval);
191 }
192 
193 Datum
194 gbt_time_fetch(PG_FUNCTION_ARGS)
195 {
196 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
197 
198 	PG_RETURN_POINTER(gbt_num_fetch(entry, &tinfo));
199 }
200 
201 Datum
202 gbt_time_consistent(PG_FUNCTION_ARGS)
203 {
204 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
205 	TimeADT		query = PG_GETARG_TIMEADT(1);
206 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
207 
208 	/* Oid		subtype = PG_GETARG_OID(3); */
209 	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
210 	timeKEY    *kkk = (timeKEY *) DatumGetPointer(entry->key);
211 	GBT_NUMKEY_R key;
212 
213 	/* All cases served by this function are exact */
214 	*recheck = false;
215 
216 	key.lower = (GBT_NUMKEY *) &kkk->lower;
217 	key.upper = (GBT_NUMKEY *) &kkk->upper;
218 
219 	PG_RETURN_BOOL(
220 				   gbt_num_consistent(&key, (void *) &query, &strategy, GIST_LEAF(entry), &tinfo, fcinfo->flinfo)
221 		);
222 }
223 
224 Datum
225 gbt_time_distance(PG_FUNCTION_ARGS)
226 {
227 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
228 	TimeADT		query = PG_GETARG_TIMEADT(1);
229 
230 	/* Oid		subtype = PG_GETARG_OID(3); */
231 	timeKEY    *kkk = (timeKEY *) DatumGetPointer(entry->key);
232 	GBT_NUMKEY_R key;
233 
234 	key.lower = (GBT_NUMKEY *) &kkk->lower;
235 	key.upper = (GBT_NUMKEY *) &kkk->upper;
236 
237 	PG_RETURN_FLOAT8(
238 					 gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo, fcinfo->flinfo)
239 		);
240 }
241 
242 Datum
243 gbt_timetz_consistent(PG_FUNCTION_ARGS)
244 {
245 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
246 	TimeTzADT  *query = PG_GETARG_TIMETZADT_P(1);
247 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
248 
249 	/* Oid		subtype = PG_GETARG_OID(3); */
250 	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
251 	timeKEY    *kkk = (timeKEY *) DatumGetPointer(entry->key);
252 	TimeADT		qqq;
253 	GBT_NUMKEY_R key;
254 
255 	/* All cases served by this function are inexact */
256 	*recheck = true;
257 
258 	qqq = query->time + (query->zone * INT64CONST(1000000));
259 
260 	key.lower = (GBT_NUMKEY *) &kkk->lower;
261 	key.upper = (GBT_NUMKEY *) &kkk->upper;
262 
263 	PG_RETURN_BOOL(
264 				   gbt_num_consistent(&key, (void *) &qqq, &strategy, GIST_LEAF(entry), &tinfo, fcinfo->flinfo)
265 		);
266 }
267 
268 
269 Datum
270 gbt_time_union(PG_FUNCTION_ARGS)
271 {
272 	GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
273 	void	   *out = palloc(sizeof(timeKEY));
274 
275 	*(int *) PG_GETARG_POINTER(1) = sizeof(timeKEY);
276 	PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo, fcinfo->flinfo));
277 }
278 
279 
280 Datum
281 gbt_time_penalty(PG_FUNCTION_ARGS)
282 {
283 	timeKEY    *origentry = (timeKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key);
284 	timeKEY    *newentry = (timeKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key);
285 	float	   *result = (float *) PG_GETARG_POINTER(2);
286 	Interval   *intr;
287 	double		res;
288 	double		res2;
289 
290 	intr = DatumGetIntervalP(DirectFunctionCall2(
291 												 time_mi_time,
292 												 TimeADTGetDatumFast(newentry->upper),
293 												 TimeADTGetDatumFast(origentry->upper)));
294 	res = INTERVAL_TO_SEC(intr);
295 	res = Max(res, 0);
296 
297 	intr = DatumGetIntervalP(DirectFunctionCall2(
298 												 time_mi_time,
299 												 TimeADTGetDatumFast(origentry->lower),
300 												 TimeADTGetDatumFast(newentry->lower)));
301 	res2 = INTERVAL_TO_SEC(intr);
302 	res2 = Max(res2, 0);
303 
304 	res += res2;
305 
306 	*result = 0.0;
307 
308 	if (res > 0)
309 	{
310 		intr = DatumGetIntervalP(DirectFunctionCall2(
311 													 time_mi_time,
312 													 TimeADTGetDatumFast(origentry->upper),
313 													 TimeADTGetDatumFast(origentry->lower)));
314 		*result += FLT_MIN;
315 		*result += (float) (res / (res + INTERVAL_TO_SEC(intr)));
316 		*result *= (FLT_MAX / (((GISTENTRY *) PG_GETARG_POINTER(0))->rel->rd_att->natts + 1));
317 	}
318 
319 	PG_RETURN_POINTER(result);
320 }
321 
322 
323 Datum
324 gbt_time_picksplit(PG_FUNCTION_ARGS)
325 {
326 	PG_RETURN_POINTER(gbt_num_picksplit(
327 										(GistEntryVector *) PG_GETARG_POINTER(0),
328 										(GIST_SPLITVEC *) PG_GETARG_POINTER(1),
329 										&tinfo, fcinfo->flinfo
330 										));
331 }
332 
333 Datum
334 gbt_time_same(PG_FUNCTION_ARGS)
335 {
336 	timeKEY    *b1 = (timeKEY *) PG_GETARG_POINTER(0);
337 	timeKEY    *b2 = (timeKEY *) PG_GETARG_POINTER(1);
338 	bool	   *result = (bool *) PG_GETARG_POINTER(2);
339 
340 	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
341 	PG_RETURN_POINTER(result);
342 }
343