PostgreSQL Source Code  git master
rangetypes_gist.c File Reference
#include "postgres.h"
#include "access/gist.h"
#include "access/stratnum.h"
#include "utils/datum.h"
#include "utils/float.h"
#include "utils/fmgrprotos.h"
#include "utils/multirangetypes.h"
#include "utils/rangetypes.h"
Include dependency graph for rangetypes_gist.c:

Go to the source code of this file.

Data Structures

struct  SingleBoundSortItem
 
struct  ConsiderSplitContext
 
struct  NonEmptyRange
 
struct  CommonEntry
 

Macros

#define CLS_NORMAL   0 /* Ordinary finite range (no bits set) */
 
#define CLS_LOWER_INF   1 /* Lower bound is infinity */
 
#define CLS_UPPER_INF   2 /* Upper bound is infinity */
 
#define CLS_CONTAIN_EMPTY   4 /* Contains underlying empty ranges */
 
#define CLS_EMPTY   8 /* Special class for empty ranges */
 
#define CLS_COUNT
 
#define LIMIT_RATIO   0.3
 
#define INFINITE_BOUND_PENALTY   2.0
 
#define CONTAIN_EMPTY_PENALTY   1.0
 
#define DEFAULT_SUBTYPE_DIFF_PENALTY   1.0
 
#define PLACE_LEFT(range, off)
 
#define PLACE_RIGHT(range, off)
 
#define rangeCopy(r)
 

Enumerations

enum  SplitLR { SPLIT_LEFT = 0, SPLIT_RIGHT }
 

Functions

static RangeTyperange_super_union (TypeCacheEntry *typcache, RangeType *r1, RangeType *r2)
 
static bool range_gist_consistent_int_range (TypeCacheEntry *typcache, StrategyNumber strategy, const RangeType *key, const RangeType *query)
 
static bool range_gist_consistent_int_multirange (TypeCacheEntry *typcache, StrategyNumber strategy, const RangeType *key, const MultirangeType *query)
 
static bool range_gist_consistent_int_element (TypeCacheEntry *typcache, StrategyNumber strategy, const RangeType *key, Datum query)
 
static bool range_gist_consistent_leaf_range (TypeCacheEntry *typcache, StrategyNumber strategy, const RangeType *key, const RangeType *query)
 
static bool range_gist_consistent_leaf_multirange (TypeCacheEntry *typcache, StrategyNumber strategy, const RangeType *key, const MultirangeType *query)
 
static bool range_gist_consistent_leaf_element (TypeCacheEntry *typcache, StrategyNumber strategy, const RangeType *key, Datum query)
 
static void range_gist_fallback_split (TypeCacheEntry *typcache, GistEntryVector *entryvec, GIST_SPLITVEC *v)
 
static void range_gist_class_split (TypeCacheEntry *typcache, GistEntryVector *entryvec, GIST_SPLITVEC *v, SplitLR *classes_groups)
 
static void range_gist_single_sorting_split (TypeCacheEntry *typcache, GistEntryVector *entryvec, GIST_SPLITVEC *v, bool use_upper_bound)
 
static void range_gist_double_sorting_split (TypeCacheEntry *typcache, GistEntryVector *entryvec, GIST_SPLITVEC *v)
 
static void range_gist_consider_split (ConsiderSplitContext *context, RangeBound *right_lower, int min_left_count, RangeBound *left_upper, int max_left_count)
 
static int get_gist_range_class (RangeType *range)
 
static int single_bound_cmp (const void *a, const void *b, void *arg)
 
static int interval_cmp_lower (const void *a, const void *b, void *arg)
 
static int interval_cmp_upper (const void *a, const void *b, void *arg)
 
static int common_entry_cmp (const void *i1, const void *i2)
 
static float8 call_subtype_diff (TypeCacheEntry *typcache, Datum val1, Datum val2)
 
Datum range_gist_consistent (PG_FUNCTION_ARGS)
 
Datum multirange_gist_compress (PG_FUNCTION_ARGS)
 
Datum multirange_gist_consistent (PG_FUNCTION_ARGS)
 
Datum range_gist_union (PG_FUNCTION_ARGS)
 
Datum range_gist_penalty (PG_FUNCTION_ARGS)
 
Datum range_gist_picksplit (PG_FUNCTION_ARGS)
 
Datum range_gist_same (PG_FUNCTION_ARGS)
 
static bool multirange_union_range_equal (TypeCacheEntry *typcache, const RangeType *r, const MultirangeType *mr)
 

Macro Definition Documentation

◆ CLS_CONTAIN_EMPTY

#define CLS_CONTAIN_EMPTY   4 /* Contains underlying empty ranges */

Definition at line 33 of file rangetypes_gist.c.

Referenced by get_gist_range_class(), and range_gist_picksplit().

◆ CLS_COUNT

#define CLS_COUNT
Value:
9 /* # of classes; includes all combinations of
* properties. CLS_EMPTY doesn't combine with
* anything else, so it's only 2^3 + 1. */

Definition at line 36 of file rangetypes_gist.c.

Referenced by range_gist_picksplit().

◆ CLS_EMPTY

#define CLS_EMPTY   8 /* Special class for empty ranges */

Definition at line 34 of file rangetypes_gist.c.

Referenced by get_gist_range_class(), and range_gist_picksplit().

◆ CLS_LOWER_INF

#define CLS_LOWER_INF   1 /* Lower bound is infinity */

Definition at line 31 of file rangetypes_gist.c.

Referenced by get_gist_range_class(), and range_gist_picksplit().

◆ CLS_NORMAL

#define CLS_NORMAL   0 /* Ordinary finite range (no bits set) */

Definition at line 30 of file rangetypes_gist.c.

Referenced by range_gist_picksplit().

◆ CLS_UPPER_INF

#define CLS_UPPER_INF   2 /* Upper bound is infinity */

Definition at line 32 of file rangetypes_gist.c.

Referenced by get_gist_range_class(), and range_gist_picksplit().

◆ CONTAIN_EMPTY_PENALTY

#define CONTAIN_EMPTY_PENALTY   1.0

Definition at line 49 of file rangetypes_gist.c.

Referenced by range_gist_penalty().

◆ DEFAULT_SUBTYPE_DIFF_PENALTY

#define DEFAULT_SUBTYPE_DIFF_PENALTY   1.0

Definition at line 50 of file rangetypes_gist.c.

Referenced by range_gist_penalty().

◆ INFINITE_BOUND_PENALTY

#define INFINITE_BOUND_PENALTY   2.0

Definition at line 48 of file rangetypes_gist.c.

Referenced by range_gist_penalty().

◆ LIMIT_RATIO

#define LIMIT_RATIO   0.3

Definition at line 45 of file rangetypes_gist.c.

Referenced by range_gist_consider_split().

◆ PLACE_LEFT

#define PLACE_LEFT (   range,
  off 
)
Value:
do { \
if (v->spl_nleft > 0) \
left_range = range_super_union(typcache, left_range, range); \
else \
left_range = (range); \
v->spl_left[v->spl_nleft++] = (off); \
} while(0)
static struct cvec * range(struct vars *v, chr a, chr b, int cases)
Definition: regc_locale.c:412
static RangeType * range_super_union(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2)

Definition at line 114 of file rangetypes_gist.c.

Referenced by range_gist_class_split(), range_gist_double_sorting_split(), range_gist_fallback_split(), and range_gist_single_sorting_split().

◆ PLACE_RIGHT

#define PLACE_RIGHT (   range,
  off 
)
Value:
do { \
if (v->spl_nright > 0) \
right_range = range_super_union(typcache, right_range, range); \
else \
right_range = (range); \
v->spl_right[v->spl_nright++] = (off); \
} while(0)
static struct cvec * range(struct vars *v, chr a, chr b, int cases)
Definition: regc_locale.c:412
static RangeType * range_super_union(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2)

Definition at line 123 of file rangetypes_gist.c.

Referenced by range_gist_class_split(), range_gist_double_sorting_split(), range_gist_fallback_split(), and range_gist_single_sorting_split().

◆ rangeCopy

#define rangeCopy (   r)
Value:
false, -1)))
#define PointerGetDatum(X)
Definition: postgres.h:600
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:131
#define DatumGetPointer(X)
Definition: postgres.h:593

Definition at line 133 of file rangetypes_gist.c.

Referenced by range_super_union().

Enumeration Type Documentation

◆ SplitLR

enum SplitLR
Enumerator
SPLIT_LEFT 
SPLIT_RIGHT 

Definition at line 62 of file rangetypes_gist.c.

63 {
64  SPLIT_LEFT = 0, /* makes initialization to SPLIT_LEFT easier */
66 } SplitLR;
SplitLR

Function Documentation

◆ call_subtype_diff()

static float8 call_subtype_diff ( TypeCacheEntry typcache,
Datum  val1,
Datum  val2 
)
static

Definition at line 1787 of file rangetypes_gist.c.

References DatumGetFloat8, FunctionCall2Coll(), TypeCacheEntry::rng_collation, TypeCacheEntry::rng_subdiff_finfo, and value.

Referenced by range_gist_consider_split(), range_gist_double_sorting_split(), and range_gist_penalty().

1788 {
1789  float8 value;
1790 
1792  typcache->rng_collation,
1793  val1, val2));
1794  /* Cope with buggy subtype_diff function by returning zero */
1795  if (value >= 0.0)
1796  return value;
1797  return 0.0;
1798 }
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1148
FmgrInfo rng_subdiff_finfo
Definition: typcache.h:102
double float8
Definition: c.h:565
#define DatumGetFloat8(X)
Definition: postgres.h:758
static struct @143 value
Oid rng_collation
Definition: typcache.h:99

◆ common_entry_cmp()

static int common_entry_cmp ( const void *  i1,
const void *  i2 
)
static

Definition at line 1769 of file rangetypes_gist.c.

Referenced by range_gist_double_sorting_split().

1770 {
1771  double delta1 = ((CommonEntry *) i1)->delta;
1772  double delta2 = ((CommonEntry *) i2)->delta;
1773 
1774  if (delta1 < delta2)
1775  return -1;
1776  else if (delta1 > delta2)
1777  return 1;
1778  else
1779  return 0;
1780 }

◆ get_gist_range_class()

static int get_gist_range_class ( RangeType range)
static

Definition at line 1703 of file rangetypes_gist.c.

References CLS_CONTAIN_EMPTY, CLS_EMPTY, CLS_LOWER_INF, CLS_UPPER_INF, RANGE_CONTAIN_EMPTY, RANGE_EMPTY, range_get_flags(), RANGE_LB_INF, and RANGE_UB_INF.

Referenced by range_gist_picksplit().

1704 {
1705  int classNumber;
1706  char flags;
1707 
1708  flags = range_get_flags(range);
1709  if (flags & RANGE_EMPTY)
1710  {
1711  classNumber = CLS_EMPTY;
1712  }
1713  else
1714  {
1715  classNumber = 0;
1716  if (flags & RANGE_LB_INF)
1717  classNumber |= CLS_LOWER_INF;
1718  if (flags & RANGE_UB_INF)
1719  classNumber |= CLS_UPPER_INF;
1720  if (flags & RANGE_CONTAIN_EMPTY)
1721  classNumber |= CLS_CONTAIN_EMPTY;
1722  }
1723  return classNumber;
1724 }
#define CLS_EMPTY
#define RANGE_EMPTY
Definition: rangetypes.h:38
char range_get_flags(const RangeType *range)
Definition: rangetypes.c:1855
#define RANGE_LB_INF
Definition: rangetypes.h:41
#define CLS_CONTAIN_EMPTY
#define CLS_LOWER_INF
#define RANGE_CONTAIN_EMPTY
Definition: rangetypes.h:45
#define CLS_UPPER_INF
#define RANGE_UB_INF
Definition: rangetypes.h:42

◆ interval_cmp_lower()

static int interval_cmp_lower ( const void *  a,
const void *  b,
void *  arg 
)
static

Definition at line 1743 of file rangetypes_gist.c.

References NonEmptyRange::lower, and range_cmp_bounds().

Referenced by range_gist_double_sorting_split().

