Line data Source code
1 : /*
2 : * contrib/btree_gist/btree_interval.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/sortsupport.h"
10 : #include "utils/timestamp.h"
11 :
12 : typedef struct
13 : {
14 : Interval lower,
15 : upper;
16 : } intvKEY;
17 :
18 : /* GiST support functions */
19 4 : PG_FUNCTION_INFO_V1(gbt_intv_compress);
20 4 : PG_FUNCTION_INFO_V1(gbt_intv_fetch);
21 4 : PG_FUNCTION_INFO_V1(gbt_intv_decompress);
22 4 : PG_FUNCTION_INFO_V1(gbt_intv_union);
23 4 : PG_FUNCTION_INFO_V1(gbt_intv_picksplit);
24 4 : PG_FUNCTION_INFO_V1(gbt_intv_consistent);
25 4 : PG_FUNCTION_INFO_V1(gbt_intv_distance);
26 4 : PG_FUNCTION_INFO_V1(gbt_intv_penalty);
27 4 : PG_FUNCTION_INFO_V1(gbt_intv_same);
28 4 : PG_FUNCTION_INFO_V1(gbt_intv_sortsupport);
29 :
30 :
31 : static bool
32 4486 : gbt_intvgt(const void *a, const void *b, FmgrInfo *flinfo)
33 : {
34 4486 : return DatumGetBool(DirectFunctionCall2(interval_gt, IntervalPGetDatum(a), IntervalPGetDatum(b)));
35 : }
36 :
37 : static bool
38 1044 : gbt_intvge(const void *a, const void *b, FmgrInfo *flinfo)
39 : {
40 1044 : return DatumGetBool(DirectFunctionCall2(interval_ge, IntervalPGetDatum(a), IntervalPGetDatum(b)));
41 : }
42 :
43 : static bool
44 300 : gbt_intveq(const void *a, const void *b, FmgrInfo *flinfo)
45 : {
46 300 : return DatumGetBool(DirectFunctionCall2(interval_eq, IntervalPGetDatum(a), IntervalPGetDatum(b)));
47 : }
48 :
49 : static bool
50 1246 : gbt_intvle(const void *a, const void *b, FmgrInfo *flinfo)
51 : {
52 1246 : return DatumGetBool(DirectFunctionCall2(interval_le, IntervalPGetDatum(a), IntervalPGetDatum(b)));
53 : }
54 :
55 : static bool
56 4186 : gbt_intvlt(const void *a, const void *b, FmgrInfo *flinfo)
57 : {
58 4186 : return DatumGetBool(DirectFunctionCall2(interval_lt, IntervalPGetDatum(a), IntervalPGetDatum(b)));
59 : }
60 :
61 : static int
62 2394 : gbt_intvkey_cmp(const void *a, const void *b, FmgrInfo *flinfo)
63 : {
64 2394 : intvKEY *ia = (intvKEY *) (((const Nsrt *) a)->t);
65 2394 : intvKEY *ib = (intvKEY *) (((const Nsrt *) b)->t);
66 : int res;
67 :
68 2394 : res = DatumGetInt32(DirectFunctionCall2(interval_cmp, IntervalPGetDatum(&ia->lower), IntervalPGetDatum(&ib->lower)));
69 2394 : if (res == 0)
70 0 : return DatumGetInt32(DirectFunctionCall2(interval_cmp, IntervalPGetDatum(&ia->upper), IntervalPGetDatum(&ib->upper)));
71 :
72 2394 : return res;
73 : }
74 :
75 :
76 : static double
77 1224 : intr2num(const Interval *i)
78 : {
79 1224 : return INTERVAL_TO_SEC(i);
80 : }
81 :
82 : static float8
83 612 : gbt_intv_dist(const void *a, const void *b, FmgrInfo *flinfo)
84 : {
85 612 : return fabs(intr2num((const Interval *) a) - intr2num((const Interval *) b));
86 : }
87 :
88 : /*
89 : * INTERVALSIZE should be the actual size-on-disk of an Interval, as shown
90 : * in pg_type. This might be less than sizeof(Interval) if the compiler
91 : * insists on adding alignment padding at the end of the struct. (Note:
92 : * this concern is obsolete with the current definition of Interval, but
93 : * was real before a separate "day" field was added to it.)
94 : */
95 : #define INTERVALSIZE 16
96 :
97 : static const gbtree_ninfo tinfo =
98 : {
99 : gbt_t_intv,
100 : sizeof(Interval),
101 : 32, /* sizeof(gbtreekey32) */
102 : gbt_intvgt,
103 : gbt_intvge,
104 : gbt_intveq,
105 : gbt_intvle,
106 : gbt_intvlt,
107 : gbt_intvkey_cmp,
108 : gbt_intv_dist
109 : };
110 :
111 :
112 : Interval *
113 4468 : abs_interval(Interval *a)
114 : {
115 : static const Interval zero = {0, 0, 0};
116 :
117 4468 : if (DatumGetBool(DirectFunctionCall2(interval_lt,
118 : IntervalPGetDatum(a),
119 : IntervalPGetDatum(&zero))))
120 2478 : a = DatumGetIntervalP(DirectFunctionCall1(interval_um,
121 : IntervalPGetDatum(a)));
122 :
123 4468 : return a;
124 : }
125 :
126 4 : PG_FUNCTION_INFO_V1(interval_dist);
127 : Datum
128 1212 : interval_dist(PG_FUNCTION_ARGS)
129 : {
130 1212 : Datum diff = DirectFunctionCall2(interval_mi,
131 : PG_GETARG_DATUM(0),
132 : PG_GETARG_DATUM(1));
133 :
134 1212 : PG_RETURN_INTERVAL_P(abs_interval(DatumGetIntervalP(diff)));
135 : }
136 :
137 :
138 : /**************************************************
139 : * GiST support functions
140 : **************************************************/
141 :
142 : Datum
143 1208 : gbt_intv_compress(PG_FUNCTION_ARGS)
144 : {
145 1208 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
146 1208 : GISTENTRY *retval = entry;
147 :
148 1208 : if (entry->leafkey || INTERVALSIZE != sizeof(Interval))
149 : {
150 1200 : char *r = (char *) palloc(2 * INTERVALSIZE);
151 :
152 1200 : retval = palloc(sizeof(GISTENTRY));
153 :
154 1200 : if (entry->leafkey)
155 : {
156 1200 : Interval *key = DatumGetIntervalP(entry->key);
157 :
158 1200 : memcpy(r, key, INTERVALSIZE);
159 1200 : memcpy(r + INTERVALSIZE, key, INTERVALSIZE);
160 : }
161 : else
162 : {
163 0 : intvKEY *key = (intvKEY *) DatumGetPointer(entry->key);
164 :
165 0 : memcpy(r, &key->lower, INTERVALSIZE);
166 0 : memcpy(r + INTERVALSIZE, &key->upper, INTERVALSIZE);
167 : }
168 1200 : gistentryinit(*retval, PointerGetDatum(r),
169 : entry->rel, entry->page,
170 : entry->offset, false);
171 : }
172 :
173 1208 : PG_RETURN_POINTER(retval);
174 : }
175 :
176 : Datum
177 300 : gbt_intv_fetch(PG_FUNCTION_ARGS)
178 : {
179 300 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
180 :
181 300 : PG_RETURN_POINTER(gbt_num_fetch(entry, &tinfo));
182 : }
183 :
184 : Datum
185 8756 : gbt_intv_decompress(PG_FUNCTION_ARGS)
186 : {
187 8756 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
188 8756 : GISTENTRY *retval = entry;
189 :
190 : if (INTERVALSIZE != sizeof(Interval))
191 : {
192 : intvKEY *r = palloc(sizeof(intvKEY));
193 : char *key = DatumGetPointer(entry->key);
194 :
195 : retval = palloc(sizeof(GISTENTRY));
196 : memcpy(&r->lower, key, INTERVALSIZE);
197 : memcpy(&r->upper, key + INTERVALSIZE, INTERVALSIZE);
198 :
199 : gistentryinit(*retval, PointerGetDatum(r),
200 : entry->rel, entry->page,
201 : entry->offset, false);
202 : }
203 8756 : PG_RETURN_POINTER(retval);
204 : }
205 :
206 :
207 : Datum
208 3340 : gbt_intv_consistent(PG_FUNCTION_ARGS)
209 : {
210 3340 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
211 3340 : Interval *query = PG_GETARG_INTERVAL_P(1);
212 3340 : StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
213 :
214 : /* Oid subtype = PG_GETARG_OID(3); */
215 3340 : bool *recheck = (bool *) PG_GETARG_POINTER(4);
216 3340 : intvKEY *kkk = (intvKEY *) DatumGetPointer(entry->key);
217 : GBT_NUMKEY_R key;
218 :
219 : /* All cases served by this function are exact */
220 3340 : *recheck = false;
221 :
222 3340 : key.lower = (GBT_NUMKEY *) &kkk->lower;
223 3340 : key.upper = (GBT_NUMKEY *) &kkk->upper;
224 :
225 3340 : PG_RETURN_BOOL(gbt_num_consistent(&key, query, &strategy,
226 : GIST_LEAF(entry), &tinfo, fcinfo->flinfo));
227 : }
228 :
229 :
230 : Datum
231 616 : gbt_intv_distance(PG_FUNCTION_ARGS)
232 : {
233 616 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
234 616 : Interval *query = PG_GETARG_INTERVAL_P(1);
235 :
236 : /* Oid subtype = PG_GETARG_OID(3); */
237 616 : intvKEY *kkk = (intvKEY *) DatumGetPointer(entry->key);
238 : GBT_NUMKEY_R key;
239 :
240 616 : key.lower = (GBT_NUMKEY *) &kkk->lower;
241 616 : key.upper = (GBT_NUMKEY *) &kkk->upper;
242 :
243 616 : PG_RETURN_FLOAT8(gbt_num_distance(&key, query, GIST_LEAF(entry),
244 : &tinfo, fcinfo->flinfo));
245 : }
246 :
247 :
248 : Datum
249 2 : gbt_intv_union(PG_FUNCTION_ARGS)
250 : {
251 2 : GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
252 2 : void *out = palloc(sizeof(intvKEY));
253 :
254 2 : *(int *) PG_GETARG_POINTER(1) = sizeof(intvKEY);
255 2 : PG_RETURN_POINTER(gbt_num_union(out, entryvec, &tinfo, fcinfo->flinfo));
256 : }
257 :
258 :
259 : Datum
260 0 : gbt_intv_penalty(PG_FUNCTION_ARGS)
261 : {
262 0 : intvKEY *origentry = (intvKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key);
263 0 : intvKEY *newentry = (intvKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key);
264 0 : float *result = (float *) PG_GETARG_POINTER(2);
265 : double iorg[2],
266 : inew[2];
267 :
268 0 : iorg[0] = intr2num(&origentry->lower);
269 0 : iorg[1] = intr2num(&origentry->upper);
270 0 : inew[0] = intr2num(&newentry->lower);
271 0 : inew[1] = intr2num(&newentry->upper);
272 :
273 0 : penalty_num(result, iorg[0], iorg[1], inew[0], inew[1]);
274 :
275 0 : PG_RETURN_POINTER(result);
276 : }
277 :
278 : Datum
279 6 : gbt_intv_picksplit(PG_FUNCTION_ARGS)
280 : {
281 6 : PG_RETURN_POINTER(gbt_num_picksplit((GistEntryVector *) PG_GETARG_POINTER(0),
282 : (GIST_SPLITVEC *) PG_GETARG_POINTER(1),
283 : &tinfo, fcinfo->flinfo));
284 : }
285 :
286 : Datum
287 0 : gbt_intv_same(PG_FUNCTION_ARGS)
288 : {
289 0 : intvKEY *b1 = (intvKEY *) PG_GETARG_POINTER(0);
290 0 : intvKEY *b2 = (intvKEY *) PG_GETARG_POINTER(1);
291 0 : bool *result = (bool *) PG_GETARG_POINTER(2);
292 :
293 0 : *result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
294 0 : PG_RETURN_POINTER(result);
295 : }
296 :
297 : static int
298 11352 : gbt_intv_ssup_cmp(Datum x, Datum y, SortSupport ssup)
299 : {
300 11352 : intvKEY *arg1 = (intvKEY *) DatumGetPointer(x);
301 11352 : intvKEY *arg2 = (intvKEY *) DatumGetPointer(y);
302 :
303 : /* for leaf items we expect lower == upper, so only compare lower */
304 11352 : return DatumGetInt32(DirectFunctionCall2(interval_cmp,
305 : IntervalPGetDatum(&arg1->lower),
306 : IntervalPGetDatum(&arg2->lower)));
307 : }
308 :
309 : Datum
310 2 : gbt_intv_sortsupport(PG_FUNCTION_ARGS)
311 : {
312 2 : SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
313 :
314 2 : ssup->comparator = gbt_intv_ssup_cmp;
315 2 : ssup->ssup_extra = NULL;
316 :
317 2 : PG_RETURN_VOID();
318 : }
|