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