1744 {
1745  NonEmptyRange *i1 = (NonEmptyRange *) a;
1746  NonEmptyRange *i2 = (NonEmptyRange *) b;
1747  TypeCacheEntry *typcache = (TypeCacheEntry *) arg;
1748 
1749  return range_cmp_bounds(typcache, &i1->lower, &i2->lower);
1750 }
RangeBound lower
void * arg
int range_cmp_bounds(TypeCacheEntry *typcache, const RangeBound *b1, const RangeBound *b2)
Definition: rangetypes.c:1924

◆ interval_cmp_upper()

static int interval_cmp_upper ( const void *  a,
const void *  b,
void *  arg 
)
static

Definition at line 1756 of file rangetypes_gist.c.

References range_cmp_bounds(), and NonEmptyRange::upper.

Referenced by range_gist_double_sorting_split().

1757 {
1758  NonEmptyRange *i1 = (NonEmptyRange *) a;
1759  NonEmptyRange *i2 = (NonEmptyRange *) b;
1760  TypeCacheEntry *typcache = (TypeCacheEntry *) arg;
1761 
1762  return range_cmp_bounds(typcache, &i1->upper, &i2->upper);
1763 }
RangeBound upper
void * arg
int range_cmp_bounds(TypeCacheEntry *typcache, const RangeBound *b1, const RangeBound *b2)
Definition: rangetypes.c:1924

◆ multirange_gist_compress()

Datum multirange_gist_compress ( PG_FUNCTION_ARGS  )

Definition at line 245 of file rangetypes_gist.c.

References DatumGetMultirangeTypeP, gistentryinit, GISTENTRY::key, GISTENTRY::leafkey, multirange_get_typcache(), multirange_get_union_range(), MultirangeTypeGetOid, GISTENTRY::offset, GISTENTRY::page, palloc(), PG_GETARG_POINTER, PG_RETURN_POINTER, RangeTypePGetDatum, GISTENTRY::rel, and TypeCacheEntry::rngtype.

246 {
247  GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
248 
249  if (entry->leafkey)
250  {
252  RangeType *r;
253  TypeCacheEntry *typcache;
254  GISTENTRY *retval = palloc(sizeof(GISTENTRY));
255 
256  typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
257  r = multirange_get_union_range(typcache->rngtype, mr);
258 
259  gistentryinit(*retval, RangeTypePGetDatum(r),
260  entry->rel, entry->page, entry->offset, false);
261 
262  PG_RETURN_POINTER(retval);
263  }
264 
265  PG_RETURN_POINTER(entry);
266 }
Relation rel
Definition: gist.h:161
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
RangeType * multirange_get_union_range(TypeCacheEntry *rangetyp, const MultirangeType *mr)
#define RangeTypePGetDatum(X)
Definition: rangetypes.h:75
Page page
Definition: gist.h:162
#define DatumGetMultirangeTypeP(X)
Datum key
Definition: gist.h:160
TypeCacheEntry * multirange_get_typcache(FunctionCallInfo fcinfo, Oid mltrngtypid)
bool leafkey
Definition: gist.h:164
#define gistentryinit(e, k, r, pg, o, l)
Definition: gist.h:244
struct TypeCacheEntry * rngtype
Definition: typcache.h:107
void * palloc(Size size)
Definition: mcxt.c:1062
#define MultirangeTypeGetOid(mr)
OffsetNumber offset
Definition: gist.h:163

◆ multirange_gist_consistent()

Datum multirange_gist_consistent ( PG_FUNCTION_ARGS  )

Definition at line 270 of file rangetypes_gist.c.

References DatumGetMultirangeTypeP, DatumGetRangeTypeP, GIST_LEAF, sort-test::key, GISTENTRY::key, OidIsValid, PG_GETARG_DATUM, PG_GETARG_OID, PG_GETARG_POINTER, PG_GETARG_UINT16, PG_RETURN_BOOL, range_get_typcache(), range_gist_consistent_int_element(), range_gist_consistent_int_multirange(), range_gist_consistent_int_range(), range_gist_consistent_leaf_element(), range_gist_consistent_leaf_multirange(), range_gist_consistent_leaf_range(), and RangeTypeGetOid.

271 {
272  GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
273  Datum query = PG_GETARG_DATUM(1);
275  bool result;
276  Oid subtype = PG_GETARG_OID(3);
277  bool *recheck = (bool *) PG_GETARG_POINTER(4);
278  RangeType *key = DatumGetRangeTypeP(entry->key);
279  TypeCacheEntry *typcache;
280 
281  /*
282  * All operators served by this function are inexact because multirange is
283  * approximated by union range with no gaps.
284  */
285  *recheck = true;
286 
287  typcache = range_get_typcache(fcinfo, RangeTypeGetOid(key));
288 
289  /*
290  * Perform consistent checking using function corresponding to key type
291  * (leaf or internal) and query subtype (range, multirange, or element).
292  * Note that invalid subtype means that query type matches key type
293  * (multirange).
294  */
295  if (GIST_LEAF(entry))
296  {
297  if (!OidIsValid(subtype) || subtype == ANYMULTIRANGEOID)
298  result = range_gist_consistent_leaf_multirange(typcache, strategy, key,
299  DatumGetMultirangeTypeP(query));
300  else if (subtype == ANYRANGEOID)
301  result = range_gist_consistent_leaf_range(typcache, strategy, key,
302  DatumGetRangeTypeP(query));
303  else
304  result = range_gist_consistent_leaf_element(typcache, strategy,
305  key, query);
306  }
307  else
308  {
309  if (!OidIsValid(subtype) || subtype == ANYMULTIRANGEOID)
310  result = range_gist_consistent_int_multirange(typcache, strategy, key,
311  DatumGetMultirangeTypeP(query));
312  else if (subtype == ANYRANGEOID)
313  result = range_gist_consistent_int_range(typcache, strategy, key,
314  DatumGetRangeTypeP(query));
315  else
316  result = range_gist_consistent_int_element(typcache, strategy,
317  key, query);
318  }
319  PG_RETURN_BOOL(result);
320 }
#define GIST_LEAF(entry)
Definition: gist.h:170
static bool range_gist_consistent_int_element(TypeCacheEntry *typcache, StrategyNumber strategy, const RangeType *key, Datum query)
TypeCacheEntry * range_get_typcache(FunctionCallInfo fcinfo, Oid rngtypid)
Definition: rangetypes.c:1635
#define RangeTypeGetOid(r)
Definition: rangetypes.h:35
static bool range_gist_consistent_int_multirange(TypeCacheEntry *typcache, StrategyNumber strategy, const RangeType *key, const MultirangeType *query)
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:268
uint16 StrategyNumber
Definition: stratnum.h:22
static bool range_gist_consistent_leaf_element(TypeCacheEntry *typcache, StrategyNumber strategy, const RangeType *key, Datum query)
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:710
static bool range_gist_consistent_leaf_multirange(TypeCacheEntry *typcache, StrategyNumber strategy, const RangeType *key, const MultirangeType *query)
static bool range_gist_consistent_leaf_range(TypeCacheEntry *typcache, StrategyNumber strategy, const RangeType *key, const RangeType *query)
#define DatumGetMultirangeTypeP(X)
Datum key
Definition: gist.h:160
#define PG_GETARG_OID(n)
Definition: fmgr.h:275
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:359
uintptr_t Datum
Definition: postgres.h:411
#define DatumGetRangeTypeP(X)
Definition: rangetypes.h:73
#define PG_GETARG_UINT16(n)
Definition: fmgr.h:272
static bool range_gist_consistent_int_range(TypeCacheEntry *typcache, StrategyNumber strategy, const RangeType *key, const RangeType *query)

◆ multirange_union_range_equal()

static bool multirange_union_range_equal ( TypeCacheEntry typcache,
const RangeType r,
const MultirangeType mr 
)
static

Definition at line 888 of file rangetypes_gist.c.

References Assert, multirange_get_bounds(), MultirangeIsEmpty, range_cmp_bounds(), range_deserialize(), MultirangeType::rangeCount, and RangeIsEmpty.

Referenced by range_gist_consistent_leaf_multirange().

891 {
892  RangeBound lower1,
893  upper1,
894  lower2,
895  upper2,
896  tmp;
897  bool empty;
898 
899  if (RangeIsEmpty(r) || MultirangeIsEmpty(mr))
900  return (RangeIsEmpty(r) && MultirangeIsEmpty(mr));
901 
902  range_deserialize(typcache, r, &lower1, &upper1, &empty);
903  Assert(!empty);
904  multirange_get_bounds(typcache, mr, 0, &lower2, &tmp);
905  multirange_get_bounds(typcache, mr, mr->rangeCount - 1, &tmp, &upper2);
906 
907  return (range_cmp_bounds(typcache, &lower1, &lower2) == 0 &&
908  range_cmp_bounds(typcache, &upper1, &upper2) == 0);
909 }
#define RangeIsEmpty(r)
Definition: rangetypes.h:56
void multirange_get_bounds(TypeCacheEntry *rangetyp, const MultirangeType *multirange, uint32 i, RangeBound *lower, RangeBound *upper)
#define Assert(condition)
Definition: c.h:804
#define MultirangeIsEmpty(mr)
static Ranges * range_deserialize(int maxvalues, SerializedRanges *range)
int range_cmp_bounds(TypeCacheEntry *typcache, const RangeBound *b1, const RangeBound *b2)
Definition: rangetypes.c:1924

◆ range_gist_class_split()

static void range_gist_class_split ( TypeCacheEntry typcache,
GistEntryVector entryvec,
GIST_SPLITVEC v,
SplitLR classes_groups 
)
static

Definition at line 1186 of file rangetypes_gist.c.

References Assert, DatumGetRangeTypeP, FirstOffsetNumber, i, GISTENTRY::key, GistEntryVector::n, OffsetNumberNext, PLACE_LEFT, PLACE_RIGHT, range(), RangeTypePGetDatum, GIST_SPLITVEC::spl_ldatum, GIST_SPLITVEC::spl_nleft, GIST_SPLITVEC::spl_nright, GIST_SPLITVEC::spl_rdatum, SPLIT_LEFT, SPLIT_RIGHT, and GistEntryVector::vector.

Referenced by range_gist_picksplit().

1190 {
1191  RangeType *left_range = NULL;
1192  RangeType *right_range = NULL;
1193  OffsetNumber i,
1194  maxoff;
1195 
1196  maxoff = entryvec->n - 1;
1197 
1198  v->spl_nleft = 0;
1199  v->spl_nright = 0;
1200  for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
1201  {
1202  RangeType *range = DatumGetRangeTypeP(entryvec->vector[i].key);
1203  int class;
1204 
1205  /* Get class of range */
1206  class = get_gist_range_class(range);
1207 
1208  /* Place range to appropriate page */
1209  if (classes_groups[class] == SPLIT_LEFT)
1210  PLACE_LEFT(range, i);
1211  else
1212  {
1213  Assert(classes_groups[class] == SPLIT_RIGHT);
1214  PLACE_RIGHT(range, i);
1215  }
1216  }
1217 
1218  v->spl_ldatum = RangeTypePGetDatum(left_range);
1219  v->spl_rdatum = RangeTypePGetDatum(right_range);
1220 }
Datum spl_rdatum
Definition: gist.h:149
int32 n
Definition: gist.h:235
int spl_nleft
Definition: gist.h:143
#define RangeTypePGetDatum(X)
Definition: rangetypes.h:75
uint16 OffsetNumber
Definition: off.h:24
GISTENTRY vector[FLEXIBLE_ARRAY_MEMBER]
Definition: gist.h:236
#define PLACE_LEFT(range, off)
int spl_nright
Definition: gist.h:148
Datum key
Definition: gist.h:160
#define FirstOffsetNumber
Definition: off.h:27
static struct cvec * range(struct vars *v, chr a, chr b, int cases)
Definition: regc_locale.c:412
#define PLACE_RIGHT(range, off)
Datum spl_ldatum
Definition: gist.h:144
#define Assert(condition)
Definition: c.h:804
#define OffsetNumberNext(offsetNumber)
Definition: off.h:52
#define DatumGetRangeTypeP(X)
Definition: rangetypes.h:73
int i

