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