Age Owner TLA Line data Source code
1 : /*
2 : * contrib/btree_gist/btree_utils_num.c
3 : */
4 : #include "postgres.h"
5 :
6 : #include "btree_gist.h"
7 : #include "btree_utils_num.h"
8 : #include "utils/cash.h"
9 : #include "utils/date.h"
10 : #include "utils/timestamp.h"
11 :
12 :
13 : GISTENTRY *
2936 heikki.linnakangas 14 CBC 10430 : gbt_num_compress(GISTENTRY *entry, const gbtree_ninfo *tinfo)
15 : {
16 : GISTENTRY *retval;
17 :
6797 bruce 18 10430 : if (entry->leafkey)
19 : {
20 : union
21 : {
22 : bool bo;
23 : int16 i2;
24 : int32 i4;
25 : int64 i8;
26 : float4 f4;
27 : float8 f8;
28 : DateADT dt;
29 : TimeADT tm;
30 : Timestamp ts;
31 : Cash ch;
32 : } v;
33 :
3250 tgl 34 9669 : GBT_NUMKEY *r = (GBT_NUMKEY *) palloc0(tinfo->indexsize);
6797 bruce 35 9669 : void *leaf = NULL;
36 :
37 9669 : switch (tinfo->t)
38 : {
519 tomas.vondra 39 2 : case gbt_t_bool:
40 2 : v.bo = DatumGetBool(entry->key);
41 2 : leaf = &v.bo;
42 2 : break;
6797 bruce 43 546 : case gbt_t_int2:
44 546 : v.i2 = DatumGetInt16(entry->key);
45 546 : leaf = &v.i2;
46 546 : break;
47 550 : case gbt_t_int4:
48 550 : v.i4 = DatumGetInt32(entry->key);
49 550 : leaf = &v.i4;
50 550 : break;
5466 tgl 51 547 : case gbt_t_int8:
52 547 : v.i8 = DatumGetInt64(entry->key);
53 547 : leaf = &v.i8;
54 547 : break;
6797 bruce 55 1532 : case gbt_t_oid:
56 : case gbt_t_enum:
57 1532 : v.i4 = DatumGetObjectId(entry->key);
58 1532 : leaf = &v.i4;
59 1532 : break;
5466 tgl 60 547 : case gbt_t_float4:
61 547 : v.f4 = DatumGetFloat4(entry->key);
62 547 : leaf = &v.f4;
63 547 : break;
64 544 : case gbt_t_float8:
65 544 : v.f8 = DatumGetFloat8(entry->key);
66 544 : leaf = &v.f8;
67 544 : break;
6797 bruce 68 544 : case gbt_t_date:
69 544 : v.dt = DatumGetDateADT(entry->key);
70 544 : leaf = &v.dt;
71 544 : break;
5466 tgl 72 544 : case gbt_t_time:
73 544 : v.tm = DatumGetTimeADT(entry->key);
74 544 : leaf = &v.tm;
75 544 : break;
76 2570 : case gbt_t_ts:
77 2570 : v.ts = DatumGetTimestamp(entry->key);
78 2570 : leaf = &v.ts;
79 2570 : break;
80 543 : case gbt_t_cash:
81 543 : v.ch = DatumGetCash(entry->key);
82 543 : leaf = &v.ch;
5469 alvherre 83 543 : break;
6797 bruce 84 1200 : default:
85 1200 : leaf = DatumGetPointer(entry->key);
86 : }
87 :
3250 tgl 88 9669 : Assert(tinfo->indexsize >= 2 * tinfo->size);
89 :
61 peter 90 GNC 9669 : memcpy(&r[0], leaf, tinfo->size);
91 9669 : memcpy(&r[tinfo->size], leaf, tinfo->size);
6797 bruce 92 CBC 9669 : retval = palloc(sizeof(GISTENTRY));
93 9669 : gistentryinit(*retval, PointerGetDatum(r), entry->rel, entry->page,
94 : entry->offset, false);
95 : }
96 : else
97 761 : retval = entry;
98 :
99 10430 : return retval;
100 : }
101 :
102 : /*
103 : * Convert a compressed leaf item back to the original type, for index-only
104 : * scans.
105 : */
106 : GISTENTRY *
2935 heikki.linnakangas 107 2210 : gbt_num_fetch(GISTENTRY *entry, const gbtree_ninfo *tinfo)
108 : {
109 : GISTENTRY *retval;
110 : Datum datum;
111 :
112 2210 : Assert(tinfo->indexsize >= 2 * tinfo->size);
113 :
114 : /*
115 : * Get the original Datum from the stored datum. On leaf entries, the
116 : * lower and upper bound are the same. We just grab the lower bound and
117 : * return it.
118 : */
119 2210 : switch (tinfo->t)
120 : {
519 tomas.vondra 121 7 : case gbt_t_bool:
122 7 : datum = BoolGetDatum(*(bool *) entry->key);
123 7 : break;
2935 heikki.linnakangas 124 287 : case gbt_t_int2:
125 287 : datum = Int16GetDatum(*(int16 *) entry->key);
126 287 : break;
127 287 : case gbt_t_int4:
128 287 : datum = Int32GetDatum(*(int32 *) entry->key);
129 287 : break;
130 139 : case gbt_t_int8:
131 139 : datum = Int64GetDatum(*(int64 *) entry->key);
132 139 : break;
2935 heikki.linnakangas 133 UBC 0 : case gbt_t_oid:
134 : case gbt_t_enum:
135 0 : datum = ObjectIdGetDatum(*(Oid *) entry->key);
136 0 : break;
2935 heikki.linnakangas 137 CBC 265 : case gbt_t_float4:
138 265 : datum = Float4GetDatum(*(float4 *) entry->key);
139 265 : break;
140 135 : case gbt_t_float8:
141 135 : datum = Float8GetDatum(*(float8 *) entry->key);
142 135 : break;
143 281 : case gbt_t_date:
144 281 : datum = DateADTGetDatum(*(DateADT *) entry->key);
145 281 : break;
146 142 : case gbt_t_time:
147 142 : datum = TimeADTGetDatum(*(TimeADT *) entry->key);
148 142 : break;
149 364 : case gbt_t_ts:
150 364 : datum = TimestampGetDatum(*(Timestamp *) entry->key);
151 364 : break;
152 143 : case gbt_t_cash:
153 143 : datum = CashGetDatum(*(Cash *) entry->key);
154 143 : break;
155 160 : default:
224 peter 156 GNC 160 : datum = entry->key;
157 : }
158 :
2935 heikki.linnakangas 159 CBC 2210 : retval = palloc(sizeof(GISTENTRY));
160 2210 : gistentryinit(*retval, datum, entry->rel, entry->page, entry->offset,
161 : false);
162 2210 : return retval;
163 : }
164 :
165 :
166 :
167 : /*
168 : ** The GiST union method for numerical values
169 : */
170 :
171 : void *
2210 andrew 172 8412 : gbt_num_union(GBT_NUMKEY *out, const GistEntryVector *entryvec, const gbtree_ninfo *tinfo, FmgrInfo *flinfo)
173 : {
174 : int i,
175 : numranges;
176 : GBT_NUMKEY *cur;
177 : GBT_NUMKEY_R o,
178 : c;
179 :
6797 bruce 180 8412 : numranges = entryvec->n;
181 8412 : cur = (GBT_NUMKEY *) DatumGetPointer((entryvec->vector[0].key));
182 :
183 :
184 8412 : o.lower = &((GBT_NUMKEY *) out)[0];
185 8412 : o.upper = &((GBT_NUMKEY *) out)[tinfo->size];
186 :
61 peter 187 GNC 8412 : memcpy(out, cur, 2 * tinfo->size);
188 :
6797 bruce 189 CBC 25690 : for (i = 1; i < numranges; i++)
190 : {
191 17278 : cur = (GBT_NUMKEY *) DatumGetPointer((entryvec->vector[i].key));
192 17278 : c.lower = &cur[0];
193 17278 : c.upper = &cur[tinfo->size];
194 : /* if out->lower > cur->lower, adopt cur as lower */
2040 peter_e 195 17278 : if (tinfo->f_gt(o.lower, c.lower, flinfo))
1531 peter 196 134 : memcpy(unconstify(GBT_NUMKEY *, o.lower), c.lower, tinfo->size);
197 : /* if out->upper < cur->upper, adopt cur as upper */
2040 peter_e 198 17278 : if (tinfo->f_lt(o.upper, c.upper, flinfo))
1531 peter 199 1351 : memcpy(unconstify(GBT_NUMKEY *, o.upper), c.upper, tinfo->size);
200 : }
201 :
6797 bruce 202 8412 : return out;
203 : }
204 :
205 :
206 :
207 : /*
208 : ** The GiST same method for numerical values
209 : */
210 :
211 : bool
2210 andrew 212 8369 : gbt_num_same(const GBT_NUMKEY *a, const GBT_NUMKEY *b, const gbtree_ninfo *tinfo, FmgrInfo *flinfo)
213 : {
214 : GBT_NUMKEY_R b1,
215 : b2;
216 :
1531 peter 217 8369 : b1.lower = &(a[0]);
218 8369 : b1.upper = &(a[tinfo->size]);
219 8369 : b2.lower = &(b[0]);
220 8369 : b2.upper = &(b[tinfo->size]);
221 :
2040 peter_e 222 16707 : return (tinfo->f_eq(b1.lower, b2.lower, flinfo) &&
223 8338 : tinfo->f_eq(b1.upper, b2.upper, flinfo));
224 : }
225 :
226 :
227 : void
2210 andrew 228 16049 : gbt_num_bin_union(Datum *u, GBT_NUMKEY *e, const gbtree_ninfo *tinfo, FmgrInfo *flinfo)
229 : {
230 : GBT_NUMKEY_R rd;
231 :
6797 bruce 232 16049 : rd.lower = &e[0];
233 16049 : rd.upper = &e[tinfo->size];
234 :
235 16049 : if (!DatumGetPointer(*u))
236 : {
3250 tgl 237 132 : *u = PointerGetDatum(palloc0(tinfo->indexsize));
1531 peter 238 132 : memcpy(&(((GBT_NUMKEY *) DatumGetPointer(*u))[0]), rd.lower, tinfo->size);
239 132 : memcpy(&(((GBT_NUMKEY *) DatumGetPointer(*u))[tinfo->size]), rd.upper, tinfo->size);
240 : }
241 : else
242 : {
243 : GBT_NUMKEY_R ur;
244 :
6797 bruce 245 15917 : ur.lower = &(((GBT_NUMKEY *) DatumGetPointer(*u))[0]);
246 15917 : ur.upper = &(((GBT_NUMKEY *) DatumGetPointer(*u))[tinfo->size]);
1531 peter 247 15917 : if (tinfo->f_gt(ur.lower, rd.lower, flinfo))
1531 peter 248 UBC 0 : memcpy(unconstify(GBT_NUMKEY *, ur.lower), rd.lower, tinfo->size);
1531 peter 249 CBC 15917 : if (tinfo->f_lt(ur.upper, rd.upper, flinfo))
250 11065 : memcpy(unconstify(GBT_NUMKEY *, ur.upper), rd.upper, tinfo->size);
251 : }
6890 teodor 252 16049 : }
253 :
254 :
255 :
256 : /*
257 : * The GiST consistent method
258 : *
259 : * Note: we currently assume that no datatypes that use this routine are
260 : * collation-aware; so we don't bother passing collation through.
261 : */
262 : bool
4421 tgl 263 41286 : gbt_num_consistent(const GBT_NUMKEY_R *key,
264 : const void *query,
265 : const StrategyNumber *strategy,
266 : bool is_leaf,
267 : const gbtree_ninfo *tinfo,
268 : FmgrInfo *flinfo)
269 : {
270 : bool retval;
271 :
6797 bruce 272 41286 : switch (*strategy)
273 : {
274 7818 : case BTLessEqualStrategyNumber:
2040 peter_e 275 7818 : retval = tinfo->f_ge(query, key->lower, flinfo);
6797 bruce 276 7818 : break;
277 8127 : case BTLessStrategyNumber:
278 8127 : if (is_leaf)
2040 peter_e 279 8044 : retval = tinfo->f_gt(query, key->lower, flinfo);
280 : else
281 83 : retval = tinfo->f_ge(query, key->lower, flinfo);
6797 bruce 282 8127 : break;
283 4887 : case BTEqualStrategyNumber:
284 4887 : if (is_leaf)
2040 peter_e 285 4804 : retval = tinfo->f_eq(query, key->lower, flinfo);
286 : else
287 128 : retval = (tinfo->f_le(key->lower, query, flinfo) &&
288 45 : tinfo->f_le(query, key->upper, flinfo));
6797 bruce 289 4887 : break;
290 10124 : case BTGreaterStrategyNumber:
291 10124 : if (is_leaf)
2040 peter_e 292 10049 : retval = tinfo->f_lt(query, key->upper, flinfo);
293 : else
294 75 : retval = tinfo->f_le(query, key->upper, flinfo);
6797 bruce 295 10124 : break;
296 10124 : case BTGreaterEqualStrategyNumber:
2040 peter_e 297 10124 : retval = tinfo->f_le(query, key->upper, flinfo);
6797 bruce 298 10124 : break;
4633 rhaas 299 206 : case BtreeGistNotEqualStrategyNumber:
2040 peter_e 300 409 : retval = (!(tinfo->f_eq(query, key->lower, flinfo) &&
301 203 : tinfo->f_eq(query, key->upper, flinfo)));
4633 rhaas 302 206 : break;
6797 bruce 303 UBC 0 : default:
4421 tgl 304 0 : retval = false;
305 : }
306 :
2061 peter_e 307 CBC 41286 : return retval;
308 : }
309 :
310 :
311 : /*
312 : ** The GiST distance method (for KNN-Gist)
313 : */
314 :
315 : float8
4421 tgl 316 2368 : gbt_num_distance(const GBT_NUMKEY_R *key,
317 : const void *query,
318 : bool is_leaf,
319 : const gbtree_ninfo *tinfo,
320 : FmgrInfo *flinfo)
321 : {
322 : float8 retval;
323 :
324 2368 : if (tinfo->f_dist == NULL)
4421 tgl 325 UBC 0 : elog(ERROR, "KNN search is not supported for btree_gist type %d",
326 : (int) tinfo->t);
2210 andrew 327 CBC 2368 : if (tinfo->f_le(query, key->lower, flinfo))
328 1254 : retval = tinfo->f_dist(query, key->lower, flinfo);
329 1114 : else if (tinfo->f_ge(query, key->upper, flinfo))
330 1102 : retval = tinfo->f_dist(query, key->upper, flinfo);
331 : else
4421 tgl 332 12 : retval = 0.0;
333 :
334 2368 : return retval;
335 : }
336 :
337 :
338 : GIST_SPLITVEC *
6797 bruce 339 66 : gbt_num_picksplit(const GistEntryVector *entryvec, GIST_SPLITVEC *v,
340 : const gbtree_ninfo *tinfo, FmgrInfo *flinfo)
341 : {
342 : OffsetNumber i,
343 66 : maxoff = entryvec->n - 1;
344 : Nsrt *arr;
345 : int nbytes;
346 :
347 66 : arr = (Nsrt *) palloc((maxoff + 1) * sizeof(Nsrt));
348 66 : nbytes = (maxoff + 2) * sizeof(OffsetNumber);
349 66 : v->spl_left = (OffsetNumber *) palloc(nbytes);
350 66 : v->spl_right = (OffsetNumber *) palloc(nbytes);
351 66 : v->spl_ldatum = PointerGetDatum(0);
352 66 : v->spl_rdatum = PointerGetDatum(0);
353 66 : v->spl_nleft = 0;
354 66 : v->spl_nright = 0;
355 :
356 : /* Sort entries */
357 :
358 16115 : for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
359 : {
360 16049 : arr[i].t = (GBT_NUMKEY *) DatumGetPointer((entryvec->vector[i].key));
361 16049 : arr[i].i = i;
362 : }
61 peter 363 GNC 66 : qsort_arg(&arr[FirstOffsetNumber], maxoff - FirstOffsetNumber + 1, sizeof(Nsrt), (qsort_arg_comparator) tinfo->f_cmp, flinfo);
364 :
365 : /* We do simply create two parts */
366 :
6797 bruce 367 CBC 16115 : for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
368 : {
369 16049 : if (i <= (maxoff - FirstOffsetNumber + 1) / 2)
370 : {
2210 andrew 371 8017 : gbt_num_bin_union(&v->spl_ldatum, arr[i].t, tinfo, flinfo);
6797 bruce 372 8017 : v->spl_left[v->spl_nleft] = arr[i].i;
373 8017 : v->spl_nleft++;
374 : }
375 : else
376 : {
2210 andrew 377 8032 : gbt_num_bin_union(&v->spl_rdatum, arr[i].t, tinfo, flinfo);
6797 bruce 378 8032 : v->spl_right[v->spl_nright] = arr[i].i;
379 8032 : v->spl_nright++;
380 : }
381 : }
382 :
383 66 : return v;
384 : }
|