◆ range_gist_consider_split()

static void range_gist_consider_split ( ConsiderSplitContext context,
RangeBound right_lower,
int  min_left_count,
RangeBound left_upper,
int  max_left_count 
)
static

Definition at line 1620 of file rangetypes_gist.c.

References call_subtype_diff(), ConsiderSplitContext::common_left, ConsiderSplitContext::common_right, ConsiderSplitContext::entries_count, ConsiderSplitContext::first, ConsiderSplitContext::has_subtype_diff, ConsiderSplitContext::left_upper, LIMIT_RATIO, Min, ConsiderSplitContext::overlap, ConsiderSplitContext::ratio, ConsiderSplitContext::right_lower, ConsiderSplitContext::typcache, and RangeBound::val.

Referenced by range_gist_double_sorting_split().

1623 {
1624  int left_count,
1625  right_count;
1626  float4 ratio,
1627  overlap;
1628 
1629  /*
1630  * Calculate entries distribution ratio assuming most uniform distribution
1631  * of common entries.
1632  */
1633  if (min_left_count >= (context->entries_count + 1) / 2)
1634  left_count = min_left_count;
1635  else if (max_left_count <= context->entries_count / 2)
1636  left_count = max_left_count;
1637  else
1638  left_count = context->entries_count / 2;
1639  right_count = context->entries_count - left_count;
1640 
1641  /*
1642  * Ratio of split: quotient between size of smaller group and total
1643  * entries count. This is necessarily 0.5 or less; if it's less than
1644  * LIMIT_RATIO then we will never accept the new split.
1645  */
1646  ratio = ((float4) Min(left_count, right_count)) /
1647  ((float4) context->entries_count);
1648 
1649  if (ratio > LIMIT_RATIO)
1650  {
1651  bool selectthis = false;
1652 
1653  /*
1654  * The ratio is acceptable, so compare current split with previously
1655  * selected one. We search for minimal overlap (allowing negative
1656  * values) and minimal ratio secondarily. If subtype_diff is
1657  * available, it's used for overlap measure. Without subtype_diff we
1658  * use number of "common entries" as an overlap measure.
1659  */
1660  if (context->has_subtype_diff)
1661  overlap = call_subtype_diff(context->typcache,
1662  left_upper->val,
1663  right_lower->val);
1664  else
1665  overlap = max_left_count - min_left_count;
1666 
1667  /* If there is no previous selection, select this split */
1668  if (context->first)
1669  selectthis = true;
1670  else
1671  {
1672  /*
1673  * Choose the new split if it has a smaller overlap, or same
1674  * overlap but better ratio.
1675  */
1676  if (overlap < context->overlap ||
1677  (overlap == context->overlap && ratio > context->ratio))
1678  selectthis = true;
1679  }
1680 
1681  if (selectthis)
1682  {
1683  /* save information about selected split */
1684  context->first = false;
1685  context->ratio = ratio;
1686  context->overlap = overlap;
1687  context->right_lower = right_lower;
1688  context->left_upper = left_upper;
1689  context->common_left = max_left_count - left_count;
1690  context->common_right = left_count - min_left_count;
1691  }
1692  }
1693 }
RangeBound * right_lower
RangeBound * left_upper
#define Min(x, y)
Definition: c.h:986
Datum val
Definition: rangetypes.h:64
static float8 call_subtype_diff(TypeCacheEntry *typcache, Datum val1, Datum val2)
#define LIMIT_RATIO
float float4
Definition: c.h:564
TypeCacheEntry * typcache

◆ range_gist_consistent()

Datum range_gist_consistent ( PG_FUNCTION_ARGS  )

Definition at line 191 of file rangetypes_gist.c.

References DatumGetMultirangeTypeP, DatumGetRangeTypeP, GIST_LEAF, sort-test::key, GISTENTRY::key, OidIsValid, PG_GETARG_DATUM, PG_GETARG_OID, PG_GETARG_POINTER, PG_GETARG_UINT16, PG_RETURN_BOOL, range_get_typcache(), range_gist_consistent_int_element(), range_gist_consistent_int_multirange(), range_gist_consistent_int_range(), range_gist_consistent_leaf_element(), range_gist_consistent_leaf_multirange(), range_gist_consistent_leaf_range(), and RangeTypeGetOid.

192 {
193  GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
194  Datum query = PG_GETARG_DATUM(1);
196  bool result;
197  Oid subtype = PG_GETARG_OID(3);
198  bool *recheck = (bool *) PG_GETARG_POINTER(4);
199  RangeType *key = DatumGetRangeTypeP(entry->key);
200  TypeCacheEntry *typcache;
201 
202  /* All operators served by this function are exact */
203  *recheck = false;
204 
205  typcache = range_get_typcache(fcinfo, RangeTypeGetOid(key));
206 
207  /*
208  * Perform consistent checking using function corresponding to key type
209  * (leaf or internal) and query subtype (range, multirange, or element).
210  * Note that invalid subtype means that query type matches key type
211  * (range).
212  */
213  if (GIST_LEAF(entry))
214  {
215  if (!OidIsValid(subtype) || subtype == ANYRANGEOID)
216  result = range_gist_consistent_leaf_range(typcache, strategy, key,
217  DatumGetRangeTypeP(query));
218  else if (subtype == ANYMULTIRANGEOID)
219  result = range_gist_consistent_leaf_multirange(typcache, strategy, key,
220  DatumGetMultirangeTypeP(query));
221  else
222  result = range_gist_consistent_leaf_element(typcache, strategy,
223  key, query);
224  }
225  else
226  {
227  if (!OidIsValid(subtype) || subtype == ANYRANGEOID)
228  result = range_gist_consistent_int_range(typcache, strategy, key,
229  DatumGetRangeTypeP(query));
230  else if (subtype == ANYMULTIRANGEOID)
231  result = range_gist_consistent_int_multirange(typcache, strategy, key,
232  DatumGetMultirangeTypeP(query));
233  else
234  result = range_gist_consistent_int_element(typcache, strategy,
235  key, query);
236  }
237  PG_RETURN_BOOL(result);
238 }
#define GIST_LEAF(entry)
Definition: gist.h:170
static bool range_gist_consistent_int_element(TypeCacheEntry *typcache, StrategyNumber strategy, const RangeType *key, Datum query)
TypeCacheEntry * range_get_typcache(FunctionCallInfo fcinfo, Oid rngtypid)
Definition: rangetypes.c:1635
#define RangeTypeGetOid(r)
Definition: rangetypes.h:35
static bool range_gist_consistent_int_multirange(TypeCacheEntry *typcache, StrategyNumber strategy, const RangeType *key, const MultirangeType *query)
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:268
uint16 StrategyNumber
Definition: stratnum.h:22
static bool range_gist_consistent_leaf_element(TypeCacheEntry *typcache, StrategyNumber strategy, const RangeType *key, Datum query)
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:710
static bool range_gist_consistent_leaf_multirange(TypeCacheEntry *typcache, StrategyNumber strategy, const RangeType *key, const MultirangeType *query)
static bool range_gist_consistent_leaf_range(TypeCacheEntry *typcache, StrategyNumber strategy, const RangeType *key, const RangeType *query)
#define DatumGetMultirangeTypeP(X)
Datum key
Definition: gist.h:160
#define PG_GETARG_OID(n)
Definition: fmgr.h:275
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:359
uintptr_t Datum
Definition: postgres.h:411
#define DatumGetRangeTypeP(X)
Definition: rangetypes.h:73
#define PG_GETARG_UINT16(n)
Definition: fmgr.h:272
static bool range_gist_consistent_int_range(TypeCacheEntry *typcache, StrategyNumber strategy, const RangeType *key, const RangeType *query)

◆ range_gist_consistent_int_element()

static bool range_gist_consistent_int_element ( TypeCacheEntry typcache,
StrategyNumber  strategy,
const RangeType key,
Datum  query 
)
static

Definition at line 1039 of file rangetypes_gist.c.

References elog, ERROR, range_contains_elem_internal(), and RANGESTRAT_CONTAINS_ELEM.

Referenced by multirange_gist_consistent(), and range_gist_consistent().

1043 {
1044  switch (strategy)
1045  {
1047  return range_contains_elem_internal(typcache, key, query);
1048  default:
1049  elog(ERROR, "unrecognized range strategy: %d", strategy);
1050  return false; /* keep compiler quiet */
1051  }
1052 }
bool range_contains_elem_internal(TypeCacheEntry *typcache, const RangeType *r, Datum val)
Definition: rangetypes.c:2473
#define ERROR
Definition: elog.h:46
#define RANGESTRAT_CONTAINS_ELEM
Definition: rangetypes.h:90
#define elog(elevel,...)
Definition: elog.h:232

◆ range_gist_consistent_int_multirange()

static bool range_gist_consistent_int_multirange ( TypeCacheEntry typcache,
StrategyNumber  strategy,
const RangeType key,
const MultirangeType query 
)
static

Definition at line 977 of file rangetypes_gist.c.

References elog, ERROR, MultirangeIsEmpty, range_adjacent_multirange_internal(), range_after_multirange_internal(), range_before_multirange_internal(), range_contains_multirange_internal(), range_overlaps_multirange_internal(), range_overleft_multirange_internal(), range_overright_multirange_internal(), RangeIsEmpty, RangeIsOrContainsEmpty, RANGESTRAT_ADJACENT, RANGESTRAT_AFTER, RANGESTRAT_BEFORE, RANGESTRAT_CONTAINED_BY, RANGESTRAT_CONTAINS, RANGESTRAT_EQ, RANGESTRAT_OVERLAPS, RANGESTRAT_OVERLEFT, and RANGESTRAT_OVERRIGHT.

Referenced by multirange_gist_consistent(), and range_gist_consistent().

981 {
982  switch (strategy)
983  {
984  case RANGESTRAT_BEFORE:
985  if (RangeIsEmpty(key) || MultirangeIsEmpty(query))
986  return false;
987  return (!range_overright_multirange_internal(typcache, key, query));
988  case RANGESTRAT_OVERLEFT:
989  if (RangeIsEmpty(key) || MultirangeIsEmpty(query))
990  return false;
991  return (!range_after_multirange_internal(typcache, key, query));
992  case RANGESTRAT_OVERLAPS:
993  return range_overlaps_multirange_internal(typcache, key, query);
995  if (RangeIsEmpty(key) || MultirangeIsEmpty(query))
996  return false;
997  return (!range_before_multirange_internal(typcache, key, query));
998  case RANGESTRAT_AFTER:
999  if (RangeIsEmpty(key) || MultirangeIsEmpty(query))
1000  return false;
1001  return (!range_overleft_multirange_internal(typcache, key, query));
1002  case RANGESTRAT_ADJACENT:
1003  if (RangeIsEmpty(key) || MultirangeIsEmpty(query))
1004  return false;
1005  if (range_adjacent_multirange_internal(typcache, key, query))
1006  return true;
1007  return range_overlaps_multirange_internal(typcache, key, query);
1008  case RANGESTRAT_CONTAINS:
1009  return range_contains_multirange_internal(typcache, key, query);
1011 
1012  /*
1013  * Empty ranges are contained by anything, so if key is or
1014  * contains any empty ranges, we must descend into it. Otherwise,
1015  * descend only if key overlaps the query.
1016  */
1017  if (RangeIsOrContainsEmpty(key))
1018  return true;
1019  return range_overlaps_multirange_internal(typcache, key, query);
1020  case RANGESTRAT_EQ:
1021 
1022  /*
1023  * If query is empty, descend only if the key is or contains any
1024  * empty ranges. Otherwise, descend if key contains query.
1025  */
1026  if (MultirangeIsEmpty(query))
1027  return RangeIsOrContainsEmpty(key);
1028  return range_contains_multirange_internal(typcache, key, query);
1029  default:
1030  elog(ERROR, "unrecognized range strategy: %d", strategy);
1031  return false; /* keep compiler quiet */
1032  }
1033 }
#define RangeIsEmpty(r)
Definition: rangetypes.h:56
#define RANGESTRAT_OVERRIGHT
Definition: rangetypes.h:85
#define RANGESTRAT_ADJACENT
Definition: rangetypes.h:87
#define ERROR
Definition: elog.h:46
bool range_overleft_multirange_internal(TypeCacheEntry *rangetyp, const RangeType *r, const MultirangeType *mr)
bool range_overright_multirange_internal(TypeCacheEntry *rangetyp, const RangeType *r, const MultirangeType *mr)
#define RANGESTRAT_BEFORE
Definition: rangetypes.h:82
bool range_before_multirange_internal(TypeCacheEntry *rangetyp, const RangeType *r, const MultirangeType *mr)
bool range_contains_multirange_internal(TypeCacheEntry *rangetyp, const RangeType *r, const MultirangeType *mr)
#define RANGESTRAT_CONTAINS
Definition: rangetypes.h:88
#define RANGESTRAT_CONTAINED_BY
Definition: rangetypes.h:89
#define RANGESTRAT_OVERLEFT
Definition: rangetypes.h:83
#define RANGESTRAT_EQ
Definition: rangetypes.h:91
#define MultirangeIsEmpty(mr)
bool range_adjacent_multirange_internal(TypeCacheEntry *rangetyp, const RangeType *r, const MultirangeType *mr)
#define RangeIsOrContainsEmpty(r)
Definition: rangetypes.h:57
#define RANGESTRAT_OVERLAPS
Definition: rangetypes.h:84
#define elog(elevel,...)
Definition: elog.h:232
bool range_overlaps_multirange_internal(TypeCacheEntry *rangetyp, const RangeType *r, const MultirangeType *mr)
#define RANGESTRAT_AFTER
Definition: rangetypes.h:86
bool range_after_multirange_internal(TypeCacheEntry *rangetyp, const RangeType *r, const MultirangeType *mr)

