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 0 : PG_FUNCTION_INFO_V1(gbt_time_compress);
22 0 : PG_FUNCTION_INFO_V1(gbt_timetz_compress);
23 0 : PG_FUNCTION_INFO_V1(gbt_time_fetch);
24 0 : PG_FUNCTION_INFO_V1(gbt_time_union);
25 0 : PG_FUNCTION_INFO_V1(gbt_time_picksplit);
26 0 : PG_FUNCTION_INFO_V1(gbt_time_consistent);
27 0 : PG_FUNCTION_INFO_V1(gbt_time_distance);
28 0 : PG_FUNCTION_INFO_V1(gbt_timetz_consistent);
29 0 : PG_FUNCTION_INFO_V1(gbt_time_penalty);
30 0 : PG_FUNCTION_INFO_V1(gbt_time_same);
31 0 : PG_FUNCTION_INFO_V1(gbt_time_sortsupport);
32 0 : PG_FUNCTION_INFO_V1(gbt_timetz_sortsupport);
33 :
34 :
35 : static bool
36 0 : gbt_timegt(const void *a, const void *b, FmgrInfo *flinfo)
37 : {
38 0 : const TimeADT *aa = (const TimeADT *) a;
39 0 : const TimeADT *bb = (const TimeADT *) b;
40 :
41 0 : return DatumGetBool(DirectFunctionCall2(time_gt,
42 : TimeADTGetDatum(*aa),
43 : TimeADTGetDatum(*bb)));
44 0 : }
45 :
46 : static bool
47 0 : gbt_timege(const void *a, const void *b, FmgrInfo *flinfo)
48 : {
49 0 : const TimeADT *aa = (const TimeADT *) a;
50 0 : const TimeADT *bb = (const TimeADT *) b;
51 :
52 0 : return DatumGetBool(DirectFunctionCall2(time_ge,
53 : TimeADTGetDatum(*aa),
54 : TimeADTGetDatum(*bb)));
55 0 : }
56 :
57 : static bool
58 0 : gbt_timeeq(const void *a, const void *b, FmgrInfo *flinfo)
59 : {
60 0 : const TimeADT *aa = (const TimeADT *) a;
61 0 : const TimeADT *bb = (const TimeADT *) b;
62 :
63 0 : return DatumGetBool(DirectFunctionCall2(time_eq,
64 : TimeADTGetDatum(*aa),
65 : TimeADTGetDatum(*bb)));
66 0 : }
67 :
68 : static bool
69 0 : gbt_timele(const void *a, const void *b, FmgrInfo *flinfo)
70 : {
71 0 : const TimeADT *aa = (const TimeADT *) a;
72 0 : const TimeADT *bb = (const TimeADT *) b;
73 :
74 0 : return DatumGetBool(DirectFunctionCall2(time_le,
75 : TimeADTGetDatum(*aa),
76 : TimeADTGetDatum(*bb)));
77 0 : }
78 :
79 : static bool
80 0 : gbt_timelt(const void *a, const void *b, FmgrInfo *flinfo)
81 : {
82 0 : const TimeADT *aa = (const TimeADT *) a;
83 0 : const TimeADT *bb = (const TimeADT *) b;
84 :
85 0 : return DatumGetBool(DirectFunctionCall2(time_lt,
86 : TimeADTGetDatum(*aa),
87 : TimeADTGetDatum(*bb)));
88 0 : }
89 :
90 : static int
91 0 : gbt_timekey_cmp(const void *a, const void *b, FmgrInfo *flinfo)
92 : {
93 0 : timeKEY *ia = (timeKEY *) (((const Nsrt *) a)->t);
94 0 : timeKEY *ib = (timeKEY *) (((const Nsrt *) b)->t);
95 0 : int res;
96 :
97 0 : res = DatumGetInt32(DirectFunctionCall2(time_cmp, TimeADTGetDatum(ia->lower), TimeADTGetDatum(ib->lower)));
98 0 : if (res == 0)
99 0 : return DatumGetInt32(DirectFunctionCall2(time_cmp, TimeADTGetDatum(ia->upper), TimeADTGetDatum(ib->upper)));
100 :
101 0 : return res;
102 0 : }
103 :
104 : static float8
105 0 : gbt_time_dist(const void *a, const void *b, FmgrInfo *flinfo)
106 : {
107 0 : const TimeADT *aa = (const TimeADT *) a;
108 0 : const TimeADT *bb = (const TimeADT *) b;
109 0 : Interval *i;
110 :
111 0 : i = DatumGetIntervalP(DirectFunctionCall2(time_mi_time,
112 : TimeADTGetDatum(*aa),
113 : TimeADTGetDatum(*bb)));
114 0 : return fabs(INTERVAL_TO_SEC(i));
115 0 : }
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 0 : PG_FUNCTION_INFO_V1(time_dist);
134 : Datum
135 0 : time_dist(PG_FUNCTION_ARGS)
136 : {
137 0 : Datum diff = DirectFunctionCall2(time_mi_time,
138 : PG_GETARG_DATUM(0),
139 : PG_GETARG_DATUM(1));
140 :
141 0 : PG_RETURN_INTERVAL_P(abs_interval(DatumGetIntervalP(diff)));
142 0 : }
143 :
144 :
145 : /**************************************************
146 : * GiST support functions
147 : **************************************************/
148 :
149 : Datum
150 0 : gbt_time_compress(PG_FUNCTION_ARGS)
151 : {
152 0 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
153 :
154 0 : PG_RETURN_POINTER(gbt_num_compress(entry, &tinfo));
155 0 : }
156 :
157 : Datum
158 0 : gbt_timetz_compress(PG_FUNCTION_ARGS)
159 : {
160 0 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
161 0 : GISTENTRY *retval;
162 :
163 0 : if (entry->leafkey)
164 : {
165 0 : timeKEY *r = palloc_object(timeKEY);
166 0 : TimeTzADT *tz = DatumGetTimeTzADTP(entry->key);
167 0 : TimeADT tmp;
168 :
169 0 : retval = palloc_object(GISTENTRY);
170 :
171 : /* We are using the time + zone only to compress */
172 0 : tmp = tz->time + (tz->zone * INT64CONST(1000000));
173 0 : r->lower = r->upper = tmp;
174 0 : gistentryinit(*retval, PointerGetDatum(r),
175 : entry->rel, entry->page,
176 : entry->offset, false);
177 0 : }
178 : else
179 0 : retval = entry;
180 0 : PG_RETURN_POINTER(retval);
181 0 : }
182 :
183 : Datum
184 0 : gbt_time_fetch(PG_FUNCTION_ARGS)
185 : {
186 0 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
187 :
188 0 : PG_RETURN_POINTER(gbt_num_fetch(entry, &tinfo));
189 0 : }
190 :
191 : Datum
192 0 : gbt_time_consistent(PG_FUNCTION_ARGS)
193 : {
194 0 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
195 0 : TimeADT query = PG_GETARG_TIMEADT(1);
196 0 : StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
197 : #ifdef NOT_USED
198 : Oid subtype = PG_GETARG_OID(3);
199 : #endif
200 0 : bool *recheck = (bool *) PG_GETARG_POINTER(4);
201 0 : timeKEY *kkk = (timeKEY *) DatumGetPointer(entry->key);
202 0 : GBT_NUMKEY_R key;
203 :
204 : /* All cases served by this function are exact */
205 0 : *recheck = false;
206 :
207 0 : key.lower = (GBT_NUMKEY *) &kkk->lower;
208 0 : key.upper = (GBT_NUMKEY *) &kkk->upper;
209 :
210 0 : PG_RETURN_BOOL(gbt_num_consistent(&key, &query, &strategy,
211 : GIST_LEAF(entry), &tinfo, fcinfo->flinfo));
212 0 : }
213 :
214 : Datum
215 0 : gbt_time_distance(PG_FUNCTION_ARGS)
216 : {
217 0 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
218 0 : TimeADT query = PG_GETARG_TIMEADT(1);
219 : #ifdef NOT_USED
220 : Oid subtype = PG_GETARG_OID(3);
221 : #endif
222 0 : timeKEY *kkk = (timeKEY *) DatumGetPointer(entry->key);
223 0 : GBT_NUMKEY_R key;
224 :
225 0 : key.lower = (GBT_NUMKEY *) &kkk->lower;
226 0 : key.upper = (GBT_NUMKEY *) &kkk->upper;
227 :
228 0 : PG_RETURN_FLOAT8(gbt_num_distance(&key, &query, GIST_LEAF(entry),
229 : &tinfo, fcinfo->flinfo));
230 0 : }
231 :
232 : Datum
233 0 : gbt_timetz_consistent(PG_FUNCTION_ARGS)
234 : {
235 0 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
236 0 : TimeTzADT *query = PG_GETARG_TIMETZADT_P(1);
237 0 : StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
238 : #ifdef NOT_USED
239 : Oid subtype = PG_GETARG_OID(3);
240 : #endif
241 0 : bool *recheck = (bool *) PG_GETARG_POINTER(4);
242 0 : timeKEY *kkk = (timeKEY *) DatumGetPointer(entry->key);
243 0 : TimeADT qqq;
244 0 : GBT_NUMKEY_R key;
245 :
246 : /* All cases served by this function are inexact */
247 0 : *recheck = true;
248 :
249 0 : qqq = query->time + (query->zone * INT64CONST(1000000));
250 :
251 0 : key.lower = (GBT_NUMKEY *) &kkk->lower;
252 0 : key.upper = (GBT_NUMKEY *) &kkk->upper;
253 :
254 0 : PG_RETURN_BOOL(gbt_num_consistent(&key, &qqq, &strategy,
255 : GIST_LEAF(entry), &tinfo, fcinfo->flinfo));
256 0 : }
257 :
258 : Datum
259 0 : gbt_time_union(PG_FUNCTION_ARGS)
260 : {
261 0 : GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
262 0 : void *out = palloc(sizeof(timeKEY));
263 :
264 0 : *(int *) PG_GETARG_POINTER(1) = sizeof(timeKEY);
265 0 : PG_RETURN_POINTER(gbt_num_union(out, entryvec, &tinfo, fcinfo->flinfo));
266 0 : }
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 0 : Interval *intr;
275 0 : double res;
276 0 : 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 0 : }
303 :
304 0 : PG_RETURN_POINTER(result);
305 0 : }
306 :
307 : Datum
308 0 : gbt_time_picksplit(PG_FUNCTION_ARGS)
309 : {
310 0 : 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 0 : }
325 :
326 : static int
327 0 : gbt_timekey_ssup_cmp(Datum x, Datum y, SortSupport ssup)
328 : {
329 0 : timeKEY *arg1 = (timeKEY *) DatumGetPointer(x);
330 0 : timeKEY *arg2 = (timeKEY *) DatumGetPointer(y);
331 :
332 : /* for leaf items we expect lower == upper, so only compare lower */
333 0 : return DatumGetInt32(DirectFunctionCall2(time_cmp,
334 : TimeADTGetDatum(arg1->lower),
335 : TimeADTGetDatum(arg2->lower)));
336 0 : }
337 :
338 : Datum
339 0 : gbt_time_sortsupport(PG_FUNCTION_ARGS)
340 : {
341 0 : SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
342 :
343 0 : ssup->comparator = gbt_timekey_ssup_cmp;
344 0 : ssup->ssup_extra = NULL;
345 :
346 0 : PG_RETURN_VOID();
347 0 : }
|