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/builtins.h"
11 : #include "utils/datetime.h"
12 : #include "utils/float.h"
13 :
14 : typedef struct
15 : {
16 : Timestamp lower;
17 : Timestamp upper;
18 : } tsKEY;
19 :
20 : /*
21 : ** timestamp ops
22 : */
23 6 : PG_FUNCTION_INFO_V1(gbt_ts_compress);
24 4 : PG_FUNCTION_INFO_V1(gbt_tstz_compress);
25 8 : PG_FUNCTION_INFO_V1(gbt_ts_fetch);
26 8 : PG_FUNCTION_INFO_V1(gbt_ts_union);
27 8 : PG_FUNCTION_INFO_V1(gbt_ts_picksplit);
28 6 : PG_FUNCTION_INFO_V1(gbt_ts_consistent);
29 6 : 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 8 : PG_FUNCTION_INFO_V1(gbt_ts_penalty);
33 8 : PG_FUNCTION_INFO_V1(gbt_ts_same);
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 : static bool
44 25024 : gbt_tsgt(const void *a, const void *b, FmgrInfo *flinfo)
45 : {
46 25024 : const Timestamp *aa = (const Timestamp *) a;
47 25024 : const Timestamp *bb = (const Timestamp *) b;
48 :
49 25024 : return DatumGetBool(DirectFunctionCall2(timestamp_gt,
50 : TimestampGetDatumFast(*aa),
51 : TimestampGetDatumFast(*bb)));
52 : }
53 :
54 : static bool
55 3706 : gbt_tsge(const void *a, const void *b, FmgrInfo *flinfo)
56 : {
57 3706 : const Timestamp *aa = (const Timestamp *) a;
58 3706 : const Timestamp *bb = (const Timestamp *) b;
59 :
60 3706 : return DatumGetBool(DirectFunctionCall2(timestamp_ge,
61 : TimestampGetDatumFast(*aa),
62 : TimestampGetDatumFast(*bb)));
63 : }
64 :
65 : static bool
66 12198 : gbt_tseq(const void *a, const void *b, FmgrInfo *flinfo)
67 : {
68 12198 : const Timestamp *aa = (const Timestamp *) a;
69 12198 : const Timestamp *bb = (const Timestamp *) b;
70 :
71 12198 : return DatumGetBool(DirectFunctionCall2(timestamp_eq,
72 : TimestampGetDatumFast(*aa),
73 : TimestampGetDatumFast(*bb)));
74 : }
75 :
76 : static bool
77 3876 : gbt_tsle(const void *a, const void *b, FmgrInfo *flinfo)
78 : {
79 3876 : const Timestamp *aa = (const Timestamp *) a;
80 3876 : const Timestamp *bb = (const Timestamp *) b;
81 :
82 3876 : return DatumGetBool(DirectFunctionCall2(timestamp_le,
83 : TimestampGetDatumFast(*aa),
84 : TimestampGetDatumFast(*bb)));
85 : }
86 :
87 : static bool
88 24654 : gbt_tslt(const void *a, const void *b, FmgrInfo *flinfo)
89 : {
90 24654 : const Timestamp *aa = (const Timestamp *) a;
91 24654 : const Timestamp *bb = (const Timestamp *) b;
92 :
93 24654 : return DatumGetBool(DirectFunctionCall2(timestamp_lt,
94 : TimestampGetDatumFast(*aa),
95 : TimestampGetDatumFast(*bb)));
96 : }
97 :
98 :
99 : static int
100 25330 : gbt_tskey_cmp(const void *a, const void *b, FmgrInfo *flinfo)
101 : {
102 25330 : tsKEY *ia = (tsKEY *) (((const Nsrt *) a)->t);
103 25330 : tsKEY *ib = (tsKEY *) (((const Nsrt *) b)->t);
104 : int res;
105 :
106 25330 : res = DatumGetInt32(DirectFunctionCall2(timestamp_cmp, TimestampGetDatumFast(ia->lower), TimestampGetDatumFast(ib->lower)));
107 25330 : if (res == 0)
108 7338 : return DatumGetInt32(DirectFunctionCall2(timestamp_cmp, TimestampGetDatumFast(ia->upper), TimestampGetDatumFast(ib->upper)));
109 :
110 17992 : return res;
111 : }
112 :
113 : static float8
114 1060 : gbt_ts_dist(const void *a, const void *b, FmgrInfo *flinfo)
115 : {
116 1060 : const Timestamp *aa = (const Timestamp *) a;
117 1060 : const Timestamp *bb = (const Timestamp *) b;
118 : Interval *i;
119 :
120 1060 : if (TIMESTAMP_NOT_FINITE(*aa) || TIMESTAMP_NOT_FINITE(*bb))
121 84 : return get_float8_infinity();
122 :
123 976 : i = DatumGetIntervalP(DirectFunctionCall2(timestamp_mi,
124 : TimestampGetDatumFast(*aa),
125 : TimestampGetDatumFast(*bb)));
126 976 : return (float8) Abs(INTERVAL_TO_SEC(i));
127 : }
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 : /**************************************************
195 : * timestamp ops
196 : **************************************************/
197 :
198 :
199 : static inline Timestamp
200 11334 : tstz_to_ts_gmt(TimestampTz ts)
201 : {
202 : /* No timezone correction is needed, since GMT is offset 0 by definition */
203 11334 : return (Timestamp) ts;
204 : }
205 :
206 :
207 : Datum
208 5236 : gbt_ts_compress(PG_FUNCTION_ARGS)
209 : {
210 5236 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
211 :
212 5236 : PG_RETURN_POINTER(gbt_num_compress(entry, &tinfo));
213 : }
214 :
215 :
216 : Datum
217 1112 : gbt_tstz_compress(PG_FUNCTION_ARGS)
218 : {
219 1112 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
220 : GISTENTRY *retval;
221 :
222 1112 : if (entry->leafkey)
223 : {
224 1098 : tsKEY *r = (tsKEY *) palloc(sizeof(tsKEY));
225 1098 : TimestampTz ts = DatumGetTimestampTz(entry->key);
226 : Timestamp gmt;
227 :
228 1098 : gmt = tstz_to_ts_gmt(ts);
229 :
230 1098 : retval = palloc(sizeof(GISTENTRY));
231 1098 : r->lower = r->upper = gmt;
232 1098 : gistentryinit(*retval, PointerGetDatum(r),
233 : entry->rel, entry->page,
234 : entry->offset, false);
235 : }
236 : else
237 14 : retval = entry;
238 :
239 1112 : PG_RETURN_POINTER(retval);
240 : }
241 :
242 : Datum
243 1052 : gbt_ts_fetch(PG_FUNCTION_ARGS)
244 : {
245 1052 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
246 :
247 1052 : PG_RETURN_POINTER(gbt_num_fetch(entry, &tinfo));
248 : }
249 :
250 : Datum
251 4014 : gbt_ts_consistent(PG_FUNCTION_ARGS)
252 : {
253 4014 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
254 4014 : Timestamp query = PG_GETARG_TIMESTAMP(1);
255 4014 : StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
256 :
257 : /* Oid subtype = PG_GETARG_OID(3); */
258 4014 : bool *recheck = (bool *) PG_GETARG_POINTER(4);
259 4014 : tsKEY *kkk = (tsKEY *) DatumGetPointer(entry->key);
260 : GBT_NUMKEY_R key;
261 :
262 : /* All cases served by this function are exact */
263 4014 : *recheck = false;
264 :
265 4014 : key.lower = (GBT_NUMKEY *) &kkk->lower;
266 4014 : key.upper = (GBT_NUMKEY *) &kkk->upper;
267 :
268 4014 : PG_RETURN_BOOL(
269 : gbt_num_consistent(&key, (void *) &query, &strategy, GIST_LEAF(entry), &tinfo, fcinfo->flinfo)
270 : );
271 : }
272 :
273 : Datum
274 422 : gbt_ts_distance(PG_FUNCTION_ARGS)
275 : {
276 422 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
277 422 : Timestamp query = PG_GETARG_TIMESTAMP(1);
278 :
279 : /* Oid subtype = PG_GETARG_OID(3); */
280 422 : tsKEY *kkk = (tsKEY *) DatumGetPointer(entry->key);
281 : GBT_NUMKEY_R key;
282 :
283 422 : key.lower = (GBT_NUMKEY *) &kkk->lower;
284 422 : key.upper = (GBT_NUMKEY *) &kkk->upper;
285 :
286 422 : PG_RETURN_FLOAT8(
287 : gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo, fcinfo->flinfo)
288 : );
289 : }
290 :
291 : Datum
292 9594 : gbt_tstz_consistent(PG_FUNCTION_ARGS)
293 : {
294 9594 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
295 9594 : TimestampTz query = PG_GETARG_TIMESTAMPTZ(1);
296 9594 : StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
297 :
298 : /* Oid subtype = PG_GETARG_OID(3); */
299 9594 : bool *recheck = (bool *) PG_GETARG_POINTER(4);
300 9594 : char *kkk = (char *) DatumGetPointer(entry->key);
301 : GBT_NUMKEY_R key;
302 : Timestamp qqq;
303 :
304 : /* All cases served by this function are exact */
305 9594 : *recheck = false;
306 :
307 9594 : key.lower = (GBT_NUMKEY *) &kkk[0];
308 9594 : key.upper = (GBT_NUMKEY *) &kkk[MAXALIGN(tinfo.size)];
309 9594 : qqq = tstz_to_ts_gmt(query);
310 :
311 9594 : PG_RETURN_BOOL(
312 : gbt_num_consistent(&key, (void *) &qqq, &strategy, GIST_LEAF(entry), &tinfo, fcinfo->flinfo)
313 : );
314 : }
315 :
316 : Datum
317 642 : gbt_tstz_distance(PG_FUNCTION_ARGS)
318 : {
319 642 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
320 642 : TimestampTz query = PG_GETARG_TIMESTAMPTZ(1);
321 :
322 : /* Oid subtype = PG_GETARG_OID(3); */
323 642 : char *kkk = (char *) DatumGetPointer(entry->key);
324 : GBT_NUMKEY_R key;
325 : Timestamp qqq;
326 :
327 642 : key.lower = (GBT_NUMKEY *) &kkk[0];
328 642 : key.upper = (GBT_NUMKEY *) &kkk[MAXALIGN(tinfo.size)];
329 642 : qqq = tstz_to_ts_gmt(query);
330 :
331 642 : PG_RETURN_FLOAT8(
332 : gbt_num_distance(&key, (void *) &qqq, GIST_LEAF(entry), &tinfo, fcinfo->flinfo)
333 : );
334 : }
335 :
336 :
337 : Datum
338 4994 : gbt_ts_union(PG_FUNCTION_ARGS)
339 : {
340 4994 : GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
341 4994 : void *out = palloc(sizeof(tsKEY));
342 :
343 4994 : *(int *) PG_GETARG_POINTER(1) = sizeof(tsKEY);
344 4994 : PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo, fcinfo->flinfo));
345 : }
346 :
347 :
348 : #define penalty_check_max_float(val) do { \
349 : if ( val > FLT_MAX ) \
350 : val = FLT_MAX; \
351 : if ( val < -FLT_MAX ) \
352 : val = -FLT_MAX; \
353 : } while(false);
354 :
355 :
356 : Datum
357 9720 : gbt_ts_penalty(PG_FUNCTION_ARGS)
358 : {
359 9720 : tsKEY *origentry = (tsKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key);
360 9720 : tsKEY *newentry = (tsKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key);
361 9720 : float *result = (float *) PG_GETARG_POINTER(2);
362 :
363 : double orgdbl[2],
364 : newdbl[2];
365 :
366 : /*
367 : * We are always using "double" timestamps here. Precision should be good
368 : * enough.
369 : */
370 9720 : orgdbl[0] = ((double) origentry->lower);
371 9720 : orgdbl[1] = ((double) origentry->upper);
372 9720 : newdbl[0] = ((double) newentry->lower);
373 9720 : newdbl[1] = ((double) newentry->upper);
374 :
375 9720 : penalty_check_max_float(orgdbl[0]);
376 9720 : penalty_check_max_float(orgdbl[1]);
377 9720 : penalty_check_max_float(newdbl[0]);
378 9720 : penalty_check_max_float(newdbl[1]);
379 :
380 9720 : penalty_num(result, orgdbl[0], orgdbl[1], newdbl[0], newdbl[1]);
381 :
382 9720 : PG_RETURN_POINTER(result);
383 :
384 : }
385 :
386 :
387 : Datum
388 46 : gbt_ts_picksplit(PG_FUNCTION_ARGS)
389 : {
390 46 : PG_RETURN_POINTER(gbt_num_picksplit(
391 : (GistEntryVector *) PG_GETARG_POINTER(0),
392 : (GIST_SPLITVEC *) PG_GETARG_POINTER(1),
393 : &tinfo, fcinfo->flinfo
394 : ));
395 : }
396 :
397 : Datum
398 4948 : gbt_ts_same(PG_FUNCTION_ARGS)
399 : {
400 4948 : tsKEY *b1 = (tsKEY *) PG_GETARG_POINTER(0);
401 4948 : tsKEY *b2 = (tsKEY *) PG_GETARG_POINTER(1);
402 4948 : bool *result = (bool *) PG_GETARG_POINTER(2);
403 :
404 4948 : *result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
405 4948 : PG_RETURN_POINTER(result);
406 : }
|