◆ range_gist_consistent_int_range()

static bool range_gist_consistent_int_range ( TypeCacheEntry typcache,
StrategyNumber  strategy,
const RangeType key,
const RangeType query 
)
static

Definition at line 915 of file rangetypes_gist.c.

References elog, ERROR, range_adjacent_internal(), range_after_internal(), range_before_internal(), range_contains_internal(), range_overlaps_internal(), range_overleft_internal(), range_overright_internal(), RangeIsEmpty, RangeIsOrContainsEmpty, RANGESTRAT_ADJACENT, RANGESTRAT_AFTER, RANGESTRAT_BEFORE, RANGESTRAT_CONTAINED_BY, RANGESTRAT_CONTAINS, RANGESTRAT_EQ, RANGESTRAT_OVERLAPS, RANGESTRAT_OVERLEFT, and RANGESTRAT_OVERRIGHT.

Referenced by multirange_gist_consistent(), and range_gist_consistent().

919 {
920  switch (strategy)
921  {
922  case RANGESTRAT_BEFORE:
923  if (RangeIsEmpty(key) || RangeIsEmpty(query))
924  return false;
925  return (!range_overright_internal(typcache, key, query));
926  case RANGESTRAT_OVERLEFT:
927  if (RangeIsEmpty(key) || RangeIsEmpty(query))
928  return false;
929  return (!range_after_internal(typcache, key, query));
930  case RANGESTRAT_OVERLAPS:
931  return range_overlaps_internal(typcache, key, query);
933  if (RangeIsEmpty(key) || RangeIsEmpty(query))
934  return false;
935  return (!range_before_internal(typcache, key, query));
936  case RANGESTRAT_AFTER:
937  if (RangeIsEmpty(key) || RangeIsEmpty(query))
938  return false;
939  return (!range_overleft_internal(typcache, key, query));
940  case RANGESTRAT_ADJACENT:
941  if (RangeIsEmpty(key) || RangeIsEmpty(query))
942  return false;
943  if (range_adjacent_internal(typcache, key, query))
944  return true;
945  return range_overlaps_internal(typcache, key, query);
946  case RANGESTRAT_CONTAINS:
947  return range_contains_internal(typcache, key, query);
949 
950  /*
951  * Empty ranges are contained by anything, so if key is or
952  * contains any empty ranges, we must descend into it. Otherwise,
953  * descend only if key overlaps the query.
954  */
955  if (RangeIsOrContainsEmpty(key))
956  return true;
957  return range_overlaps_internal(typcache, key, query);
958  case RANGESTRAT_EQ:
959 
960  /*
961  * If query is empty, descend only if the key is or contains any
962  * empty ranges. Otherwise, descend if key contains query.
963  */
964  if (RangeIsEmpty(query))
965  return RangeIsOrContainsEmpty(key);
966  return range_contains_internal(typcache, key, query);
967  default:
968  elog(ERROR, "unrecognized range strategy: %d", strategy);
969  return false; /* keep compiler quiet */
970  }
971 }
#define RangeIsEmpty(r)
Definition: rangetypes.h:56
bool range_overlaps_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
Definition: rangetypes.c:823
#define RANGESTRAT_OVERRIGHT
Definition: rangetypes.h:85
#define RANGESTRAT_ADJACENT
Definition: rangetypes.h:87
bool range_after_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
Definition: rangetypes.c:684
#define ERROR
Definition: elog.h:46
#define RANGESTRAT_BEFORE
Definition: rangetypes.h:82
bool range_contains_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
Definition: rangetypes.c:2432
#define RANGESTRAT_CONTAINS
Definition: rangetypes.h:88
bool range_overleft_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
Definition: rangetypes.c:869
bool range_before_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
Definition: rangetypes.c:646
#define RANGESTRAT_CONTAINED_BY
Definition: rangetypes.h:89
#define RANGESTRAT_OVERLEFT
Definition: rangetypes.h:83
#define RANGESTRAT_EQ
Definition: rangetypes.h:91
#define RangeIsOrContainsEmpty(r)
Definition: rangetypes.h:57
bool range_overright_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
Definition: rangetypes.c:910
#define RANGESTRAT_OVERLAPS
Definition: rangetypes.h:84
#define elog(elevel,...)
Definition: elog.h:232
bool range_adjacent_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
Definition: rangetypes.c:780
#define RANGESTRAT_AFTER
Definition: rangetypes.h:86

◆ range_gist_consistent_leaf_element()

static bool range_gist_consistent_leaf_element ( TypeCacheEntry typcache,
StrategyNumber  strategy,
const RangeType key,
Datum  query 
)
static

Definition at line 1128 of file rangetypes_gist.c.

References elog, ERROR, range_contains_elem_internal(), and RANGESTRAT_CONTAINS_ELEM.

Referenced by multirange_gist_consistent(), and range_gist_consistent().

1132 {
1133  switch (strategy)
1134  {
1136  return range_contains_elem_internal(typcache, key, query);
1137  default:
1138  elog(ERROR, "unrecognized range strategy: %d", strategy);
1139  return false; /* keep compiler quiet */
1140  }
1141 }
bool range_contains_elem_internal(TypeCacheEntry *typcache, const RangeType *r, Datum val)
Definition: rangetypes.c:2473
#define ERROR
Definition: elog.h:46
#define RANGESTRAT_CONTAINS_ELEM
Definition: rangetypes.h:90
#define elog(elevel,...)
Definition: elog.h:232

◆ range_gist_consistent_leaf_multirange()

static bool range_gist_consistent_leaf_multirange ( TypeCacheEntry typcache,
StrategyNumber  strategy,
const RangeType key,
const MultirangeType query 
)
static

Definition at line 1093 of file rangetypes_gist.c.

References elog, ERROR, multirange_contains_range_internal(), multirange_union_range_equal(), range_adjacent_multirange_internal(), range_after_multirange_internal(), range_before_multirange_internal(), range_contains_multirange_internal(), range_overlaps_multirange_internal(), range_overleft_multirange_internal(), range_overright_multirange_internal(), RANGESTRAT_ADJACENT, RANGESTRAT_AFTER, RANGESTRAT_BEFORE, RANGESTRAT_CONTAINED_BY, RANGESTRAT_CONTAINS, RANGESTRAT_EQ, RANGESTRAT_OVERLAPS, RANGESTRAT_OVERLEFT, and RANGESTRAT_OVERRIGHT.

Referenced by multirange_gist_consistent(), and range_gist_consistent().

1097 {
1098  switch (strategy)
1099  {
1100  case RANGESTRAT_BEFORE:
1101  return range_before_multirange_internal(typcache, key, query);
1102  case RANGESTRAT_OVERLEFT:
1103  return range_overleft_multirange_internal(typcache, key, query);
1104  case RANGESTRAT_OVERLAPS:
1105  return range_overlaps_multirange_internal(typcache, key, query);
1106  case RANGESTRAT_OVERRIGHT:
1107  return range_overright_multirange_internal(typcache, key, query);
1108  case RANGESTRAT_AFTER:
1109  return range_after_multirange_internal(typcache, key, query);
1110  case RANGESTRAT_ADJACENT:
1111  return range_adjacent_multirange_internal(typcache, key, query);
1112  case RANGESTRAT_CONTAINS:
1113  return range_contains_multirange_internal(typcache, key, query);
1115  return multirange_contains_range_internal(typcache, query, key);
1116  case RANGESTRAT_EQ:
1117  return multirange_union_range_equal(typcache, key, query);
1118  default:
1119  elog(ERROR, "unrecognized range strategy: %d", strategy);
1120  return false; /* keep compiler quiet */
1121  }
1122 }
#define RANGESTRAT_OVERRIGHT
Definition: rangetypes.h:85
#define RANGESTRAT_ADJACENT
Definition: rangetypes.h:87
#define ERROR
Definition: elog.h:46
bool range_overleft_multirange_internal(TypeCacheEntry *rangetyp, const RangeType *r, const MultirangeType *mr)
bool range_overright_multirange_internal(TypeCacheEntry *rangetyp, const RangeType *r, const MultirangeType *mr)
#define RANGESTRAT_BEFORE
Definition: rangetypes.h:82
bool range_before_multirange_internal(TypeCacheEntry *rangetyp, const RangeType *r, const MultirangeType *mr)
bool range_contains_multirange_internal(TypeCacheEntry *rangetyp, const RangeType *r, const MultirangeType *mr)
static bool multirange_union_range_equal(TypeCacheEntry *typcache, const RangeType *r, const MultirangeType *mr)
#define RANGESTRAT_CONTAINS
Definition: rangetypes.h:88
bool multirange_contains_range_internal(TypeCacheEntry *rangetyp, const MultirangeType *mr, const RangeType *r)
#define RANGESTRAT_CONTAINED_BY
Definition: rangetypes.h:89
#define RANGESTRAT_OVERLEFT
Definition: rangetypes.h:83
#define RANGESTRAT_EQ
Definition: rangetypes.h:91
bool range_adjacent_multirange_internal(TypeCacheEntry *rangetyp, const RangeType *r, const MultirangeType *mr)
#define RANGESTRAT_OVERLAPS
Definition: rangetypes.h:84
#define elog(elevel,...)
Definition: elog.h:232
bool range_overlaps_multirange_internal(TypeCacheEntry *rangetyp, const RangeType *r, const MultirangeType *mr)
#define RANGESTRAT_AFTER
Definition: rangetypes.h:86
bool range_after_multirange_internal(TypeCacheEntry *rangetyp, const RangeType *r, const MultirangeType *mr)

◆ range_gist_consistent_leaf_range()

static bool range_gist_consistent_leaf_range ( TypeCacheEntry typcache,
StrategyNumber  strategy,
const RangeType key,
const RangeType query 
)
static

Definition at line 1058 of file rangetypes_gist.c.

References elog, ERROR, range_adjacent_internal(), range_after_internal(), range_before_internal(), range_contained_by_internal(), range_contains_internal(), range_eq_internal(), range_overlaps_internal(), range_overleft_internal(), range_overright_internal(), RANGESTRAT_ADJACENT, RANGESTRAT_AFTER, RANGESTRAT_BEFORE, RANGESTRAT_CONTAINED_BY, RANGESTRAT_CONTAINS, RANGESTRAT_EQ, RANGESTRAT_OVERLAPS, RANGESTRAT_OVERLEFT, and RANGESTRAT_OVERRIGHT.

