1 /*
2 * contrib/btree_gist/btree_time.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/date.h"
10 #include "utils/timestamp.h"
11
12 typedef struct
13 {
14 TimeADT lower;
15 TimeADT upper;
16 } timeKEY;
17
18 /*
19 ** time ops
20 */
21 PG_FUNCTION_INFO_V1(gbt_time_compress);
22 PG_FUNCTION_INFO_V1(gbt_timetz_compress);
23 PG_FUNCTION_INFO_V1(gbt_time_fetch);
24 PG_FUNCTION_INFO_V1(gbt_time_union);
25 PG_FUNCTION_INFO_V1(gbt_time_picksplit);
26 PG_FUNCTION_INFO_V1(gbt_time_consistent);
27 PG_FUNCTION_INFO_V1(gbt_time_distance);
28 PG_FUNCTION_INFO_V1(gbt_timetz_consistent);
29 PG_FUNCTION_INFO_V1(gbt_time_penalty);
30 PG_FUNCTION_INFO_V1(gbt_time_same);
31
32
33 #ifdef USE_FLOAT8_BYVAL
34 #define TimeADTGetDatumFast(X) TimeADTGetDatum(X)
35 #else
36 #define TimeADTGetDatumFast(X) PointerGetDatum(&(X))
37 #endif
38
39
40 static bool
gbt_timegt(const void * a,const void * b,FmgrInfo * flinfo)41 gbt_timegt(const void *a, const void *b, FmgrInfo *flinfo)
42 {
43 const TimeADT *aa = (const TimeADT *) a;
44 const TimeADT *bb = (const TimeADT *) b;
45
46 return DatumGetBool(DirectFunctionCall2(time_gt,
47 TimeADTGetDatumFast(*aa),
48 TimeADTGetDatumFast(*bb)));
49 }
50
51 static bool
gbt_timege(const void * a,const void * b,FmgrInfo * flinfo)52 gbt_timege(const void *a, const void *b, FmgrInfo *flinfo)
53 {
54 const TimeADT *aa = (const TimeADT *) a;
55 const TimeADT *bb = (const TimeADT *) b;
56
57 return DatumGetBool(DirectFunctionCall2(time_ge,
58 TimeADTGetDatumFast(*aa),
59 TimeADTGetDatumFast(*bb)));
60 }
61
62 static bool
gbt_timeeq(const void * a,const void * b,FmgrInfo * flinfo)63 gbt_timeeq(const void *a, const void *b, FmgrInfo *flinfo)
64 {
65 const TimeADT *aa = (const TimeADT *) a;
66 const TimeADT *bb = (const TimeADT *) b;
67
68 return DatumGetBool(DirectFunctionCall2(time_eq,
69 TimeADTGetDatumFast(*aa),
70 TimeADTGetDatumFast(*bb)));
71 }
72
73 static bool
gbt_timele(const void * a,const void * b,FmgrInfo * flinfo)74 gbt_timele(const void *a, const void *b, FmgrInfo *flinfo)
75 {
76 const TimeADT *aa = (const TimeADT *) a;
77 const TimeADT *bb = (const TimeADT *) b;
78
79 return DatumGetBool(DirectFunctionCall2(time_le,
80 TimeADTGetDatumFast(*aa),
81 TimeADTGetDatumFast(*bb)));
82 }
83
84 static bool
gbt_timelt(const void * a,const void * b,FmgrInfo * flinfo)85 gbt_timelt(const void *a, const void *b, FmgrInfo *flinfo)
86 {
87 const TimeADT *aa = (const TimeADT *) a;
88 const TimeADT *bb = (const TimeADT *) b;
89
90 return DatumGetBool(DirectFunctionCall2(time_lt,
91 TimeADTGetDatumFast(*aa),
92 TimeADTGetDatumFast(*bb)));
93 }
94
95
96
97 static int
gbt_timekey_cmp(const void * a,const void * b,FmgrInfo * flinfo)98 gbt_timekey_cmp(const void *a, const void *b, FmgrInfo *flinfo)
99 {
100 timeKEY *ia = (timeKEY *) (((const Nsrt *) a)->t);
101 timeKEY *ib = (timeKEY *) (((const Nsrt *) b)->t);
102 int res;
103
104 res = DatumGetInt32(DirectFunctionCall2(time_cmp, TimeADTGetDatumFast(ia->lower), TimeADTGetDatumFast(ib->lower)));
105 if (res == 0)
106 return DatumGetInt32(DirectFunctionCall2(time_cmp, TimeADTGetDatumFast(ia->upper), TimeADTGetDatumFast(ib->upper)));
107
108 return res;
109 }
110
111 static float8
gbt_time_dist(const void * a,const void * b,FmgrInfo * flinfo)112 gbt_time_dist(const void *a, const void *b, FmgrInfo *flinfo)
113 {
114 const TimeADT *aa = (const TimeADT *) a;
115 const TimeADT *bb = (const TimeADT *) b;
116 Interval *i;
117
118 i = DatumGetIntervalP(DirectFunctionCall2(time_mi_time,
119 TimeADTGetDatumFast(*aa),
120 TimeADTGetDatumFast(*bb)));
121 return (float8) Abs(INTERVAL_TO_SEC(i));
122 }
123
124
125 static const gbtree_ninfo tinfo =
126 {
127 gbt_t_time,
128 sizeof(TimeADT),
129 16, /* sizeof(gbtreekey16) */
130 gbt_timegt,
131 gbt_timege,
132 gbt_timeeq,
133 gbt_timele,
134 gbt_timelt,
135 gbt_timekey_cmp,
136 gbt_time_dist
137 };
138
139
140 PG_FUNCTION_INFO_V1(time_dist);
141 Datum
time_dist(PG_FUNCTION_ARGS)142 time_dist(PG_FUNCTION_ARGS)
143 {
144 Datum diff = DirectFunctionCall2(time_mi_time,
145 PG_GETARG_DATUM(0),
146 PG_GETARG_DATUM(1));
147
148 PG_RETURN_INTERVAL_P(abs_interval(DatumGetIntervalP(diff)));
149 }
150
151
152 /**************************************************
153 * time ops
154 **************************************************/
155
156
157
158 Datum
gbt_time_compress(PG_FUNCTION_ARGS)159 gbt_time_compress(PG_FUNCTION_ARGS)
160 {
161 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
162
163 PG_RETURN_POINTER(gbt_num_compress(entry, &tinfo));
164 }
165
166
167 Datum
gbt_timetz_compress(PG_FUNCTION_ARGS)168 gbt_timetz_compress(PG_FUNCTION_ARGS)
169 {
170 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
171 GISTENTRY *retval;
172
173 if (entry->leafkey)
174 {
175 timeKEY *r = (timeKEY *) palloc(sizeof(timeKEY));
176 TimeTzADT *tz = DatumGetTimeTzADTP(entry->key);
177 TimeADT tmp;
178
179 retval = palloc(sizeof(GISTENTRY));
180
181 /* We are using the time + zone only to compress */
182 tmp = tz->time + (tz->zone * INT64CONST(1000000));
183 r->lower = r->upper = tmp;
184 gistentryinit(*retval, PointerGetDatum(r),
185 entry->rel, entry->page,
186 entry->offset, false);
187 }
188 else
189 retval = entry;
190 PG_RETURN_POINTER(retval);
191 }
192
193 Datum
gbt_time_fetch(PG_FUNCTION_ARGS)194 gbt_time_fetch(PG_FUNCTION_ARGS)
195 {
196 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
197
198 PG_RETURN_POINTER(gbt_num_fetch(entry, &tinfo));
199 }
200
201 Datum
gbt_time_consistent(PG_FUNCTION_ARGS)202 gbt_time_consistent(PG_FUNCTION_ARGS)
203 {
204 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
205 TimeADT query = PG_GETARG_TIMEADT(1);
206 StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
207
208 /* Oid subtype = PG_GETARG_OID(3); */
209 bool *recheck = (bool *) PG_GETARG_POINTER(4);
210 timeKEY *kkk = (timeKEY *) DatumGetPointer(entry->key);
211 GBT_NUMKEY_R key;
212
213 /* All cases served by this function are exact */
214 *recheck = false;
215
216 key.lower = (GBT_NUMKEY *) &kkk->lower;
217 key.upper = (GBT_NUMKEY *) &kkk->upper;
218
219 PG_RETURN_BOOL(
220 gbt_num_consistent(&key, (void *) &query, &strategy, GIST_LEAF(entry), &tinfo, fcinfo->flinfo)
221 );
222 }
223
224 Datum
gbt_time_distance(PG_FUNCTION_ARGS)225 gbt_time_distance(PG_FUNCTION_ARGS)
226 {
227 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
228 TimeADT query = PG_GETARG_TIMEADT(1);
229
230 /* Oid subtype = PG_GETARG_OID(3); */
231 timeKEY *kkk = (timeKEY *) DatumGetPointer(entry->key);
232 GBT_NUMKEY_R key;
233
234 key.lower = (GBT_NUMKEY *) &kkk->lower;
235 key.upper = (GBT_NUMKEY *) &kkk->upper;
236
237 PG_RETURN_FLOAT8(
238 gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo, fcinfo->flinfo)
239 );
240 }
241
242 Datum
gbt_timetz_consistent(PG_FUNCTION_ARGS)243 gbt_timetz_consistent(PG_FUNCTION_ARGS)
244 {
245 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
246 TimeTzADT *query = PG_GETARG_TIMETZADT_P(1);
247 StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
248
249 /* Oid subtype = PG_GETARG_OID(3); */
250 bool *recheck = (bool *) PG_GETARG_POINTER(4);
251 timeKEY *kkk = (timeKEY *) DatumGetPointer(entry->key);
252 TimeADT qqq;
253 GBT_NUMKEY_R key;
254
255 /* All cases served by this function are inexact */
256 *recheck = true;
257
258 qqq = query->time + (query->zone * INT64CONST(1000000));
259
260 key.lower = (GBT_NUMKEY *) &kkk->lower;
261 key.upper = (GBT_NUMKEY *) &kkk->upper;
262
263 PG_RETURN_BOOL(
264 gbt_num_consistent(&key, (void *) &qqq, &strategy, GIST_LEAF(entry), &tinfo, fcinfo->flinfo)
265 );
266 }
267
268
269 Datum
gbt_time_union(PG_FUNCTION_ARGS)270 gbt_time_union(PG_FUNCTION_ARGS)
271 {
272 GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
273 void *out = palloc(sizeof(timeKEY));
274
275 *(int *) PG_GETARG_POINTER(1) = sizeof(timeKEY);
276 PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo, fcinfo->flinfo));
277 }
278
279
280 Datum
gbt_time_penalty(PG_FUNCTION_ARGS)281 gbt_time_penalty(PG_FUNCTION_ARGS)
282 {
283 timeKEY *origentry = (timeKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key);
284 timeKEY *newentry = (timeKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key);
285 float *result = (float *) PG_GETARG_POINTER(2);
286 Interval *intr;
287 double res;
288 double res2;
289
290 intr = DatumGetIntervalP(DirectFunctionCall2(
291 time_mi_time,
292 TimeADTGetDatumFast(newentry->upper),
293 TimeADTGetDatumFast(origentry->upper)));
294 res = INTERVAL_TO_SEC(intr);
295 res = Max(res, 0);
296
297 intr = DatumGetIntervalP(DirectFunctionCall2(
298 time_mi_time,
299 TimeADTGetDatumFast(origentry->lower),
300 TimeADTGetDatumFast(newentry->lower)));
301 res2 = INTERVAL_TO_SEC(intr);
302 res2 = Max(res2, 0);
303
304 res += res2;
305
306 *result = 0.0;
307
308 if (res > 0)
309 {
310 intr = DatumGetIntervalP(DirectFunctionCall2(
311 time_mi_time,
312 TimeADTGetDatumFast(origentry->upper),
313 TimeADTGetDatumFast(origentry->lower)));
314 *result += FLT_MIN;
315 *result += (float) (res / (res + INTERVAL_TO_SEC(intr)));
316 *result *= (FLT_MAX / (((GISTENTRY *) PG_GETARG_POINTER(0))->rel->rd_att->natts + 1));
317 }
318
319 PG_RETURN_POINTER(result);
320 }
321
322
323 Datum
gbt_time_picksplit(PG_FUNCTION_ARGS)324 gbt_time_picksplit(PG_FUNCTION_ARGS)
325 {
326 PG_RETURN_POINTER(gbt_num_picksplit(
327 (GistEntryVector *) PG_GETARG_POINTER(0),
328 (GIST_SPLITVEC *) PG_GETARG_POINTER(1),
329 &tinfo, fcinfo->flinfo
330 ));
331 }
332
333 Datum
gbt_time_same(PG_FUNCTION_ARGS)334 gbt_time_same(PG_FUNCTION_ARGS)
335 {
336 timeKEY *b1 = (timeKEY *) PG_GETARG_POINTER(0);
337 timeKEY *b2 = (timeKEY *) PG_GETARG_POINTER(1);
338 bool *result = (bool *) PG_GETARG_POINTER(2);
339
340 *result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
341 PG_RETURN_POINTER(result);
342 }
343