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 
302  in = DatumGetArrayTypeP(entry->key);
303 
304  CHECKARRVALID(in);
305  if (ARRISEMPTY(in))
306  {
307  if (in != (ArrayType *) DatumGetPointer(entry->key))
308  {
309  retval = palloc(sizeof(GISTENTRY));
310  gistentryinit(*retval, PointerGetDatum(in),
311  entry->rel, entry->page, entry->offset, false);
312  PG_RETURN_POINTER(retval);
313  }
314 
315  PG_RETURN_POINTER(entry);
316  }
317 
318  lenin = ARRNELEMS(in);
319 
320  if (lenin < 2 * num_ranges)
321  { /* not compressed value */
322  if (in != (ArrayType *) DatumGetPointer(entry->key))
323  {
324  retval = palloc(sizeof(GISTENTRY));
325  gistentryinit(*retval, PointerGetDatum(in),
326  entry->rel, entry->page, entry->offset, false);
327 
328  PG_RETURN_POINTER(retval);
329  }
330  PG_RETURN_POINTER(entry);
331  }
332 
333  din = ARRPTR(in);
334  lenr = internal_size(din, lenin);
335  if (lenr < 0 || lenr > MAXNUMELTS)
336  ereport(ERROR,
337  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
338  errmsg("compressed array is too big, recreate index using gist__intbig_ops opclass instead")));
339 
340  r = new_intArrayType(lenr);
341  dr = ARRPTR(r);
342 
343  for (i = 0; i < lenin; i += 2)
344  {
345  /* use int64 for j in case din[i + 1] is INT_MAX */
346  for (int64 j = din[i]; j <= din[i + 1]; j++)
347  if ((!i) || *(dr - 1) != j)
348  *dr++ = (int) j;
349  }
350 
351  if (in != (ArrayType *) DatumGetPointer(entry->key))
352  pfree(in);
353  retval = palloc(sizeof(GISTENTRY));
354  gistentryinit(*retval, PointerGetDatum(r),
355  entry->rel, entry->page, entry->offset, false);
356 
357  PG_RETURN_POINTER(retval);
358 }
359 
360 /*
361 ** The GiST Penalty method for _intments
362 */
363 Datum
365 {
366  GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0);
367  GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
368  float *result = (float *) PG_GETARG_POINTER(2);
369  ArrayType *ud;
370  float tmp1,
371  tmp2;
372 
373  ud = inner_int_union((ArrayType *) DatumGetPointer(origentry->key),
374  (ArrayType *) DatumGetPointer(newentry->key));
375  rt__int_size(ud, &tmp1);
376  rt__int_size((ArrayType *) DatumGetPointer(origentry->key), &tmp2);
377  *result = tmp1 - tmp2;
378  pfree(ud);
379 
380  PG_RETURN_POINTER(result);
381 }
382 
383 
384 
385 Datum
387 {
390  bool *result = (bool *) PG_GETARG_POINTER(2);
391  int32 n = ARRNELEMS(a);
392  int32 *da,
393  *db;
394 
395  CHECKARRVALID(a);
396  CHECKARRVALID(b);
397 
398  if (n != ARRNELEMS(b))
399  {
400  *result = false;
401  PG_RETURN_POINTER(result);
402  }
403  *result = true;
404  da = ARRPTR(a);
405  db = ARRPTR(b);
406  while (n--)
407  {
408  if (*da++ != *db++)
409  {
410  *result = false;
411  break;
412  }
413  }
414 
415  PG_RETURN_POINTER(result);
416 }
417 
418 /*****************************************************************
419 ** Common GiST Method
420 *****************************************************************/
421 
422 typedef struct
423 {
424  OffsetNumber pos;
425  float cost;
426 } SPLITCOST;
427 
428 static int
429 comparecost(const void *a, const void *b)
430 {
431  if (((const SPLITCOST *) a)->cost == ((const SPLITCOST *) b)->cost)
432  return 0;
433  else
434  return (((const SPLITCOST *) a)->cost > ((const SPLITCOST *) b)->cost) ? 1 : -1;
435 }
436 
437 /*
438 ** The GiST PickSplit method for _intments
439 ** We use Guttman's poly time split algorithm
440 */
441 Datum
443 {
446  OffsetNumber i,
447  j;
448  ArrayType *datum_alpha,
449  *datum_beta;
450  ArrayType *datum_l,
451  *datum_r;
452  ArrayType *union_d,
453  *union_dl,
454  *union_dr;
455  ArrayType *inter_d;
456  bool firsttime;
457  float size_alpha,
458  size_beta,
459  size_union,
460  size_inter;
461  float size_waste,
462  waste;
463  float size_l,
464  size_r;
465  int nbytes;
466  OffsetNumber seed_1 = 0,
467  seed_2 = 0;
468  OffsetNumber *left,
469  *right;
470  OffsetNumber maxoff;
471  SPLITCOST *costvector;
472 
473 #ifdef GIST_DEBUG
474  elog(DEBUG3, "--------picksplit %d", entryvec->n);
475 #endif
476 
477  maxoff = entryvec->n - 2;
478  nbytes = (maxoff + 2) * sizeof(OffsetNumber);
479  v->spl_left = (OffsetNumber *) palloc(nbytes);
480  v->spl_right = (OffsetNumber *) palloc(nbytes);
481 
482  firsttime = true;
483  waste = 0.0;
484  for (i = FirstOffsetNumber; i < maxoff; i = OffsetNumberNext(i))
485  {
486  datum_alpha = GETENTRY(entryvec, i);
487  for (j = OffsetNumberNext(i); j <= maxoff; j = OffsetNumberNext(j))
488  {
489  datum_beta = GETENTRY(entryvec, j);
490 
491  /* compute the wasted space by unioning these guys */
492  /* size_waste = size_union - size_inter; */
493  union_d = inner_int_union(datum_alpha, datum_beta);
494  rt__int_size(union_d, &size_union);
495  inter_d = inner_int_inter(datum_alpha, datum_beta);
496  rt__int_size(inter_d, &size_inter);
497  size_waste = size_union - size_inter;
498 
499  pfree(union_d);
500  pfree(inter_d);
501 
502  /*
503  * are these a more promising split that what we've already seen?
504  */
505 
506  if (size_waste > waste || firsttime)
507  {
508  waste = size_waste;
509  seed_1 = i;
510  seed_2 = j;
511  firsttime = false;
512  }
513  }
514  }
515 
516  left = v->spl_left;
517  v->spl_nleft = 0;
518  right = v->spl_right;
519  v->spl_nright = 0;
520  if (seed_1 == 0 || seed_2 == 0)
521  {
522  seed_1 = 1;
523  seed_2 = 2;
524  }
525 
526  datum_alpha = GETENTRY(entryvec, seed_1);
527  datum_l = copy_intArrayType(datum_alpha);
528  rt__int_size(datum_l, &size_l);
529  datum_beta = GETENTRY(entryvec, seed_2);
530  datum_r = copy_intArrayType(datum_beta);
531  rt__int_size(datum_r, &size_r);
532 
533  maxoff = OffsetNumberNext(maxoff);
534 
535  /*
536  * sort entries
537  */
538  costvector = (SPLITCOST *) palloc(sizeof(SPLITCOST) * maxoff);
539  for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
540  {
541  costvector[i - 1].pos = i;
542  datum_alpha = GETENTRY(entryvec, i);
543  union_d = inner_int_union(datum_l, datum_alpha);
544  rt__int_size(union_d, &size_alpha);
545  pfree(union_d);
546  union_d = inner_int_union(datum_r, datum_alpha);
547  rt__int_size(union_d, &size_beta);
548  pfree(union_d);
549  costvector[i - 1].cost = fabsf((size_alpha - size_l) - (size_beta - size_r));
550  }
551  qsort(costvector, maxoff, sizeof(SPLITCOST), comparecost);
552 
553  /*
554  * Now split up the regions between the two seeds. An important property
555  * of this split algorithm is that the split vector v has the indices of
556  * items to be split in order in its left and right vectors. We exploit
557  * this property by doing a merge in the code that actually splits the
558  * page.
559  *
560  * For efficiency, we also place the new index tuple in this loop. This is
561  * handled at the very end, when we have placed all the existing tuples
562  * and i == maxoff + 1.
563  */
564 
565 
566  for (j = 0; j < maxoff; j++)
567  {
568  i = costvector[j].pos;
569 
570  /*
571  * If we've already decided where to place this item, just put it on
572  * the right list. Otherwise, we need to figure out which page needs
573  * the least enlargement in order to store the item.
574  */
575 
576  if (i == seed_1)
577  {
578  *left++ = i;
579  v->spl_nleft++;
580  continue;
581  }
582  else if (i == seed_2)
583  {
584  *right++ = i;
585  v->spl_nright++;
586  continue;
587  }
588 
589  /* okay, which page needs least enlargement? */
590  datum_alpha = GETENTRY(entryvec, i);
591  union_dl = inner_int_union(datum_l, datum_alpha);
592  union_dr = inner_int_union(datum_r, datum_alpha);
593  rt__int_size(union_dl, &size_alpha);
594  rt__int_size(union_dr, &size_beta);
595 
596  /* pick which page to add it to */
597  if (size_alpha - size_l < size_beta - size_r + WISH_F(v->spl_nleft, v->spl_nright, 0.01))
598  {
599  pfree(datum_l);
600  pfree(union_dr);
601  datum_l = union_dl;
602  size_l = size_alpha;
603  *left++ = i;
604  v->spl_nleft++;
605  }
606  else
607  {
608  pfree(datum_r);
609  pfree(union_dl);
610  datum_r = union_dr;
611  size_r = size_beta;
612  *right++ = i;
613  v->spl_nright++;
614  }
615  }
616  pfree(costvector);
617  *right = *left = FirstOffsetNumber;
618 
619  v->spl_ldatum = PointerGetDatum(datum_l);
620  v->spl_rdatum = PointerGetDatum(datum_r);
621 
623 }
624 
625 Datum
627 {
629 
630  init_local_reloptions(relopts, sizeof(GISTIntArrayOptions));
631  add_local_int_reloption(relopts, "numranges",
632  "number of ranges for compression",
634  offsetof(GISTIntArrayOptions, num_ranges));
635 
636  PG_RETURN_VOID();
637 }
ArrayType * inner_int_union(ArrayType *a, ArrayType *b)
Definition: _int_tool.c:79
bool inner_int_overlap(ArrayType *a, ArrayType *b)
Definition: _int_tool.c:50
ArrayType * inner_int_inter(ArrayType *a, ArrayType *b)
Definition: _int_tool.c:136
bool inner_int_contains(ArrayType *a, ArrayType *b)
Definition: _int_tool.c:15
#define G_INT_GET_NUMRANGES()
Definition: _int.h:14
int internal_size(int *a, int len)
Definition: _int_tool.c:293
#define PREPAREARR(x)
Definition: _int.h:49
ArrayType * copy_intArrayType(ArrayType *a)
Definition: _int_tool.c:281
void rt__int_size(ArrayType *a, float *size)
Definition: _int_tool.c:184
#define QSORT(a, direction)
Definition: _int.h:183
#define CHECKARRVALID(x)
Definition: _int.h:30
ArrayType * _int_unique(ArrayType *r)
Definition: _int_tool.c:311
#define BooleanSearchStrategy
Definition: _int.h:134
ArrayType * new_intArrayType(int num)
Definition: _int_tool.c:222
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:250
#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:364
Datum g_int_picksplit(PG_FUNCTION_ARGS)
Definition: _int_gist.c:442
#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:626
Datum g_int_same(PG_FUNCTION_ARGS)
Definition: _int_gist.c:386
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:429
#define DatumGetArrayTypePCopy(X)
Definition: array.h:262
#define PG_GETARG_ARRAYTYPE_P_COPY(n)
Definition: array.h:264
#define PG_GETARG_ARRAYTYPE_P(n)
Definition: array.h:263
#define DatumGetArrayTypeP(X)
Definition: array.h:261
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:860
int errmsg(const char *fmt,...)
Definition: elog.c:1075
#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:170
#define gistentryinit(e, k, r, pg, o, l)
Definition: gist.h:244
#define WISH_F(a, b, c)
Definition: hstore_gist.c:77
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:1431
void * palloc(Size size)
Definition: mcxt.c:1201
#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:449
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:163
Datum key
Definition: gist.h:160
Page page
Definition: gist.h:162
Relation rel
Definition: gist.h:161
bool leafkey
Definition: gist.h:164
int spl_nleft
Definition: gist.h:143
OffsetNumber * spl_right
Definition: gist.h:147
Datum spl_ldatum
Definition: gist.h:144
Datum spl_rdatum
Definition: gist.h:149
int spl_nright
Definition: gist.h:148
OffsetNumber * spl_left
Definition: gist.h:142
int32 n
Definition: gist.h:235
int32 cost
Definition: hstore_gist.c:354
OffsetNumber pos
Definition: hstore_gist.c:353
float cost
Definition: _int_gist.c:425
#define VARSIZE(PTR)
Definition: varatt.h:279