Referenced by multirange_gist_consistent(), and range_gist_consistent().

1062 {
1063  switch (strategy)
1064  {
1065  case RANGESTRAT_BEFORE:
1066  return range_before_internal(typcache, key, query);
1067  case RANGESTRAT_OVERLEFT:
1068  return range_overleft_internal(typcache, key, query);
1069  case RANGESTRAT_OVERLAPS:
1070  return range_overlaps_internal(typcache, key, query);
1071  case RANGESTRAT_OVERRIGHT:
1072  return range_overright_internal(typcache, key, query);
1073  case RANGESTRAT_AFTER:
1074  return range_after_internal(typcache, key, query);
1075  case RANGESTRAT_ADJACENT:
1076  return range_adjacent_internal(typcache, key, query);
1077  case RANGESTRAT_CONTAINS:
1078  return range_contains_internal(typcache, key, query);
1080  return range_contained_by_internal(typcache, key, query);
1081  case RANGESTRAT_EQ:
1082  return range_eq_internal(typcache, key, query);
1083  default:
1084  elog(ERROR, "unrecognized range strategy: %d", strategy);
1085  return false; /* keep compiler quiet */
1086  }
1087 }
bool range_overlaps_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
Definition: rangetypes.c:823
#define RANGESTRAT_OVERRIGHT
Definition: rangetypes.h:85
#define RANGESTRAT_ADJACENT
Definition: rangetypes.h:87
bool range_after_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
Definition: rangetypes.c:684
#define ERROR
Definition: elog.h:46
#define RANGESTRAT_BEFORE
Definition: rangetypes.h:82
bool range_contains_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
Definition: rangetypes.c:2432
#define RANGESTRAT_CONTAINS
Definition: rangetypes.h:88
bool range_overleft_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
Definition: rangetypes.c:869
bool range_before_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
Definition: rangetypes.c:646
bool range_contained_by_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
Definition: rangetypes.c:2464
#define RANGESTRAT_CONTAINED_BY
Definition: rangetypes.h:89
#define RANGESTRAT_OVERLEFT
Definition: rangetypes.h:83
#define RANGESTRAT_EQ
Definition: rangetypes.h:91
bool range_overright_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
Definition: rangetypes.c:910
#define RANGESTRAT_OVERLAPS
Definition: rangetypes.h:84
#define elog(elevel,...)
Definition: elog.h:232
bool range_adjacent_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
Definition: rangetypes.c:780
#define RANGESTRAT_AFTER
Definition: rangetypes.h:86
bool range_eq_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
Definition: rangetypes.c:555

◆ range_gist_double_sorting_split()

static void range_gist_double_sorting_split ( TypeCacheEntry typcache,
GistEntryVector entryvec,
GIST_SPLITVEC v 
)
static

Definition at line 1318 of file rangetypes_gist.c.

References Assert, call_subtype_diff(), common_entry_cmp(), ConsiderSplitContext::common_left, DatumGetRangeTypeP, CommonEntry::delta, ConsiderSplitContext::entries_count, ConsiderSplitContext::first, FirstOffsetNumber, FmgrInfo::fn_oid, ConsiderSplitContext::has_subtype_diff, i, idx(), CommonEntry::index, interval_cmp_lower(), interval_cmp_upper(), GISTENTRY::key, ConsiderSplitContext::left_upper, lower(), NonEmptyRange::lower, GistEntryVector::n, OffsetNumberNext, OidIsValid, palloc(), PLACE_LEFT, PLACE_RIGHT, PointerGetDatum, qsort, qsort_arg(), range(), range_cmp_bounds(), range_deserialize(), range_gist_consider_split(), range_gist_fallback_split(), ConsiderSplitContext::right_lower, TypeCacheEntry::rng_subdiff_finfo, GIST_SPLITVEC::spl_ldatum, GIST_SPLITVEC::spl_left, GIST_SPLITVEC::spl_nleft, GIST_SPLITVEC::spl_nright, GIST_SPLITVEC::spl_rdatum, GIST_SPLITVEC::spl_right, ConsiderSplitContext::typcache, upper(), NonEmptyRange::upper, RangeBound::val, and GistEntryVector::vector.

Referenced by range_gist_picksplit().

