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