2005-07-01 21:19:05 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* gistproc.c
|
2012-01-30 01:23:56 +01:00
|
|
|
* Support procedures for GiSTs over 2-D objects (boxes, polygons, circles,
|
|
|
|
* points).
|
2005-07-01 21:19:05 +02:00
|
|
|
*
|
|
|
|
* This gives R-tree behavior, with Guttman's poly-time split algorithm.
|
|
|
|
*
|
|
|
|
*
|
2018-01-03 05:30:12 +01:00
|
|
|
* Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
|
2005-07-01 21:19:05 +02:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2010-09-20 22:08:53 +02:00
|
|
|
* src/backend/access/gist/gistproc.c
|
2005-07-01 21:19:05 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
#include "postgres.h"
|
|
|
|
|
2016-07-15 00:45:59 +02:00
|
|
|
#include <math.h>
|
|
|
|
|
2005-07-01 21:19:05 +02:00
|
|
|
#include "access/gist.h"
|
2015-05-15 22:03:16 +02:00
|
|
|
#include "access/stratnum.h"
|
2016-07-15 00:45:59 +02:00
|
|
|
#include "utils/builtins.h"
|
2005-07-01 21:19:05 +02:00
|
|
|
#include "utils/geo_decls.h"
|
|
|
|
|
|
|
|
|
|
|
|
static bool gist_box_leaf_consistent(BOX *key, BOX *query,
|
2005-09-22 22:44:36 +02:00
|
|
|
StrategyNumber strategy);
|
2005-07-01 21:19:05 +02:00
|
|
|
static bool rtree_internal_consistent(BOX *key, BOX *query,
|
2005-09-22 22:44:36 +02:00
|
|
|
StrategyNumber strategy);
|
2005-07-01 21:19:05 +02:00
|
|
|
|
2011-10-06 09:03:46 +02:00
|
|
|
/* Minimum accepted ratio of split */
|
|
|
|
#define LIMIT_RATIO 0.3
|
|
|
|
|
2016-07-15 00:45:59 +02:00
|
|
|
/* Convenience macros for NaN-aware comparisons */
|
|
|
|
#define FLOAT8_EQ(a,b) (float8_cmp_internal(a, b) == 0)
|
|
|
|
#define FLOAT8_LT(a,b) (float8_cmp_internal(a, b) < 0)
|
|
|
|
#define FLOAT8_LE(a,b) (float8_cmp_internal(a, b) <= 0)
|
|
|
|
#define FLOAT8_GT(a,b) (float8_cmp_internal(a, b) > 0)
|
|
|
|
#define FLOAT8_GE(a,b) (float8_cmp_internal(a, b) >= 0)
|
|
|
|
#define FLOAT8_MAX(a,b) (FLOAT8_GT(a, b) ? (a) : (b))
|
|
|
|
#define FLOAT8_MIN(a,b) (FLOAT8_LT(a, b) ? (a) : (b))
|
|
|
|
|
2005-07-01 21:19:05 +02:00
|
|
|
|
|
|
|
/**************************************************
|
|
|
|
* Box ops
|
|
|
|
**************************************************/
|
|
|
|
|
2011-10-09 17:55:27 +02:00
|
|
|
/*
|
|
|
|
* Calculates union of two boxes, a and b. The result is stored in *n.
|
|
|
|
*/
|
|
|
|
static void
|
2016-07-15 00:45:59 +02:00
|
|
|
rt_box_union(BOX *n, const BOX *a, const BOX *b)
|
|
|
|
{
|
|
|
|
n->high.x = FLOAT8_MAX(a->high.x, b->high.x);
|
|
|
|
n->high.y = FLOAT8_MAX(a->high.y, b->high.y);
|
|
|
|
n->low.x = FLOAT8_MIN(a->low.x, b->low.x);
|
|
|
|
n->low.y = FLOAT8_MIN(a->low.y, b->low.y);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Size of a BOX for penalty-calculation purposes.
|
|
|
|
* The result can be +Infinity, but not NaN.
|
|
|
|
*/
|
|
|
|
static double
|
|
|
|
size_box(const BOX *box)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Check for zero-width cases. Note that we define the size of a zero-
|
|
|
|
* by-infinity box as zero. It's important to special-case this somehow,
|
|
|
|
* as naively multiplying infinity by zero will produce NaN.
|
|
|
|
*
|
|
|
|
* The less-than cases should not happen, but if they do, say "zero".
|
|
|
|
*/
|
|
|
|
if (FLOAT8_LE(box->high.x, box->low.x) ||
|
|
|
|
FLOAT8_LE(box->high.y, box->low.y))
|
|
|
|
return 0.0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We treat NaN as larger than +Infinity, so any distance involving a NaN
|
|
|
|
* and a non-NaN is infinite. Note the previous check eliminated the
|
|
|
|
* possibility that the low fields are NaNs.
|
|
|
|
*/
|
|
|
|
if (isnan(box->high.x) || isnan(box->high.y))
|
|
|
|
return get_float8_infinity();
|
|
|
|
return (box->high.x - box->low.x) * (box->high.y - box->low.y);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Return amount by which the union of the two boxes is larger than
|
|
|
|
* the original BOX's area. The result can be +Infinity, but not NaN.
|
|
|
|
*/
|
|
|
|
static double
|
|
|
|
box_penalty(const BOX *original, const BOX *new)
|
2005-11-07 18:36:47 +01:00
|
|
|
{
|
2016-07-15 00:45:59 +02:00
|
|
|
BOX unionbox;
|
|
|
|
|
|
|
|
rt_box_union(&unionbox, original, new);
|
|
|
|
return size_box(&unionbox) - size_box(original);
|
2005-11-07 18:36:47 +01:00
|
|
|
}
|
|
|
|
|
2005-07-01 21:19:05 +02:00
|
|
|
/*
|
|
|
|
* The GiST Consistent method for boxes
|
|
|
|
*
|
|
|
|
* Should return false if for all data items x below entry,
|
2017-08-16 06:22:32 +02:00
|
|
|
* the predicate x op query must be false, where op is the oper
|
2005-07-01 21:19:05 +02:00
|
|
|
* corresponding to strategy in the pg_amop table.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
gist_box_consistent(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
|
|
|
BOX *query = PG_GETARG_BOX_P(1);
|
|
|
|
StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
|
2009-06-11 16:49:15 +02:00
|
|
|
|
2008-04-14 19:05:34 +02:00
|
|
|
/* Oid subtype = PG_GETARG_OID(3); */
|
|
|
|
bool *recheck = (bool *) PG_GETARG_POINTER(4);
|
|
|
|
|
|
|
|
/* All cases served by this function are exact */
|
|
|
|
*recheck = false;
|
2005-07-01 21:19:05 +02:00
|
|
|
|
|
|
|
if (DatumGetBoxP(entry->key) == NULL || query == NULL)
|
2017-08-16 06:22:32 +02:00
|
|
|
PG_RETURN_BOOL(false);
|
2005-07-01 21:19:05 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* if entry is not leaf, use rtree_internal_consistent, else use
|
|
|
|
* gist_box_leaf_consistent
|
|
|
|
*/
|
|
|
|
if (GIST_LEAF(entry))
|
|
|
|
PG_RETURN_BOOL(gist_box_leaf_consistent(DatumGetBoxP(entry->key),
|
|
|
|
query,
|
|
|
|
strategy));
|
|
|
|
else
|
|
|
|
PG_RETURN_BOOL(rtree_internal_consistent(DatumGetBoxP(entry->key),
|
|
|
|
query,
|
|
|
|
strategy));
|
|
|
|
}
|
|
|
|
|
2016-07-15 00:45:59 +02:00
|
|
|
/*
|
|
|
|
* Increase BOX b to include addon.
|
|
|
|
*/
|
2006-06-28 14:00:14 +02:00
|
|
|
static void
|
2016-07-15 00:45:59 +02:00
|
|
|
adjustBox(BOX *b, const BOX *addon)
|
2006-10-04 02:30:14 +02:00
|
|
|
{
|
2016-07-15 00:45:59 +02:00
|
|
|
if (FLOAT8_LT(b->high.x, addon->high.x))
|
2006-06-28 14:00:14 +02:00
|
|
|
b->high.x = addon->high.x;
|
2016-07-15 00:45:59 +02:00
|
|
|
if (FLOAT8_GT(b->low.x, addon->low.x))
|
2006-06-28 14:00:14 +02:00
|
|
|
b->low.x = addon->low.x;
|
2016-07-15 00:45:59 +02:00
|
|
|
if (FLOAT8_LT(b->high.y, addon->high.y))
|
2006-06-28 14:00:14 +02:00
|
|
|
b->high.y = addon->high.y;
|
2016-07-15 00:45:59 +02:00
|
|
|
if (FLOAT8_GT(b->low.y, addon->low.y))
|
2006-06-28 14:00:14 +02:00
|
|
|
b->low.y = addon->low.y;
|
|
|
|
}
|
2005-07-01 21:19:05 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* The GiST Union method for boxes
|
|
|
|
*
|
|
|
|
* returns the minimal bounding box that encloses all the entries in entryvec
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
gist_box_union(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
|
|
|
|
int *sizep = (int *) PG_GETARG_POINTER(1);
|
|
|
|
int numranges,
|
|
|
|
i;
|
|
|
|
BOX *cur,
|
|
|
|
*pageunion;
|
|
|
|
|
|
|
|
numranges = entryvec->n;
|
|
|
|
pageunion = (BOX *) palloc(sizeof(BOX));
|
|
|
|
cur = DatumGetBoxP(entryvec->vector[0].key);
|
|
|
|
memcpy((void *) pageunion, (void *) cur, sizeof(BOX));
|
|
|
|
|
|
|
|
for (i = 1; i < numranges; i++)
|
|
|
|
{
|
|
|
|
cur = DatumGetBoxP(entryvec->vector[i].key);
|
2006-10-04 02:30:14 +02:00
|
|
|
adjustBox(pageunion, cur);
|
2005-07-01 21:19:05 +02:00
|
|
|
}
|
|
|
|
*sizep = sizeof(BOX);
|
|
|
|
|
|
|
|
PG_RETURN_POINTER(pageunion);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-09-20 05:32:45 +02:00
|
|
|
* We store boxes as boxes in GiST indexes, so we do not need
|
|
|
|
* compress, decompress, or fetch functions.
|
2005-07-01 21:19:05 +02:00
|
|
|
*/
|
2015-03-26 18:12:00 +01:00
|
|
|
|
2005-07-01 21:19:05 +02:00
|
|
|
/*
|
2010-01-14 17:31:09 +01:00
|
|
|
* The GiST Penalty method for boxes (also used for points)
|
2005-07-01 21:19:05 +02:00
|
|
|
*
|
|
|
|
* As in the R-tree paper, we use change in area as our penalty metric
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
gist_box_penalty(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
|
|
|
GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
|
|
|
|
float *result = (float *) PG_GETARG_POINTER(2);
|
2011-10-09 17:55:27 +02:00
|
|
|
BOX *origbox = DatumGetBoxP(origentry->key);
|
|
|
|
BOX *newbox = DatumGetBoxP(newentry->key);
|
2005-07-01 21:19:05 +02:00
|
|
|
|
2016-07-15 00:45:59 +02:00
|
|
|
*result = (float) box_penalty(origbox, newbox);
|
2005-07-01 21:19:05 +02:00
|
|
|
PG_RETURN_POINTER(result);
|
|
|
|
}
|
|
|
|
|
2009-04-06 16:27:27 +02:00
|
|
|
/*
|
|
|
|
* Trivial split: half of entries will be placed on one page
|
|
|
|
* and another half - to another
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
fallbackSplit(GistEntryVector *entryvec, GIST_SPLITVEC *v)
|
|
|
|
{
|
2009-06-11 16:49:15 +02:00
|
|
|
OffsetNumber i,
|
|
|
|
maxoff;
|
|
|
|
BOX *unionL = NULL,
|
|
|
|
*unionR = NULL;
|
|
|
|
int nbytes;
|
2009-04-06 16:27:27 +02:00
|
|
|
|
|
|
|
maxoff = entryvec->n - 1;
|
|
|
|
|
|
|
|
nbytes = (maxoff + 2) * sizeof(OffsetNumber);
|
|
|
|
v->spl_left = (OffsetNumber *) palloc(nbytes);
|
|
|
|
v->spl_right = (OffsetNumber *) palloc(nbytes);
|
|
|
|
v->spl_nleft = v->spl_nright = 0;
|
|
|
|
|
|
|
|
for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
|
|
|
|
{
|
2009-06-11 16:49:15 +02:00
|
|
|
BOX *cur = DatumGetBoxP(entryvec->vector[i].key);
|
2009-04-06 16:27:27 +02:00
|
|
|
|
|
|
|
if (i <= (maxoff - FirstOffsetNumber + 1) / 2)
|
|
|
|
{
|
|
|
|
v->spl_left[v->spl_nleft] = i;
|
|
|
|
if (unionL == NULL)
|
|
|
|
{
|
|
|
|
unionL = (BOX *) palloc(sizeof(BOX));
|
|
|
|
*unionL = *cur;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
adjustBox(unionL, cur);
|
|
|
|
|
|
|
|
v->spl_nleft++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
v->spl_right[v->spl_nright] = i;
|
|
|
|
if (unionR == NULL)
|
|
|
|
{
|
|
|
|
unionR = (BOX *) palloc(sizeof(BOX));
|
|
|
|
*unionR = *cur;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
adjustBox(unionR, cur);
|
|
|
|
|
|
|
|
v->spl_nright++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
v->spl_ldatum = BoxPGetDatum(unionL);
|
|
|
|
v->spl_rdatum = BoxPGetDatum(unionR);
|
|
|
|
}
|
|
|
|
|
2005-07-01 21:19:05 +02:00
|
|
|
/*
|
2011-10-06 09:03:46 +02:00
|
|
|
* Represents information about an entry that can be placed to either group
|
|
|
|
* without affecting overlap over selected axis ("common entry").
|
|
|
|
*/
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
/* Index of entry in the initial array */
|
|
|
|
int index;
|
|
|
|
/* Delta between penalties of entry insertion into different groups */
|
|
|
|
double delta;
|
2012-06-10 21:20:04 +02:00
|
|
|
} CommonEntry;
|
2011-10-06 09:03:46 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Context for g_box_consider_split. Contains information about currently
|
|
|
|
* selected split and some general information.
|
|
|
|
*/
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
int entriesCount; /* total number of entries being split */
|
|
|
|
BOX boundingBox; /* minimum bounding box across all entries */
|
|
|
|
|
|
|
|
/* Information about currently selected split follows */
|
|
|
|
|
|
|
|
bool first; /* true if no split was selected yet */
|
|
|
|
|
|
|
|
double leftUpper; /* upper bound of left interval */
|
|
|
|
double rightLower; /* lower bound of right interval */
|
|
|
|
|
|
|
|
float4 ratio;
|
|
|
|
float4 overlap;
|
|
|
|
int dim; /* axis of this split */
|
|
|
|
double range; /* width of general MBR projection to the
|
|
|
|
* selected axis */
|
2012-06-10 21:20:04 +02:00
|
|
|
} ConsiderSplitContext;
|
2011-10-06 09:03:46 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Interval represents projection of box to axis.
|
|
|
|
*/
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
double lower,
|
|
|
|
upper;
|
2012-06-10 21:20:04 +02:00
|
|
|
} SplitInterval;
|
2011-10-06 09:03:46 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Interval comparison function by lower bound of the interval;
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
interval_cmp_lower(const void *i1, const void *i2)
|
|
|
|
{
|
2012-02-28 11:42:08 +01:00
|
|
|
double lower1 = ((const SplitInterval *) i1)->lower,
|
|
|
|
lower2 = ((const SplitInterval *) i2)->lower;
|
2011-10-06 09:03:46 +02:00
|
|
|
|
2016-07-15 00:45:59 +02:00
|
|
|
return float8_cmp_internal(lower1, lower2);
|
2011-10-06 09:03:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Interval comparison function by upper bound of the interval;
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
interval_cmp_upper(const void *i1, const void *i2)
|
|
|
|
{
|
2012-02-28 11:42:08 +01:00
|
|
|
double upper1 = ((const SplitInterval *) i1)->upper,
|
|
|
|
upper2 = ((const SplitInterval *) i2)->upper;
|
2011-10-06 09:03:46 +02:00
|
|
|
|
2016-07-15 00:45:59 +02:00
|
|
|
return float8_cmp_internal(upper1, upper2);
|
2011-10-06 09:03:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2016-07-15 00:45:59 +02:00
|
|
|
* Replace negative (or NaN) value with zero.
|
2011-10-06 09:03:46 +02:00
|
|
|
*/
|
|
|
|
static inline float
|
|
|
|
non_negative(float val)
|
|
|
|
{
|
|
|
|
if (val >= 0.0f)
|
|
|
|
return val;
|
|
|
|
else
|
|
|
|
return 0.0f;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Consider replacement of currently selected split with the better one.
|
|
|
|
*/
|
2012-05-12 11:52:02 +02:00
|
|
|
static inline void
|
2011-10-06 09:03:46 +02:00
|
|
|
g_box_consider_split(ConsiderSplitContext *context, int dimNum,
|
|
|
|
double rightLower, int minLeftCount,
|
|
|
|
double leftUpper, int maxLeftCount)
|
|
|
|
{
|
|
|
|
int leftCount,
|
|
|
|
rightCount;
|
|
|
|
float4 ratio,
|
|
|
|
overlap;
|
|
|
|
double range;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Calculate entries distribution ratio assuming most uniform distribution
|
|
|
|
* of common entries.
|
|
|
|
*/
|
|
|
|
if (minLeftCount >= (context->entriesCount + 1) / 2)
|
|
|
|
{
|
|
|
|
leftCount = minLeftCount;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (maxLeftCount <= context->entriesCount / 2)
|
|
|
|
leftCount = maxLeftCount;
|
|
|
|
else
|
|
|
|
leftCount = context->entriesCount / 2;
|
|
|
|
}
|
|
|
|
rightCount = context->entriesCount - leftCount;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Ratio of split - quotient between size of lesser group and total
|
|
|
|
* entries count.
|
|
|
|
*/
|
|
|
|
ratio = ((float4) Min(leftCount, rightCount)) /
|
|
|
|
((float4) context->entriesCount);
|
|
|
|
|
|
|
|
if (ratio > LIMIT_RATIO)
|
|
|
|
{
|
|
|
|
bool selectthis = false;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The ratio is acceptable, so compare current split with previously
|
|
|
|
* selected one. Between splits of one dimension we search for minimal
|
|
|
|
* overlap (allowing negative values) and minimal ration (between same
|
|
|
|
* overlaps. We switch dimension if find less overlap (non-negative)
|
|
|
|
* or less range with same overlap.
|
|
|
|
*/
|
|
|
|
if (dimNum == 0)
|
|
|
|
range = context->boundingBox.high.x - context->boundingBox.low.x;
|
|
|
|
else
|
|
|
|
range = context->boundingBox.high.y - context->boundingBox.low.y;
|
|
|
|
|
|
|
|
overlap = (leftUpper - rightLower) / range;
|
|
|
|
|
|
|
|
/* If there is no previous selection, select this */
|
|
|
|
if (context->first)
|
|
|
|
selectthis = true;
|
|
|
|
else if (context->dim == dimNum)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Within the same dimension, choose the new split if it has a
|
|
|
|
* smaller overlap, or same overlap but better ratio.
|
|
|
|
*/
|
|
|
|
if (overlap < context->overlap ||
|
|
|
|
(overlap == context->overlap && ratio > context->ratio))
|
|
|
|
selectthis = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Across dimensions, choose the new split if it has a smaller
|
|
|
|
* *non-negative* overlap, or same *non-negative* overlap but
|
|
|
|
* bigger range. This condition differs from the one described in
|
|
|
|
* the article. On the datasets where leaf MBRs don't overlap
|
|
|
|
* themselves, non-overlapping splits (i.e. splits which have zero
|
|
|
|
* *non-negative* overlap) are frequently possible. In this case
|
|
|
|
* splits tends to be along one dimension, because most distant
|
|
|
|
* non-overlapping splits (i.e. having lowest negative overlap)
|
|
|
|
* appears to be in the same dimension as in the previous split.
|
|
|
|
* Therefore MBRs appear to be very prolonged along another
|
|
|
|
* dimension, which leads to bad search performance. Using range
|
|
|
|
* as the second split criteria makes MBRs more quadratic. Using
|
|
|
|
* *non-negative* overlap instead of overlap as the first split
|
|
|
|
* criteria gives to range criteria a chance to matter, because
|
|
|
|
* non-overlapping splits are equivalent in this criteria.
|
|
|
|
*/
|
|
|
|
if (non_negative(overlap) < non_negative(context->overlap) ||
|
|
|
|
(range > context->range &&
|
|
|
|
non_negative(overlap) <= non_negative(context->overlap)))
|
|
|
|
selectthis = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (selectthis)
|
|
|
|
{
|
|
|
|
/* save information about selected split */
|
|
|
|
context->first = false;
|
|
|
|
context->ratio = ratio;
|
|
|
|
context->range = range;
|
|
|
|
context->overlap = overlap;
|
|
|
|
context->rightLower = rightLower;
|
|
|
|
context->leftUpper = leftUpper;
|
|
|
|
context->dim = dimNum;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Compare common entries by their deltas.
|
2016-07-15 00:45:59 +02:00
|
|
|
* (We assume the deltas can't be NaN.)
|
2011-10-06 09:03:46 +02:00
|
|
|
*/
|
|
|
|
static int
|
|
|
|
common_entry_cmp(const void *i1, const void *i2)
|
|
|
|
{
|
2012-02-28 11:42:08 +01:00
|
|
|
double delta1 = ((const CommonEntry *) i1)->delta,
|
|
|
|
delta2 = ((const CommonEntry *) i2)->delta;
|
2011-10-06 09:03:46 +02:00
|
|
|
|
|
|
|
if (delta1 < delta2)
|
|
|
|
return -1;
|
|
|
|
else if (delta1 > delta2)
|
|
|
|
return 1;
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* --------------------------------------------------------------------------
|
|
|
|
* Double sorting split algorithm. This is used for both boxes and points.
|
2005-07-01 21:19:05 +02:00
|
|
|
*
|
2011-10-06 09:03:46 +02:00
|
|
|
* The algorithm finds split of boxes by considering splits along each axis.
|
|
|
|
* Each entry is first projected as an interval on the X-axis, and different
|
|
|
|
* ways to split the intervals into two groups are considered, trying to
|
|
|
|
* minimize the overlap of the groups. Then the same is repeated for the
|
|
|
|
* Y-axis, and the overall best split is chosen. The quality of a split is
|
|
|
|
* determined by overlap along that axis and some other criteria (see
|
|
|
|
* g_box_consider_split).
|
2010-01-14 17:31:09 +01:00
|
|
|
*
|
2011-10-06 09:03:46 +02:00
|
|
|
* After that, all the entries are divided into three groups:
|
|
|
|
*
|
|
|
|
* 1) Entries which should be placed to the left group
|
|
|
|
* 2) Entries which should be placed to the right group
|
|
|
|
* 3) "Common entries" which can be placed to any of groups without affecting
|
|
|
|
* of overlap along selected axis.
|
|
|
|
*
|
|
|
|
* The common entries are distributed by minimizing penalty.
|
|
|
|
*
|
|
|
|
* For details see:
|
|
|
|
* "A new double sorting-based node splitting algorithm for R-tree", A. Korotkov
|
|
|
|
* http://syrcose.ispras.ru/2011/files/SYRCoSE2011_Proceedings.pdf#page=36
|
|
|
|
* --------------------------------------------------------------------------
|
2005-07-01 21:19:05 +02:00
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
gist_box_picksplit(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
|
|
|
|
GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
|
2011-10-06 09:03:46 +02:00
|
|
|
OffsetNumber i,
|
|
|
|
maxoff;
|
|
|
|
ConsiderSplitContext context;
|
|
|
|
BOX *box,
|
|
|
|
*leftBox,
|
|
|
|
*rightBox;
|
|
|
|
int dim,
|
|
|
|
commonEntriesCount;
|
|
|
|
SplitInterval *intervalsLower,
|
|
|
|
*intervalsUpper;
|
|
|
|
CommonEntry *commonEntries;
|
|
|
|
int nentries;
|
|
|
|
|
|
|
|
memset(&context, 0, sizeof(ConsiderSplitContext));
|
2005-07-01 21:19:05 +02:00
|
|
|
|
|
|
|
maxoff = entryvec->n - 1;
|
2011-10-06 09:03:46 +02:00
|
|
|
nentries = context.entriesCount = maxoff - FirstOffsetNumber + 1;
|
2005-07-01 21:19:05 +02:00
|
|
|
|
2011-10-06 09:03:46 +02:00
|
|
|
/* Allocate arrays for intervals along axes */
|
|
|
|
intervalsLower = (SplitInterval *) palloc(nentries * sizeof(SplitInterval));
|
|
|
|
intervalsUpper = (SplitInterval *) palloc(nentries * sizeof(SplitInterval));
|
2005-07-01 21:19:05 +02:00
|
|
|
|
2011-10-06 09:03:46 +02:00
|
|
|
/*
|
|
|
|
* Calculate the overall minimum bounding box over all the entries.
|
|
|
|
*/
|
|
|
|
for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
|
2005-07-01 21:19:05 +02:00
|
|
|
{
|
2011-10-06 09:03:46 +02:00
|
|
|
box = DatumGetBoxP(entryvec->vector[i].key);
|
|
|
|
if (i == FirstOffsetNumber)
|
|
|
|
context.boundingBox = *box;
|
|
|
|
else
|
|
|
|
adjustBox(&context.boundingBox, box);
|
2005-07-01 21:19:05 +02:00
|
|
|
}
|
|
|
|
|
2011-10-06 09:03:46 +02:00
|
|
|
/*
|
|
|
|
* Iterate over axes for optimal split searching.
|
|
|
|
*/
|
|
|
|
context.first = true; /* nothing selected yet */
|
|
|
|
for (dim = 0; dim < 2; dim++)
|
2005-07-01 21:19:05 +02:00
|
|
|
{
|
2011-10-06 09:03:46 +02:00
|
|
|
double leftUpper,
|
|
|
|
rightLower;
|
|
|
|
int i1,
|
|
|
|
i2;
|
|
|
|
|
|
|
|
/* Project each entry as an interval on the selected axis. */
|
|
|
|
for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
|
|
|
|
{
|
|
|
|
box = DatumGetBoxP(entryvec->vector[i].key);
|
|
|
|
if (dim == 0)
|
|
|
|
{
|
|
|
|
intervalsLower[i - FirstOffsetNumber].lower = box->low.x;
|
|
|
|
intervalsLower[i - FirstOffsetNumber].upper = box->high.x;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
intervalsLower[i - FirstOffsetNumber].lower = box->low.y;
|
|
|
|
intervalsLower[i - FirstOffsetNumber].upper = box->high.y;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make two arrays of intervals: one sorted by lower bound and another
|
|
|
|
* sorted by upper bound.
|
|
|
|
*/
|
|
|
|
memcpy(intervalsUpper, intervalsLower,
|
|
|
|
sizeof(SplitInterval) * nentries);
|
|
|
|
qsort(intervalsLower, nentries, sizeof(SplitInterval),
|
|
|
|
interval_cmp_lower);
|
|
|
|
qsort(intervalsUpper, nentries, sizeof(SplitInterval),
|
|
|
|
interval_cmp_upper);
|
|
|
|
|
|
|
|
/*----
|
|
|
|
* The goal is to form a left and right interval, so that every entry
|
|
|
|
* interval is contained by either left or right interval (or both).
|
|
|
|
*
|
|
|
|
* For example, with the intervals (0,1), (1,3), (2,3), (2,4):
|
|
|
|
*
|
|
|
|
* 0 1 2 3 4
|
|
|
|
* +-+
|
|
|
|
* +---+
|
|
|
|
* +-+
|
|
|
|
* +---+
|
|
|
|
*
|
|
|
|
* The left and right intervals are of the form (0,a) and (b,4).
|
|
|
|
* We first consider splits where b is the lower bound of an entry.
|
|
|
|
* We iterate through all entries, and for each b, calculate the
|
|
|
|
* smallest possible a. Then we consider splits where a is the
|
2015-09-05 10:35:49 +02:00
|
|
|
* upper bound of an entry, and for each a, calculate the greatest
|
2011-10-06 09:03:46 +02:00
|
|
|
* possible b.
|
|
|
|
*
|
|
|
|
* In the above example, the first loop would consider splits:
|
|
|
|
* b=0: (0,1)-(0,4)
|
|
|
|
* b=1: (0,1)-(1,4)
|
|
|
|
* b=2: (0,3)-(2,4)
|
|
|
|
*
|
|
|
|
* And the second loop:
|
|
|
|
* a=1: (0,1)-(1,4)
|
|
|
|
* a=3: (0,3)-(2,4)
|
|
|
|
* a=4: (0,4)-(2,4)
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Iterate over lower bound of right group, finding smallest possible
|
|
|
|
* upper bound of left group.
|
|
|
|
*/
|
|
|
|
i1 = 0;
|
|
|
|
i2 = 0;
|
|
|
|
rightLower = intervalsLower[i1].lower;
|
|
|
|
leftUpper = intervalsUpper[i2].lower;
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Find next lower bound of right group.
|
|
|
|
*/
|
2016-07-15 00:45:59 +02:00
|
|
|
while (i1 < nentries &&
|
|
|
|
FLOAT8_EQ(rightLower, intervalsLower[i1].lower))
|
2011-10-06 09:03:46 +02:00
|
|
|
{
|
2016-07-15 00:45:59 +02:00
|
|
|
if (FLOAT8_LT(leftUpper, intervalsLower[i1].upper))
|
|
|
|
leftUpper = intervalsLower[i1].upper;
|
2011-10-06 09:03:46 +02:00
|
|
|
i1++;
|
|
|
|
}
|
|
|
|
if (i1 >= nentries)
|
|
|
|
break;
|
|
|
|
rightLower = intervalsLower[i1].lower;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Find count of intervals which anyway should be placed to the
|
|
|
|
* left group.
|
|
|
|
*/
|
2016-07-15 00:45:59 +02:00
|
|
|
while (i2 < nentries &&
|
|
|
|
FLOAT8_LE(intervalsUpper[i2].upper, leftUpper))
|
2011-10-06 09:03:46 +02:00
|
|
|
i2++;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Consider found split.
|
|
|
|
*/
|
|
|
|
g_box_consider_split(&context, dim, rightLower, i1, leftUpper, i2);
|
|
|
|
}
|
|
|
|
|
2009-04-06 16:27:27 +02:00
|
|
|
/*
|
2015-09-05 10:35:49 +02:00
|
|
|
* Iterate over upper bound of left group finding greatest possible
|
2011-10-06 09:03:46 +02:00
|
|
|
* lower bound of right group.
|
2009-04-06 16:27:27 +02:00
|
|
|
*/
|
2011-10-06 09:03:46 +02:00
|
|
|
i1 = nentries - 1;
|
|
|
|
i2 = nentries - 1;
|
|
|
|
rightLower = intervalsLower[i1].upper;
|
|
|
|
leftUpper = intervalsUpper[i2].upper;
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Find next upper bound of left group.
|
|
|
|
*/
|
2016-07-15 00:45:59 +02:00
|
|
|
while (i2 >= 0 && FLOAT8_EQ(leftUpper, intervalsUpper[i2].upper))
|
2011-10-06 09:03:46 +02:00
|
|
|
{
|
2016-07-15 00:45:59 +02:00
|
|
|
if (FLOAT8_GT(rightLower, intervalsUpper[i2].lower))
|
|
|
|
rightLower = intervalsUpper[i2].lower;
|
2011-10-06 09:03:46 +02:00
|
|
|
i2--;
|
|
|
|
}
|
|
|
|
if (i2 < 0)
|
|
|
|
break;
|
|
|
|
leftUpper = intervalsUpper[i2].upper;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Find count of intervals which anyway should be placed to the
|
|
|
|
* right group.
|
|
|
|
*/
|
2016-07-15 00:45:59 +02:00
|
|
|
while (i1 >= 0 && FLOAT8_GE(intervalsLower[i1].lower, rightLower))
|
2011-10-06 09:03:46 +02:00
|
|
|
i1--;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Consider found split.
|
|
|
|
*/
|
|
|
|
g_box_consider_split(&context, dim,
|
|
|
|
rightLower, i1 + 1, leftUpper, i2 + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we failed to find any acceptable splits, use trivial split.
|
|
|
|
*/
|
|
|
|
if (context.first)
|
|
|
|
{
|
2009-04-06 16:27:27 +02:00
|
|
|
fallbackSplit(entryvec, v);
|
|
|
|
PG_RETURN_POINTER(v);
|
2005-07-01 21:19:05 +02:00
|
|
|
}
|
|
|
|
|
2011-10-06 09:03:46 +02:00
|
|
|
/*
|
|
|
|
* Ok, we have now selected the split across one axis.
|
|
|
|
*
|
|
|
|
* While considering the splits, we already determined that there will be
|
|
|
|
* enough entries in both groups to reach the desired ratio, but we did
|
|
|
|
* not memorize which entries go to which group. So determine that now.
|
|
|
|
*/
|
2005-07-01 21:19:05 +02:00
|
|
|
|
2011-10-06 09:03:46 +02:00
|
|
|
/* Allocate vectors for results */
|
|
|
|
v->spl_left = (OffsetNumber *) palloc(nentries * sizeof(OffsetNumber));
|
|
|
|
v->spl_right = (OffsetNumber *) palloc(nentries * sizeof(OffsetNumber));
|
|
|
|
v->spl_nleft = 0;
|
|
|
|
v->spl_nright = 0;
|
|
|
|
|
|
|
|
/* Allocate bounding boxes of left and right groups */
|
|
|
|
leftBox = palloc0(sizeof(BOX));
|
|
|
|
rightBox = palloc0(sizeof(BOX));
|
2005-07-01 21:19:05 +02:00
|
|
|
|
2011-10-06 09:03:46 +02:00
|
|
|
/*
|
|
|
|
* Allocate an array for "common entries" - entries which can be placed to
|
|
|
|
* either group without affecting overlap along selected axis.
|
|
|
|
*/
|
|
|
|
commonEntriesCount = 0;
|
|
|
|
commonEntries = (CommonEntry *) palloc(nentries * sizeof(CommonEntry));
|
|
|
|
|
|
|
|
/* Helper macros to place an entry in the left or right group */
|
|
|
|
#define PLACE_LEFT(box, off) \
|
|
|
|
do { \
|
|
|
|
if (v->spl_nleft > 0) \
|
|
|
|
adjustBox(leftBox, box); \
|
|
|
|
else \
|
|
|
|
*leftBox = *(box); \
|
|
|
|
v->spl_left[v->spl_nleft++] = off; \
|
|
|
|
} while(0)
|
|
|
|
|
|
|
|
#define PLACE_RIGHT(box, off) \
|
|
|
|
do { \
|
|
|
|
if (v->spl_nright > 0) \
|
|
|
|
adjustBox(rightBox, box); \
|
|
|
|
else \
|
|
|
|
*rightBox = *(box); \
|
|
|
|
v->spl_right[v->spl_nright++] = off; \
|
|
|
|
} while(0)
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Distribute entries which can be distributed unambiguously, and collect
|
|
|
|
* common entries.
|
|
|
|
*/
|
|
|
|
for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
|
2005-07-01 21:19:05 +02:00
|
|
|
{
|
2011-10-06 09:03:46 +02:00
|
|
|
double lower,
|
|
|
|
upper;
|
2005-07-01 21:19:05 +02:00
|
|
|
|
2011-10-06 09:03:46 +02:00
|
|
|
/*
|
|
|
|
* Get upper and lower bounds along selected axis.
|
|
|
|
*/
|
|
|
|
box = DatumGetBoxP(entryvec->vector[i].key);
|
|
|
|
if (context.dim == 0)
|
2005-07-01 21:19:05 +02:00
|
|
|
{
|
2011-10-06 09:03:46 +02:00
|
|
|
lower = box->low.x;
|
|
|
|
upper = box->high.x;
|
2005-07-01 21:19:05 +02:00
|
|
|
}
|
2011-10-06 09:03:46 +02:00
|
|
|
else
|
2005-07-01 21:19:05 +02:00
|
|
|
{
|
2011-10-06 09:03:46 +02:00
|
|
|
lower = box->low.y;
|
|
|
|
upper = box->high.y;
|
|
|
|
}
|
2007-11-15 22:14:46 +01:00
|
|
|
|
2016-07-15 00:45:59 +02:00
|
|
|
if (FLOAT8_LE(upper, context.leftUpper))
|
2011-10-06 09:03:46 +02:00
|
|
|
{
|
|
|
|
/* Fits to the left group */
|
2016-07-15 00:45:59 +02:00
|
|
|
if (FLOAT8_GE(lower, context.rightLower))
|
2005-07-01 21:19:05 +02:00
|
|
|
{
|
2011-10-06 09:03:46 +02:00
|
|
|
/* Fits also to the right group, so "common entry" */
|
|
|
|
commonEntries[commonEntriesCount++].index = i;
|
2005-07-01 21:19:05 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-10-06 09:03:46 +02:00
|
|
|
/* Doesn't fit to the right group, so join to the left group */
|
|
|
|
PLACE_LEFT(box, i);
|
2005-07-01 21:19:05 +02:00
|
|
|
}
|
|
|
|
}
|
2011-10-06 09:03:46 +02:00
|
|
|
else
|
2009-04-06 16:27:27 +02:00
|
|
|
{
|
2011-10-06 09:03:46 +02:00
|
|
|
/*
|
|
|
|
* Each entry should fit on either left or right group. Since this
|
|
|
|
* entry didn't fit on the left group, it better fit in the right
|
|
|
|
* group.
|
|
|
|
*/
|
2016-07-15 00:45:59 +02:00
|
|
|
Assert(FLOAT8_GE(lower, context.rightLower));
|
2011-10-06 09:03:46 +02:00
|
|
|
|
|
|
|
/* Doesn't fit to the left group, so join to the right group */
|
|
|
|
PLACE_RIGHT(box, i);
|
2009-04-06 16:27:27 +02:00
|
|
|
}
|
2005-07-01 21:19:05 +02:00
|
|
|
}
|
|
|
|
|
2011-10-06 09:03:46 +02:00
|
|
|
/*
|
|
|
|
* Distribute "common entries", if any.
|
|
|
|
*/
|
|
|
|
if (commonEntriesCount > 0)
|
2005-07-01 21:19:05 +02:00
|
|
|
{
|
2011-10-06 09:03:46 +02:00
|
|
|
/*
|
|
|
|
* Calculate minimum number of entries that must be placed in both
|
|
|
|
* groups, to reach LIMIT_RATIO.
|
|
|
|
*/
|
|
|
|
int m = ceil(LIMIT_RATIO * (double) nentries);
|
2005-07-01 21:19:05 +02:00
|
|
|
|
2011-10-06 09:03:46 +02:00
|
|
|
/*
|
|
|
|
* Calculate delta between penalties of join "common entries" to
|
|
|
|
* different groups.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < commonEntriesCount; i++)
|
|
|
|
{
|
|
|
|
box = DatumGetBoxP(entryvec->vector[commonEntries[i].index].key);
|
|
|
|
commonEntries[i].delta = Abs(box_penalty(leftBox, box) -
|
|
|
|
box_penalty(rightBox, box));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Sort "common entries" by calculated deltas in order to distribute
|
|
|
|
* the most ambiguous entries first.
|
|
|
|
*/
|
|
|
|
qsort(commonEntries, commonEntriesCount, sizeof(CommonEntry), common_entry_cmp);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Distribute "common entries" between groups.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < commonEntriesCount; i++)
|
|
|
|
{
|
|
|
|
box = DatumGetBoxP(entryvec->vector[commonEntries[i].index].key);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if we have to place this entry in either group to achieve
|
|
|
|
* LIMIT_RATIO.
|
|
|
|
*/
|
|
|
|
if (v->spl_nleft + (commonEntriesCount - i) <= m)
|
|
|
|
PLACE_LEFT(box, commonEntries[i].index);
|
|
|
|
else if (v->spl_nright + (commonEntriesCount - i) <= m)
|
|
|
|
PLACE_RIGHT(box, commonEntries[i].index);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Otherwise select the group by minimal penalty */
|
|
|
|
if (box_penalty(leftBox, box) < box_penalty(rightBox, box))
|
|
|
|
PLACE_LEFT(box, commonEntries[i].index);
|
|
|
|
else
|
|
|
|
PLACE_RIGHT(box, commonEntries[i].index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-07-01 21:19:05 +02:00
|
|
|
|
2011-10-06 09:03:46 +02:00
|
|
|
v->spl_ldatum = PointerGetDatum(leftBox);
|
|
|
|
v->spl_rdatum = PointerGetDatum(rightBox);
|
2005-07-01 21:19:05 +02:00
|
|
|
PG_RETURN_POINTER(v);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Equality method
|
2010-01-14 17:31:09 +01:00
|
|
|
*
|
Fix gist_box_same and gist_point_consistent to handle fuzziness correctly.
While there's considerable doubt that we want fuzzy behavior in the
geometric operators at all (let alone as currently implemented), nobody is
stepping forward to redesign that stuff. In the meantime it behooves us
to make sure that index searches agree with the behavior of the underlying
operators. This patch fixes two problems in this area.
First, gist_box_same was using fuzzy equality, but it really needs to use
exact equality to prevent not-quite-identical upper index keys from being
treated as identical, which for example would prevent an existing upper
key from being extended by an amount less than epsilon. This would result
in inconsistent indexes. (The next release notes will need to recommend
that users reindex GiST indexes on boxes, polygons, circles, and points,
since all four opclasses use gist_box_same.)
Second, gist_point_consistent used exact comparisons for upper-page
comparisons in ~= searches, when it needs to use fuzzy comparisons to
ensure it finds all matches; and it used fuzzy comparisons for point <@ box
searches, when it needs to use exact comparisons because that's what the
<@ operator (rather inconsistently) does.
The added regression test cases illustrate all three misbehaviors.
Back-patch to all active branches. (8.4 did not have GiST point_ops,
but it still seems prudent to apply the gist_box_same patch to it.)
Alexander Korotkov, reviewed by Noah Misch
2013-02-09 00:03:17 +01:00
|
|
|
* This is used for boxes, points, circles, and polygons, all of which store
|
|
|
|
* boxes as GiST index entries.
|
|
|
|
*
|
|
|
|
* Returns true only when boxes are exactly the same. We can't use fuzzy
|
|
|
|
* comparisons here without breaking index consistency; therefore, this isn't
|
|
|
|
* equivalent to box_same().
|
2005-07-01 21:19:05 +02:00
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
gist_box_same(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
BOX *b1 = PG_GETARG_BOX_P(0);
|
|
|
|
BOX *b2 = PG_GETARG_BOX_P(1);
|
|
|
|
bool *result = (bool *) PG_GETARG_POINTER(2);
|
|
|
|
|
|
|
|
if (b1 && b2)
|
2016-07-15 00:45:59 +02:00
|
|
|
*result = (FLOAT8_EQ(b1->low.x, b2->low.x) &&
|
|
|
|
FLOAT8_EQ(b1->low.y, b2->low.y) &&
|
|
|
|
FLOAT8_EQ(b1->high.x, b2->high.x) &&
|
|
|
|
FLOAT8_EQ(b1->high.y, b2->high.y));
|
2005-07-01 21:19:05 +02:00
|
|
|
else
|
Fix gist_box_same and gist_point_consistent to handle fuzziness correctly.
While there's considerable doubt that we want fuzzy behavior in the
geometric operators at all (let alone as currently implemented), nobody is
stepping forward to redesign that stuff. In the meantime it behooves us
to make sure that index searches agree with the behavior of the underlying
operators. This patch fixes two problems in this area.
First, gist_box_same was using fuzzy equality, but it really needs to use
exact equality to prevent not-quite-identical upper index keys from being
treated as identical, which for example would prevent an existing upper
key from being extended by an amount less than epsilon. This would result
in inconsistent indexes. (The next release notes will need to recommend
that users reindex GiST indexes on boxes, polygons, circles, and points,
since all four opclasses use gist_box_same.)
Second, gist_point_consistent used exact comparisons for upper-page
comparisons in ~= searches, when it needs to use fuzzy comparisons to
ensure it finds all matches; and it used fuzzy comparisons for point <@ box
searches, when it needs to use exact comparisons because that's what the
<@ operator (rather inconsistently) does.
The added regression test cases illustrate all three misbehaviors.
Back-patch to all active branches. (8.4 did not have GiST point_ops,
but it still seems prudent to apply the gist_box_same patch to it.)
Alexander Korotkov, reviewed by Noah Misch
2013-02-09 00:03:17 +01:00
|
|
|
*result = (b1 == NULL && b2 == NULL);
|
2005-07-01 21:19:05 +02:00
|
|
|
PG_RETURN_POINTER(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Leaf-level consistency for boxes: just apply the query operator
|
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
gist_box_leaf_consistent(BOX *key, BOX *query, StrategyNumber strategy)
|
|
|
|
{
|
|
|
|
bool retval;
|
|
|
|
|
|
|
|
switch (strategy)
|
|
|
|
{
|
|
|
|
case RTLeftStrategyNumber:
|
|
|
|
retval = DatumGetBool(DirectFunctionCall2(box_left,
|
|
|
|
PointerGetDatum(key),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
PointerGetDatum(query)));
|
2005-07-01 21:19:05 +02:00
|
|
|
break;
|
|
|
|
case RTOverLeftStrategyNumber:
|
|
|
|
retval = DatumGetBool(DirectFunctionCall2(box_overleft,
|
|
|
|
PointerGetDatum(key),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
PointerGetDatum(query)));
|
2005-07-01 21:19:05 +02:00
|
|
|
break;
|
|
|
|
case RTOverlapStrategyNumber:
|
|
|
|
retval = DatumGetBool(DirectFunctionCall2(box_overlap,
|
|
|
|
PointerGetDatum(key),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
PointerGetDatum(query)));
|
2005-07-01 21:19:05 +02:00
|
|
|
break;
|
|
|
|
case RTOverRightStrategyNumber:
|
|
|
|
retval = DatumGetBool(DirectFunctionCall2(box_overright,
|
|
|
|
PointerGetDatum(key),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
PointerGetDatum(query)));
|
2005-07-01 21:19:05 +02:00
|
|
|
break;
|
|
|
|
case RTRightStrategyNumber:
|
|
|
|
retval = DatumGetBool(DirectFunctionCall2(box_right,
|
|
|
|
PointerGetDatum(key),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
PointerGetDatum(query)));
|
2005-07-01 21:19:05 +02:00
|
|
|
break;
|
|
|
|
case RTSameStrategyNumber:
|
|
|
|
retval = DatumGetBool(DirectFunctionCall2(box_same,
|
|
|
|
PointerGetDatum(key),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
PointerGetDatum(query)));
|
2005-07-01 21:19:05 +02:00
|
|
|
break;
|
|
|
|
case RTContainsStrategyNumber:
|
2006-09-10 02:29:35 +02:00
|
|
|
case RTOldContainsStrategyNumber:
|
2005-07-01 21:19:05 +02:00
|
|
|
retval = DatumGetBool(DirectFunctionCall2(box_contain,
|
|
|
|
PointerGetDatum(key),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
PointerGetDatum(query)));
|
2005-07-01 21:19:05 +02:00
|
|
|
break;
|
|
|
|
case RTContainedByStrategyNumber:
|
2006-09-10 02:29:35 +02:00
|
|
|
case RTOldContainedByStrategyNumber:
|
2005-07-01 21:19:05 +02:00
|
|
|
retval = DatumGetBool(DirectFunctionCall2(box_contained,
|
|
|
|
PointerGetDatum(key),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
PointerGetDatum(query)));
|
2005-07-01 21:19:05 +02:00
|
|
|
break;
|
|
|
|
case RTOverBelowStrategyNumber:
|
|
|
|
retval = DatumGetBool(DirectFunctionCall2(box_overbelow,
|
|
|
|
PointerGetDatum(key),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
PointerGetDatum(query)));
|
2005-07-01 21:19:05 +02:00
|
|
|
break;
|
|
|
|
case RTBelowStrategyNumber:
|
|
|
|
retval = DatumGetBool(DirectFunctionCall2(box_below,
|
|
|
|
PointerGetDatum(key),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
PointerGetDatum(query)));
|
2005-07-01 21:19:05 +02:00
|
|
|
break;
|
|
|
|
case RTAboveStrategyNumber:
|
|
|
|
retval = DatumGetBool(DirectFunctionCall2(box_above,
|
|
|
|
PointerGetDatum(key),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
PointerGetDatum(query)));
|
2005-07-01 21:19:05 +02:00
|
|
|
break;
|
|
|
|
case RTOverAboveStrategyNumber:
|
|
|
|
retval = DatumGetBool(DirectFunctionCall2(box_overabove,
|
|
|
|
PointerGetDatum(key),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
PointerGetDatum(query)));
|
2005-07-01 21:19:05 +02:00
|
|
|
break;
|
|
|
|
default:
|
2014-04-14 17:10:32 +02:00
|
|
|
elog(ERROR, "unrecognized strategy number: %d", strategy);
|
|
|
|
retval = false; /* keep compiler quiet */
|
|
|
|
break;
|
2005-07-01 21:19:05 +02:00
|
|
|
}
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*****************************************
|
|
|
|
* Common rtree functions (for boxes, polygons, and circles)
|
|
|
|
*****************************************/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Internal-page consistency for all these types
|
|
|
|
*
|
|
|
|
* We can use the same function since all types use bounding boxes as the
|
|
|
|
* internal-page representation.
|
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
rtree_internal_consistent(BOX *key, BOX *query, StrategyNumber strategy)
|
|
|
|
{
|
|
|
|
bool retval;
|
|
|
|
|
|
|
|
switch (strategy)
|
|
|
|
{
|
|
|
|
case RTLeftStrategyNumber:
|
|
|
|
retval = !DatumGetBool(DirectFunctionCall2(box_overright,
|
|
|
|
PointerGetDatum(key),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
PointerGetDatum(query)));
|
2005-07-01 21:19:05 +02:00
|
|
|
break;
|
|
|
|
case RTOverLeftStrategyNumber:
|
|
|
|
retval = !DatumGetBool(DirectFunctionCall2(box_right,
|
|
|
|
PointerGetDatum(key),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
PointerGetDatum(query)));
|
2005-07-01 21:19:05 +02:00
|
|
|
break;
|
|
|
|
case RTOverlapStrategyNumber:
|
|
|
|
retval = DatumGetBool(DirectFunctionCall2(box_overlap,
|
|
|
|
PointerGetDatum(key),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
PointerGetDatum(query)));
|
2005-07-01 21:19:05 +02:00
|
|
|
break;
|
|
|
|
case RTOverRightStrategyNumber:
|
|
|
|
retval = !DatumGetBool(DirectFunctionCall2(box_left,
|
|
|
|
PointerGetDatum(key),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
PointerGetDatum(query)));
|
2005-07-01 21:19:05 +02:00
|
|
|
break;
|
|
|
|
case RTRightStrategyNumber:
|
|
|
|
retval = !DatumGetBool(DirectFunctionCall2(box_overleft,
|
|
|
|
PointerGetDatum(key),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
PointerGetDatum(query)));
|
2005-07-01 21:19:05 +02:00
|
|
|
break;
|
|
|
|
case RTSameStrategyNumber:
|
|
|
|
case RTContainsStrategyNumber:
|
2006-09-10 02:29:35 +02:00
|
|
|
case RTOldContainsStrategyNumber:
|
2005-07-01 21:19:05 +02:00
|
|
|
retval = DatumGetBool(DirectFunctionCall2(box_contain,
|
|
|
|
PointerGetDatum(key),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
PointerGetDatum(query)));
|
2005-07-01 21:19:05 +02:00
|
|
|
break;
|
|
|
|
case RTContainedByStrategyNumber:
|
2006-09-10 02:29:35 +02:00
|
|
|
case RTOldContainedByStrategyNumber:
|
2005-07-01 21:19:05 +02:00
|
|
|
retval = DatumGetBool(DirectFunctionCall2(box_overlap,
|
|
|
|
PointerGetDatum(key),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
PointerGetDatum(query)));
|
2005-07-01 21:19:05 +02:00
|
|
|
break;
|
|
|
|
case RTOverBelowStrategyNumber:
|
|
|
|
retval = !DatumGetBool(DirectFunctionCall2(box_above,
|
|
|
|
PointerGetDatum(key),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
PointerGetDatum(query)));
|
2005-07-01 21:19:05 +02:00
|
|
|
break;
|
|
|
|
case RTBelowStrategyNumber:
|
|
|
|
retval = !DatumGetBool(DirectFunctionCall2(box_overabove,
|
|
|
|
PointerGetDatum(key),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
PointerGetDatum(query)));
|
2005-07-01 21:19:05 +02:00
|
|
|
break;
|
|
|
|
case RTAboveStrategyNumber:
|
|
|
|
retval = !DatumGetBool(DirectFunctionCall2(box_overbelow,
|
|
|
|
PointerGetDatum(key),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
PointerGetDatum(query)));
|
2005-07-01 21:19:05 +02:00
|
|
|
break;
|
|
|
|
case RTOverAboveStrategyNumber:
|
|
|
|
retval = !DatumGetBool(DirectFunctionCall2(box_below,
|
|
|
|
PointerGetDatum(key),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
PointerGetDatum(query)));
|
2005-07-01 21:19:05 +02:00
|
|
|
break;
|
|
|
|
default:
|
2014-04-14 17:10:32 +02:00
|
|
|
elog(ERROR, "unrecognized strategy number: %d", strategy);
|
|
|
|
retval = false; /* keep compiler quiet */
|
|
|
|
break;
|
2005-07-01 21:19:05 +02:00
|
|
|
}
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**************************************************
|
|
|
|
* Polygon ops
|
|
|
|
**************************************************/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* GiST compress for polygons: represent a polygon by its bounding box
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
gist_poly_compress(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
|
|
|
GISTENTRY *retval;
|
|
|
|
|
|
|
|
if (entry->leafkey)
|
|
|
|
{
|
2015-01-28 08:47:39 +01:00
|
|
|
POLYGON *in = DatumGetPolygonP(entry->key);
|
|
|
|
BOX *r;
|
2005-07-01 21:19:05 +02:00
|
|
|
|
2015-01-28 08:47:39 +01:00
|
|
|
r = (BOX *) palloc(sizeof(BOX));
|
|
|
|
memcpy((void *) r, (void *) &(in->boundbox), sizeof(BOX));
|
2005-07-01 21:19:05 +02:00
|
|
|
|
2015-01-28 08:47:39 +01:00
|
|
|
retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
|
|
|
|
gistentryinit(*retval, PointerGetDatum(r),
|
|
|
|
entry->rel, entry->page,
|
2017-08-16 06:22:32 +02:00
|
|
|
entry->offset, false);
|
2005-07-01 21:19:05 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
retval = entry;
|
|
|
|
PG_RETURN_POINTER(retval);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The GiST Consistent method for polygons
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
gist_poly_consistent(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
|
|
|
POLYGON *query = PG_GETARG_POLYGON_P(1);
|
|
|
|
StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
|
2009-06-11 16:49:15 +02:00
|
|
|
|
2008-04-14 19:05:34 +02:00
|
|
|
/* Oid subtype = PG_GETARG_OID(3); */
|
|
|
|
bool *recheck = (bool *) PG_GETARG_POINTER(4);
|
2005-07-01 21:19:05 +02:00
|
|
|
bool result;
|
|
|
|
|
2008-04-14 19:05:34 +02:00
|
|
|
/* All cases served by this function are inexact */
|
|
|
|
*recheck = true;
|
|
|
|
|
2005-07-01 21:19:05 +02:00
|
|
|
if (DatumGetBoxP(entry->key) == NULL || query == NULL)
|
2017-08-16 06:22:32 +02:00
|
|
|
PG_RETURN_BOOL(false);
|
2005-07-01 21:19:05 +02:00
|
|
|
|
|
|
|
/*
|
2008-04-14 19:05:34 +02:00
|
|
|
* Since the operators require recheck anyway, we can just use
|
2005-09-22 22:44:36 +02:00
|
|
|
* rtree_internal_consistent even at leaf nodes. (This works in part
|
|
|
|
* because the index entries are bounding boxes not polygons.)
|
2005-07-01 21:19:05 +02:00
|
|
|
*/
|
|
|
|
result = rtree_internal_consistent(DatumGetBoxP(entry->key),
|
|
|
|
&(query->boundbox), strategy);
|
|
|
|
|
|
|
|
/* Avoid memory leak if supplied poly is toasted */
|
|
|
|
PG_FREE_IF_COPY(query, 1);
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**************************************************
|
|
|
|
* Circle ops
|
|
|
|
**************************************************/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* GiST compress for circles: represent a circle by its bounding box
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
gist_circle_compress(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
|
|
|
GISTENTRY *retval;
|
|
|
|
|
|
|
|
if (entry->leafkey)
|
|
|
|
{
|
2015-01-28 08:47:39 +01:00
|
|
|
CIRCLE *in = DatumGetCircleP(entry->key);
|
|
|
|
BOX *r;
|
|
|
|
|
|
|
|
r = (BOX *) palloc(sizeof(BOX));
|
|
|
|
r->high.x = in->center.x + in->radius;
|
|
|
|
r->low.x = in->center.x - in->radius;
|
|
|
|
r->high.y = in->center.y + in->radius;
|
|
|
|
r->low.y = in->center.y - in->radius;
|
|
|
|
|
|
|
|
retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
|
|
|
|
gistentryinit(*retval, PointerGetDatum(r),
|
|
|
|
entry->rel, entry->page,
|
2017-08-16 06:22:32 +02:00
|
|
|
entry->offset, false);
|
2005-07-01 21:19:05 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
retval = entry;
|
|
|
|
PG_RETURN_POINTER(retval);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The GiST Consistent method for circles
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
gist_circle_consistent(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
2005-09-22 22:44:36 +02:00
|
|
|
CIRCLE *query = PG_GETARG_CIRCLE_P(1);
|
2005-07-01 21:19:05 +02:00
|
|
|
StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
|
2009-06-11 16:49:15 +02:00
|
|
|
|
2008-04-14 19:05:34 +02:00
|
|
|
/* Oid subtype = PG_GETARG_OID(3); */
|
|
|
|
bool *recheck = (bool *) PG_GETARG_POINTER(4);
|
2005-07-01 21:19:05 +02:00
|
|
|
BOX bbox;
|
|
|
|
bool result;
|
|
|
|
|
2008-04-14 19:05:34 +02:00
|
|
|
/* All cases served by this function are inexact */
|
|
|
|
*recheck = true;
|
|
|
|
|
2005-07-01 21:19:05 +02:00
|
|
|
if (DatumGetBoxP(entry->key) == NULL || query == NULL)
|
2017-08-16 06:22:32 +02:00
|
|
|
PG_RETURN_BOOL(false);
|
2005-07-01 21:19:05 +02:00
|
|
|
|
|
|
|
/*
|
2008-04-14 19:05:34 +02:00
|
|
|
* Since the operators require recheck anyway, we can just use
|
2005-09-22 22:44:36 +02:00
|
|
|
* rtree_internal_consistent even at leaf nodes. (This works in part
|
|
|
|
* because the index entries are bounding boxes not circles.)
|
2005-07-01 21:19:05 +02:00
|
|
|
*/
|
|
|
|
bbox.high.x = query->center.x + query->radius;
|
|
|
|
bbox.low.x = query->center.x - query->radius;
|
|
|
|
bbox.high.y = query->center.y + query->radius;
|
|
|
|
bbox.low.y = query->center.y - query->radius;
|
|
|
|
|
|
|
|
result = rtree_internal_consistent(DatumGetBoxP(entry->key),
|
|
|
|
&bbox, strategy);
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(result);
|
|
|
|
}
|
2010-01-14 17:31:09 +01:00
|
|
|
|
|
|
|
/**************************************************
|
|
|
|
* Point ops
|
|
|
|
**************************************************/
|
|
|
|
|
|
|
|
Datum
|
|
|
|
gist_point_compress(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
|
|
|
|
|
|
|
if (entry->leafkey) /* Point, actually */
|
|
|
|
{
|
2010-02-26 03:01:40 +01:00
|
|
|
BOX *box = palloc(sizeof(BOX));
|
|
|
|
Point *point = DatumGetPointP(entry->key);
|
2010-01-14 17:31:09 +01:00
|
|
|
GISTENTRY *retval = palloc(sizeof(GISTENTRY));
|
|
|
|
|
|
|
|
box->high = box->low = *point;
|
|
|
|
|
|
|
|
gistentryinit(*retval, BoxPGetDatum(box),
|
2017-08-16 06:22:32 +02:00
|
|
|
entry->rel, entry->page, entry->offset, false);
|
2010-01-14 17:31:09 +01:00
|
|
|
|
|
|
|
PG_RETURN_POINTER(retval);
|
|
|
|
}
|
|
|
|
|
|
|
|
PG_RETURN_POINTER(entry);
|
|
|
|
}
|
|
|
|
|
2015-03-26 18:12:00 +01:00
|
|
|
/*
|
|
|
|
* GiST Fetch method for point
|
|
|
|
*
|
|
|
|
* Get point coordinates from its bounding box coordinates and form new
|
|
|
|
* gistentry.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
gist_point_fetch(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
|
|
|
BOX *in = DatumGetBoxP(entry->key);
|
|
|
|
Point *r;
|
|
|
|
GISTENTRY *retval;
|
|
|
|
|
|
|
|
retval = palloc(sizeof(GISTENTRY));
|
|
|
|
|
|
|
|
r = (Point *) palloc(sizeof(Point));
|
|
|
|
r->x = in->high.x;
|
|
|
|
r->y = in->high.y;
|
|
|
|
gistentryinit(*retval, PointerGetDatum(r),
|
|
|
|
entry->rel, entry->page,
|
2017-08-16 06:22:32 +02:00
|
|
|
entry->offset, false);
|
2015-03-26 18:12:00 +01:00
|
|
|
|
|
|
|
PG_RETURN_POINTER(retval);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-04-10 17:42:00 +02:00
|
|
|
#define point_point_distance(p1,p2) \
|
2010-12-04 02:52:18 +01:00
|
|
|
DatumGetFloat8(DirectFunctionCall2(point_distance, \
|
|
|
|
PointPGetDatum(p1), PointPGetDatum(p2)))
|
|
|
|
|
|
|
|
static double
|
|
|
|
computeDistance(bool isLeaf, BOX *box, Point *point)
|
|
|
|
{
|
|
|
|
double result = 0.0;
|
|
|
|
|
|
|
|
if (isLeaf)
|
|
|
|
{
|
|
|
|
/* simple point to point distance */
|
|
|
|
result = point_point_distance(point, &box->low);
|
|
|
|
}
|
|
|
|
else if (point->x <= box->high.x && point->x >= box->low.x &&
|
|
|
|
point->y <= box->high.y && point->y >= box->low.y)
|
|
|
|
{
|
|
|
|
/* point inside the box */
|
|
|
|
result = 0.0;
|
|
|
|
}
|
|
|
|
else if (point->x <= box->high.x && point->x >= box->low.x)
|
|
|
|
{
|
|
|
|
/* point is over or below box */
|
|
|
|
Assert(box->low.y <= box->high.y);
|
|
|
|
if (point->y > box->high.y)
|
|
|
|
result = point->y - box->high.y;
|
|
|
|
else if (point->y < box->low.y)
|
|
|
|
result = box->low.y - point->y;
|
|
|
|
else
|
|
|
|
elog(ERROR, "inconsistent point values");
|
|
|
|
}
|
|
|
|
else if (point->y <= box->high.y && point->y >= box->low.y)
|
|
|
|
{
|
|
|
|
/* point is to left or right of box */
|
|
|
|
Assert(box->low.x <= box->high.x);
|
|
|
|
if (point->x > box->high.x)
|
|
|
|
result = point->x - box->high.x;
|
|
|
|
else if (point->x < box->low.x)
|
|
|
|
result = box->low.x - point->x;
|
|
|
|
else
|
|
|
|
elog(ERROR, "inconsistent point values");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* closest point will be a vertex */
|
2011-04-10 17:42:00 +02:00
|
|
|
Point p;
|
|
|
|
double subresult;
|
2010-12-04 02:52:18 +01:00
|
|
|
|
|
|
|
result = point_point_distance(point, &box->low);
|
|
|
|
|
|
|
|
subresult = point_point_distance(point, &box->high);
|
|
|
|
if (result > subresult)
|
|
|
|
result = subresult;
|
|
|
|
|
|
|
|
p.x = box->low.x;
|
|
|
|
p.y = box->high.y;
|
|
|
|
subresult = point_point_distance(point, &p);
|
|
|
|
if (result > subresult)
|
|
|
|
result = subresult;
|
|
|
|
|
|
|
|
p.x = box->high.x;
|
|
|
|
p.y = box->low.y;
|
|
|
|
subresult = point_point_distance(point, &p);
|
|
|
|
if (result > subresult)
|
|
|
|
result = subresult;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2010-01-14 17:31:09 +01:00
|
|
|
static bool
|
|
|
|
gist_point_consistent_internal(StrategyNumber strategy,
|
2010-02-26 03:01:40 +01:00
|
|
|
bool isLeaf, BOX *key, Point *query)
|
2010-01-14 17:31:09 +01:00
|
|
|
{
|
2010-02-26 03:01:40 +01:00
|
|
|
bool result = false;
|
2010-01-14 17:31:09 +01:00
|
|
|
|
|
|
|
switch (strategy)
|
|
|
|
{
|
|
|
|
case RTLeftStrategyNumber:
|
|
|
|
result = FPlt(key->low.x, query->x);
|
|
|
|
break;
|
|
|
|
case RTRightStrategyNumber:
|
|
|
|
result = FPgt(key->high.x, query->x);
|
|
|
|
break;
|
|
|
|
case RTAboveStrategyNumber:
|
|
|
|
result = FPgt(key->high.y, query->y);
|
|
|
|
break;
|
|
|
|
case RTBelowStrategyNumber:
|
|
|
|
result = FPlt(key->low.y, query->y);
|
|
|
|
break;
|
|
|
|
case RTSameStrategyNumber:
|
|
|
|
if (isLeaf)
|
|
|
|
{
|
Fix gist_box_same and gist_point_consistent to handle fuzziness correctly.
While there's considerable doubt that we want fuzzy behavior in the
geometric operators at all (let alone as currently implemented), nobody is
stepping forward to redesign that stuff. In the meantime it behooves us
to make sure that index searches agree with the behavior of the underlying
operators. This patch fixes two problems in this area.
First, gist_box_same was using fuzzy equality, but it really needs to use
exact equality to prevent not-quite-identical upper index keys from being
treated as identical, which for example would prevent an existing upper
key from being extended by an amount less than epsilon. This would result
in inconsistent indexes. (The next release notes will need to recommend
that users reindex GiST indexes on boxes, polygons, circles, and points,
since all four opclasses use gist_box_same.)
Second, gist_point_consistent used exact comparisons for upper-page
comparisons in ~= searches, when it needs to use fuzzy comparisons to
ensure it finds all matches; and it used fuzzy comparisons for point <@ box
searches, when it needs to use exact comparisons because that's what the
<@ operator (rather inconsistently) does.
The added regression test cases illustrate all three misbehaviors.
Back-patch to all active branches. (8.4 did not have GiST point_ops,
but it still seems prudent to apply the gist_box_same patch to it.)
Alexander Korotkov, reviewed by Noah Misch
2013-02-09 00:03:17 +01:00
|
|
|
/* key.high must equal key.low, so we can disregard it */
|
|
|
|
result = (FPeq(key->low.x, query->x) &&
|
|
|
|
FPeq(key->low.y, query->y));
|
2010-01-14 17:31:09 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
Fix gist_box_same and gist_point_consistent to handle fuzziness correctly.
While there's considerable doubt that we want fuzzy behavior in the
geometric operators at all (let alone as currently implemented), nobody is
stepping forward to redesign that stuff. In the meantime it behooves us
to make sure that index searches agree with the behavior of the underlying
operators. This patch fixes two problems in this area.
First, gist_box_same was using fuzzy equality, but it really needs to use
exact equality to prevent not-quite-identical upper index keys from being
treated as identical, which for example would prevent an existing upper
key from being extended by an amount less than epsilon. This would result
in inconsistent indexes. (The next release notes will need to recommend
that users reindex GiST indexes on boxes, polygons, circles, and points,
since all four opclasses use gist_box_same.)
Second, gist_point_consistent used exact comparisons for upper-page
comparisons in ~= searches, when it needs to use fuzzy comparisons to
ensure it finds all matches; and it used fuzzy comparisons for point <@ box
searches, when it needs to use exact comparisons because that's what the
<@ operator (rather inconsistently) does.
The added regression test cases illustrate all three misbehaviors.
Back-patch to all active branches. (8.4 did not have GiST point_ops,
but it still seems prudent to apply the gist_box_same patch to it.)
Alexander Korotkov, reviewed by Noah Misch
2013-02-09 00:03:17 +01:00
|
|
|
result = (FPle(query->x, key->high.x) &&
|
|
|
|
FPge(query->x, key->low.x) &&
|
|
|
|
FPle(query->y, key->high.y) &&
|
|
|
|
FPge(query->y, key->low.y));
|
2010-01-14 17:31:09 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
2014-04-14 17:10:32 +02:00
|
|
|
elog(ERROR, "unrecognized strategy number: %d", strategy);
|
|
|
|
result = false; /* keep compiler quiet */
|
|
|
|
break;
|
2010-01-14 17:31:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define GeoStrategyNumberOffset 20
|
|
|
|
#define PointStrategyNumberGroup 0
|
|
|
|
#define BoxStrategyNumberGroup 1
|
|
|
|
#define PolygonStrategyNumberGroup 2
|
|
|
|
#define CircleStrategyNumberGroup 3
|
|
|
|
|
|
|
|
Datum
|
|
|
|
gist_point_consistent(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
2010-02-26 03:01:40 +01:00
|
|
|
StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
|
2010-01-14 17:31:09 +01:00
|
|
|
bool *recheck = (bool *) PG_GETARG_POINTER(4);
|
2010-12-04 02:52:18 +01:00
|
|
|
bool result;
|
2010-02-26 03:01:40 +01:00
|
|
|
StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset;
|
2010-01-14 17:31:09 +01:00
|
|
|
|
|
|
|
switch (strategyGroup)
|
|
|
|
{
|
|
|
|
case PointStrategyNumberGroup:
|
|
|
|
result = gist_point_consistent_internal(strategy % GeoStrategyNumberOffset,
|
|
|
|
GIST_LEAF(entry),
|
|
|
|
DatumGetBoxP(entry->key),
|
|
|
|
PG_GETARG_POINT_P(1));
|
|
|
|
*recheck = false;
|
|
|
|
break;
|
|
|
|
case BoxStrategyNumberGroup:
|
Fix gist_box_same and gist_point_consistent to handle fuzziness correctly.
While there's considerable doubt that we want fuzzy behavior in the
geometric operators at all (let alone as currently implemented), nobody is
stepping forward to redesign that stuff. In the meantime it behooves us
to make sure that index searches agree with the behavior of the underlying
operators. This patch fixes two problems in this area.
First, gist_box_same was using fuzzy equality, but it really needs to use
exact equality to prevent not-quite-identical upper index keys from being
treated as identical, which for example would prevent an existing upper
key from being extended by an amount less than epsilon. This would result
in inconsistent indexes. (The next release notes will need to recommend
that users reindex GiST indexes on boxes, polygons, circles, and points,
since all four opclasses use gist_box_same.)
Second, gist_point_consistent used exact comparisons for upper-page
comparisons in ~= searches, when it needs to use fuzzy comparisons to
ensure it finds all matches; and it used fuzzy comparisons for point <@ box
searches, when it needs to use exact comparisons because that's what the
<@ operator (rather inconsistently) does.
The added regression test cases illustrate all three misbehaviors.
Back-patch to all active branches. (8.4 did not have GiST point_ops,
but it still seems prudent to apply the gist_box_same patch to it.)
Alexander Korotkov, reviewed by Noah Misch
2013-02-09 00:03:17 +01:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* The only operator in this group is point <@ box (on_pb), so
|
|
|
|
* we needn't examine strategy again.
|
|
|
|
*
|
|
|
|
* For historical reasons, on_pb uses exact rather than fuzzy
|
|
|
|
* comparisons. We could use box_overlap when at an internal
|
|
|
|
* page, but that would lead to possibly visiting child pages
|
|
|
|
* uselessly, because box_overlap uses fuzzy comparisons.
|
|
|
|
* Instead we write a non-fuzzy overlap test. The same code
|
|
|
|
* will also serve for leaf-page tests, since leaf keys have
|
|
|
|
* high == low.
|
|
|
|
*/
|
|
|
|
BOX *query,
|
|
|
|
*key;
|
|
|
|
|
|
|
|
query = PG_GETARG_BOX_P(1);
|
|
|
|
key = DatumGetBoxP(entry->key);
|
|
|
|
|
|
|
|
result = (key->high.x >= query->low.x &&
|
|
|
|
key->low.x <= query->high.x &&
|
|
|
|
key->high.y >= query->low.y &&
|
|
|
|
key->low.y <= query->high.y);
|
|
|
|
*recheck = false;
|
|
|
|
}
|
2010-01-14 17:31:09 +01:00
|
|
|
break;
|
|
|
|
case PolygonStrategyNumberGroup:
|
|
|
|
{
|
|
|
|
POLYGON *query = PG_GETARG_POLYGON_P(1);
|
|
|
|
|
|
|
|
result = DatumGetBool(DirectFunctionCall5(
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
gist_poly_consistent,
|
|
|
|
PointerGetDatum(entry),
|
|
|
|
PolygonPGetDatum(query),
|
|
|
|
Int16GetDatum(RTOverlapStrategyNumber),
|
|
|
|
0, PointerGetDatum(recheck)));
|
2010-01-14 17:31:09 +01:00
|
|
|
|
|
|
|
if (GIST_LEAF(entry) && result)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* We are on leaf page and quick check shows overlapping
|
|
|
|
* of polygon's bounding box and point
|
|
|
|
*/
|
2010-02-26 03:01:40 +01:00
|
|
|
BOX *box = DatumGetBoxP(entry->key);
|
2010-01-14 17:31:09 +01:00
|
|
|
|
|
|
|
Assert(box->high.x == box->low.x
|
2010-02-26 03:01:40 +01:00
|
|
|
&& box->high.y == box->low.y);
|
2010-01-14 17:31:09 +01:00
|
|
|
result = DatumGetBool(DirectFunctionCall2(
|
2010-02-26 03:01:40 +01:00
|
|
|
poly_contain_pt,
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
PolygonPGetDatum(query),
|
|
|
|
PointPGetDatum(&box->high)));
|
2010-01-14 17:31:09 +01:00
|
|
|
*recheck = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case CircleStrategyNumberGroup:
|
|
|
|
{
|
2010-02-26 03:01:40 +01:00
|
|
|
CIRCLE *query = PG_GETARG_CIRCLE_P(1);
|
2010-01-14 17:31:09 +01:00
|
|
|
|
|
|
|
result = DatumGetBool(DirectFunctionCall5(
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
gist_circle_consistent,
|
|
|
|
PointerGetDatum(entry),
|
|
|
|
CirclePGetDatum(query),
|
|
|
|
Int16GetDatum(RTOverlapStrategyNumber),
|
|
|
|
0, PointerGetDatum(recheck)));
|
2010-01-14 17:31:09 +01:00
|
|
|
|
|
|
|
if (GIST_LEAF(entry) && result)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* We are on leaf page and quick check shows overlapping
|
|
|
|
* of polygon's bounding box and point
|
|
|
|
*/
|
2010-02-26 03:01:40 +01:00
|
|
|
BOX *box = DatumGetBoxP(entry->key);
|
2010-01-14 17:31:09 +01:00
|
|
|
|
|
|
|
Assert(box->high.x == box->low.x
|
2010-02-26 03:01:40 +01:00
|
|
|
&& box->high.y == box->low.y);
|
2010-01-14 17:31:09 +01:00
|
|
|
result = DatumGetBool(DirectFunctionCall2(
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
circle_contain_pt,
|
|
|
|
CirclePGetDatum(query),
|
|
|
|
PointPGetDatum(&box->high)));
|
2010-01-14 17:31:09 +01:00
|
|
|
*recheck = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
2014-04-14 17:10:32 +02:00
|
|
|
elog(ERROR, "unrecognized strategy number: %d", strategy);
|
2010-12-04 02:52:18 +01:00
|
|
|
result = false; /* keep compiler quiet */
|
2014-04-14 17:10:32 +02:00
|
|
|
break;
|
2010-01-14 17:31:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(result);
|
|
|
|
}
|
2010-12-04 02:52:18 +01:00
|
|
|
|
|
|
|
Datum
|
|
|
|
gist_point_distance(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
|
|
|
StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
|
|
|
|
double distance;
|
|
|
|
StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset;
|
|
|
|
|
|
|
|
switch (strategyGroup)
|
|
|
|
{
|
|
|
|
case PointStrategyNumberGroup:
|
|
|
|
distance = computeDistance(GIST_LEAF(entry),
|
|
|
|
DatumGetBoxP(entry->key),
|
|
|
|
PG_GETARG_POINT_P(1));
|
|
|
|
break;
|
|
|
|
default:
|
2014-04-14 17:10:32 +02:00
|
|
|
elog(ERROR, "unrecognized strategy number: %d", strategy);
|
2010-12-04 02:52:18 +01:00
|
|
|
distance = 0.0; /* keep compiler quiet */
|
2014-04-14 17:10:32 +02:00
|
|
|
break;
|
2010-12-04 02:52:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
PG_RETURN_FLOAT8(distance);
|
|
|
|
}
|
2015-05-15 13:26:51 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* The inexact GiST distance method for geometric types that store bounding
|
|
|
|
* boxes.
|
|
|
|
*
|
|
|
|
* Compute lossy distance from point to index entries. The result is inexact
|
|
|
|
* because index entries are bounding boxes, not the exact shapes of the
|
|
|
|
* indexed geometric types. We use distance from point to MBR of index entry.
|
|
|
|
* This is a lower bound estimate of distance from point to indexed geometric
|
|
|
|
* type.
|
|
|
|
*/
|
Fix assorted inconsistencies in GiST opclass support function declarations.
The conventions specified by the GiST SGML documentation were widely
ignored. For example, the strategy-number argument for "consistent" and
"distance" functions is specified to be a smallint, but most of the
built-in support functions declared it as an integer, and for that matter
the core code passed it using Int32GetDatum not Int16GetDatum. None of
that makes any real difference at runtime, but it's quite confusing for
newcomers to the code, and it makes it very hard to write an amvalidate()
function that checks support function signatures. So let's try to instill
some consistency here.
Another similar issue is that the "query" argument is not of a single
well-defined type, but could have different types depending on the strategy
(corresponding to search operators with different righthand-side argument
types). Some of the functions threw up their hands and declared the query
argument as being of "internal" type, which surely isn't right ("any" would
have been more appropriate); but the majority position seemed to be to
declare it as being of the indexed data type, corresponding to a search
operator with both input types the same. So I've specified a convention
that that's what to do always.
Also, the result of the "union" support function actually must be of the
index's storage type, but the documentation suggested declaring it to
return "internal", and some of the functions followed that. Standardize
on telling the truth, instead.
Similarly, standardize on declaring the "same" function's inputs as
being of the storage type, not "internal".
Also, somebody had forgotten to add the "recheck" argument to both
the documentation of the "distance" support function and all of their
SQL declarations, even though the C code was happily using that argument.
Clean that up too.
Fix up some other omissions in the docs too, such as documenting that
union's second input argument is vestigial.
So far as the errors in core function declarations go, we can just fix
pg_proc.h and bump catversion. Adjusting the erroneous declarations in
contrib modules is more debatable: in principle any change in those
scripts should involve an extension version bump, which is a pain.
However, since these changes are purely cosmetic and make no functional
difference, I think we can get away without doing that.
2016-01-19 18:04:32 +01:00
|
|
|
static double
|
|
|
|
gist_bbox_distance(GISTENTRY *entry, Datum query,
|
|
|
|
StrategyNumber strategy, bool *recheck)
|
2015-05-15 13:26:51 +02:00
|
|
|
{
|
|
|
|
double distance;
|
|
|
|
StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset;
|
|
|
|
|
|
|
|
/* Bounding box distance is always inexact. */
|
|
|
|
*recheck = true;
|
|
|
|
|
|
|
|
switch (strategyGroup)
|
|
|
|
{
|
|
|
|
case PointStrategyNumberGroup:
|
|
|
|
distance = computeDistance(false,
|
|
|
|
DatumGetBoxP(entry->key),
|
Fix assorted inconsistencies in GiST opclass support function declarations.
The conventions specified by the GiST SGML documentation were widely
ignored. For example, the strategy-number argument for "consistent" and
"distance" functions is specified to be a smallint, but most of the
built-in support functions declared it as an integer, and for that matter
the core code passed it using Int32GetDatum not Int16GetDatum. None of
that makes any real difference at runtime, but it's quite confusing for
newcomers to the code, and it makes it very hard to write an amvalidate()
function that checks support function signatures. So let's try to instill
some consistency here.
Another similar issue is that the "query" argument is not of a single
well-defined type, but could have different types depending on the strategy
(corresponding to search operators with different righthand-side argument
types). Some of the functions threw up their hands and declared the query
argument as being of "internal" type, which surely isn't right ("any" would
have been more appropriate); but the majority position seemed to be to
declare it as being of the indexed data type, corresponding to a search
operator with both input types the same. So I've specified a convention
that that's what to do always.
Also, the result of the "union" support function actually must be of the
index's storage type, but the documentation suggested declaring it to
return "internal", and some of the functions followed that. Standardize
on telling the truth, instead.
Similarly, standardize on declaring the "same" function's inputs as
being of the storage type, not "internal".
Also, somebody had forgotten to add the "recheck" argument to both
the documentation of the "distance" support function and all of their
SQL declarations, even though the C code was happily using that argument.
Clean that up too.
Fix up some other omissions in the docs too, such as documenting that
union's second input argument is vestigial.
So far as the errors in core function declarations go, we can just fix
pg_proc.h and bump catversion. Adjusting the erroneous declarations in
contrib modules is more debatable: in principle any change in those
scripts should involve an extension version bump, which is a pain.
However, since these changes are purely cosmetic and make no functional
difference, I think we can get away without doing that.
2016-01-19 18:04:32 +01:00
|
|
|
DatumGetPointP(query));
|
2015-05-15 13:26:51 +02:00
|
|
|
break;
|
|
|
|
default:
|
Fix assorted inconsistencies in GiST opclass support function declarations.
The conventions specified by the GiST SGML documentation were widely
ignored. For example, the strategy-number argument for "consistent" and
"distance" functions is specified to be a smallint, but most of the
built-in support functions declared it as an integer, and for that matter
the core code passed it using Int32GetDatum not Int16GetDatum. None of
that makes any real difference at runtime, but it's quite confusing for
newcomers to the code, and it makes it very hard to write an amvalidate()
function that checks support function signatures. So let's try to instill
some consistency here.
Another similar issue is that the "query" argument is not of a single
well-defined type, but could have different types depending on the strategy
(corresponding to search operators with different righthand-side argument
types). Some of the functions threw up their hands and declared the query
argument as being of "internal" type, which surely isn't right ("any" would
have been more appropriate); but the majority position seemed to be to
declare it as being of the indexed data type, corresponding to a search
operator with both input types the same. So I've specified a convention
that that's what to do always.
Also, the result of the "union" support function actually must be of the
index's storage type, but the documentation suggested declaring it to
return "internal", and some of the functions followed that. Standardize
on telling the truth, instead.
Similarly, standardize on declaring the "same" function's inputs as
being of the storage type, not "internal".
Also, somebody had forgotten to add the "recheck" argument to both
the documentation of the "distance" support function and all of their
SQL declarations, even though the C code was happily using that argument.
Clean that up too.
Fix up some other omissions in the docs too, such as documenting that
union's second input argument is vestigial.
So far as the errors in core function declarations go, we can just fix
pg_proc.h and bump catversion. Adjusting the erroneous declarations in
contrib modules is more debatable: in principle any change in those
scripts should involve an extension version bump, which is a pain.
However, since these changes are purely cosmetic and make no functional
difference, I think we can get away without doing that.
2016-01-19 18:04:32 +01:00
|
|
|
elog(ERROR, "unrecognized strategy number: %d", strategy);
|
2015-05-15 13:26:51 +02:00
|
|
|
distance = 0.0; /* keep compiler quiet */
|
|
|
|
}
|
|
|
|
|
Fix assorted inconsistencies in GiST opclass support function declarations.
The conventions specified by the GiST SGML documentation were widely
ignored. For example, the strategy-number argument for "consistent" and
"distance" functions is specified to be a smallint, but most of the
built-in support functions declared it as an integer, and for that matter
the core code passed it using Int32GetDatum not Int16GetDatum. None of
that makes any real difference at runtime, but it's quite confusing for
newcomers to the code, and it makes it very hard to write an amvalidate()
function that checks support function signatures. So let's try to instill
some consistency here.
Another similar issue is that the "query" argument is not of a single
well-defined type, but could have different types depending on the strategy
(corresponding to search operators with different righthand-side argument
types). Some of the functions threw up their hands and declared the query
argument as being of "internal" type, which surely isn't right ("any" would
have been more appropriate); but the majority position seemed to be to
declare it as being of the indexed data type, corresponding to a search
operator with both input types the same. So I've specified a convention
that that's what to do always.
Also, the result of the "union" support function actually must be of the
index's storage type, but the documentation suggested declaring it to
return "internal", and some of the functions followed that. Standardize
on telling the truth, instead.
Similarly, standardize on declaring the "same" function's inputs as
being of the storage type, not "internal".
Also, somebody had forgotten to add the "recheck" argument to both
the documentation of the "distance" support function and all of their
SQL declarations, even though the C code was happily using that argument.
Clean that up too.
Fix up some other omissions in the docs too, such as documenting that
union's second input argument is vestigial.
So far as the errors in core function declarations go, we can just fix
pg_proc.h and bump catversion. Adjusting the erroneous declarations in
contrib modules is more debatable: in principle any change in those
scripts should involve an extension version bump, which is a pain.
However, since these changes are purely cosmetic and make no functional
difference, I think we can get away without doing that.
2016-01-19 18:04:32 +01:00
|
|
|
return distance;
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
gist_circle_distance(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
|
|
|
Datum query = PG_GETARG_DATUM(1);
|
|
|
|
StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
|
|
|
|
|
|
|
|
/* Oid subtype = PG_GETARG_OID(3); */
|
|
|
|
bool *recheck = (bool *) PG_GETARG_POINTER(4);
|
|
|
|
double distance;
|
|
|
|
|
|
|
|
distance = gist_bbox_distance(entry, query, strategy, recheck);
|
|
|
|
|
|
|
|
PG_RETURN_FLOAT8(distance);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
gist_poly_distance(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
|
|
|
Datum query = PG_GETARG_DATUM(1);
|
|
|
|
StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
|
|
|
|
|
|
|
|
/* Oid subtype = PG_GETARG_OID(3); */
|
|
|
|
bool *recheck = (bool *) PG_GETARG_POINTER(4);
|
|
|
|
double distance;
|
|
|
|
|
|
|
|
distance = gist_bbox_distance(entry, query, strategy, recheck);
|
|
|
|
|
2015-05-15 13:26:51 +02:00
|
|
|
PG_RETURN_FLOAT8(distance);
|
|
|
|
}
|