1321 {
1322  ConsiderSplitContext context;
1323  OffsetNumber i,
1324  maxoff;
1325  RangeType *range,
1326  *left_range = NULL,
1327  *right_range = NULL;
1328  int common_entries_count;
1329  NonEmptyRange *by_lower,
1330  *by_upper;
1331  CommonEntry *common_entries;
1332  int nentries,
1333  i1,
1334  i2;
1335  RangeBound *right_lower,
1336  *left_upper;
1337 
1338  memset(&context, 0, sizeof(ConsiderSplitContext));
1339  context.typcache = typcache;
1340  context.has_subtype_diff = OidIsValid(typcache->rng_subdiff_finfo.fn_oid);
1341 
1342  maxoff = entryvec->n - 1;
1343  nentries = context.entries_count = maxoff - FirstOffsetNumber + 1;
1344  context.first = true;
1345 
1346  /* Allocate arrays for sorted range bounds */
1347  by_lower = (NonEmptyRange *) palloc(nentries * sizeof(NonEmptyRange));
1348  by_upper = (NonEmptyRange *) palloc(nentries * sizeof(NonEmptyRange));
1349 
1350  /* Fill arrays of bounds */
1351  for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
1352  {
1353  RangeType *range = DatumGetRangeTypeP(entryvec->vector[i].key);
1354  bool empty;
1355 
1356  range_deserialize(typcache, range,
1357  &by_lower[i - FirstOffsetNumber].lower,
1358  &by_lower[i - FirstOffsetNumber].upper,
1359  &empty);
1360  Assert(!empty);
1361  }
1362 
1363  /*
1364  * Make two arrays of range bounds: one sorted by lower bound and another
1365  * sorted by upper bound.
1366  */
1367  memcpy(by_upper, by_lower, nentries * sizeof(NonEmptyRange));
1368  qsort_arg(by_lower, nentries, sizeof(NonEmptyRange),
1369  interval_cmp_lower, typcache);
1370  qsort_arg(by_upper, nentries, sizeof(NonEmptyRange),
1371  interval_cmp_upper, typcache);
1372 
1373  /*----------
1374  * The goal is to form a left and right range, so that every entry
1375  * range is contained by either left or right interval (or both).
1376  *
1377  * For example, with the ranges (0,1), (1,3), (2,3), (2,4):
1378  *
1379  * 0 1 2 3 4
1380  * +-+
1381  * +---+
1382  * +-+
1383  * +---+
1384  *
1385  * The left and right ranges are of the form (0,a) and (b,4).
1386  * We first consider splits where b is the lower bound of an entry.
1387  * We iterate through all entries, and for each b, calculate the
1388  * smallest possible a. Then we consider splits where a is the
1389  * upper bound of an entry, and for each a, calculate the greatest
1390  * possible b.
1391  *
1392  * In the above example, the first loop would consider splits:
1393  * b=0: (0,1)-(0,4)
1394  * b=1: (0,1)-(1,4)
1395  * b=2: (0,3)-(2,4)
1396  *
1397  * And the second loop:
1398  * a=1: (0,1)-(1,4)
1399  * a=3: (0,3)-(2,4)
1400  * a=4: (0,4)-(2,4)
1401  *----------
1402  */
1403 
1404  /*
1405  * Iterate over lower bound of right group, finding smallest possible
1406  * upper bound of left group.
1407  */
1408  i1 = 0;
1409  i2 = 0;
1410  right_lower = &by_lower[i1].lower;
1411  left_upper = &by_upper[i2].lower;
1412  while (true)
1413  {
1414  /*
1415  * Find next lower bound of right group.
1416  */
1417  while (i1 < nentries &&
1418  range_cmp_bounds(typcache, right_lower,
1419  &by_lower[i1].lower) == 0)
1420  {
1421  if (range_cmp_bounds(typcache, &by_lower[i1].upper,
1422  left_upper) > 0)
1423  left_upper = &by_lower[i1].upper;
1424  i1++;
1425  }
1426  if (i1 >= nentries)
1427  break;
1428  right_lower = &by_lower[i1].lower;
1429 
1430  /*
1431  * Find count of ranges which anyway should be placed to the left
1432  * group.
1433  */
1434  while (i2 < nentries &&
1435  range_cmp_bounds(typcache, &by_upper[i2].upper,
1436  left_upper) <= 0)
1437  i2++;
1438 
1439  /*
1440  * Consider found split to see if it's better than what we had.
1441  */
1442  range_gist_consider_split(&context, right_lower, i1, left_upper, i2);
1443  }
1444 
1445  /*
1446  * Iterate over upper bound of left group finding greatest possible lower
1447  * bound of right group.
1448  */
1449  i1 = nentries - 1;
1450  i2 = nentries - 1;
1451  right_lower = &by_lower[i1].upper;
1452  left_upper = &by_upper[i2].upper;
1453  while (true)
1454  {
1455  /*
1456  * Find next upper bound of left group.
1457  */
1458  while (i2 >= 0 &&
1459  range_cmp_bounds(typcache, left_upper,
1460  &by_upper[i2].upper) == 0)
1461  {
1462  if (range_cmp_bounds(typcache, &by_upper[i2].lower,
1463  right_lower) < 0)
1464  right_lower = &by_upper[i2].lower;
1465  i2--;
1466  }
1467  if (i2 < 0)
1468  break;
1469  left_upper = &by_upper[i2].upper;
1470 
1471  /*
1472  * Find count of intervals which anyway should be placed to the right
1473  * group.
1474  */
1475  while (i1 >= 0 &&
1476  range_cmp_bounds(typcache, &by_lower[i1].lower,
1477  right_lower) >= 0)
1478  i1--;
1479 
1480  /*
1481  * Consider found split to see if it's better than what we had.
1482  */
1483  range_gist_consider_split(&context, right_lower, i1 + 1,
1484  left_upper, i2 + 1);
1485  }
1486 
1487  /*
1488  * If we failed to find any acceptable splits, use trivial split.
1489  */
1490  if (context.first)
1491  {
1492  range_gist_fallback_split(typcache, entryvec, v);
1493  return;
1494  }
1495 
1496  /*
1497  * Ok, we have now selected bounds of the groups. Now we have to
1498  * distribute entries themselves. At first we distribute entries which can
1499  * be placed unambiguously and collect "common entries" to array.
1500  */
1501 
1502  /* Allocate vectors for results */
1503  v->spl_left = (OffsetNumber *) palloc(nentries * sizeof(OffsetNumber));
1504  v->spl_right = (OffsetNumber *) palloc(nentries * sizeof(OffsetNumber));
1505  v->spl_nleft = 0;
1506  v->spl_nright = 0;
1507 
1508  /*
1509  * Allocate an array for "common entries" - entries which can be placed to
1510  * either group without affecting overlap along selected axis.
1511  */
1512  common_entries_count = 0;
1513  common_entries = (CommonEntry *) palloc(nentries * sizeof(CommonEntry));
1514 
1515  /*
1516  * Distribute entries which can be distributed unambiguously, and collect
1517  * common entries.
1518  */
1519  for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
1520  {
1521  RangeBound lower,
1522  upper;
1523  bool empty;
1524 
1525  /*
1526  * Get upper and lower bounds along selected axis.
1527  */
1528  range = DatumGetRangeTypeP(entryvec->vector[i].key);
1529 
1530  range_deserialize(typcache, range, &lower, &upper, &empty);
1531 
1532  if (range_cmp_bounds(typcache, &upper, context.left_upper) <= 0)
1533  {
1534  /* Fits in the left group */
1535  if (range_cmp_bounds(typcache, &lower, context.right_lower) >= 0)
1536  {
1537  /* Fits also in the right group, so "common entry" */
1538  common_entries[common_entries_count].index = i;
1539  if (context.has_subtype_diff)
1540  {
1541  /*
1542  * delta = (lower - context.right_lower) -
1543  * (context.left_upper - upper)
1544  */
1545  common_entries[common_entries_count].delta =
1546  call_subtype_diff(typcache,
1547  lower.val,
1548  context.right_lower->val) -
1549  call_subtype_diff(typcache,
1550  context.left_upper->val,
1551  upper.val);
1552  }
1553  else
1554  {
1555  /* Without subtype_diff, take all deltas as zero */
1556  common_entries[common_entries_count].delta = 0;
1557  }
1558  common_entries_count++;
1559  }
1560  else
1561  {
1562  /* Doesn't fit to the right group, so join to the left group */
1563  PLACE_LEFT(range, i);
1564  }
1565  }
1566  else
1567  {
1568  /*
1569  * Each entry should fit on either left or right group. Since this
1570  * entry didn't fit in the left group, it better fit in the right
1571  * group.
1572  */
1573  Assert(range_cmp_bounds(typcache, &lower,
1574  context.right_lower) >= 0);
1575  PLACE_RIGHT(range, i);
1576  }
1577  }
1578 
1579  /*
1580  * Distribute "common entries", if any.
1581  */
1582  if (common_entries_count > 0)
1583  {
1584  /*
1585  * Sort "common entries" by calculated deltas in order to distribute
1586  * the most ambiguous entries first.
1587  */
1588  qsort(common_entries, common_entries_count, sizeof(CommonEntry),
1590 
1591  /*
1592  * Distribute "common entries" between groups according to sorting.
1593  */
1594  for (i = 0; i < common_entries_count; i++)
1595  {
1596  int idx = common_entries[i].index;
1597 
1598  range = DatumGetRangeTypeP(entryvec->vector[idx].key);
1599 
1600  /*
1601  * Check if we have to place this entry in either group to achieve
1602  * LIMIT_RATIO.
1603  */
1604  if (i < context.common_left)
1605  PLACE_LEFT(range, idx);
1606  else
1607  PLACE_RIGHT(range, idx);
1608  }
1609  }
1610 
1611  v->spl_ldatum = PointerGetDatum(left_range);
1612  v->spl_rdatum = PointerGetDatum(right_range);
1613 }
RangeBound upper
static void range_gist_consider_split(ConsiderSplitContext *context, RangeBound *right_lower, int min_left_count, RangeBound *left_upper, int max_left_count)
Datum lower(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:46
#define PointerGetDatum(X)
Definition: postgres.h:600
RangeBound * right_lower
float8 delta
Definition: gistproc.c:277
RangeBound * left_upper
OffsetNumber * spl_left
Definition: gist.h:142
Datum spl_rdatum
Definition: gist.h:149
Datum val
Definition: rangetypes.h:64
static float8 call_subtype_diff(TypeCacheEntry *typcache, Datum val1, Datum val2)
int32 n
Definition: gist.h:235
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:259
Datum upper(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:77
int spl_nleft
Definition: gist.h:143
#define OidIsValid(objectId)
Definition: c.h:710
uint16 OffsetNumber
Definition: off.h:24
GISTENTRY vector[FLEXIBLE_ARRAY_MEMBER]
Definition: gist.h:236
FmgrInfo rng_subdiff_finfo
Definition: typcache.h:102
#define PLACE_LEFT(range, off)
int spl_nright
Definition: gist.h:148
RangeBound lower
Datum key
Definition: gist.h:160
#define FirstOffsetNumber
Definition: off.h:27
static struct cvec * range(struct vars *v, chr a, chr b, int cases)
Definition: regc_locale.c:412
void qsort_arg(void *base, size_t nel, size_t elsize, qsort_arg_comparator cmp, void *arg)
#define PLACE_RIGHT(range, off)
static void range_gist_fallback_split(TypeCacheEntry *typcache, GistEntryVector *entryvec, GIST_SPLITVEC *v)
Oid fn_oid
Definition: fmgr.h:59
Datum spl_ldatum
Definition: gist.h:144
#define Assert(condition)
Definition: c.h:804
#define OffsetNumberNext(offsetNumber)
Definition: off.h:52
OffsetNumber * spl_right
Definition: gist.h:147
#define DatumGetRangeTypeP(X)
Definition: rangetypes.h:73
static Ranges * range_deserialize(int maxvalues, SerializedRanges *range)
void * palloc(Size size)
Definition: mcxt.c:1062
int i
#define qsort(a, b, c, d)
Definition: port.h:504
static int interval_cmp_lower(const void *a, const void *b, void *arg)
TypeCacheEntry * typcache
int range_cmp_bounds(TypeCacheEntry *typcache, const RangeBound *b1, const RangeBound *b2)
Definition: rangetypes.c:1924
static int interval_cmp_upper(const void *a, const void *b, void *arg)
static int common_entry_cmp(const void *i1, const void *i2)

◆ range_gist_fallback_split()

static void range_gist_fallback_split ( TypeCacheEntry typcache,
GistEntryVector entryvec,
GIST_SPLITVEC v 
)
static

Definition at line 1148 of file rangetypes_gist.c.

References DatumGetRangeTypeP, FirstOffsetNumber, i, GISTENTRY::key, GistEntryVector::n, PLACE_LEFT, PLACE_RIGHT, range(), RangeTypePGetDatum, GIST_SPLITVEC::spl_ldatum, GIST_SPLITVEC::spl_nleft, GIST_SPLITVEC::spl_nright, GIST_SPLITVEC::spl_rdatum, and GistEntryVector::vector.

Referenced by range_gist_double_sorting_split(), and range_gist_picksplit().

1151 {
1152  RangeType *left_range = NULL;
1153  RangeType *right_range = NULL;
1154  OffsetNumber i,
1155  maxoff,
1156  split_idx;
1157 
1158  maxoff = entryvec->n - 1;
1159  /* Split entries before this to left page, after to right: */
1160  split_idx = (maxoff - FirstOffsetNumber) / 2 + FirstOffsetNumber;
1161 
1162  v->spl_nleft = 0;
1163  v->spl_nright = 0;
1164  for (i = FirstOffsetNumber; i <= maxoff; i++)
1165  {
1166  RangeType *range = DatumGetRangeTypeP(entryvec->vector[i].key);
1167 
1168  if (i < split_idx)
1169  PLACE_LEFT(range, i);
1170  else
1171  PLACE_RIGHT(range, i);
1172  }
1173 
1174  v->spl_ldatum = RangeTypePGetDatum(left_range);
1175  v->spl_rdatum = RangeTypePGetDatum(right_range);
1176 }
Datum spl_rdatum
Definition: gist.h:149
int32 n
Definition: gist.h:235
int spl_nleft
Definition: gist.h:143
#define RangeTypePGetDatum(X)
Definition: rangetypes.h:75
uint16 OffsetNumber
Definition: off.h:24
GISTENTRY vector[FLEXIBLE_ARRAY_MEMBER]
Definition: gist.h:236
#define PLACE_LEFT(range, off)
int spl_nright
Definition: gist.h:148
Datum key
Definition: gist.h:160
#define FirstOffsetNumber
Definition: off.h:27
static struct cvec * range(struct vars *v, chr a, chr b, int cases)
Definition: regc_locale.c:412
#define PLACE_RIGHT(range, off)
Datum spl_ldatum
Definition: gist.h:144
#define DatumGetRangeTypeP(X)
Definition: rangetypes.h:73
int i

◆ range_gist_penalty()

Datum range_gist_penalty ( PG_FUNCTION_ARGS  )

Definition at line 362 of file rangetypes_gist.c.

References call_subtype_diff(), CONTAIN_EMPTY_PENALTY, DatumGetRangeTypeP, DEFAULT_SUBTYPE_DIFF_PENALTY, elog, ERROR, FmgrInfo::fn_oid, get_float4_infinity(), RangeBound::infinite, INFINITE_BOUND_PENALTY, GISTENTRY::key, OidIsValid, PG_GETARG_POINTER, PG_RETURN_POINTER, range_cmp_bounds(), range_deserialize(), range_get_typcache(), RangeIsOrContainsEmpty, RangeTypeGetOid, TypeCacheEntry::rng_subdiff_finfo, and RangeBound::val.

363 {
364  GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0);
365  GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
366  float *penalty = (float *) PG_GETARG_POINTER(2);
367  RangeType *orig = DatumGetRangeTypeP(origentry->key);
368  RangeType *new = DatumGetRangeTypeP(newentry->key);
369  TypeCacheEntry *typcache;
370  bool has_subtype_diff;
371  RangeBound orig_lower,
372  new_lower,
373  orig_upper,
374  new_upper;
375  bool orig_empty,
376  new_empty;
377 
378  if (RangeTypeGetOid(orig) != RangeTypeGetOid(new))
379  elog(ERROR, "range types do not match");
380 
381  typcache = range_get_typcache(fcinfo, RangeTypeGetOid(orig));
382 
383  has_subtype_diff = OidIsValid(typcache->rng_subdiff_finfo.fn_oid);
384 
385  range_deserialize(typcache, orig, &orig_lower, &orig_upper, &orig_empty);
386  range_deserialize(typcache, new, &new_lower, &new_upper, &new_empty);
387 
388  /*
389  * Distinct branches for handling distinct classes of ranges. Note that
390  * penalty values only need to be commensurate within the same class of
391  * new range.
392  */
393  if (new_empty)
394  {
395  /* Handle insertion of empty range */
396  if (orig_empty)
397  {
398  /*
399  * The best case is to insert it to empty original range.
400  * Insertion here means no broadening of original range. Also
401  * original range is the most narrow.
402  */
403  *penalty = 0.0;
404  }
405  else if (RangeIsOrContainsEmpty(orig))
406  {
407  /*
408  * The second case is to insert empty range into range which
409  * contains at least one underlying empty range. There is still
410  * no broadening of original range, but original range is not as
411  * narrow as possible.
412  */
413  *penalty = CONTAIN_EMPTY_PENALTY;
414  }
415  else if (orig_lower.infinite && orig_upper.infinite)
416  {
417  /*
418  * Original range requires broadening. (-inf; +inf) is most far
419  * from normal range in this case.
420  */
421  *penalty = 2 * CONTAIN_EMPTY_PENALTY;
422  }
423  else if (orig_lower.infinite || orig_upper.infinite)
424  {
425  /*
426  * (-inf, x) or (x, +inf) original ranges are closer to normal
427  * ranges, so it's worse to mix it with empty ranges.
428  */
429  *penalty = 3 * CONTAIN_EMPTY_PENALTY;
430  }
431  else
432  {
433  /*
434  * The least preferred case is broadening of normal range.
435  */
436  *penalty = 4 * CONTAIN_EMPTY_PENALTY;
437  }
438  }
439  else if (new_lower.infinite && new_upper.infinite)
440  {
441  /* Handle insertion of (-inf, +inf) range */
442  if (orig_lower.infinite && orig_upper.infinite)
443  {
444  /*
445  * Best case is inserting to (-inf, +inf) original range.
446  */
447  *penalty = 0.0;
448  }
449  else if (orig_lower.infinite || orig_upper.infinite)
450  {
451  /*
452  * When original range is (-inf, x) or (x, +inf) it requires
453  * broadening of original range (extension of one bound to
454  * infinity).
455  */
456  *penalty = INFINITE_BOUND_PENALTY;
457  }
458  else
459  {
460  /*
461  * Insertion to normal original range is least preferred.
462  */
463  *penalty = 2 * INFINITE_BOUND_PENALTY;
464  }
465 
466  if (RangeIsOrContainsEmpty(orig))
467  {
468  /*
469  * Original range is narrower when it doesn't contain empty
470  * ranges. Add additional penalty otherwise.
471  */
472  *penalty += CONTAIN_EMPTY_PENALTY;
473  }
474  }
475  else if (new_lower.infinite)
476  {
477  /* Handle insertion of (-inf, x) range */
478  if (!orig_empty && orig_lower.infinite)
479  {
480  if (orig_upper.infinite)
481  {
482  /*
483  * (-inf, +inf) range won't be extended by insertion of (-inf,
484  * x) range. It's a less desirable case than insertion to
485  * (-inf, y) original range without extension, because in that
486  * case original range is narrower. But we can't express that
487  * in single float value.
488  */
489  *penalty = 0.0;
490  }
491  else
492  {
493  if (range_cmp_bounds(typcache, &new_upper, &orig_upper) > 0)
494  {
495  /*
496  * Get extension of original range using subtype_diff. Use
497  * constant if subtype_diff unavailable.
498  */
499  if (has_subtype_diff)
500  *penalty = call_subtype_diff(typcache,
501  new_upper.val,
502  orig_upper.val);
503  else
504  *penalty = DEFAULT_SUBTYPE_DIFF_PENALTY;
505  }
506  else
507  {
508  /* No extension of original range */
509  *penalty = 0.0;
510  }
511  }
512  }
513  else
514  {
515  /*
516  * If lower bound of original range is not -inf, then extension of
517  * it is infinity.
518  */
519  *penalty = get_float4_infinity();
520  }
521  }
522  else if (new_upper.infinite)
523  {
524  /* Handle insertion of (x, +inf) range */
525  if (!orig_empty && orig_upper.infinite)
526  {
527  if (orig_lower.infinite)
528  {
529  /*
530  * (-inf, +inf) range won't be extended by insertion of (x,
531  * +inf) range. It's a less desirable case than insertion to
532  * (y, +inf) original range without extension, because in that
533  * case original range is narrower. But we can't express that
534  * in single float value.
535  */
536  *penalty = 0.0;
537  }
538  else
539  {
540  if (range_cmp_bounds(typcache, &new_lower, &orig_lower) < 0)
541  {
542  /*
543  * Get extension of original range using subtype_diff. Use
544  * constant if subtype_diff unavailable.
545  */
546  if (has_subtype_diff)
547  *penalty = call_subtype_diff(typcache,
548  orig_lower.val,
549  new_lower.val);
550  else
551  *penalty = DEFAULT_SUBTYPE_DIFF_PENALTY;
552  }
553  else
554  {
555  /* No extension of original range */
556  *penalty = 0.0;
557  }
558  }
559  }
560  else
561  {
562  /*
563  * If upper bound of original range is not +inf, then extension of
564  * it is infinity.
565  */
566  *penalty = get_float4_infinity();
567  }
568  }
569  else
570  {
571  /* Handle insertion of normal (non-empty, non-infinite) range */
572  if (orig_empty || orig_lower.infinite || orig_upper.infinite)
573  {
574  /*
575  * Avoid mixing normal ranges with infinite and empty ranges.
576  */
577  *penalty = get_float4_infinity();
578  }
579  else
580  {
581  /*
582  * Calculate extension of original range by calling subtype_diff.
583  * Use constant if subtype_diff unavailable.
584  */
585  float8 diff = 0.0;
586 
587  if (range_cmp_bounds(typcache, &new_lower, &orig_lower) < 0)
588  {
589  if (has_subtype_diff)
590  diff += call_subtype_diff(typcache,
591  orig_lower.val,
592  new_lower.val);
593  else
595  }
596  if (range_cmp_bounds(typcache, &new_upper, &orig_upper) > 0)
597  {
598  if (has_subtype_diff)
599  diff += call_subtype_diff(typcache,
600  new_upper.val,
601  orig_upper.val);
602  else
604  }
605  *penalty = diff;
606  }
607  }
608 
609  PG_RETURN_POINTER(penalty);
610 }
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
TypeCacheEntry * range_get_typcache(FunctionCallInfo fcinfo, Oid rngtypid)
Definition: rangetypes.c:1635
#define RangeTypeGetOid(r)
Definition: rangetypes.h:35
#define CONTAIN_EMPTY_PENALTY
#define INFINITE_BOUND_PENALTY
Datum val
Definition: rangetypes.h:64
static float8 call_subtype_diff(TypeCacheEntry *typcache, Datum val1, Datum val2)
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
#define OidIsValid(objectId)
Definition: c.h:710
FmgrInfo rng_subdiff_finfo
Definition: typcache.h:102
#define ERROR
Definition: elog.h:46
double float8
Definition: c.h:565
Datum key
Definition: gist.h:160
Oid fn_oid
Definition: fmgr.h:59
#define DatumGetRangeTypeP(X)
Definition: rangetypes.h:73
bool infinite
Definition: rangetypes.h:65
#define DEFAULT_SUBTYPE_DIFF_PENALTY
static Ranges * range_deserialize(int maxvalues, SerializedRanges *range)
#define RangeIsOrContainsEmpty(r)
Definition: rangetypes.h:57
#define elog(elevel,...)
Definition: elog.h:232
int range_cmp_bounds(TypeCacheEntry *typcache, const RangeBound *b1, const RangeBound *b2)
Definition: rangetypes.c:1924
static float4 get_float4_infinity(void)
Definition: float.h:73

◆ range_gist_picksplit()

Datum range_gist_picksplit ( PG_FUNCTION_ARGS  )

Definition at line 619 of file rangetypes_gist.c.

References Abs, Assert, CLS_CONTAIN_EMPTY, CLS_COUNT, CLS_EMPTY, CLS_LOWER_INF, CLS_NORMAL, CLS_UPPER_INF, DatumGetRangeTypeP, FirstOffsetNumber, get_gist_range_class(), i, GISTENTRY::key, GistEntryVector::n, OffsetNumberNext, palloc(), PG_GETARG_POINTER, PG_RETURN_POINTER, range(), range_get_typcache(), range_gist_class_split(), range_gist_double_sorting_split(), range_gist_fallback_split(), range_gist_single_sorting_split(), RangeTypeGetOid, GIST_SPLITVEC::spl_left, GIST_SPLITVEC::spl_right, SPLIT_RIGHT, and GistEntryVector::vector.

620 {
623  TypeCacheEntry *typcache;
624  OffsetNumber i;
625  RangeType *pred_left;
626  int nbytes;
627  OffsetNumber maxoff;
628  int count_in_classes[CLS_COUNT];
629  int j;
630  int non_empty_classes_count = 0;
631  int biggest_class = -1;
632  int biggest_class_count = 0;
633  int total_count;
634 
635  /* use first item to look up range type's info */
636  pred_left = DatumGetRangeTypeP(entryvec->vector[FirstOffsetNumber].key);
637  typcache = range_get_typcache(fcinfo, RangeTypeGetOid(pred_left));
638 
639  maxoff = entryvec->n - 1;
640  nbytes = (maxoff + 1) * sizeof(OffsetNumber);
641  v->spl_left = (OffsetNumber *) palloc(nbytes);
642  v->spl_right = (OffsetNumber *) palloc(nbytes);
643 
644  /*
645  * Get count distribution of range classes.
646  */
647  memset(count_in_classes, 0, sizeof(count_in_classes));
648  for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
649  {
650  RangeType *range = DatumGetRangeTypeP(entryvec->vector[i].key);
651 
652  count_in_classes[get_gist_range_class(range)]++;
653  }
654 
655  /*
656  * Count non-empty classes and find biggest class.
657  */
658  total_count = maxoff;
659  for (j = 0; j < CLS_COUNT; j++)
660  {
661  if (count_in_classes[j] > 0)
662  {
663  if (count_in_classes[j] > biggest_class_count)
664  {
665  biggest_class_count = count_in_classes[j];
666  biggest_class = j;
667  }
668  non_empty_classes_count++;
669  }
670  }
671 
672  Assert(non_empty_classes_count > 0);
673 
674  if (non_empty_classes_count == 1)
675  {
676  /* One non-empty class, so split inside class */
677  if ((biggest_class & ~CLS_CONTAIN_EMPTY) == CLS_NORMAL)
678  {
679  /* double sorting split for normal ranges */
680  range_gist_double_sorting_split(typcache, entryvec, v);
681  }
682  else if ((biggest_class & ~CLS_CONTAIN_EMPTY) == CLS_LOWER_INF)
683  {
684  /* upper bound sorting split for (-inf, x) ranges */
685  range_gist_single_sorting_split(typcache, entryvec, v, true);
686  }
687  else if ((biggest_class & ~CLS_CONTAIN_EMPTY) == CLS_UPPER_INF)
688  {
689  /* lower bound sorting split for (x, +inf) ranges */
690  range_gist_single_sorting_split(typcache, entryvec, v, false);
691  }
692  else
693  {
694  /* trivial split for all (-inf, +inf) or all empty ranges */
695  range_gist_fallback_split(typcache, entryvec, v);
696  }
697  }
698  else
699  {
700  /*
701  * Class based split.
702  *
703  * To which side of the split should each class go? Initialize them
704  * all to go to the left side.
705  */
706  SplitLR classes_groups[CLS_COUNT];
707 
708  memset(classes_groups, 0, sizeof(classes_groups));
709 
710  if (count_in_classes[CLS_NORMAL] > 0)
711  {
712  /* separate normal ranges if any */
713  classes_groups[CLS_NORMAL] = SPLIT_RIGHT;
714  }
715  else
716  {
717  /*----------
718  * Try to split classes in one of two ways:
719  * 1) containing infinities - not containing infinities
720  * 2) containing empty - not containing empty
721  *
722  * Select the way which balances the ranges between left and right
723  * the best. If split in these ways is not possible, there are at
724  * most 3 classes, so just separate biggest class.
725  *----------
726  */
727  int infCount,
728  nonInfCount;
729  int emptyCount,
730  nonEmptyCount;
731 
732  nonInfCount =
733  count_in_classes[CLS_NORMAL] +
734  count_in_classes[CLS_CONTAIN_EMPTY] +
735  count_in_classes[CLS_EMPTY];
736  infCount = total_count - nonInfCount;
737 
738  nonEmptyCount =
739  count_in_classes[CLS_NORMAL] +
740  count_in_classes[CLS_LOWER_INF] +
741  count_in_classes[CLS_UPPER_INF] +
742  count_in_classes[CLS_LOWER_INF | CLS_UPPER_INF];
743  emptyCount = total_count - nonEmptyCount;
744 
745  if (infCount > 0 && nonInfCount > 0 &&
746  (Abs(infCount - nonInfCount) <=
747  Abs(emptyCount - nonEmptyCount)))
748  {
749  classes_groups[CLS_NORMAL] = SPLIT_RIGHT;
750  classes_groups[CLS_CONTAIN_EMPTY] = SPLIT_RIGHT;
751  classes_groups[CLS_EMPTY] = SPLIT_RIGHT;
752  }
753  else if (emptyCount > 0 && nonEmptyCount > 0)
754  {
755  classes_groups[CLS_NORMAL] = SPLIT_RIGHT;
756  classes_groups[CLS_LOWER_INF] = SPLIT_RIGHT;
757  classes_groups[CLS_UPPER_INF] = SPLIT_RIGHT;
758  classes_groups[CLS_LOWER_INF | CLS_UPPER_INF] = SPLIT_RIGHT;
759  }
760  else
761  {
762  /*
763  * Either total_count == emptyCount or total_count ==
764  * infCount.
765  */
766  classes_groups[biggest_class] = SPLIT_RIGHT;
767  }
768  }
769 
770  range_gist_class_split(typcache, entryvec, v, classes_groups);
771  }
772 
774 }
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
#define CLS_EMPTY
#define CLS_COUNT
TypeCacheEntry * range_get_typcache(FunctionCallInfo fcinfo, Oid rngtypid)
Definition: rangetypes.c:1635
#define RangeTypeGetOid(r)
Definition: rangetypes.h:35
static void range_gist_class_split(TypeCacheEntry *typcache, GistEntryVector *entryvec, GIST_SPLITVEC *v, SplitLR *classes_groups)
OffsetNumber * spl_left
Definition: gist.h:142
int32 n
Definition: gist.h:235
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
#define CLS_CONTAIN_EMPTY
uint16 OffsetNumber
Definition: off.h:24
#define Abs(x)
Definition: c.h:992
GISTENTRY vector[FLEXIBLE_ARRAY_MEMBER]
Definition: gist.h:236
static int get_gist_range_class(RangeType *range)
Datum key
Definition: gist.h:160
#define FirstOffsetNumber
Definition: off.h:27
static struct cvec * range(struct vars *v, chr a, chr b, int cases)
Definition: regc_locale.c:412
SplitLR
static void range_gist_fallback_split(TypeCacheEntry *typcache, GistEntryVector *entryvec, GIST_SPLITVEC *v)
#define CLS_LOWER_INF
#define Assert(condition)
Definition: c.h:804
#define CLS_UPPER_INF
#define OffsetNumberNext(offsetNumber)
Definition: off.h:52
OffsetNumber * spl_right
Definition: gist.h:147
#define DatumGetRangeTypeP(X)
Definition: rangetypes.h:73
static void range_gist_double_sorting_split(TypeCacheEntry *typcache, GistEntryVector *entryvec, GIST_SPLITVEC *v)
void * palloc(Size size)
Definition: mcxt.c:1062
int i
static void range_gist_single_sorting_split(TypeCacheEntry *typcache, GistEntryVector *entryvec, GIST_SPLITVEC *v, bool use_upper_bound)
#define CLS_NORMAL

◆ range_gist_same()

Datum range_gist_same ( PG_FUNCTION_ARGS  )

Definition at line 778 of file rangetypes_gist.c.

References PG_GETARG_POINTER, PG_GETARG_RANGE_P, PG_RETURN_POINTER, range_eq_internal(), range_get_flags(), range_get_typcache(), and RangeTypeGetOid.

779 {
780  RangeType *r1 = PG_GETARG_RANGE_P(0);
781  RangeType *r2 = PG_GETARG_RANGE_P(1);
782  bool *result = (bool *) PG_GETARG_POINTER(2);
783 
784  /*
785  * range_eq will ignore the RANGE_CONTAIN_EMPTY flag, so we have to check
786  * that for ourselves. More generally, if the entries have been properly
787  * normalized, then unequal flags bytes must mean unequal ranges ... so
788  * let's just test all the flag bits at once.
789  */
790  if (range_get_flags(r1) != range_get_flags(r2))
791  *result = false;
792  else
793  {
794  TypeCacheEntry *typcache;
795 
796  typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
797 
798  *result = range_eq_internal(typcache, r1, r2);
799  }
800 
801  PG_RETURN_POINTER(result);
802 }
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
TypeCacheEntry * range_get_typcache(FunctionCallInfo fcinfo, Oid rngtypid)
Definition: rangetypes.c:1635
#define RangeTypeGetOid(r)
Definition: rangetypes.h:35
char range_get_flags(const RangeType *range)
Definition: rangetypes.c:1855
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
#define PG_GETARG_RANGE_P(n)
Definition: rangetypes.h:76
bool range_eq_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType *r2)
Definition: rangetypes.c:555

◆ range_gist_single_sorting_split()

static void range_gist_single_sorting_split ( TypeCacheEntry typcache,
GistEntryVector entryvec,
GIST_SPLITVEC v,
bool  use_upper_bound 
)
static

Definition at line 1229 of file rangetypes_gist.c.

References Assert, DatumGetRangeTypeP, FirstOffsetNumber, i, idx(), SingleBoundSortItem::index, GISTENTRY::key, GistEntryVector::n, OffsetNumberNext, palloc(), PLACE_LEFT, PLACE_RIGHT, qsort_arg(), range(), range_deserialize(), RangeTypePGetDatum, single_bound_cmp(), GIST_SPLITVEC::spl_ldatum, GIST_SPLITVEC::spl_nleft, GIST_SPLITVEC::spl_nright, GIST_SPLITVEC::spl_rdatum, and GistEntryVector::vector.

Referenced by range_gist_picksplit().

1233 {
1234  SingleBoundSortItem *sortItems;
1235  RangeType *left_range = NULL;
1236  RangeType *right_range = NULL;
1237  OffsetNumber i,
1238  maxoff,
1239  split_idx;
1240 
1241  maxoff = entryvec->n - 1;
1242 
1243  sortItems = (SingleBoundSortItem *)
1244  palloc(maxoff * sizeof(SingleBoundSortItem));
1245 
1246  /*
1247  * Prepare auxiliary array and sort the values.
1248  */
1249  for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
1250  {
1251  RangeType *range = DatumGetRangeTypeP(entryvec->vector[i].key);
1252  RangeBound bound2;
1253  bool empty;
1254 
1255  sortItems[i - 1].index = i;
1256  /* Put appropriate bound into array */
1257  if (use_upper_bound)
1258  range_deserialize(typcache, range, &bound2,
1259  &sortItems[i - 1].bound, &empty);
1260  else
1261  range_deserialize(typcache, range, &sortItems[i - 1].bound,
1262  &bound2, &empty);
1263  Assert(!empty);
1264  }
1265 
1266  qsort_arg(sortItems, maxoff, sizeof(SingleBoundSortItem),
1267  single_bound_cmp, typcache);
1268 
1269  split_idx = maxoff / 2;
1270 
1271  v->spl_nleft = 0;
1272  v->spl_nright = 0;
1273 
1274  for (i = 0; i < maxoff; i++)
1275  {
1276  int idx = sortItems[i].index;
1277  RangeType *range = DatumGetRangeTypeP(entryvec->vector[idx].key);
1278 
1279  if (i < split_idx)
1280  PLACE_LEFT(range, idx);
1281  else
1282  PLACE_RIGHT(range, idx);
1283  }
1284 
1285  v->spl_ldatum = RangeTypePGetDatum(left_range);
1286  v->spl_rdatum = RangeTypePGetDatum(right_range);
1287 }
Datum spl_rdatum
Definition: gist.h:149
int32 n
Definition: gist.h:235
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:259
int spl_nleft
Definition: gist.h:143
#define RangeTypePGetDatum(X)
Definition: rangetypes.h:75
uint16 OffsetNumber
Definition: off.h:24
GISTENTRY vector[FLEXIBLE_ARRAY_MEMBER]
Definition: gist.h:236
#define PLACE_LEFT(range, off)
int spl_nright
Definition: gist.h:148
Datum key
Definition: gist.h:160
#define FirstOffsetNumber
Definition: off.h:27
static struct cvec * range(struct vars *v, chr a, chr b, int cases)
Definition: regc_locale.c:412
void qsort_arg(void *base, size_t nel, size_t elsize, qsort_arg_comparator cmp, void *arg)
#define PLACE_RIGHT(range, off)
Datum spl_ldatum
Definition: gist.h:144
static int single_bound_cmp(const void *a, const void *b, void *arg)
#define Assert(condition)
Definition: c.h:804
#define OffsetNumberNext(offsetNumber)
Definition: off.h:52
#define DatumGetRangeTypeP(X)
Definition: rangetypes.h:73
static Ranges * range_deserialize(int maxvalues, SerializedRanges *range)
void * palloc(Size size)
Definition: mcxt.c:1062
int i

◆ range_gist_union()

Datum range_gist_union ( PG_FUNCTION_ARGS  )

Definition at line 324 of file rangetypes_gist.c.

References DatumGetRangeTypeP, i, sort-test::key, GistEntryVector::n, PG_GETARG_POINTER, PG_RETURN_RANGE_P, range_get_typcache(), range_super_union(), RangeTypeGetOid, and GistEntryVector::vector.

325 {
327  GISTENTRY *ent = entryvec->vector;
328  RangeType *result_range;
329  TypeCacheEntry *typcache;
330  int i;
331 
332  result_range = DatumGetRangeTypeP(ent[0].key);
333 
334  typcache = range_get_typcache(fcinfo, RangeTypeGetOid(result_range));
335 
336  for (i = 1; i < entryvec->n; i++)
337  {
338  result_range = range_super_union(typcache, result_range,
339  DatumGetRangeTypeP(ent[i].key));
340  }
341 
342  PG_RETURN_RANGE_P(result_range);
343 }
TypeCacheEntry * range_get_typcache(FunctionCallInfo fcinfo, Oid rngtypid)
Definition: rangetypes.c:1635
#define RangeTypeGetOid(r)
Definition: rangetypes.h:35
int32 n
Definition: gist.h:235
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
GISTENTRY vector[FLEXIBLE_ARRAY_MEMBER]
Definition: gist.h:236
#define PG_RETURN_RANGE_P(x)
Definition: rangetypes.h:78
static RangeType * range_super_union(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2)
#define DatumGetRangeTypeP(X)
Definition: rangetypes.h:73
int i

◆ range_super_union()

static RangeType * range_super_union ( TypeCacheEntry typcache,
RangeType r1,
RangeType r2 
)
static

Definition at line 821 of file rangetypes_gist.c.

References make_range(), range_cmp_bounds(), RANGE_CONTAIN_EMPTY, range_deserialize(), RANGE_EMPTY, range_get_flags(), range_set_contain_empty(), and rangeCopy.

Referenced by range_gist_union().

822 {
823  RangeType *result;
824  RangeBound lower1,
825  lower2;
826  RangeBound upper1,
827  upper2;
828  bool empty1,
829  empty2;
830  char flags1,
831  flags2;
832  RangeBound *result_lower;
833  RangeBound *result_upper;
834 
835  range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
836  range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
837  flags1 = range_get_flags(r1);
838  flags2 = range_get_flags(r2);
839 
840  if (empty1)
841  {
842  /* We can return r2 as-is if it already is or contains empty */
843  if (flags2 & (RANGE_EMPTY | RANGE_CONTAIN_EMPTY))
844  return r2;
845  /* Else we'd better copy it (modify-in-place isn't safe) */
846  r2 = rangeCopy(r2);
848  return r2;
849  }
850  if (empty2)
851  {
852  /* We can return r1 as-is if it already is or contains empty */
853  if (flags1 & (RANGE_EMPTY | RANGE_CONTAIN_EMPTY))
854  return r1;
855  /* Else we'd better copy it (modify-in-place isn't safe) */
856  r1 = rangeCopy(r1);
858  return r1;
859  }
860 
861  if (range_cmp_bounds(typcache, &lower1, &lower2) <= 0)
862  result_lower = &lower1;
863  else
864  result_lower = &lower2;
865 
866  if (range_cmp_bounds(typcache, &upper1, &upper2) >= 0)
867  result_upper = &upper1;
868  else
869  result_upper = &upper2;
870 
871  /* optimization to avoid constructing a new range */
872  if (result_lower == &lower1 && result_upper == &upper1 &&
873  ((flags1 & RANGE_CONTAIN_EMPTY) || !(flags2 & RANGE_CONTAIN_EMPTY)))
874  return r1;
875  if (result_lower == &lower2 && result_upper == &upper2 &&
876  ((flags2 & RANGE_CONTAIN_EMPTY) || !(flags1 & RANGE_CONTAIN_EMPTY)))
877  return r2;
878 
879  result = make_range(typcache, result_lower, result_upper, false);
880 
881  if ((flags1 & RANGE_CONTAIN_EMPTY) || (flags2 & RANGE_CONTAIN_EMPTY))
882  range_set_contain_empty(result);
883 
884  return result;
885 }
RangeType * make_range(TypeCacheEntry *typcache, RangeBound *lower, RangeBound *upper, bool empty)
Definition: rangetypes.c:1884
#define RANGE_EMPTY
Definition: rangetypes.h:38
char range_get_flags(const RangeType *range)
Definition: rangetypes.c:1855
void range_set_contain_empty(RangeType *range)
Definition: rangetypes.c:1869
#define RANGE_CONTAIN_EMPTY
Definition: rangetypes.h:45
static Ranges * range_deserialize(int maxvalues, SerializedRanges *range)
#define rangeCopy(r)
int range_cmp_bounds(TypeCacheEntry *typcache, const RangeBound *b1, const RangeBound *b2)
Definition: rangetypes.c:1924

◆ single_bound_cmp()

static int single_bound_cmp ( const void *  a,
const void *  b,
void *  arg 
)
static

Definition at line 1730 of file rangetypes_gist.c.

References SingleBoundSortItem::bound, and range_cmp_bounds().

Referenced by range_gist_single_sorting_split().

1731 {
1734  TypeCacheEntry *typcache = (TypeCacheEntry *) arg;
1735 
1736  return range_cmp_bounds(typcache, &i1->bound, &i2->bound);
1737 }
void * arg
int range_cmp_bounds(TypeCacheEntry *typcache, const RangeBound *b1, const RangeBound *b2)
Definition: rangetypes.c:1924