Line data Source code
1 : /*
2 : * contrib/btree_gist/btree_ts.c
3 : */
4 : #include "postgres.h"
5 :
6 : #include <limits.h>
7 :
8 : #include "btree_gist.h"
9 : #include "btree_utils_num.h"
10 : #include "utils/fmgrprotos.h"
11 : #include "utils/timestamp.h"
12 : #include "utils/float.h"
13 : #include "utils/sortsupport.h"
14 :
15 : typedef struct
16 : {
17 : Timestamp lower;
18 : Timestamp upper;
19 : } tsKEY;
20 :
21 : /* GiST support functions */
22 6 : PG_FUNCTION_INFO_V1(gbt_ts_compress);
23 4 : PG_FUNCTION_INFO_V1(gbt_tstz_compress);
24 8 : PG_FUNCTION_INFO_V1(gbt_ts_fetch);
25 8 : PG_FUNCTION_INFO_V1(gbt_ts_union);
26 8 : PG_FUNCTION_INFO_V1(gbt_ts_picksplit);
27 6 : PG_FUNCTION_INFO_V1(gbt_ts_consistent);
28 6 : PG_FUNCTION_INFO_V1(gbt_ts_distance);
29 4 : PG_FUNCTION_INFO_V1(gbt_tstz_consistent);
30 4 : PG_FUNCTION_INFO_V1(gbt_tstz_distance);
31 8 : PG_FUNCTION_INFO_V1(gbt_ts_penalty);
32 8 : PG_FUNCTION_INFO_V1(gbt_ts_same);
33 8 : PG_FUNCTION_INFO_V1(gbt_ts_sortsupport);
34 :
35 :
36 : #ifdef USE_FLOAT8_BYVAL
37 : #define TimestampGetDatumFast(X) TimestampGetDatum(X)
38 : #else
39 : #define TimestampGetDatumFast(X) PointerGetDatum(&(X))
40 : #endif
41 :
42 :
43 : /* define for comparison */
44 :
45 : static bool
46 25938 : gbt_tsgt(const void *a, const void *b, FmgrInfo *flinfo)
47 : {
48 25938 : const Timestamp *aa = (const Timestamp *) a;
49 25938 : const Timestamp *bb = (const Timestamp *) b;
50 :
51 25938 : return DatumGetBool(DirectFunctionCall2(timestamp_gt,
52 : TimestampGetDatumFast(*aa),
53 : TimestampGetDatumFast(*bb)));
54 : }
55 :
56 : static bool
57 4690 : gbt_tsge(const void *a, const void *b, FmgrInfo *flinfo)
58 : {
59 4690 : const Timestamp *aa = (const Timestamp *) a;
60 4690 : const Timestamp *bb = (const Timestamp *) b;
61 :
62 4690 : return DatumGetBool(DirectFunctionCall2(timestamp_ge,
63 : TimestampGetDatumFast(*aa),
64 : TimestampGetDatumFast(*bb)));
65 : }
66 :
67 : static bool
68 10370 : gbt_tseq(const void *a, const void *b, FmgrInfo *flinfo)
69 : {
70 10370 : const Timestamp *aa = (const Timestamp *) a;
71 10370 : const Timestamp *bb = (const Timestamp *) b;
72 :
73 10370 : return DatumGetBool(DirectFunctionCall2(timestamp_eq,
74 : TimestampGetDatumFast(*aa),
75 : TimestampGetDatumFast(*bb)));
76 : }
77 :
78 : static bool
79 3974 : gbt_tsle(const void *a, const void *b, FmgrInfo *flinfo)
80 : {
81 3974 : const Timestamp *aa = (const Timestamp *) a;
82 3974 : const Timestamp *bb = (const Timestamp *) b;
83 :
84 3974 : return DatumGetBool(DirectFunctionCall2(timestamp_le,
85 : TimestampGetDatumFast(*aa),
86 : TimestampGetDatumFast(*bb)));
87 : }
88 :
89 : static bool
90 24862 : gbt_tslt(const void *a, const void *b, FmgrInfo *flinfo)
91 : {
92 24862 : const Timestamp *aa = (const Timestamp *) a;
93 24862 : const Timestamp *bb = (const Timestamp *) b;
94 :
95 24862 : return DatumGetBool(DirectFunctionCall2(timestamp_lt,
96 : TimestampGetDatumFast(*aa),
97 : TimestampGetDatumFast(*bb)));
98 : }
99 :
100 : static int
101 9632 : gbt_tskey_cmp(const void *a, const void *b, FmgrInfo *flinfo)
102 : {
103 9632 : tsKEY *ia = (tsKEY *) (((const Nsrt *) a)->t);
104 9632 : tsKEY *ib = (tsKEY *) (((const Nsrt *) b)->t);
105 : int res;
106 :
107 9632 : res = DatumGetInt32(DirectFunctionCall2(timestamp_cmp, TimestampGetDatumFast(ia->lower), TimestampGetDatumFast(ib->lower)));
108 9632 : if (res == 0)
109 7458 : return DatumGetInt32(DirectFunctionCall2(timestamp_cmp, TimestampGetDatumFast(ia->upper), TimestampGetDatumFast(ib->upper)));
110 :
111 2174 : return res;
112 : }
113 :
114 : static float8
115 1122 : gbt_ts_dist(const void *a, const void *b, FmgrInfo *flinfo)
116 : {
117 1122 : const Timestamp *aa = (const Timestamp *) a;
118 1122 : const Timestamp *bb = (const Timestamp *) b;
119 : Interval *i;
120 :
121 1122 : if (TIMESTAMP_NOT_FINITE(*aa) || TIMESTAMP_NOT_FINITE(*bb))
122 40 : return get_float8_infinity();
123 :
124 1082 : i = DatumGetIntervalP(DirectFunctionCall2(timestamp_mi,
125 : TimestampGetDatumFast(*aa),
126 : TimestampGetDatumFast(*bb)));
127 1082 : return fabs(INTERVAL_TO_SEC(i));
128 : }
129 :
130 : static const gbtree_ninfo tinfo =
131 : {
132 : gbt_t_ts,
133 : sizeof(Timestamp),
134 : 16, /* sizeof(gbtreekey16) */
135 : gbt_tsgt,
136 : gbt_tsge,
137 : gbt_tseq,
138 : gbt_tsle,
139 : gbt_tslt,
140 : gbt_tskey_cmp,
141 : gbt_ts_dist
142 : };
143 :
144 :
145 4 : PG_FUNCTION_INFO_V1(ts_dist);
146 : Datum
147 1142 : ts_dist(PG_FUNCTION_ARGS)
148 : {
149 1142 : Timestamp a = PG_GETARG_TIMESTAMP(0);
150 1142 : Timestamp b = PG_GETARG_TIMESTAMP(1);
151 : Interval *r;
152 :
153 1142 : if (TIMESTAMP_NOT_FINITE(a) || TIMESTAMP_NOT_FINITE(b))
154 : {
155 48 : Interval *p = palloc(sizeof(Interval));
156 :
157 48 : p->day = INT_MAX;
158 48 : p->month = INT_MAX;
159 48 : p->time = PG_INT64_MAX;
160 48 : PG_RETURN_INTERVAL_P(p);
161 : }
162 : else
163 1094 : r = DatumGetIntervalP(DirectFunctionCall2(timestamp_mi,
164 : PG_GETARG_DATUM(0),
165 : PG_GETARG_DATUM(1)));
166 1094 : PG_RETURN_INTERVAL_P(abs_interval(r));
167 : }
168 :
169 4 : PG_FUNCTION_INFO_V1(tstz_dist);
170 : Datum
171 1104 : tstz_dist(PG_FUNCTION_ARGS)
172 : {
173 1104 : TimestampTz a = PG_GETARG_TIMESTAMPTZ(0);
174 1104 : TimestampTz b = PG_GETARG_TIMESTAMPTZ(1);
175 : Interval *r;
176 :
177 1104 : if (TIMESTAMP_NOT_FINITE(a) || TIMESTAMP_NOT_FINITE(b))
178 : {
179 36 : Interval *p = palloc(sizeof(Interval));
180 :
181 36 : p->day = INT_MAX;
182 36 : p->month = INT_MAX;
183 36 : p->time = PG_INT64_MAX;
184 36 : PG_RETURN_INTERVAL_P(p);
185 : }
186 :
187 1068 : r = DatumGetIntervalP(DirectFunctionCall2(timestamp_mi,
188 : PG_GETARG_DATUM(0),
189 : PG_GETARG_DATUM(1)));
190 1068 : PG_RETURN_INTERVAL_P(abs_interval(r));
191 : }
192 :
193 : /**************************************************
194 : * GiST support functions
195 : **************************************************/
196 :
197 : static inline Timestamp
198 13250 : tstz_to_ts_gmt(TimestampTz ts)
199 : {
200 : /* No timezone correction is needed, since GMT is offset 0 by definition */
201 13250 : return (Timestamp) ts;
202 : }
203 :
204 :
205 : Datum
206 5224 : gbt_ts_compress(PG_FUNCTION_ARGS)
207 : {
208 5224 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
209 :
210 5224 : PG_RETURN_POINTER(gbt_num_compress(entry, &tinfo));
211 : }
212 :
213 : Datum
214 1102 : gbt_tstz_compress(PG_FUNCTION_ARGS)
215 : {
216 1102 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
217 : GISTENTRY *retval;
218 :
219 1102 : if (entry->leafkey)
220 : {
221 1098 : tsKEY *r = (tsKEY *) palloc(sizeof(tsKEY));
222 1098 : TimestampTz ts = DatumGetTimestampTz(entry->key);
223 : Timestamp gmt;
224 :
225 1098 : gmt = tstz_to_ts_gmt(ts);
226 :
227 1098 : retval = palloc(sizeof(GISTENTRY));
228 1098 : r->lower = r->upper = gmt;
229 1098 : gistentryinit(*retval, PointerGetDatum(r),
230 : entry->rel, entry->page,
231 : entry->offset, false);
232 : }
233 : else
234 4 : retval = entry;
235 :
236 1102 : PG_RETURN_POINTER(retval);
237 : }
238 :
239 : Datum
240 1118 : gbt_ts_fetch(PG_FUNCTION_ARGS)
241 : {
242 1118 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
243 :
244 1118 : PG_RETURN_POINTER(gbt_num_fetch(entry, &tinfo));
245 : }
246 :
247 : Datum
248 4408 : gbt_ts_consistent(PG_FUNCTION_ARGS)
249 : {
250 4408 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
251 4408 : Timestamp query = PG_GETARG_TIMESTAMP(1);
252 4408 : StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
253 :
254 : /* Oid subtype = PG_GETARG_OID(3); */
255 4408 : bool *recheck = (bool *) PG_GETARG_POINTER(4);
256 4408 : tsKEY *kkk = (tsKEY *) DatumGetPointer(entry->key);
257 : GBT_NUMKEY_R key;
258 :
259 : /* All cases served by this function are exact */
260 4408 : *recheck = false;
261 :
262 4408 : key.lower = (GBT_NUMKEY *) &kkk->lower;
263 4408 : key.upper = (GBT_NUMKEY *) &kkk->upper;
264 :
265 4408 : PG_RETURN_BOOL(gbt_num_consistent(&key, &query, &strategy,
266 : GIST_LEAF(entry), &tinfo, fcinfo->flinfo));
267 : }
268 :
269 : Datum
270 572 : gbt_ts_distance(PG_FUNCTION_ARGS)
271 : {
272 572 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
273 572 : Timestamp query = PG_GETARG_TIMESTAMP(1);
274 :
275 : /* Oid subtype = PG_GETARG_OID(3); */
276 572 : tsKEY *kkk = (tsKEY *) DatumGetPointer(entry->key);
277 : GBT_NUMKEY_R key;
278 :
279 572 : key.lower = (GBT_NUMKEY *) &kkk->lower;
280 572 : key.upper = (GBT_NUMKEY *) &kkk->upper;
281 :
282 572 : PG_RETURN_FLOAT8(gbt_num_distance(&key, &query, GIST_LEAF(entry),
283 : &tinfo, fcinfo->flinfo));
284 : }
285 :
286 : Datum
287 11598 : gbt_tstz_consistent(PG_FUNCTION_ARGS)
288 : {
289 11598 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
290 11598 : TimestampTz query = PG_GETARG_TIMESTAMPTZ(1);
291 11598 : StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
292 :
293 : /* Oid subtype = PG_GETARG_OID(3); */
294 11598 : bool *recheck = (bool *) PG_GETARG_POINTER(4);
295 11598 : char *kkk = (char *) DatumGetPointer(entry->key);
296 : GBT_NUMKEY_R key;
297 : Timestamp qqq;
298 :
299 : /* All cases served by this function are exact */
300 11598 : *recheck = false;
301 :
302 11598 : key.lower = (GBT_NUMKEY *) &kkk[0];
303 11598 : key.upper = (GBT_NUMKEY *) &kkk[MAXALIGN(tinfo.size)];
304 11598 : qqq = tstz_to_ts_gmt(query);
305 :
306 11598 : PG_RETURN_BOOL(gbt_num_consistent(&key, &qqq, &strategy,
307 : GIST_LEAF(entry), &tinfo, fcinfo->flinfo));
308 : }
309 :
310 : Datum
311 554 : gbt_tstz_distance(PG_FUNCTION_ARGS)
312 : {
313 554 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
314 554 : TimestampTz query = PG_GETARG_TIMESTAMPTZ(1);
315 :
316 : /* Oid subtype = PG_GETARG_OID(3); */
317 554 : char *kkk = (char *) DatumGetPointer(entry->key);
318 : GBT_NUMKEY_R key;
319 : Timestamp qqq;
320 :
321 554 : key.lower = (GBT_NUMKEY *) &kkk[0];
322 554 : key.upper = (GBT_NUMKEY *) &kkk[MAXALIGN(tinfo.size)];
323 554 : qqq = tstz_to_ts_gmt(query);
324 :
325 554 : PG_RETURN_FLOAT8(gbt_num_distance(&key, &qqq, GIST_LEAF(entry),
326 : &tinfo, fcinfo->flinfo));
327 : }
328 :
329 :
330 : Datum
331 3716 : gbt_ts_union(PG_FUNCTION_ARGS)
332 : {
333 3716 : GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
334 3716 : void *out = palloc(sizeof(tsKEY));
335 :
336 3716 : *(int *) PG_GETARG_POINTER(1) = sizeof(tsKEY);
337 3716 : PG_RETURN_POINTER(gbt_num_union(out, entryvec, &tinfo, fcinfo->flinfo));
338 : }
339 :
340 :
341 : #define penalty_check_max_float(val) \
342 : do { \
343 : if ( val > FLT_MAX ) \
344 : val = FLT_MAX; \
345 : if ( val < -FLT_MAX ) \
346 : val = -FLT_MAX; \
347 : } while (0)
348 :
349 :
350 : Datum
351 8248 : gbt_ts_penalty(PG_FUNCTION_ARGS)
352 : {
353 8248 : tsKEY *origentry = (tsKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key);
354 8248 : tsKEY *newentry = (tsKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key);
355 8248 : float *result = (float *) PG_GETARG_POINTER(2);
356 :
357 : double orgdbl[2],
358 : newdbl[2];
359 :
360 : /*
361 : * We are always using "double" timestamps here. Precision should be good
362 : * enough.
363 : */
364 8248 : orgdbl[0] = ((double) origentry->lower);
365 8248 : orgdbl[1] = ((double) origentry->upper);
366 8248 : newdbl[0] = ((double) newentry->lower);
367 8248 : newdbl[1] = ((double) newentry->upper);
368 :
369 8248 : penalty_check_max_float(orgdbl[0]);
370 8248 : penalty_check_max_float(orgdbl[1]);
371 8248 : penalty_check_max_float(newdbl[0]);
372 8248 : penalty_check_max_float(newdbl[1]);
373 :
374 8248 : penalty_num(result, orgdbl[0], orgdbl[1], newdbl[0], newdbl[1]);
375 :
376 8248 : PG_RETURN_POINTER(result);
377 : }
378 :
379 :
380 : Datum
381 42 : gbt_ts_picksplit(PG_FUNCTION_ARGS)
382 : {
383 42 : PG_RETURN_POINTER(gbt_num_picksplit((GistEntryVector *) PG_GETARG_POINTER(0),
384 : (GIST_SPLITVEC *) PG_GETARG_POINTER(1),
385 : &tinfo, fcinfo->flinfo));
386 : }
387 :
388 : Datum
389 3670 : gbt_ts_same(PG_FUNCTION_ARGS)
390 : {
391 3670 : tsKEY *b1 = (tsKEY *) PG_GETARG_POINTER(0);
392 3670 : tsKEY *b2 = (tsKEY *) PG_GETARG_POINTER(1);
393 3670 : bool *result = (bool *) PG_GETARG_POINTER(2);
394 :
395 3670 : *result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
396 3670 : PG_RETURN_POINTER(result);
397 : }
398 :
399 : static int
400 22230 : gbt_ts_ssup_cmp(Datum x, Datum y, SortSupport ssup)
401 : {
402 22230 : tsKEY *arg1 = (tsKEY *) DatumGetPointer(x);
403 22230 : tsKEY *arg2 = (tsKEY *) DatumGetPointer(y);
404 :
405 : /* for leaf items we expect lower == upper, so only compare lower */
406 22230 : return DatumGetInt32(DirectFunctionCall2(timestamp_cmp,
407 : TimestampGetDatumFast(arg1->lower),
408 : TimestampGetDatumFast(arg2->lower)));
409 : }
410 :
411 : Datum
412 6 : gbt_ts_sortsupport(PG_FUNCTION_ARGS)
413 : {
414 6 : SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
415 :
416 6 : ssup->comparator = gbt_ts_ssup_cmp;
417 6 : ssup->ssup_extra = NULL;
418 :
419 6 : PG_RETURN_VOID();
420 : }
|