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  ereport(ERROR,
185  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
186  errmsg("input array is too big (%d maximum allowed, %d current), use gist__intbig_ops opclass instead",
187  2 * num_ranges - 1, ARRNELEMS(r))));
188 
189  retval = palloc(sizeof(GISTENTRY));
190  gistentryinit(*retval, PointerGetDatum(r),
191  entry->rel, entry->page, entry->offset, false);
192 
193  PG_RETURN_POINTER(retval);
194  }
195 
196  /*
197  * leaf entries never compress one more time, only when entry->leafkey
198  * ==true, so now we work only with internal keys
199  */
200 
201  r = DatumGetArrayTypeP(entry->key);
202  CHECKARRVALID(r);
203  if (ARRISEMPTY(r))
204  {
205  if (r != (ArrayType *) DatumGetPointer(entry->key))
206  pfree(r);
207  PG_RETURN_POINTER(entry);
208  }
209 
210  if ((len = ARRNELEMS(r)) >= 2 * num_ranges)
211  { /* compress */
212  if (r == (ArrayType *) DatumGetPointer(entry->key))
213  r = DatumGetArrayTypePCopy(entry->key);
214  r = resize_intArrayType(r, 2 * (len));
215 
216  dr = ARRPTR(r);
217 
218  /*
219  * "len" at this point is the number of ranges we will construct.
220  * "lenr" is the number of ranges we must eventually remove by
221  * merging, we must be careful to remove no more than this number.
222  */
223  lenr = len - num_ranges;
224 
225  /*
226  * Initially assume we can merge consecutive ints into a range. but we
227  * must count every value removed and stop when lenr runs out
228  */
229  for (j = i = len - 1; i > 0 && lenr > 0; i--, j--)
230  {
231  int r_end = dr[i];
232  int r_start = r_end;
233 
234  while (i > 0 && lenr > 0 && dr[i - 1] == r_start - 1)
235  --r_start, --i, --lenr;
236  dr[2 * j] = r_start;
237  dr[2 * j + 1] = r_end;
238  }
239  /* just copy the rest, if any, as trivial ranges */
240  for (; i >= 0; i--, j--)
241  dr[2 * j] = dr[2 * j + 1] = dr[i];
242 
243  if (++j)
244  {
245  /*
246  * shunt everything down to start at the right place
247  */
248  memmove(&dr[0], &dr[2 * j], 2 * (len - j) * sizeof(int32));
249  }
250 
251  /*
252  * make "len" be number of array elements, not ranges
253  */
254  len = 2 * (len - j);
255  cand = 1;
256  while (len > num_ranges * 2)
257  {
258  min = PG_INT64_MAX;
259  for (i = 2; i < len; i += 2)
260  if (min > ((int64) dr[i] - (int64) dr[i - 1]))
261  {
262  min = ((int64) dr[i] - (int64) dr[i - 1]);
263  cand = i;
264  }
265  memmove(&dr[cand - 1], &dr[cand + 1], (len - cand - 1) * sizeof(int32));
266  len -= 2;
267  }
268 
269  /*
270  * check sparseness of result
271  */
272  lenr = internal_size(dr, len);
273  if (lenr < 0 || lenr > MAXNUMELTS)
274  ereport(ERROR,
275  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
276  errmsg("data is too sparse, recreate index using gist__intbig_ops opclass instead")));
277 
278  r = resize_intArrayType(r, len);
279  retval = palloc(sizeof(GISTENTRY));
280  gistentryinit(*retval, PointerGetDatum(r),
281  entry->rel, entry->page, entry->offset, false);
282  PG_RETURN_POINTER(retval);
283  }
284  else
285  PG_RETURN_POINTER(entry);
286 }
287 
288 Datum
290 {
291  GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
292  GISTENTRY *retval;
293  ArrayType *r;
294  int num_ranges = G_INT_GET_NUMRANGES();
295  int *dr,
296  lenr;
297  ArrayType *in;
298  int lenin;
299  int *din;
300  int i,
301  j;
302 
303  in = DatumGetArrayTypeP(entry->key);
304 
305  CHECKARRVALID(in);
306  if (ARRISEMPTY(in))
307  {
308  if (in != (ArrayType *) DatumGetPointer(entry->key))
309  {
310  retval = palloc(sizeof(GISTENTRY));
311  gistentryinit(*retval, PointerGetDatum(in),
312  entry->rel, entry->page, entry->offset, false);
313  PG_RETURN_POINTER(retval);
314  }
315 
316  PG_RETURN_POINTER(entry);
317  }
318 
319  lenin = ARRNELEMS(in);
320 
321  if (lenin < 2 * num_ranges)
322  { /* not compressed value */
323  if (in != (ArrayType *) DatumGetPointer(entry->key))
324  {
325  retval = palloc(sizeof(GISTENTRY));
326  gistentryinit(*retval, PointerGetDatum(in),
327  entry->rel, entry->page, entry->offset, false);
328 
329  PG_RETURN_POINTER(retval);
330  }
331  PG_RETURN_POINTER(entry);
332  }
333 
334  din = ARRPTR(in);
335  lenr = internal_size(din, lenin);
336  if (lenr < 0 || lenr > MAXNUMELTS)
337  ereport(ERROR,
338  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
339  errmsg("compressed array is too big, recreate index using gist__intbig_ops opclass instead")));
340 
341  r = new_intArrayType(lenr);
342  dr = ARRPTR(r);
343 
344  for (i = 0; i < lenin; i += 2)
345  for (j = din[i]; j <= din[i + 1]; j++)
346  if ((!i) || *(dr - 1) != j)
347  *dr++ = j;
348 
349  if (in != (ArrayType *) DatumGetPointer(entry->key))
350  pfree(in);
351  retval = palloc(sizeof(GISTENTRY));
352  gistentryinit(*retval, PointerGetDatum(r),
353  entry->rel, entry->page, entry->offset, false);
354 
355  PG_RETURN_POINTER(retval);
356 }
357 
358 /*
359 ** The GiST Penalty method for _intments
360 */
361 Datum
363 {
364  GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0);
365  GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
366  float *result = (float *) PG_GETARG_POINTER(2);
367  ArrayType *ud;
368  float tmp1,
369  tmp2;
370 
371  ud = inner_int_union((ArrayType *) DatumGetPointer(origentry->key),
372  (ArrayType *) DatumGetPointer(newentry->key));
373  rt__int_size(ud, &tmp1);
374  rt__int_size((ArrayType *) DatumGetPointer(origentry->key), &tmp2);
375  *result = tmp1 - tmp2;
376  pfree(ud);
377 
378  PG_RETURN_POINTER(result);
379 }
380 
381 
382 
383 Datum
385 {
388  bool *result = (bool *) PG_GETARG_POINTER(2);
389  int32 n = ARRNELEMS(a);
390  int32 *da,
391  *db;
392 
393  CHECKARRVALID(a);
394  CHECKARRVALID(b);
395 
396  if (n != ARRNELEMS(b))
397  {
398  *result = false;
399  PG_RETURN_POINTER(result);
400  }
401  *result = true;
402  da = ARRPTR(a);
403  db = ARRPTR(b);
404  while (n--)
405  {
406  if (*da++ != *db++)
407  {
408  *result = false;
409  break;
410  }
411  }
412 
413  PG_RETURN_POINTER(result);
414 }
415 
416 /*****************************************************************
417 ** Common GiST Method
418 *****************************************************************/
419 
420 typedef struct
421 {
422  OffsetNumber pos;
423  float cost;
424 } SPLITCOST;
425 
426 static int
427 comparecost(const void *a, const void *b)
428 {
429  if (((const SPLITCOST *) a)->cost == ((const SPLITCOST *) b)->cost)
430  return 0;
431  else
432  return (((const SPLITCOST *) a)->cost > ((const SPLITCOST *) b)->cost) ? 1 : -1;
433 }
434 
435 /*
436 ** The GiST PickSplit method for _intments
437 ** We use Guttman's poly time split algorithm
438 */
439 Datum
441 {
444  OffsetNumber i,
445  j;
446  ArrayType *datum_alpha,
447  *datum_beta;
448  ArrayType *datum_l,
449  *datum_r;
450  ArrayType *union_d,
451  *union_dl,
452  *union_dr;
453  ArrayType *inter_d;
454  bool firsttime;
455  float size_alpha,
456  size_beta,
457  size_union,
458  size_inter;
459  float size_waste,
460  waste;
461  float size_l,
462  size_r;
463  int nbytes;
464  OffsetNumber seed_1 = 0,
465  seed_2 = 0;
466  OffsetNumber *left,
467  *right;
468  OffsetNumber maxoff;
469  SPLITCOST *costvector;
470 
471 #ifdef GIST_DEBUG
472  elog(DEBUG3, "--------picksplit %d", entryvec->n);
473 #endif
474 
475  maxoff = entryvec->n - 2;
476  nbytes = (maxoff + 2) * sizeof(OffsetNumber);
477  v->spl_left = (OffsetNumber *) palloc(nbytes);
478  v->spl_right = (OffsetNumber *) palloc(nbytes);
479 
480  firsttime = true;
481  waste = 0.0;
482  for (i = FirstOffsetNumber; i < maxoff; i = OffsetNumberNext(i))
483  {
484  datum_alpha = GETENTRY(entryvec, i);
485  for (j = OffsetNumberNext(i); j <= maxoff; j = OffsetNumberNext(j))
486  {
487  datum_beta = GETENTRY(entryvec, j);
488 
489  /* compute the wasted space by unioning these guys */
490  /* size_waste = size_union - size_inter; */
491  union_d = inner_int_union(datum_alpha, datum_beta);
492  rt__int_size(union_d, &size_union);
493  inter_d = inner_int_inter(datum_alpha, datum_beta);
494  rt__int_size(inter_d, &size_inter);
495  size_waste = size_union - size_inter;
496 
497  pfree(union_d);
498  pfree(inter_d);
499 
500  /*
501  * are these a more promising split that what we've already seen?
502  */
503 
504  if (size_waste > waste || firsttime)
505  {
506  waste = size_waste;
507  seed_1 = i;
508  seed_2 = j;
509  firsttime = false;
510  }
511  }
512  }
513 
514  left = v->spl_left;
515  v->spl_nleft = 0;
516  right = v->spl_right;
517  v->spl_nright = 0;
518  if (seed_1 == 0 || seed_2 == 0)
519  {
520  seed_1 = 1;
521  seed_2 = 2;
522  }
523 
524  datum_alpha = GETENTRY(entryvec, seed_1);
525  datum_l = copy_intArrayType(datum_alpha);
526  rt__int_size(datum_l, &size_l);
527  datum_beta = GETENTRY(entryvec, seed_2);
528  datum_r = copy_intArrayType(datum_beta);
529  rt__int_size(datum_r, &size_r);
530 
531  maxoff = OffsetNumberNext(maxoff);
532 
533  /*
534  * sort entries
535  */
536  costvector = (SPLITCOST *) palloc(sizeof(SPLITCOST) * maxoff);
537  for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
538  {
539  costvector[i - 1].pos = i;
540  datum_alpha = GETENTRY(entryvec, i);
541  union_d = inner_int_union(datum_l, datum_alpha);
542  rt__int_size(union_d, &size_alpha);
543  pfree(union_d);
544  union_d = inner_int_union(datum_r, datum_alpha);
545  rt__int_size(union_d, &size_beta);
546  pfree(union_d);
547  costvector[i - 1].cost = fabsf((size_alpha - size_l) - (size_beta - size_r));
548  }
549  qsort(costvector, maxoff, sizeof(SPLITCOST), comparecost);
550 
551  /*
552  * Now split up the regions between the two seeds. An important property
553  * of this split algorithm is that the split vector v has the indices of
554  * items to be split in order in its left and right vectors. We exploit
555  * this property by doing a merge in the code that actually splits the
556  * page.
557  *
558  * For efficiency, we also place the new index tuple in this loop. This is
559  * handled at the very end, when we have placed all the existing tuples
560  * and i == maxoff + 1.
561  */
562 
563 
564  for (j = 0; j < maxoff; j++)
565  {
566  i = costvector[j].pos;
567 
568  /*
569  * If we've already decided where to place this item, just put it on
570  * the right list. Otherwise, we need to figure out which page needs
571  * the least enlargement in order to store the item.
572  */
573 
574  if (i == seed_1)
575  {
576  *left++ = i;
577  v->spl_nleft++;
578  continue;
579  }
580  else if (i == seed_2)
581  {
582  *right++ = i;
583  v->spl_nright++;
584  continue;
585  }
586 
587  /* okay, which page needs least enlargement? */
588  datum_alpha = GETENTRY(entryvec, i);
589  union_dl = inner_int_union(datum_l, datum_alpha);
590  union_dr = inner_int_union(datum_r, datum_alpha);
591  rt__int_size(union_dl, &size_alpha);
592  rt__int_size(union_dr, &size_beta);
593 
594  /* pick which page to add it to */
595  if (size_alpha - size_l < size_beta - size_r + WISH_F(v->spl_nleft, v->spl_nright, 0.01))
596  {
597  pfree(datum_l);
598  pfree(union_dr);
599  datum_l = union_dl;
600  size_l = size_alpha;
601  *left++ = i;
602  v->spl_nleft++;
603  }
604  else
605  {
606  pfree(datum_r);
607  pfree(union_dl);
608  datum_r = union_dr;
609  size_r = size_beta;
610  *right++ = i;
611  v->spl_nright++;
612  }
613  }
614  pfree(costvector);
615  *right = *left = FirstOffsetNumber;
616 
617  v->spl_ldatum = PointerGetDatum(datum_l);
618  v->spl_rdatum = PointerGetDatum(datum_r);
619 
621 }
622 
623 Datum
625 {
627 
628  init_local_reloptions(relopts, sizeof(GISTIntArrayOptions));
629  add_local_int_reloption(relopts, "numranges",
630  "number of ranges for compression",
632  offsetof(GISTIntArrayOptions, num_ranges));
633 
634  PG_RETURN_VOID();
635 }
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:362
Datum g_int_picksplit(PG_FUNCTION_ARGS)
Definition: _int_gist.c:440
#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:624
Datum g_int_same(PG_FUNCTION_ARGS)
Definition: _int_gist.c:384
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:289
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:427
#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:483
#define PG_INT64_MAX
Definition: c.h:581
#define ARRNELEMS(x)
Definition: cube.c:26
#define ARRPTR(x)
Definition: cube.c:25
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define DEBUG3
Definition: elog.h:28
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
#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:1456
void * palloc(Size size)
Definition: mcxt.c:1226
#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:322
uintptr_t Datum
Definition: postgres.h:64
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312
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:353
OffsetNumber pos
Definition: hstore_gist.c:352
float cost
Definition: _int_gist.c:423
#define VARSIZE(PTR)
Definition: varatt.h:279