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 :
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 25030 : gbt_tsgt(const void *a, const void *b, FmgrInfo *flinfo)
45 : {
46 25030 : const Timestamp *aa = (const Timestamp *) a;
47 25030 : const Timestamp *bb = (const Timestamp *) b;
48 :
49 25030 : return DatumGetBool(DirectFunctionCall2(timestamp_gt,
50 : TimestampGetDatumFast(*aa),
51 : TimestampGetDatumFast(*bb)));
52 : }
53 :
54 : static bool
55 3708 : gbt_tsge(const void *a, const void *b, FmgrInfo *flinfo)
56 : {
57 3708 : const Timestamp *aa = (const Timestamp *) a;
58 3708 : const Timestamp *bb = (const Timestamp *) b;
59 :
60 3708 : return DatumGetBool(DirectFunctionCall2(timestamp_ge,
61 : TimestampGetDatumFast(*aa),
62 : TimestampGetDatumFast(*bb)));
63 : }
64 :
65 : static bool
66 12192 : gbt_tseq(const void *a, const void *b, FmgrInfo *flinfo)
67 : {
68 12192 : const Timestamp *aa = (const Timestamp *) a;
69 12192 : const Timestamp *bb = (const Timestamp *) b;
70 :
71 12192 : return DatumGetBool(DirectFunctionCall2(timestamp_eq,
72 : TimestampGetDatumFast(*aa),
73 : TimestampGetDatumFast(*bb)));
74 : }
75 :
76 : static bool
77 3558 : gbt_tsle(const void *a, const void *b, FmgrInfo *flinfo)
78 : {
79 3558 : const Timestamp *aa = (const Timestamp *) a;
80 3558 : const Timestamp *bb = (const Timestamp *) b;
81 :
82 3558 : 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 25316 : gbt_tskey_cmp(const void *a, const void *b, FmgrInfo *flinfo)
101 : {
102 25316 : tsKEY *ia = (tsKEY *) (((const Nsrt *) a)->t);
103 25316 : tsKEY *ib = (tsKEY *) (((const Nsrt *) b)->t);
104 : int res;
105 :
106 25316 : res = DatumGetInt32(DirectFunctionCall2(timestamp_cmp, TimestampGetDatumFast(ia->lower), TimestampGetDatumFast(ib->lower)));
107 25316 : if (res == 0)
108 7342 : return DatumGetInt32(DirectFunctionCall2(timestamp_cmp, TimestampGetDatumFast(ia->upper), TimestampGetDatumFast(ib->upper)));
109 :
110 17974 : return res;
111 : }
112 :
113 : static float8
114 742 : gbt_ts_dist(const void *a, const void *b, FmgrInfo *flinfo)
115 : {
116 742 : const Timestamp *aa = (const Timestamp *) a;
117 742 : const Timestamp *bb = (const Timestamp *) b;
118 : Interval *i;
119 :
120 742 : if (TIMESTAMP_NOT_FINITE(*aa) || TIMESTAMP_NOT_FINITE(*bb))
121 60 : return get_float8_infinity();
122 :
123 682 : i = DatumGetIntervalP(DirectFunctionCall2(timestamp_mi,
124 : TimestampGetDatumFast(*aa),
125 : TimestampGetDatumFast(*bb)));
126 682 : return fabs(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 11082 : tstz_to_ts_gmt(TimestampTz ts)
201 : {
202 : /* No timezone correction is needed, since GMT is offset 0 by definition */
203 11082 : 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 1114 : gbt_tstz_compress(PG_FUNCTION_ARGS)
218 : {
219 1114 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
220 : GISTENTRY *retval;
221 :
222 1114 : 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 16 : retval = entry;
238 :
239 1114 : PG_RETURN_POINTER(retval);
240 : }
241 :
242 : Datum
243 734 : gbt_ts_fetch(PG_FUNCTION_ARGS)
244 : {
245 734 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
246 :
247 734 : PG_RETURN_POINTER(gbt_num_fetch(entry, &tinfo));
248 : }
249 :
250 : Datum
251 3972 : gbt_ts_consistent(PG_FUNCTION_ARGS)
252 : {
253 3972 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
254 3972 : Timestamp query = PG_GETARG_TIMESTAMP(1);
255 3972 : StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
256 :
257 : /* Oid subtype = PG_GETARG_OID(3); */
258 3972 : bool *recheck = (bool *) PG_GETARG_POINTER(4);
259 3972 : tsKEY *kkk = (tsKEY *) DatumGetPointer(entry->key);
260 : GBT_NUMKEY_R key;
261 :
262 : /* All cases served by this function are exact */
263 3972 : *recheck = false;
264 :
265 3972 : key.lower = (GBT_NUMKEY *) &kkk->lower;
266 3972 : key.upper = (GBT_NUMKEY *) &kkk->upper;
267 :
268 3972 : PG_RETURN_BOOL(gbt_num_consistent(&key, &query, &strategy,
269 : GIST_LEAF(entry), &tinfo, fcinfo->flinfo));
270 : }
271 :
272 : Datum
273 410 : gbt_ts_distance(PG_FUNCTION_ARGS)
274 : {
275 410 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
276 410 : Timestamp query = PG_GETARG_TIMESTAMP(1);
277 :
278 : /* Oid subtype = PG_GETARG_OID(3); */
279 410 : tsKEY *kkk = (tsKEY *) DatumGetPointer(entry->key);
280 : GBT_NUMKEY_R key;
281 :
282 410 : key.lower = (GBT_NUMKEY *) &kkk->lower;
283 410 : key.upper = (GBT_NUMKEY *) &kkk->upper;
284 :
285 410 : PG_RETURN_FLOAT8(gbt_num_distance(&key, &query, GIST_LEAF(entry),
286 : &tinfo, fcinfo->flinfo));
287 : }
288 :
289 : Datum
290 9648 : gbt_tstz_consistent(PG_FUNCTION_ARGS)
291 : {
292 9648 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
293 9648 : TimestampTz query = PG_GETARG_TIMESTAMPTZ(1);
294 9648 : StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
295 :
296 : /* Oid subtype = PG_GETARG_OID(3); */
297 9648 : bool *recheck = (bool *) PG_GETARG_POINTER(4);
298 9648 : char *kkk = (char *) DatumGetPointer(entry->key);
299 : GBT_NUMKEY_R key;
300 : Timestamp qqq;
301 :
302 : /* All cases served by this function are exact */
303 9648 : *recheck = false;
304 :
305 9648 : key.lower = (GBT_NUMKEY *) &kkk[0];
306 9648 : key.upper = (GBT_NUMKEY *) &kkk[MAXALIGN(tinfo.size)];
307 9648 : qqq = tstz_to_ts_gmt(query);
308 :
309 9648 : PG_RETURN_BOOL(gbt_num_consistent(&key, &qqq, &strategy,
310 : GIST_LEAF(entry), &tinfo, fcinfo->flinfo));
311 : }
312 :
313 : Datum
314 336 : gbt_tstz_distance(PG_FUNCTION_ARGS)
315 : {
316 336 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
317 336 : TimestampTz query = PG_GETARG_TIMESTAMPTZ(1);
318 :
319 : /* Oid subtype = PG_GETARG_OID(3); */
320 336 : char *kkk = (char *) DatumGetPointer(entry->key);
321 : GBT_NUMKEY_R key;
322 : Timestamp qqq;
323 :
324 336 : key.lower = (GBT_NUMKEY *) &kkk[0];
325 336 : key.upper = (GBT_NUMKEY *) &kkk[MAXALIGN(tinfo.size)];
326 336 : qqq = tstz_to_ts_gmt(query);
327 :
328 336 : PG_RETURN_FLOAT8(gbt_num_distance(&key, &qqq, GIST_LEAF(entry),
329 : &tinfo, fcinfo->flinfo));
330 : }
331 :
332 :
333 : Datum
334 4994 : gbt_ts_union(PG_FUNCTION_ARGS)
335 : {
336 4994 : GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
337 4994 : void *out = palloc(sizeof(tsKEY));
338 :
339 4994 : *(int *) PG_GETARG_POINTER(1) = sizeof(tsKEY);
340 4994 : PG_RETURN_POINTER(gbt_num_union(out, entryvec, &tinfo, fcinfo->flinfo));
341 : }
342 :
343 :
344 : #define penalty_check_max_float(val) \
345 : do { \
346 : if ( val > FLT_MAX ) \
347 : val = FLT_MAX; \
348 : if ( val < -FLT_MAX ) \
349 : val = -FLT_MAX; \
350 : } while (0)
351 :
352 :
353 : Datum
354 9878 : gbt_ts_penalty(PG_FUNCTION_ARGS)
355 : {
356 9878 : tsKEY *origentry = (tsKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key);
357 9878 : tsKEY *newentry = (tsKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key);
358 9878 : float *result = (float *) PG_GETARG_POINTER(2);
359 :
360 : double orgdbl[2],
361 : newdbl[2];
362 :
363 : /*
364 : * We are always using "double" timestamps here. Precision should be good
365 : * enough.
366 : */
367 9878 : orgdbl[0] = ((double) origentry->lower);
368 9878 : orgdbl[1] = ((double) origentry->upper);
369 9878 : newdbl[0] = ((double) newentry->lower);
370 9878 : newdbl[1] = ((double) newentry->upper);
371 :
372 9878 : penalty_check_max_float(orgdbl[0]);
373 9878 : penalty_check_max_float(orgdbl[1]);
374 9878 : penalty_check_max_float(newdbl[0]);
375 9878 : penalty_check_max_float(newdbl[1]);
376 :
377 9878 : penalty_num(result, orgdbl[0], orgdbl[1], newdbl[0], newdbl[1]);
378 :
379 9878 : PG_RETURN_POINTER(result);
380 : }
381 :
382 :
383 : Datum
384 46 : gbt_ts_picksplit(PG_FUNCTION_ARGS)
385 : {
386 46 : PG_RETURN_POINTER(gbt_num_picksplit((GistEntryVector *) PG_GETARG_POINTER(0),
387 : (GIST_SPLITVEC *) PG_GETARG_POINTER(1),
388 : &tinfo, fcinfo->flinfo));
389 : }
390 :
391 : Datum
392 4948 : gbt_ts_same(PG_FUNCTION_ARGS)
393 : {
394 4948 : tsKEY *b1 = (tsKEY *) PG_GETARG_POINTER(0);
395 4948 : tsKEY *b2 = (tsKEY *) PG_GETARG_POINTER(1);
396 4948 : bool *result = (bool *) PG_GETARG_POINTER(2);
397 :
398 4948 : *result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
399 4948 : PG_RETURN_POINTER(result);
400 : }
|