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