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