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