PostgreSQL Source Code  git master
_int_gist.c
Go to the documentation of this file.
1 /*
2  * contrib/intarray/_int_gist.c
3  */
4 #include "postgres.h"
5 
6 #include <limits.h>
7 #include <math.h>
8 
9 #include "_int.h"
10 #include "access/gist.h"
11 #include "access/reloptions.h"
12 #include "access/stratnum.h"
13 
14 #define GETENTRY(vec,pos) ((ArrayType *) DatumGetPointer((vec)->vector[(pos)].key))
15 
16 /*
17  * Control the maximum sparseness of compressed keys.
18  *
19  * The upper safe bound for this limit is half the maximum allocatable array
20  * size. A lower bound would give more guarantees that pathological data
21  * wouldn't eat excessive CPU and memory, but at the expense of breaking
22  * possibly working (after a fashion) indexes.
23  */
24 #define MAXNUMELTS (Min((MaxAllocSize / sizeof(Datum)),((MaxAllocSize - ARR_OVERHEAD_NONULLS(1)) / sizeof(int)))/2)
25 /* or: #define MAXNUMELTS 1000000 */
26 
27 /*
28 ** GiST support methods
29 */
38 
39 
40 /*
41 ** The GiST Consistent method for _intments
42 ** Should return false if for all data items x below entry,
43 ** the predicate x op query == false, where op is the oper
44 ** corresponding to strategy in the pg_amop table.
45 */
46 Datum
48 {
49  GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
52 
53  /* Oid subtype = PG_GETARG_OID(3); */
54  bool *recheck = (bool *) PG_GETARG_POINTER(4);
55  bool retval = false; /* silence compiler warning */
56 
57  /* this is exact except for RTSameStrategyNumber */
58  *recheck = (strategy == RTSameStrategyNumber);
59 
60  if (strategy == BooleanSearchStrategy)
61  {
62  retval = execconsistent((QUERYTYPE *) query,
63  (ArrayType *) DatumGetPointer(entry->key),
64  GIST_LEAF(entry));
65 
66  pfree(query);
67  PG_RETURN_BOOL(retval);
68  }
69 
70  /* sort query for fast search, key is already sorted */
71  CHECKARRVALID(query);
72  PREPAREARR(query);
73 
74  switch (strategy)
75  {
77  retval = inner_int_overlap((ArrayType *) DatumGetPointer(entry->key),
78  query);
79  break;
81  if (GIST_LEAF(entry))
83  entry->key,
84  PointerGetDatum(query),
85  PointerGetDatum(&retval));
86  else
87  retval = inner_int_contains((ArrayType *) DatumGetPointer(entry->key),
88  query);
89  break;
92  retval = inner_int_contains((ArrayType *) DatumGetPointer(entry->key),
93  query);
94  break;
97 
98  /*
99  * This code is unreachable as of intarray 1.4, because the <@
100  * operator has been removed from the opclass. We keep it for now
101  * to support older versions of the SQL definitions.
102  */
103  if (GIST_LEAF(entry))
104  retval = inner_int_contains(query,
105  (ArrayType *) DatumGetPointer(entry->key));
106  else
107  {
108  /*
109  * Unfortunately, because empty arrays could be anywhere in
110  * the index, we must search the whole tree.
111  */
112  retval = true;
113  }
114  break;
115  default:
116  retval = false;
117  }
118  pfree(query);
119  PG_RETURN_BOOL(retval);
120 }
121 
122 Datum
124 {
126  int *size = (int *) PG_GETARG_POINTER(1);
127  int32 i,
128  *ptr;
129  ArrayType *res;
130  int totlen = 0;
131 
132  for (i = 0; i < entryvec->n; i++)
133  {
134  ArrayType *ent = GETENTRY(entryvec, i);
135 
136  CHECKARRVALID(ent);
137  totlen += ARRNELEMS(ent);
138  }
139 
140  res = new_intArrayType(totlen);
141  ptr = ARRPTR(res);
142 
143  for (i = 0; i < entryvec->n; i++)
144  {
145  ArrayType *ent = GETENTRY(entryvec, i);
146  int nel;
147 
148  nel = ARRNELEMS(ent);
149  memcpy(ptr, ARRPTR(ent), nel * sizeof(int32));
150  ptr += nel;
151  }
152 
153  QSORT(res, 1);
154  res = _int_unique(res);
155  *size = VARSIZE(res);
157 }
158 
159 /*
160 ** GiST Compress and Decompress methods
161 */
162 Datum
164 {
165  GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
166  GISTENTRY *retval;
167  ArrayType *r;
168  int num_ranges = G_INT_GET_NUMRANGES();
169  int len,
170  lenr;
171  int *dr;
172  int i,
173  j,
174  cand;
175  int64 min;
176 
177  if (entry->leafkey)
178  {
179  r = DatumGetArrayTypePCopy(entry->key);
180  CHECKARRVALID(r);
181  PREPAREARR(r);
182 
183  if (ARRNELEMS(r) >= 2 * num_ranges)
184  elog(NOTICE, "input array is too big (%d maximum allowed, %d current), use gist__intbig_ops opclass instead",
185  2 * num_ranges - 1, ARRNELEMS(r));
186 
187  retval = palloc(sizeof(GISTENTRY));
188  gistentryinit(*retval, PointerGetDatum(r),
189  entry->rel, entry->page, entry->offset, false);
190 
191  PG_RETURN_POINTER(retval);
192  }
193 
194  /*
195  * leaf entries never compress one more time, only when entry->leafkey
196  * ==true, so now we work only with internal keys
197  */
198 
199  r = DatumGetArrayTypeP(entry->key);
200  CHECKARRVALID(r);
201  if (ARRISEMPTY(r))
202  {
203  if (r != (ArrayType *) DatumGetPointer(entry->key))
204  pfree(r);
205  PG_RETURN_POINTER(entry);
206  }
207 
208  if ((len = ARRNELEMS(r)) >= 2 * num_ranges)
209  { /* compress */
210  if (r == (ArrayType *) DatumGetPointer(entry->key))
211  r = DatumGetArrayTypePCopy(entry->key);
212  r = resize_intArrayType(r, 2 * (len));
213 
214  dr = ARRPTR(r);
215 
216  /*
217  * "len" at this point is the number of ranges we will construct.
218  * "lenr" is the number of ranges we must eventually remove by
219  * merging, we must be careful to remove no more than this number.
220  */
221  lenr = len - num_ranges;
222 
223  /*
224  * Initially assume we can merge consecutive ints into a range. but we
225  * must count every value removed and stop when lenr runs out
226  */
227  for (j = i = len - 1; i > 0 && lenr > 0; i--, j--)
228  {
229  int r_end = dr[i];
230  int r_start = r_end;
231 
232  while (i > 0 && lenr > 0 && dr[i - 1] == r_start - 1)
233  --r_start, --i, --lenr;
234  dr[2 * j] = r_start;
235  dr[2 * j + 1] = r_end;
236  }
237  /* just copy the rest, if any, as trivial ranges */
238  for (; i >= 0; i--, j--)
239  dr[2 * j] = dr[2 * j + 1] = dr[i];
240 
241  if (++j)
242  {
243  /*
244  * shunt everything down to start at the right place
245  */
246  memmove((void *) &dr[0], (void *) &dr[2 * j], 2 * (len - j) * sizeof(int32));
247  }
248 
249  /*
250  * make "len" be number of array elements, not ranges
251  */
252  len = 2 * (len - j);
253  cand = 1;
254  while (len > num_ranges * 2)
255  {
256  min = PG_INT64_MAX;
257  for (i = 2; i < len; i += 2)
258  if (min > ((int64) dr[i] - (int64) dr[i - 1]))
259  {
260  min = ((int64) dr[i] - (int64) dr[i - 1]);
261  cand = i;
262  }
263  memmove((void *) &dr[cand - 1], (void *) &dr[cand + 1], (len - cand - 1) * sizeof(int32));
264  len -= 2;
265  }
266 
267  /*
268  * check sparseness of result
269  */
270  lenr = internal_size(dr, len);
271  if (lenr < 0 || lenr > MAXNUMELTS)
272  ereport(ERROR,
273  (errmsg("data is too sparse, recreate index using gist__intbig_ops opclass instead")));
274 
275  r = resize_intArrayType(r, len);
276  retval = palloc(sizeof(GISTENTRY));
277  gistentryinit(*retval, PointerGetDatum(r),
278  entry->rel, entry->page, entry->offset, false);
279  PG_RETURN_POINTER(retval);
280  }
281  else
282  PG_RETURN_POINTER(entry);
283 }
284 
285 Datum
287 {
288  GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
289  GISTENTRY *retval;
290  ArrayType *r;
291  int num_ranges = G_INT_GET_NUMRANGES();
292  int *dr,
293  lenr;
294  ArrayType *in;
295  int lenin;
296  int *din;
297  int i,
298  j;
299 
300  in = DatumGetArrayTypeP(entry->key);
301 
302  CHECKARRVALID(in);
303  if (ARRISEMPTY(in))
304  {
305  if (in != (ArrayType *) DatumGetPointer(entry->key))
306  {
307  retval = palloc(sizeof(GISTENTRY));
308  gistentryinit(*retval, PointerGetDatum(in),
309  entry->rel, entry->page, entry->offset, false);
310  PG_RETURN_POINTER(retval);
311  }
312 
313  PG_RETURN_POINTER(entry);
314  }
315 
316  lenin = ARRNELEMS(in);
317 
318  if (lenin < 2 * num_ranges)
319  { /* not compressed value */
320  if (in != (ArrayType *) DatumGetPointer(entry->key))
321  {
322  retval = palloc(sizeof(GISTENTRY));
323  gistentryinit(*retval, PointerGetDatum(in),
324  entry->rel, entry->page, entry->offset, false);
325 
326  PG_RETURN_POINTER(retval);
327  }
328  PG_RETURN_POINTER(entry);
329  }
330 
331  din = ARRPTR(in);
332  lenr = internal_size(din, lenin);
333  if (lenr < 0 || lenr > MAXNUMELTS)
334  ereport(ERROR,
335  (errmsg("compressed array is too big, recreate index using gist__intbig_ops opclass instead")));
336 
337  r = new_intArrayType(lenr);
338  dr = ARRPTR(r);
339 
340  for (i = 0; i < lenin; i += 2)
341  for (j = din[i]; j <= din[i + 1]; j++)
342  if ((!i) || *(dr - 1) != j)
343  *dr++ = j;
344 
345  if (in != (ArrayType *) DatumGetPointer(entry->key))
346  pfree(in);
347  retval = palloc(sizeof(GISTENTRY));
348  gistentryinit(*retval, PointerGetDatum(r),
349  entry->rel, entry->page, entry->offset, false);
350 
351  PG_RETURN_POINTER(retval);
352 }
353 
354 /*
355 ** The GiST Penalty method for _intments
356 */
357 Datum
359 {
360  GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0);
361  GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
362  float *result = (float *) PG_GETARG_POINTER(2);
363  ArrayType *ud;
364  float tmp1,
365  tmp2;
366 
367  ud = inner_int_union((ArrayType *) DatumGetPointer(origentry->key),
368  (ArrayType *) DatumGetPointer(newentry->key));
369  rt__int_size(ud, &tmp1);
370  rt__int_size((ArrayType *) DatumGetPointer(origentry->key), &tmp2);
371  *result = tmp1 - tmp2;
372  pfree(ud);
373 
374  PG_RETURN_POINTER(result);
375 }
376 
377 
378 
379 Datum
381 {
384  bool *result = (bool *) PG_GETARG_POINTER(2);
385  int32 n = ARRNELEMS(a);
386  int32 *da,
387  *db;
388 
389  CHECKARRVALID(a);
390  CHECKARRVALID(b);
391 
392  if (n != ARRNELEMS(b))
393  {
394  *result = false;
395  PG_RETURN_POINTER(result);
396  }
397  *result = true;
398  da = ARRPTR(a);
399  db = ARRPTR(b);
400  while (n--)
401  {
402  if (*da++ != *db++)
403  {
404  *result = false;
405  break;
406  }
407  }
408 
409  PG_RETURN_POINTER(result);
410 }
411 
412 /*****************************************************************
413 ** Common GiST Method
414 *****************************************************************/
415 
416 typedef struct
417 {
418  OffsetNumber pos;
419  float cost;
420 } SPLITCOST;
421 
422 static int
423 comparecost(const void *a, const void *b)
424 {
425  if (((const SPLITCOST *) a)->cost == ((const SPLITCOST *) b)->cost)
426  return 0;
427  else
428  return (((const SPLITCOST *) a)->cost > ((const SPLITCOST *) b)->cost) ? 1 : -1;
429 }
430 
431 /*
432 ** The GiST PickSplit method for _intments
433 ** We use Guttman's poly time split algorithm
434 */
435 Datum
437 {
440  OffsetNumber i,
441  j;
442  ArrayType *datum_alpha,
443  *datum_beta;
444  ArrayType *datum_l,
445  *datum_r;
446  ArrayType *union_d,
447  *union_dl,
448  *union_dr;
449  ArrayType *inter_d;
450  bool firsttime;
451  float size_alpha,
452  size_beta,
453  size_union,
454  size_inter;
455  float size_waste,
456  waste;
457  float size_l,
458  size_r;
459  int nbytes;
460  OffsetNumber seed_1 = 0,
461  seed_2 = 0;
462  OffsetNumber *left,
463  *right;
464  OffsetNumber maxoff;
465  SPLITCOST *costvector;
466 
467 #ifdef GIST_DEBUG
468  elog(DEBUG3, "--------picksplit %d", entryvec->n);
469 #endif
470 
471  maxoff = entryvec->n - 2;
472  nbytes = (maxoff + 2) * sizeof(OffsetNumber);
473  v->spl_left = (OffsetNumber *) palloc(nbytes);
474  v->spl_right = (OffsetNumber *) palloc(nbytes);
475 
476  firsttime = true;
477  waste = 0.0;
478  for (i = FirstOffsetNumber; i < maxoff; i = OffsetNumberNext(i))
479  {
480  datum_alpha = GETENTRY(entryvec, i);
481  for (j = OffsetNumberNext(i); j <= maxoff; j = OffsetNumberNext(j))
482  {
483  datum_beta = GETENTRY(entryvec, j);
484 
485  /* compute the wasted space by unioning these guys */
486  /* size_waste = size_union - size_inter; */
487  union_d = inner_int_union(datum_alpha, datum_beta);
488  rt__int_size(union_d, &size_union);
489  inter_d = inner_int_inter(datum_alpha, datum_beta);
490  rt__int_size(inter_d, &size_inter);
491  size_waste = size_union - size_inter;
492 
493  pfree(union_d);
494  pfree(inter_d);
495 
496  /*
497  * are these a more promising split that what we've already seen?
498  */
499 
500  if (size_waste > waste || firsttime)
501  {
502  waste = size_waste;
503  seed_1 = i;
504  seed_2 = j;
505  firsttime = false;
506  }
507  }
508  }
509 
510  left = v->spl_left;
511  v->spl_nleft = 0;
512  right = v->spl_right;
513  v->spl_nright = 0;
514  if (seed_1 == 0 || seed_2 == 0)
515  {
516  seed_1 = 1;
517  seed_2 = 2;
518  }
519 
520  datum_alpha = GETENTRY(entryvec, seed_1);
521  datum_l = copy_intArrayType(datum_alpha);
522  rt__int_size(datum_l, &size_l);
523  datum_beta = GETENTRY(entryvec, seed_2);
524  datum_r = copy_intArrayType(datum_beta);
525  rt__int_size(datum_r, &size_r);
526 
527  maxoff = OffsetNumberNext(maxoff);
528 
529  /*
530  * sort entries
531  */
532  costvector = (SPLITCOST *) palloc(sizeof(SPLITCOST) * maxoff);
533  for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
534  {
535  costvector[i - 1].pos = i;
536  datum_alpha = GETENTRY(entryvec, i);
537  union_d = inner_int_union(datum_l, datum_alpha);
538  rt__int_size(union_d, &size_alpha);
539  pfree(union_d);
540  union_d = inner_int_union(datum_r, datum_alpha);
541  rt__int_size(union_d, &size_beta);
542  pfree(union_d);
543  costvector[i - 1].cost = fabsf((size_alpha - size_l) - (size_beta - size_r));
544  }
545  qsort((void *) costvector, maxoff, sizeof(SPLITCOST), comparecost);
546 
547  /*
548  * Now split up the regions between the two seeds. An important property
549  * of this split algorithm is that the split vector v has the indices of
550  * items to be split in order in its left and right vectors. We exploit
551  * this property by doing a merge in the code that actually splits the
552  * page.
553  *
554  * For efficiency, we also place the new index tuple in this loop. This is
555  * handled at the very end, when we have placed all the existing tuples
556  * and i == maxoff + 1.
557  */
558 
559 
560  for (j = 0; j < maxoff; j++)
561  {
562  i = costvector[j].pos;
563 
564  /*
565  * If we've already decided where to place this item, just put it on
566  * the right list. Otherwise, we need to figure out which page needs
567  * the least enlargement in order to store the item.
568  */
569 
570  if (i == seed_1)
571  {
572  *left++ = i;
573  v->spl_nleft++;
574  continue;
575  }
576  else if (i == seed_2)
577  {
578  *right++ = i;
579  v->spl_nright++;
580  continue;
581  }
582 
583  /* okay, which page needs least enlargement? */
584  datum_alpha = GETENTRY(entryvec, i);
585  union_dl = inner_int_union(datum_l, datum_alpha);
586  union_dr = inner_int_union(datum_r, datum_alpha);
587  rt__int_size(union_dl, &size_alpha);
588  rt__int_size(union_dr, &size_beta);
589 
590  /* pick which page to add it to */
591  if (size_alpha - size_l < size_beta - size_r + WISH_F(v->spl_nleft, v->spl_nright, 0.01))
592  {
593  pfree(datum_l);
594  pfree(union_dr);
595  datum_l = union_dl;
596  size_l = size_alpha;
597  *left++ = i;
598  v->spl_nleft++;
599  }
600  else
601  {
602  pfree(datum_r);
603  pfree(union_dl);
604  datum_r = union_dr;
605  size_r = size_beta;
606  *right++ = i;
607  v->spl_nright++;
608  }
609  }
610  pfree(costvector);
611  *right = *left = FirstOffsetNumber;
612 
613  v->spl_ldatum = PointerGetDatum(datum_l);
614  v->spl_rdatum = PointerGetDatum(datum_r);
615 
617 }
618 
619 Datum
621 {
623 
624  init_local_reloptions(relopts, sizeof(GISTIntArrayOptions));
625  add_local_int_reloption(relopts, "numranges",
626  "number of ranges for compression",
628  offsetof(GISTIntArrayOptions, num_ranges));
629 
630  PG_RETURN_VOID();
631 }
ArrayType * inner_int_union(ArrayType *a, ArrayType *b)
Definition: _int_tool.c:78
bool inner_int_overlap(ArrayType *a, ArrayType *b)
Definition: _int_tool.c:49
ArrayType * inner_int_inter(ArrayType *a, ArrayType *b)
Definition: _int_tool.c:135
bool inner_int_contains(ArrayType *a, ArrayType *b)
Definition: _int_tool.c:14
#define G_INT_GET_NUMRANGES()
Definition: _int.h:14
int internal_size(int *a, int len)
Definition: _int_tool.c:292
#define PREPAREARR(x)
Definition: _int.h:49
ArrayType * copy_intArrayType(ArrayType *a)
Definition: _int_tool.c:280
void rt__int_size(ArrayType *a, float *size)
Definition: _int_tool.c:183
#define QSORT(a, direction)
Definition: _int.h:183
#define CHECKARRVALID(x)
Definition: _int.h:30
ArrayType * _int_unique(ArrayType *r)
Definition: _int_tool.c:310
#define BooleanSearchStrategy
Definition: _int.h:134
ArrayType * new_intArrayType(int num)
Definition: _int_tool.c:221
bool execconsistent(QUERYTYPE *query, ArrayType *array, bool calcnot)
Definition: _int_bool.c:308
#define ARRISEMPTY(x)
Definition: _int.h:38
ArrayType * resize_intArrayType(ArrayType *a, int num)
Definition: _int_tool.c:249
#define G_INT_NUMRANGES_DEFAULT
Definition: _int.h:11
#define G_INT_NUMRANGES_MAX
Definition: _int.h:12
Datum g_int_penalty(PG_FUNCTION_ARGS)
Definition: _int_gist.c:358
Datum g_int_picksplit(PG_FUNCTION_ARGS)
Definition: _int_gist.c:436
#define MAXNUMELTS
Definition: _int_gist.c:24
#define GETENTRY(vec, pos)
Definition: _int_gist.c:14
Datum g_int_options(PG_FUNCTION_ARGS)
Definition: _int_gist.c:620
Datum g_int_same(PG_FUNCTION_ARGS)
Definition: _int_gist.c:380
Datum g_int_compress(PG_FUNCTION_ARGS)
Definition: _int_gist.c:163
Datum g_int_union(PG_FUNCTION_ARGS)
Definition: _int_gist.c:123
Datum g_int_decompress(PG_FUNCTION_ARGS)
Definition: _int_gist.c:286
PG_FUNCTION_INFO_V1(g_int_consistent)
Datum g_int_consistent(PG_FUNCTION_ARGS)
Definition: _int_gist.c:47
static int comparecost(const void *a, const void *b)
Definition: _int_gist.c:423
#define DatumGetArrayTypePCopy(X)
Definition: array.h:255
#define PG_GETARG_ARRAYTYPE_P_COPY(n)
Definition: array.h:257
#define PG_GETARG_ARRAYTYPE_P(n)
Definition: array.h:256
#define DatumGetArrayTypeP(X)
Definition: array.h:254
signed int int32
Definition: c.h:430
#define PG_INT64_MAX
Definition: c.h:528
#define ARRNELEMS(x)
Definition: cube.c:26
#define ARRPTR(x)
Definition: cube.c:25
int errmsg(const char *fmt,...)
Definition: elog.c:906
#define DEBUG3
Definition: elog.h:24
#define ERROR
Definition: elog.h:35
#define NOTICE
Definition: elog.h:31
#define ereport(elevel,...)
Definition: elog.h:145
#define PG_RETURN_VOID()
Definition: fmgr.h:349
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
#define PG_GETARG_UINT16(n)
Definition: fmgr.h:272
#define DirectFunctionCall3(func, arg1, arg2, arg3)
Definition: fmgr.h:646
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:359
#define GIST_LEAF(entry)
Definition: gist.h:168
#define gistentryinit(e, k, r, pg, o, l)
Definition: gist.h:242
#define WISH_F(a, b, c)
Definition: hstore_gist.c:76
int b
Definition: isn.c:70
int a
Definition: isn.c:69
int j
Definition: isn.c:74
int i
Definition: isn.c:73
void pfree(void *pointer)
Definition: mcxt.c:1306
void * palloc(Size size)
Definition: mcxt.c:1199
#define OffsetNumberNext(offsetNumber)
Definition: off.h:52
uint16 OffsetNumber
Definition: off.h:24
#define FirstOffsetNumber
Definition: off.h:27
const void size_t len
#define qsort(a, b, c, d)
Definition: port.h:445
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:670
uintptr_t Datum
Definition: postgres.h:412
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:660
#define VARSIZE(PTR)
Definition: postgres.h:317
void init_local_reloptions(local_relopts *relopts, Size relopt_struct_size)
Definition: reloptions.c:736
void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset)
Definition: reloptions.c:920
#define RTOldContainsStrategyNumber
Definition: stratnum.h:63
uint16 StrategyNumber
Definition: stratnum.h:22
#define RTOverlapStrategyNumber
Definition: stratnum.h:53
#define RTSameStrategyNumber
Definition: stratnum.h:56
#define RTContainsStrategyNumber
Definition: stratnum.h:57
#define RTOldContainedByStrategyNumber
Definition: stratnum.h:64
#define RTContainedByStrategyNumber
Definition: stratnum.h:58
OffsetNumber offset
Definition: gist.h:161
Datum key
Definition: gist.h:158
Page page
Definition: gist.h:160
Relation rel
Definition: gist.h:159
bool leafkey
Definition: gist.h:162
int spl_nleft
Definition: gist.h:141
OffsetNumber * spl_right
Definition: gist.h:145
Datum spl_ldatum
Definition: gist.h:142
Datum spl_rdatum
Definition: gist.h:147
int spl_nright
Definition: gist.h:146
OffsetNumber * spl_left
Definition: gist.h:140
int32 n
Definition: gist.h:233
int32 cost
Definition: hstore_gist.c:347
OffsetNumber pos
Definition: hstore_gist.c:346
float cost
Definition: _int_gist.c:419