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