diff --git a/contrib/btree_gist/btree_cash.c b/contrib/btree_gist/btree_cash.c
index bfda21b058c..7938a70f17a 100644
--- a/contrib/btree_gist/btree_cash.c
+++ b/contrib/btree_gist/btree_cash.c
@@ -18,6 +18,7 @@ PG_FUNCTION_INFO_V1(gbt_cash_compress);
PG_FUNCTION_INFO_V1(gbt_cash_union);
PG_FUNCTION_INFO_V1(gbt_cash_picksplit);
PG_FUNCTION_INFO_V1(gbt_cash_consistent);
+PG_FUNCTION_INFO_V1(gbt_cash_distance);
PG_FUNCTION_INFO_V1(gbt_cash_penalty);
PG_FUNCTION_INFO_V1(gbt_cash_same);
@@ -25,6 +26,7 @@ Datum gbt_cash_compress(PG_FUNCTION_ARGS);
Datum gbt_cash_union(PG_FUNCTION_ARGS);
Datum gbt_cash_picksplit(PG_FUNCTION_ARGS);
Datum gbt_cash_consistent(PG_FUNCTION_ARGS);
+Datum gbt_cash_distance(PG_FUNCTION_ARGS);
Datum gbt_cash_penalty(PG_FUNCTION_ARGS);
Datum gbt_cash_same(PG_FUNCTION_ARGS);
@@ -71,6 +73,12 @@ gbt_cashkey_cmp(const void *a, const void *b)
return (ia->lower > ib->lower) ? 1 : -1;
}
+static float8
+gbt_cash_dist(const void *a, const void *b)
+{
+ return GET_FLOAT_DISTANCE(Cash, a, b);
+}
+
static const gbtree_ninfo tinfo =
{
@@ -81,10 +89,33 @@ static const gbtree_ninfo tinfo =
gbt_casheq,
gbt_cashle,
gbt_cashlt,
- gbt_cashkey_cmp
+ gbt_cashkey_cmp,
+ gbt_cash_dist
};
+PG_FUNCTION_INFO_V1(cash_dist);
+Datum cash_dist(PG_FUNCTION_ARGS);
+Datum
+cash_dist(PG_FUNCTION_ARGS)
+{
+ Cash a = PG_GETARG_CASH(0);
+ Cash b = PG_GETARG_CASH(1);
+ Cash r;
+ Cash ra;
+
+ r = a - b;
+ ra = Abs(r);
+
+ /* Overflow check. */
+ if (ra < 0 || (!SAMESIGN(a, b) && !SAMESIGN(r, a)))
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("money out of range")));
+
+ PG_RETURN_CASH(ra);
+}
+
/**************************************************
* Cash ops
**************************************************/
@@ -124,6 +155,25 @@ gbt_cash_consistent(PG_FUNCTION_ARGS)
}
+Datum
+gbt_cash_distance(PG_FUNCTION_ARGS)
+{
+ GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+ Cash query = PG_GETARG_CASH(1);
+
+ /* Oid subtype = PG_GETARG_OID(3); */
+ cashKEY *kkk = (cashKEY *) DatumGetPointer(entry->key);
+ GBT_NUMKEY_R key;
+
+ key.lower = (GBT_NUMKEY *) &kkk->lower;
+ key.upper = (GBT_NUMKEY *) &kkk->upper;
+
+ PG_RETURN_FLOAT8(
+ gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo)
+ );
+}
+
+
Datum
gbt_cash_union(PG_FUNCTION_ARGS)
{
diff --git a/contrib/btree_gist/btree_date.c b/contrib/btree_gist/btree_date.c
index 11904af2573..ccd7e2ad3f3 100644
--- a/contrib/btree_gist/btree_date.c
+++ b/contrib/btree_gist/btree_date.c
@@ -18,6 +18,7 @@ PG_FUNCTION_INFO_V1(gbt_date_compress);
PG_FUNCTION_INFO_V1(gbt_date_union);
PG_FUNCTION_INFO_V1(gbt_date_picksplit);
PG_FUNCTION_INFO_V1(gbt_date_consistent);
+PG_FUNCTION_INFO_V1(gbt_date_distance);
PG_FUNCTION_INFO_V1(gbt_date_penalty);
PG_FUNCTION_INFO_V1(gbt_date_same);
@@ -25,6 +26,7 @@ Datum gbt_date_compress(PG_FUNCTION_ARGS);
Datum gbt_date_union(PG_FUNCTION_ARGS);
Datum gbt_date_picksplit(PG_FUNCTION_ARGS);
Datum gbt_date_consistent(PG_FUNCTION_ARGS);
+Datum gbt_date_distance(PG_FUNCTION_ARGS);
Datum gbt_date_penalty(PG_FUNCTION_ARGS);
Datum gbt_date_same(PG_FUNCTION_ARGS);
@@ -84,6 +86,17 @@ gbt_datekey_cmp(const void *a, const void *b)
return res;
}
+static float8
+gdb_date_dist(const void *a, const void *b)
+{
+ /* we assume the difference can't overflow */
+ Datum diff = DirectFunctionCall2(date_mi,
+ DateADTGetDatum(*((const DateADT *) a)),
+ DateADTGetDatum(*((const DateADT *) b)));
+
+ return (float8) Abs(DatumGetInt32(diff));
+}
+
static const gbtree_ninfo tinfo =
{
@@ -94,10 +107,25 @@ static const gbtree_ninfo tinfo =
gbt_dateeq,
gbt_datele,
gbt_datelt,
- gbt_datekey_cmp
+ gbt_datekey_cmp,
+ gdb_date_dist
};
+PG_FUNCTION_INFO_V1(date_dist);
+Datum date_dist(PG_FUNCTION_ARGS);
+Datum
+date_dist(PG_FUNCTION_ARGS)
+{
+ /* we assume the difference can't overflow */
+ Datum diff = DirectFunctionCall2(date_mi,
+ PG_GETARG_DATUM(0),
+ PG_GETARG_DATUM(1));
+
+ PG_RETURN_INT32(Abs(DatumGetInt32(diff)));
+}
+
+
/**************************************************
* date ops
**************************************************/
@@ -139,6 +167,25 @@ gbt_date_consistent(PG_FUNCTION_ARGS)
}
+Datum
+gbt_date_distance(PG_FUNCTION_ARGS)
+{
+ GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+ DateADT query = PG_GETARG_DATEADT(1);
+
+ /* Oid subtype = PG_GETARG_OID(3); */
+ dateKEY *kkk = (dateKEY *) DatumGetPointer(entry->key);
+ GBT_NUMKEY_R key;
+
+ key.lower = (GBT_NUMKEY *) &kkk->lower;
+ key.upper = (GBT_NUMKEY *) &kkk->upper;
+
+ PG_RETURN_FLOAT8(
+ gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo)
+ );
+}
+
+
Datum
gbt_date_union(PG_FUNCTION_ARGS)
{
diff --git a/contrib/btree_gist/btree_float4.c b/contrib/btree_gist/btree_float4.c
index 4cfeddfc687..932a941f889 100644
--- a/contrib/btree_gist/btree_float4.c
+++ b/contrib/btree_gist/btree_float4.c
@@ -17,6 +17,7 @@ PG_FUNCTION_INFO_V1(gbt_float4_compress);
PG_FUNCTION_INFO_V1(gbt_float4_union);
PG_FUNCTION_INFO_V1(gbt_float4_picksplit);
PG_FUNCTION_INFO_V1(gbt_float4_consistent);
+PG_FUNCTION_INFO_V1(gbt_float4_distance);
PG_FUNCTION_INFO_V1(gbt_float4_penalty);
PG_FUNCTION_INFO_V1(gbt_float4_same);
@@ -24,6 +25,7 @@ Datum gbt_float4_compress(PG_FUNCTION_ARGS);
Datum gbt_float4_union(PG_FUNCTION_ARGS);
Datum gbt_float4_picksplit(PG_FUNCTION_ARGS);
Datum gbt_float4_consistent(PG_FUNCTION_ARGS);
+Datum gbt_float4_distance(PG_FUNCTION_ARGS);
Datum gbt_float4_penalty(PG_FUNCTION_ARGS);
Datum gbt_float4_same(PG_FUNCTION_ARGS);
@@ -70,6 +72,12 @@ gbt_float4key_cmp(const void *a, const void *b)
return (ia->lower > ib->lower) ? 1 : -1;
}
+static float8
+gbt_float4_dist(const void *a, const void *b)
+{
+ return GET_FLOAT_DISTANCE(float4, a, b);
+}
+
static const gbtree_ninfo tinfo =
{
@@ -80,10 +88,27 @@ static const gbtree_ninfo tinfo =
gbt_float4eq,
gbt_float4le,
gbt_float4lt,
- gbt_float4key_cmp
+ gbt_float4key_cmp,
+ gbt_float4_dist
};
+PG_FUNCTION_INFO_V1(float4_dist);
+Datum float4_dist(PG_FUNCTION_ARGS);
+Datum
+float4_dist(PG_FUNCTION_ARGS)
+{
+ float4 a = PG_GETARG_FLOAT4(0);
+ float4 b = PG_GETARG_FLOAT4(1);
+ float4 r;
+
+ r = a - b;
+ CHECKFLOATVAL(r, isinf(a) || isinf(b), true);
+
+ PG_RETURN_FLOAT4( Abs(r) );
+}
+
+
/**************************************************
* float4 ops
**************************************************/
@@ -123,6 +148,25 @@ gbt_float4_consistent(PG_FUNCTION_ARGS)
}
+Datum
+gbt_float4_distance(PG_FUNCTION_ARGS)
+{
+ GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+ float4 query = PG_GETARG_FLOAT4(1);
+
+ /* Oid subtype = PG_GETARG_OID(3); */
+ float4KEY *kkk = (float4KEY *) DatumGetPointer(entry->key);
+ GBT_NUMKEY_R key;
+
+ key.lower = (GBT_NUMKEY *) &kkk->lower;
+ key.upper = (GBT_NUMKEY *) &kkk->upper;
+
+ PG_RETURN_FLOAT8(
+ gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo)
+ );
+}
+
+
Datum
gbt_float4_union(PG_FUNCTION_ARGS)
{
diff --git a/contrib/btree_gist/btree_float8.c b/contrib/btree_gist/btree_float8.c
index 1386983272c..0c39980ba1e 100644
--- a/contrib/btree_gist/btree_float8.c
+++ b/contrib/btree_gist/btree_float8.c
@@ -17,6 +17,7 @@ PG_FUNCTION_INFO_V1(gbt_float8_compress);
PG_FUNCTION_INFO_V1(gbt_float8_union);
PG_FUNCTION_INFO_V1(gbt_float8_picksplit);
PG_FUNCTION_INFO_V1(gbt_float8_consistent);
+PG_FUNCTION_INFO_V1(gbt_float8_distance);
PG_FUNCTION_INFO_V1(gbt_float8_penalty);
PG_FUNCTION_INFO_V1(gbt_float8_same);
@@ -24,6 +25,7 @@ Datum gbt_float8_compress(PG_FUNCTION_ARGS);
Datum gbt_float8_union(PG_FUNCTION_ARGS);
Datum gbt_float8_picksplit(PG_FUNCTION_ARGS);
Datum gbt_float8_consistent(PG_FUNCTION_ARGS);
+Datum gbt_float8_distance(PG_FUNCTION_ARGS);
Datum gbt_float8_penalty(PG_FUNCTION_ARGS);
Datum gbt_float8_same(PG_FUNCTION_ARGS);
@@ -71,6 +73,19 @@ gbt_float8key_cmp(const void *a, const void *b)
return (ia->lower > ib->lower) ? 1 : -1;
}
+static float8
+gbt_float8_dist(const void *a, const void *b)
+{
+ float8 arg1 = *(const float8 *)a;
+ float8 arg2 = *(const float8 *)b;
+ float8 r;
+
+ r = arg1 - arg2;
+ CHECKFLOATVAL(r, isinf(arg1) || isinf(arg2), true);
+
+ return Abs(r);
+}
+
static const gbtree_ninfo tinfo =
{
@@ -81,10 +96,26 @@ static const gbtree_ninfo tinfo =
gbt_float8eq,
gbt_float8le,
gbt_float8lt,
- gbt_float8key_cmp
+ gbt_float8key_cmp,
+ gbt_float8_dist
};
+PG_FUNCTION_INFO_V1(float8_dist);
+Datum float8_dist(PG_FUNCTION_ARGS);
+Datum
+float8_dist(PG_FUNCTION_ARGS)
+{
+ float8 a = PG_GETARG_FLOAT8(0);
+ float8 b = PG_GETARG_FLOAT8(1);
+ float8 r;
+
+ r = a - b;
+ CHECKFLOATVAL(r, isinf(a) || isinf(b), true);
+
+ PG_RETURN_FLOAT8( Abs(r) );
+}
+
/**************************************************
* float8 ops
**************************************************/
@@ -124,6 +155,25 @@ gbt_float8_consistent(PG_FUNCTION_ARGS)
}
+Datum
+gbt_float8_distance(PG_FUNCTION_ARGS)
+{
+ GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+ float8 query = PG_GETARG_FLOAT8(1);
+
+ /* Oid subtype = PG_GETARG_OID(3); */
+ float8KEY *kkk = (float8KEY *) DatumGetPointer(entry->key);
+ GBT_NUMKEY_R key;
+
+ key.lower = (GBT_NUMKEY *) &kkk->lower;
+ key.upper = (GBT_NUMKEY *) &kkk->upper;
+
+ PG_RETURN_FLOAT8(
+ gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo)
+ );
+}
+
+
Datum
gbt_float8_union(PG_FUNCTION_ARGS)
{
diff --git a/contrib/btree_gist/btree_gist--1.0.sql b/contrib/btree_gist/btree_gist--1.0.sql
index 1ea5fa2db41..dd428995c18 100644
--- a/contrib/btree_gist/btree_gist--1.0.sql
+++ b/contrib/btree_gist/btree_gist--1.0.sql
@@ -81,6 +81,151 @@ CREATE TYPE gbtreekey_var (
STORAGE = EXTENDED
);
+--distance operators
+
+CREATE FUNCTION cash_dist(money, money)
+RETURNS money
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OPERATOR <-> (
+ LEFTARG = money,
+ RIGHTARG = money,
+ PROCEDURE = cash_dist,
+ COMMUTATOR = '<->'
+);
+
+CREATE FUNCTION date_dist(date, date)
+RETURNS int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OPERATOR <-> (
+ LEFTARG = date,
+ RIGHTARG = date,
+ PROCEDURE = date_dist,
+ COMMUTATOR = '<->'
+);
+
+CREATE FUNCTION float4_dist(float4, float4)
+RETURNS float4
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OPERATOR <-> (
+ LEFTARG = float4,
+ RIGHTARG = float4,
+ PROCEDURE = float4_dist,
+ COMMUTATOR = '<->'
+);
+
+CREATE FUNCTION float8_dist(float8, float8)
+RETURNS float8
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OPERATOR <-> (
+ LEFTARG = float8,
+ RIGHTARG = float8,
+ PROCEDURE = float8_dist,
+ COMMUTATOR = '<->'
+);
+
+CREATE FUNCTION int2_dist(int2, int2)
+RETURNS int2
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OPERATOR <-> (
+ LEFTARG = int2,
+ RIGHTARG = int2,
+ PROCEDURE = int2_dist,
+ COMMUTATOR = '<->'
+);
+
+CREATE FUNCTION int4_dist(int4, int4)
+RETURNS int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OPERATOR <-> (
+ LEFTARG = int4,
+ RIGHTARG = int4,
+ PROCEDURE = int4_dist,
+ COMMUTATOR = '<->'
+);
+
+CREATE FUNCTION int8_dist(int8, int8)
+RETURNS int8
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OPERATOR <-> (
+ LEFTARG = int8,
+ RIGHTARG = int8,
+ PROCEDURE = int8_dist,
+ COMMUTATOR = '<->'
+);
+
+CREATE FUNCTION interval_dist(interval, interval)
+RETURNS interval
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OPERATOR <-> (
+ LEFTARG = interval,
+ RIGHTARG = interval,
+ PROCEDURE = interval_dist,
+ COMMUTATOR = '<->'
+);
+
+CREATE FUNCTION oid_dist(oid, oid)
+RETURNS oid
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OPERATOR <-> (
+ LEFTARG = oid,
+ RIGHTARG = oid,
+ PROCEDURE = oid_dist,
+ COMMUTATOR = '<->'
+);
+
+CREATE FUNCTION time_dist(time, time)
+RETURNS interval
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OPERATOR <-> (
+ LEFTARG = time,
+ RIGHTARG = time,
+ PROCEDURE = time_dist,
+ COMMUTATOR = '<->'
+);
+
+CREATE FUNCTION ts_dist(timestamp, timestamp)
+RETURNS interval
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OPERATOR <-> (
+ LEFTARG = timestamp,
+ RIGHTARG = timestamp,
+ PROCEDURE = ts_dist,
+ COMMUTATOR = '<->'
+);
+
+CREATE FUNCTION tstz_dist(timestamptz, timestamptz)
+RETURNS interval
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OPERATOR <-> (
+ LEFTARG = timestamptz,
+ RIGHTARG = timestamptz,
+ PROCEDURE = tstz_dist,
+ COMMUTATOR = '<->'
+);
--
@@ -96,6 +241,11 @@ RETURNS bool
AS 'MODULE_PATHNAME'
LANGUAGE C IMMUTABLE STRICT;
+CREATE FUNCTION gbt_oid_distance(internal,oid,int2,oid)
+RETURNS float8
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
CREATE FUNCTION gbt_oid_compress(internal)
RETURNS internal
AS 'MODULE_PATHNAME'
@@ -154,7 +304,9 @@ AS
-- that's the only state that can be reproduced during an upgrade from 9.0.
ALTER OPERATOR FAMILY gist_oid_ops USING gist ADD
- OPERATOR 6 <> (oid, oid) ;
+ OPERATOR 6 <> (oid, oid) ,
+ OPERATOR 15 <-> (oid, oid) FOR ORDER BY pg_catalog.oid_ops ,
+ FUNCTION 8 (oid, oid) gbt_oid_distance (internal, oid, int2, oid) ;
--
@@ -170,6 +322,11 @@ RETURNS bool
AS 'MODULE_PATHNAME'
LANGUAGE C IMMUTABLE STRICT;
+CREATE FUNCTION gbt_int2_distance(internal,int2,int2,oid)
+RETURNS float8
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
CREATE FUNCTION gbt_int2_compress(internal)
RETURNS internal
AS 'MODULE_PATHNAME'
@@ -214,7 +371,9 @@ AS
STORAGE gbtreekey4;
ALTER OPERATOR FAMILY gist_int2_ops USING gist ADD
- OPERATOR 6 <> (int2, int2) ;
+ OPERATOR 6 <> (int2, int2) ,
+ OPERATOR 15 <-> (int2, int2) FOR ORDER BY pg_catalog.integer_ops ,
+ FUNCTION 8 (int2, int2) gbt_int2_distance (internal, int2, int2, oid) ;
--
@@ -230,6 +389,11 @@ RETURNS bool
AS 'MODULE_PATHNAME'
LANGUAGE C IMMUTABLE STRICT;
+CREATE FUNCTION gbt_int4_distance(internal,int4,int2,oid)
+RETURNS float8
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
CREATE FUNCTION gbt_int4_compress(internal)
RETURNS internal
AS 'MODULE_PATHNAME'
@@ -274,7 +438,9 @@ AS
STORAGE gbtreekey8;
ALTER OPERATOR FAMILY gist_int4_ops USING gist ADD
- OPERATOR 6 <> (int4, int4) ;
+ OPERATOR 6 <> (int4, int4) ,
+ OPERATOR 15 <-> (int4, int4) FOR ORDER BY pg_catalog.integer_ops ,
+ FUNCTION 8 (int4, int4) gbt_int4_distance (internal, int4, int2, oid) ;
--
@@ -290,6 +456,11 @@ RETURNS bool
AS 'MODULE_PATHNAME'
LANGUAGE C IMMUTABLE STRICT;
+CREATE FUNCTION gbt_int8_distance(internal,int8,int2,oid)
+RETURNS float8
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
CREATE FUNCTION gbt_int8_compress(internal)
RETURNS internal
AS 'MODULE_PATHNAME'
@@ -334,7 +505,9 @@ AS
STORAGE gbtreekey16;
ALTER OPERATOR FAMILY gist_int8_ops USING gist ADD
- OPERATOR 6 <> (int8, int8) ;
+ OPERATOR 6 <> (int8, int8) ,
+ OPERATOR 15 <-> (int8, int8) FOR ORDER BY pg_catalog.integer_ops ,
+ FUNCTION 8 (int8, int8) gbt_int8_distance (internal, int8, int2, oid) ;
--
@@ -350,6 +523,11 @@ RETURNS bool
AS 'MODULE_PATHNAME'
LANGUAGE C IMMUTABLE STRICT;
+CREATE FUNCTION gbt_float4_distance(internal,float4,int2,oid)
+RETURNS float8
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
CREATE FUNCTION gbt_float4_compress(internal)
RETURNS internal
AS 'MODULE_PATHNAME'
@@ -394,7 +572,9 @@ AS
STORAGE gbtreekey8;
ALTER OPERATOR FAMILY gist_float4_ops USING gist ADD
- OPERATOR 6 <> (float4, float4) ;
+ OPERATOR 6 <> (float4, float4) ,
+ OPERATOR 15 <-> (float4, float4) FOR ORDER BY pg_catalog.float_ops ,
+ FUNCTION 8 (float4, float4) gbt_float4_distance (internal, float4, int2, oid) ;
--
@@ -410,6 +590,11 @@ RETURNS bool
AS 'MODULE_PATHNAME'
LANGUAGE C IMMUTABLE STRICT;
+CREATE FUNCTION gbt_float8_distance(internal,float8,int2,oid)
+RETURNS float8
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
CREATE FUNCTION gbt_float8_compress(internal)
RETURNS internal
AS 'MODULE_PATHNAME'
@@ -454,7 +639,9 @@ AS
STORAGE gbtreekey16;
ALTER OPERATOR FAMILY gist_float8_ops USING gist ADD
- OPERATOR 6 <> (float8, float8) ;
+ OPERATOR 6 <> (float8, float8) ,
+ OPERATOR 15 <-> (float8, float8) FOR ORDER BY pg_catalog.float_ops ,
+ FUNCTION 8 (float8, float8) gbt_float8_distance (internal, float8, int2, oid) ;
--
@@ -470,11 +657,21 @@ RETURNS bool
AS 'MODULE_PATHNAME'
LANGUAGE C IMMUTABLE STRICT;
+CREATE FUNCTION gbt_ts_distance(internal,timestamp,int2,oid)
+RETURNS float8
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
CREATE FUNCTION gbt_tstz_consistent(internal,timestamptz,int2,oid,internal)
RETURNS bool
AS 'MODULE_PATHNAME'
LANGUAGE C IMMUTABLE STRICT;
+CREATE FUNCTION gbt_tstz_distance(internal,timestamptz,int2,oid)
+RETURNS float8
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
CREATE FUNCTION gbt_ts_compress(internal)
RETURNS internal
AS 'MODULE_PATHNAME'
@@ -524,7 +721,9 @@ AS
STORAGE gbtreekey16;
ALTER OPERATOR FAMILY gist_timestamp_ops USING gist ADD
- OPERATOR 6 <> (timestamp, timestamp) ;
+ OPERATOR 6 <> (timestamp, timestamp) ,
+ OPERATOR 15 <-> (timestamp, timestamp) FOR ORDER BY pg_catalog.interval_ops ,
+ FUNCTION 8 (timestamp, timestamp) gbt_ts_distance (internal, timestamp, int2, oid) ;
-- Create the operator class
@@ -546,7 +745,9 @@ AS
STORAGE gbtreekey16;
ALTER OPERATOR FAMILY gist_timestamptz_ops USING gist ADD
- OPERATOR 6 <> (timestamptz, timestamptz) ;
+ OPERATOR 6 <> (timestamptz, timestamptz) ,
+ OPERATOR 15 <-> (timestamptz, timestamptz) FOR ORDER BY pg_catalog.interval_ops ,
+ FUNCTION 8 (timestamptz, timestamptz) gbt_tstz_distance (internal, timestamptz, int2, oid) ;
--
@@ -562,6 +763,11 @@ RETURNS bool
AS 'MODULE_PATHNAME'
LANGUAGE C IMMUTABLE STRICT;
+CREATE FUNCTION gbt_time_distance(internal,time,int2,oid)
+RETURNS float8
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
CREATE FUNCTION gbt_timetz_consistent(internal,timetz,int2,oid,internal)
RETURNS bool
AS 'MODULE_PATHNAME'
@@ -616,7 +822,9 @@ AS
STORAGE gbtreekey16;
ALTER OPERATOR FAMILY gist_time_ops USING gist ADD
- OPERATOR 6 <> (time, time) ;
+ OPERATOR 6 <> (time, time) ,
+ OPERATOR 15 <-> (time, time) FOR ORDER BY pg_catalog.interval_ops ,
+ FUNCTION 8 (time, time) gbt_time_distance (internal, time, int2, oid) ;
CREATE OPERATOR CLASS gist_timetz_ops
@@ -653,6 +861,11 @@ RETURNS bool
AS 'MODULE_PATHNAME'
LANGUAGE C IMMUTABLE STRICT;
+CREATE FUNCTION gbt_date_distance(internal,date,int2,oid)
+RETURNS float8
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
CREATE FUNCTION gbt_date_compress(internal)
RETURNS internal
AS 'MODULE_PATHNAME'
@@ -697,7 +910,9 @@ AS
STORAGE gbtreekey8;
ALTER OPERATOR FAMILY gist_date_ops USING gist ADD
- OPERATOR 6 <> (date, date) ;
+ OPERATOR 6 <> (date, date) ,
+ OPERATOR 15 <-> (date, date) FOR ORDER BY pg_catalog.integer_ops ,
+ FUNCTION 8 (date, date) gbt_date_distance (internal, date, int2, oid) ;
--
@@ -713,6 +928,11 @@ RETURNS bool
AS 'MODULE_PATHNAME'
LANGUAGE C IMMUTABLE STRICT;
+CREATE FUNCTION gbt_intv_distance(internal,interval,int2,oid)
+RETURNS float8
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
CREATE FUNCTION gbt_intv_compress(internal)
RETURNS internal
AS 'MODULE_PATHNAME'
@@ -762,7 +982,9 @@ AS
STORAGE gbtreekey32;
ALTER OPERATOR FAMILY gist_interval_ops USING gist ADD
- OPERATOR 6 <> (interval, interval) ;
+ OPERATOR 6 <> (interval, interval) ,
+ OPERATOR 15 <-> (interval, interval) FOR ORDER BY pg_catalog.interval_ops ,
+ FUNCTION 8 (interval, interval) gbt_intv_distance (internal, interval, int2, oid) ;
--
@@ -778,6 +1000,11 @@ RETURNS bool
AS 'MODULE_PATHNAME'
LANGUAGE C IMMUTABLE STRICT;
+CREATE FUNCTION gbt_cash_distance(internal,money,int2,oid)
+RETURNS float8
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
CREATE FUNCTION gbt_cash_compress(internal)
RETURNS internal
AS 'MODULE_PATHNAME'
@@ -822,7 +1049,9 @@ AS
STORAGE gbtreekey16;
ALTER OPERATOR FAMILY gist_cash_ops USING gist ADD
- OPERATOR 6 <> (money, money) ;
+ OPERATOR 6 <> (money, money) ,
+ OPERATOR 15 <-> (money, money) FOR ORDER BY pg_catalog.money_ops ,
+ FUNCTION 8 (money, money) gbt_cash_distance (internal, money, int2, oid) ;
--
diff --git a/contrib/btree_gist/btree_gist--unpackaged--1.0.sql b/contrib/btree_gist/btree_gist--unpackaged--1.0.sql
index d8631d6bc26..00252bf7c38 100644
--- a/contrib/btree_gist/btree_gist--unpackaged--1.0.sql
+++ b/contrib/btree_gist/btree_gist--unpackaged--1.0.sql
@@ -171,46 +171,282 @@ ALTER EXTENSION btree_gist ADD operator class gist_inet_ops using gist;
ALTER EXTENSION btree_gist ADD operator family gist_cidr_ops using gist;
ALTER EXTENSION btree_gist ADD operator class gist_cidr_ops using gist;
+
+-- Add functions and operators that are new in 9.1
+
+--distance operators
+
+CREATE FUNCTION cash_dist(money, money)
+RETURNS money
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OPERATOR <-> (
+ LEFTARG = money,
+ RIGHTARG = money,
+ PROCEDURE = cash_dist,
+ COMMUTATOR = '<->'
+);
+
+CREATE FUNCTION date_dist(date, date)
+RETURNS int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OPERATOR <-> (
+ LEFTARG = date,
+ RIGHTARG = date,
+ PROCEDURE = date_dist,
+ COMMUTATOR = '<->'
+);
+
+CREATE FUNCTION float4_dist(float4, float4)
+RETURNS float4
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OPERATOR <-> (
+ LEFTARG = float4,
+ RIGHTARG = float4,
+ PROCEDURE = float4_dist,
+ COMMUTATOR = '<->'
+);
+
+CREATE FUNCTION float8_dist(float8, float8)
+RETURNS float8
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OPERATOR <-> (
+ LEFTARG = float8,
+ RIGHTARG = float8,
+ PROCEDURE = float8_dist,
+ COMMUTATOR = '<->'
+);
+
+CREATE FUNCTION int2_dist(int2, int2)
+RETURNS int2
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OPERATOR <-> (
+ LEFTARG = int2,
+ RIGHTARG = int2,
+ PROCEDURE = int2_dist,
+ COMMUTATOR = '<->'
+);
+
+CREATE FUNCTION int4_dist(int4, int4)
+RETURNS int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OPERATOR <-> (
+ LEFTARG = int4,
+ RIGHTARG = int4,
+ PROCEDURE = int4_dist,
+ COMMUTATOR = '<->'
+);
+
+CREATE FUNCTION int8_dist(int8, int8)
+RETURNS int8
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OPERATOR <-> (
+ LEFTARG = int8,
+ RIGHTARG = int8,
+ PROCEDURE = int8_dist,
+ COMMUTATOR = '<->'
+);
+
+CREATE FUNCTION interval_dist(interval, interval)
+RETURNS interval
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OPERATOR <-> (
+ LEFTARG = interval,
+ RIGHTARG = interval,
+ PROCEDURE = interval_dist,
+ COMMUTATOR = '<->'
+);
+
+CREATE FUNCTION oid_dist(oid, oid)
+RETURNS oid
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OPERATOR <-> (
+ LEFTARG = oid,
+ RIGHTARG = oid,
+ PROCEDURE = oid_dist,
+ COMMUTATOR = '<->'
+);
+
+CREATE FUNCTION time_dist(time, time)
+RETURNS interval
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OPERATOR <-> (
+ LEFTARG = time,
+ RIGHTARG = time,
+ PROCEDURE = time_dist,
+ COMMUTATOR = '<->'
+);
+
+CREATE FUNCTION ts_dist(timestamp, timestamp)
+RETURNS interval
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OPERATOR <-> (
+ LEFTARG = timestamp,
+ RIGHTARG = timestamp,
+ PROCEDURE = ts_dist,
+ COMMUTATOR = '<->'
+);
+
+CREATE FUNCTION tstz_dist(timestamptz, timestamptz)
+RETURNS interval
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OPERATOR <-> (
+ LEFTARG = timestamptz,
+ RIGHTARG = timestamptz,
+ PROCEDURE = tstz_dist,
+ COMMUTATOR = '<->'
+);
+
+-- Support functions for distance operators
+
+CREATE FUNCTION gbt_oid_distance(internal,oid,int2,oid)
+RETURNS float8
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_int2_distance(internal,int2,int2,oid)
+RETURNS float8
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_int4_distance(internal,int4,int2,oid)
+RETURNS float8
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_int8_distance(internal,int8,int2,oid)
+RETURNS float8
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_float4_distance(internal,float4,int2,oid)
+RETURNS float8
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_float8_distance(internal,float8,int2,oid)
+RETURNS float8
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_ts_distance(internal,timestamp,int2,oid)
+RETURNS float8
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_tstz_distance(internal,timestamptz,int2,oid)
+RETURNS float8
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_time_distance(internal,time,int2,oid)
+RETURNS float8
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_date_distance(internal,date,int2,oid)
+RETURNS float8
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_intv_distance(internal,interval,int2,oid)
+RETURNS float8
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_cash_distance(internal,money,int2,oid)
+RETURNS float8
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+
-- Add new-in-9.1 stuff to the operator classes.
ALTER OPERATOR FAMILY gist_oid_ops USING gist ADD
- OPERATOR 6 <> (oid, oid) ;
+ OPERATOR 6 <> (oid, oid) ,
+ OPERATOR 15 <-> (oid, oid) FOR ORDER BY pg_catalog.oid_ops ,
+ FUNCTION 8 (oid, oid) gbt_oid_distance (internal, oid, int2, oid) ;
ALTER OPERATOR FAMILY gist_int2_ops USING gist ADD
- OPERATOR 6 <> (int2, int2) ;
+ OPERATOR 6 <> (int2, int2) ,
+ OPERATOR 15 <-> (int2, int2) FOR ORDER BY pg_catalog.integer_ops ,
+ FUNCTION 8 (int2, int2) gbt_int2_distance (internal, int2, int2, oid) ;
ALTER OPERATOR FAMILY gist_int4_ops USING gist ADD
- OPERATOR 6 <> (int4, int4) ;
+ OPERATOR 6 <> (int4, int4) ,
+ OPERATOR 15 <-> (int4, int4) FOR ORDER BY pg_catalog.integer_ops ,
+ FUNCTION 8 (int4, int4) gbt_int4_distance (internal, int4, int2, oid) ;
ALTER OPERATOR FAMILY gist_int8_ops USING gist ADD
- OPERATOR 6 <> (int8, int8) ;
+ OPERATOR 6 <> (int8, int8) ,
+ OPERATOR 15 <-> (int8, int8) FOR ORDER BY pg_catalog.integer_ops ,
+ FUNCTION 8 (int8, int8) gbt_int8_distance (internal, int8, int2, oid) ;
ALTER OPERATOR FAMILY gist_float4_ops USING gist ADD
- OPERATOR 6 <> (float4, float4) ;
+ OPERATOR 6 <> (float4, float4) ,
+ OPERATOR 15 <-> (float4, float4) FOR ORDER BY pg_catalog.float_ops ,
+ FUNCTION 8 (float4, float4) gbt_float4_distance (internal, float4, int2, oid) ;
ALTER OPERATOR FAMILY gist_float8_ops USING gist ADD
- OPERATOR 6 <> (float8, float8) ;
+ OPERATOR 6 <> (float8, float8) ,
+ OPERATOR 15 <-> (float8, float8) FOR ORDER BY pg_catalog.float_ops ,
+ FUNCTION 8 (float8, float8) gbt_float8_distance (internal, float8, int2, oid) ;
ALTER OPERATOR FAMILY gist_timestamp_ops USING gist ADD
- OPERATOR 6 <> (timestamp, timestamp) ;
+ OPERATOR 6 <> (timestamp, timestamp) ,
+ OPERATOR 15 <-> (timestamp, timestamp) FOR ORDER BY pg_catalog.interval_ops ,
+ FUNCTION 8 (timestamp, timestamp) gbt_ts_distance (internal, timestamp, int2, oid) ;
ALTER OPERATOR FAMILY gist_timestamptz_ops USING gist ADD
- OPERATOR 6 <> (timestamptz, timestamptz) ;
+ OPERATOR 6 <> (timestamptz, timestamptz) ,
+ OPERATOR 15 <-> (timestamptz, timestamptz) FOR ORDER BY pg_catalog.interval_ops ,
+ FUNCTION 8 (timestamptz, timestamptz) gbt_tstz_distance (internal, timestamptz, int2, oid) ;
ALTER OPERATOR FAMILY gist_time_ops USING gist ADD
- OPERATOR 6 <> (time, time) ;
+ OPERATOR 6 <> (time, time) ,
+ OPERATOR 15 <-> (time, time) FOR ORDER BY pg_catalog.interval_ops ,
+ FUNCTION 8 (time, time) gbt_time_distance (internal, time, int2, oid) ;
ALTER OPERATOR FAMILY gist_timetz_ops USING gist ADD
OPERATOR 6 <> (timetz, timetz) ;
ALTER OPERATOR FAMILY gist_date_ops USING gist ADD
- OPERATOR 6 <> (date, date) ;
+ OPERATOR 6 <> (date, date) ,
+ OPERATOR 15 <-> (date, date) FOR ORDER BY pg_catalog.integer_ops ,
+ FUNCTION 8 (date, date) gbt_date_distance (internal, date, int2, oid) ;
ALTER OPERATOR FAMILY gist_interval_ops USING gist ADD
- OPERATOR 6 <> (interval, interval) ;
+ OPERATOR 6 <> (interval, interval) ,
+ OPERATOR 15 <-> (interval, interval) FOR ORDER BY pg_catalog.interval_ops ,
+ FUNCTION 8 (interval, interval) gbt_intv_distance (internal, interval, int2, oid) ;
ALTER OPERATOR FAMILY gist_cash_ops USING gist ADD
- OPERATOR 6 <> (money, money) ;
+ OPERATOR 6 <> (money, money) ,
+ OPERATOR 15 <-> (money, money) FOR ORDER BY pg_catalog.money_ops ,
+ FUNCTION 8 (money, money) gbt_cash_distance (internal, money, int2, oid) ;
ALTER OPERATOR FAMILY gist_macaddr_ops USING gist ADD
OPERATOR 6 <> (macaddr, macaddr) ;
diff --git a/contrib/btree_gist/btree_inet.c b/contrib/btree_gist/btree_inet.c
index dcc934d1562..690a01cbc7a 100644
--- a/contrib/btree_gist/btree_inet.c
+++ b/contrib/btree_gist/btree_inet.c
@@ -84,7 +84,8 @@ static const gbtree_ninfo tinfo =
gbt_ineteq,
gbt_inetle,
gbt_inetlt,
- gbt_inetkey_cmp
+ gbt_inetkey_cmp,
+ NULL
};
diff --git a/contrib/btree_gist/btree_int2.c b/contrib/btree_gist/btree_int2.c
index 2e981174520..c06d170a5e1 100644
--- a/contrib/btree_gist/btree_int2.c
+++ b/contrib/btree_gist/btree_int2.c
@@ -17,6 +17,7 @@ PG_FUNCTION_INFO_V1(gbt_int2_compress);
PG_FUNCTION_INFO_V1(gbt_int2_union);
PG_FUNCTION_INFO_V1(gbt_int2_picksplit);
PG_FUNCTION_INFO_V1(gbt_int2_consistent);
+PG_FUNCTION_INFO_V1(gbt_int2_distance);
PG_FUNCTION_INFO_V1(gbt_int2_penalty);
PG_FUNCTION_INFO_V1(gbt_int2_same);
@@ -24,6 +25,7 @@ Datum gbt_int2_compress(PG_FUNCTION_ARGS);
Datum gbt_int2_union(PG_FUNCTION_ARGS);
Datum gbt_int2_picksplit(PG_FUNCTION_ARGS);
Datum gbt_int2_consistent(PG_FUNCTION_ARGS);
+Datum gbt_int2_distance(PG_FUNCTION_ARGS);
Datum gbt_int2_penalty(PG_FUNCTION_ARGS);
Datum gbt_int2_same(PG_FUNCTION_ARGS);
@@ -70,6 +72,12 @@ gbt_int2key_cmp(const void *a, const void *b)
return (ia->lower > ib->lower) ? 1 : -1;
}
+static float8
+gbt_int2_dist(const void *a, const void *b)
+{
+ return GET_FLOAT_DISTANCE(int2, a, b);
+}
+
static const gbtree_ninfo tinfo =
{
@@ -80,12 +88,32 @@ static const gbtree_ninfo tinfo =
gbt_int2eq,
gbt_int2le,
gbt_int2lt,
- gbt_int2key_cmp
+ gbt_int2key_cmp,
+ gbt_int2_dist
};
+PG_FUNCTION_INFO_V1(int2_dist);
+Datum int2_dist(PG_FUNCTION_ARGS);
+Datum
+int2_dist(PG_FUNCTION_ARGS)
+{
+ int2 a = PG_GETARG_INT16(0);
+ int2 b = PG_GETARG_INT16(1);
+ int2 r;
+ int2 ra;
+ r = a - b;
+ ra = Abs(r);
+ /* Overflow check. */
+ if (ra < 0 || (!SAMESIGN(a, b) && !SAMESIGN(r, a)))
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("smallint out of range")));
+
+ PG_RETURN_INT16(ra);
+}
/**************************************************
@@ -127,6 +155,25 @@ gbt_int2_consistent(PG_FUNCTION_ARGS)
}
+Datum
+gbt_int2_distance(PG_FUNCTION_ARGS)
+{
+ GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+ int16 query = PG_GETARG_INT16(1);
+
+ /* Oid subtype = PG_GETARG_OID(3); */
+ int16KEY *kkk = (int16KEY *) DatumGetPointer(entry->key);
+ GBT_NUMKEY_R key;
+
+ key.lower = (GBT_NUMKEY *) &kkk->lower;
+ key.upper = (GBT_NUMKEY *) &kkk->upper;
+
+ PG_RETURN_FLOAT8(
+ gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo)
+ );
+}
+
+
Datum
gbt_int2_union(PG_FUNCTION_ARGS)
{
diff --git a/contrib/btree_gist/btree_int4.c b/contrib/btree_gist/btree_int4.c
index 678d653fd0b..ef7af524e76 100644
--- a/contrib/btree_gist/btree_int4.c
+++ b/contrib/btree_gist/btree_int4.c
@@ -17,6 +17,7 @@ PG_FUNCTION_INFO_V1(gbt_int4_compress);
PG_FUNCTION_INFO_V1(gbt_int4_union);
PG_FUNCTION_INFO_V1(gbt_int4_picksplit);
PG_FUNCTION_INFO_V1(gbt_int4_consistent);
+PG_FUNCTION_INFO_V1(gbt_int4_distance);
PG_FUNCTION_INFO_V1(gbt_int4_penalty);
PG_FUNCTION_INFO_V1(gbt_int4_same);
@@ -24,6 +25,7 @@ Datum gbt_int4_compress(PG_FUNCTION_ARGS);
Datum gbt_int4_union(PG_FUNCTION_ARGS);
Datum gbt_int4_picksplit(PG_FUNCTION_ARGS);
Datum gbt_int4_consistent(PG_FUNCTION_ARGS);
+Datum gbt_int4_distance(PG_FUNCTION_ARGS);
Datum gbt_int4_penalty(PG_FUNCTION_ARGS);
Datum gbt_int4_same(PG_FUNCTION_ARGS);
@@ -71,6 +73,12 @@ gbt_int4key_cmp(const void *a, const void *b)
return (ia->lower > ib->lower) ? 1 : -1;
}
+static float8
+gbt_int4_dist(const void *a, const void *b)
+{
+ return GET_FLOAT_DISTANCE(int4, a, b);
+}
+
static const gbtree_ninfo tinfo =
{
@@ -81,10 +89,34 @@ static const gbtree_ninfo tinfo =
gbt_int4eq,
gbt_int4le,
gbt_int4lt,
- gbt_int4key_cmp
+ gbt_int4key_cmp,
+ gbt_int4_dist
};
+PG_FUNCTION_INFO_V1(int4_dist);
+Datum int4_dist(PG_FUNCTION_ARGS);
+Datum
+int4_dist(PG_FUNCTION_ARGS)
+{
+ int4 a = PG_GETARG_INT32(0);
+ int4 b = PG_GETARG_INT32(1);
+ int4 r;
+ int4 ra;
+
+ r = a - b;
+ ra = Abs(r);
+
+ /* Overflow check. */
+ if (ra < 0 || (!SAMESIGN(a, b) && !SAMESIGN(r, a)))
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("integer out of range")));
+
+ PG_RETURN_INT32(ra);
+}
+
+
/**************************************************
* int32 ops
**************************************************/
@@ -124,6 +156,25 @@ gbt_int4_consistent(PG_FUNCTION_ARGS)
}
+Datum
+gbt_int4_distance(PG_FUNCTION_ARGS)
+{
+ GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+ int32 query = PG_GETARG_INT32(1);
+
+ /* Oid subtype = PG_GETARG_OID(3); */
+ int32KEY *kkk = (int32KEY *) DatumGetPointer(entry->key);
+ GBT_NUMKEY_R key;
+
+ key.lower = (GBT_NUMKEY *) &kkk->lower;
+ key.upper = (GBT_NUMKEY *) &kkk->upper;
+
+ PG_RETURN_FLOAT8(
+ gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo)
+ );
+}
+
+
Datum
gbt_int4_union(PG_FUNCTION_ARGS)
{
diff --git a/contrib/btree_gist/btree_int8.c b/contrib/btree_gist/btree_int8.c
index 8afa5b0af24..1f14d82891d 100644
--- a/contrib/btree_gist/btree_int8.c
+++ b/contrib/btree_gist/btree_int8.c
@@ -17,6 +17,7 @@ PG_FUNCTION_INFO_V1(gbt_int8_compress);
PG_FUNCTION_INFO_V1(gbt_int8_union);
PG_FUNCTION_INFO_V1(gbt_int8_picksplit);
PG_FUNCTION_INFO_V1(gbt_int8_consistent);
+PG_FUNCTION_INFO_V1(gbt_int8_distance);
PG_FUNCTION_INFO_V1(gbt_int8_penalty);
PG_FUNCTION_INFO_V1(gbt_int8_same);
@@ -24,6 +25,7 @@ Datum gbt_int8_compress(PG_FUNCTION_ARGS);
Datum gbt_int8_union(PG_FUNCTION_ARGS);
Datum gbt_int8_picksplit(PG_FUNCTION_ARGS);
Datum gbt_int8_consistent(PG_FUNCTION_ARGS);
+Datum gbt_int8_distance(PG_FUNCTION_ARGS);
Datum gbt_int8_penalty(PG_FUNCTION_ARGS);
Datum gbt_int8_same(PG_FUNCTION_ARGS);
@@ -71,6 +73,12 @@ gbt_int8key_cmp(const void *a, const void *b)
return (ia->lower > ib->lower) ? 1 : -1;
}
+static float8
+gbt_int8_dist(const void *a, const void *b)
+{
+ return GET_FLOAT_DISTANCE(int64, a, b);
+}
+
static const gbtree_ninfo tinfo =
{
@@ -81,10 +89,34 @@ static const gbtree_ninfo tinfo =
gbt_int8eq,
gbt_int8le,
gbt_int8lt,
- gbt_int8key_cmp
+ gbt_int8key_cmp,
+ gbt_int8_dist
};
+PG_FUNCTION_INFO_V1(int8_dist);
+Datum int8_dist(PG_FUNCTION_ARGS);
+Datum
+int8_dist(PG_FUNCTION_ARGS)
+{
+ int64 a = PG_GETARG_INT64(0);
+ int64 b = PG_GETARG_INT64(1);
+ int64 r;
+ int64 ra;
+
+ r = a - b;
+ ra = Abs(r);
+
+ /* Overflow check. */
+ if (ra < 0 || (!SAMESIGN(a, b) && !SAMESIGN(r, a)))
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("bigint out of range")));
+
+ PG_RETURN_INT64(ra);
+}
+
+
/**************************************************
* int64 ops
**************************************************/
@@ -124,6 +156,25 @@ gbt_int8_consistent(PG_FUNCTION_ARGS)
}
+Datum
+gbt_int8_distance(PG_FUNCTION_ARGS)
+{
+ GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+ int64 query = PG_GETARG_INT64(1);
+
+ /* Oid subtype = PG_GETARG_OID(3); */
+ int64KEY *kkk = (int64KEY *) DatumGetPointer(entry->key);
+ GBT_NUMKEY_R key;
+
+ key.lower = (GBT_NUMKEY *) &kkk->lower;
+ key.upper = (GBT_NUMKEY *) &kkk->upper;
+
+ PG_RETURN_FLOAT8(
+ gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo)
+ );
+}
+
+
Datum
gbt_int8_union(PG_FUNCTION_ARGS)
{
diff --git a/contrib/btree_gist/btree_interval.c b/contrib/btree_gist/btree_interval.c
index 0715346f234..5195284afa1 100644
--- a/contrib/btree_gist/btree_interval.c
+++ b/contrib/btree_gist/btree_interval.c
@@ -20,6 +20,7 @@ PG_FUNCTION_INFO_V1(gbt_intv_decompress);
PG_FUNCTION_INFO_V1(gbt_intv_union);
PG_FUNCTION_INFO_V1(gbt_intv_picksplit);
PG_FUNCTION_INFO_V1(gbt_intv_consistent);
+PG_FUNCTION_INFO_V1(gbt_intv_distance);
PG_FUNCTION_INFO_V1(gbt_intv_penalty);
PG_FUNCTION_INFO_V1(gbt_intv_same);
@@ -28,6 +29,7 @@ Datum gbt_intv_decompress(PG_FUNCTION_ARGS);
Datum gbt_intv_union(PG_FUNCTION_ARGS);
Datum gbt_intv_picksplit(PG_FUNCTION_ARGS);
Datum gbt_intv_consistent(PG_FUNCTION_ARGS);
+Datum gbt_intv_distance(PG_FUNCTION_ARGS);
Datum gbt_intv_penalty(PG_FUNCTION_ARGS);
Datum gbt_intv_same(PG_FUNCTION_ARGS);
@@ -83,6 +85,12 @@ intr2num(const Interval *i)
return INTERVAL_TO_SEC(i);
}
+static float8
+gbt_intv_dist(const void *a, const void *b)
+{
+ return (float8)Abs(intr2num((Interval*)a) - intr2num((Interval*)b));
+}
+
/*
* INTERVALSIZE should be the actual size-on-disk of an Interval, as shown
* in pg_type. This might be less than sizeof(Interval) if the compiler
@@ -99,10 +107,38 @@ static const gbtree_ninfo tinfo =
gbt_intveq,
gbt_intvle,
gbt_intvlt,
- gbt_intvkey_cmp
+ gbt_intvkey_cmp,
+ gbt_intv_dist
};
+Interval *
+abs_interval(Interval *a)
+{
+ static Interval zero = {0, 0, 0};
+
+ if (DatumGetBool(DirectFunctionCall2(interval_lt,
+ IntervalPGetDatum(a),
+ IntervalPGetDatum(&zero))))
+ a = DatumGetIntervalP(DirectFunctionCall1(interval_um,
+ IntervalPGetDatum(a)));
+
+ return a;
+}
+
+PG_FUNCTION_INFO_V1(interval_dist);
+Datum interval_dist(PG_FUNCTION_ARGS);
+Datum
+interval_dist(PG_FUNCTION_ARGS)
+{
+ Datum diff = DirectFunctionCall2(interval_mi,
+ PG_GETARG_DATUM(0),
+ PG_GETARG_DATUM(1));
+
+ PG_RETURN_INTERVAL_P(abs_interval(DatumGetIntervalP(diff)));
+}
+
+
/**************************************************
* interval ops
**************************************************/
@@ -190,6 +226,25 @@ gbt_intv_consistent(PG_FUNCTION_ARGS)
}
+Datum
+gbt_intv_distance(PG_FUNCTION_ARGS)
+{
+ GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+ Interval *query = PG_GETARG_INTERVAL_P(1);
+
+ /* Oid subtype = PG_GETARG_OID(3); */
+ intvKEY *kkk = (intvKEY *) DatumGetPointer(entry->key);
+ GBT_NUMKEY_R key;
+
+ key.lower = (GBT_NUMKEY *) &kkk->lower;
+ key.upper = (GBT_NUMKEY *) &kkk->upper;
+
+ PG_RETURN_FLOAT8(
+ gbt_num_distance(&key, (void *) query, GIST_LEAF(entry), &tinfo)
+ );
+}
+
+
Datum
gbt_intv_union(PG_FUNCTION_ARGS)
{
diff --git a/contrib/btree_gist/btree_macaddr.c b/contrib/btree_gist/btree_macaddr.c
index fb440c3f198..aa150e26a23 100644
--- a/contrib/btree_gist/btree_macaddr.c
+++ b/contrib/btree_gist/btree_macaddr.c
@@ -84,7 +84,8 @@ static const gbtree_ninfo tinfo =
gbt_macadeq,
gbt_macadle,
gbt_macadlt,
- gbt_macadkey_cmp
+ gbt_macadkey_cmp,
+ NULL
};
diff --git a/contrib/btree_gist/btree_oid.c b/contrib/btree_gist/btree_oid.c
index 4927448258f..c81dd31799e 100644
--- a/contrib/btree_gist/btree_oid.c
+++ b/contrib/btree_gist/btree_oid.c
@@ -17,6 +17,7 @@ PG_FUNCTION_INFO_V1(gbt_oid_compress);
PG_FUNCTION_INFO_V1(gbt_oid_union);
PG_FUNCTION_INFO_V1(gbt_oid_picksplit);
PG_FUNCTION_INFO_V1(gbt_oid_consistent);
+PG_FUNCTION_INFO_V1(gbt_oid_distance);
PG_FUNCTION_INFO_V1(gbt_oid_penalty);
PG_FUNCTION_INFO_V1(gbt_oid_same);
@@ -24,6 +25,7 @@ Datum gbt_oid_compress(PG_FUNCTION_ARGS);
Datum gbt_oid_union(PG_FUNCTION_ARGS);
Datum gbt_oid_picksplit(PG_FUNCTION_ARGS);
Datum gbt_oid_consistent(PG_FUNCTION_ARGS);
+Datum gbt_oid_distance(PG_FUNCTION_ARGS);
Datum gbt_oid_penalty(PG_FUNCTION_ARGS);
Datum gbt_oid_same(PG_FUNCTION_ARGS);
@@ -71,6 +73,18 @@ gbt_oidkey_cmp(const void *a, const void *b)
return (ia->lower > ib->lower) ? 1 : -1;
}
+static float8
+gbt_oid_dist(const void *a, const void *b)
+{
+ Oid aa = *(const Oid *) a;
+ Oid bb = *(const Oid *) b;
+
+ if (aa < bb)
+ return (float8) (bb - aa);
+ else
+ return (float8) (aa - bb);
+}
+
static const gbtree_ninfo tinfo =
{
@@ -81,10 +95,28 @@ static const gbtree_ninfo tinfo =
gbt_oideq,
gbt_oidle,
gbt_oidlt,
- gbt_oidkey_cmp
+ gbt_oidkey_cmp,
+ gbt_oid_dist
};
+PG_FUNCTION_INFO_V1(oid_dist);
+Datum oid_dist(PG_FUNCTION_ARGS);
+Datum
+oid_dist(PG_FUNCTION_ARGS)
+{
+ Oid a = PG_GETARG_OID(0);
+ Oid b = PG_GETARG_OID(1);
+ Oid res;
+
+ if (a < b)
+ res = b - a;
+ else
+ res = a - b;
+ PG_RETURN_OID(res);
+}
+
+
/**************************************************
* Oid ops
**************************************************/
@@ -124,6 +156,25 @@ gbt_oid_consistent(PG_FUNCTION_ARGS)
}
+Datum
+gbt_oid_distance(PG_FUNCTION_ARGS)
+{
+ GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+ Oid query = PG_GETARG_OID(1);
+
+ /* Oid subtype = PG_GETARG_OID(3); */
+ oidKEY *kkk = (oidKEY *) DatumGetPointer(entry->key);
+ GBT_NUMKEY_R key;
+
+ key.lower = (GBT_NUMKEY *) &kkk->lower;
+ key.upper = (GBT_NUMKEY *) &kkk->upper;
+
+ PG_RETURN_FLOAT8(
+ gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo)
+ );
+}
+
+
Datum
gbt_oid_union(PG_FUNCTION_ARGS)
{
diff --git a/contrib/btree_gist/btree_time.c b/contrib/btree_gist/btree_time.c
index 01163e906ad..44f6923409f 100644
--- a/contrib/btree_gist/btree_time.c
+++ b/contrib/btree_gist/btree_time.c
@@ -20,6 +20,7 @@ PG_FUNCTION_INFO_V1(gbt_timetz_compress);
PG_FUNCTION_INFO_V1(gbt_time_union);
PG_FUNCTION_INFO_V1(gbt_time_picksplit);
PG_FUNCTION_INFO_V1(gbt_time_consistent);
+PG_FUNCTION_INFO_V1(gbt_time_distance);
PG_FUNCTION_INFO_V1(gbt_timetz_consistent);
PG_FUNCTION_INFO_V1(gbt_time_penalty);
PG_FUNCTION_INFO_V1(gbt_time_same);
@@ -29,6 +30,7 @@ Datum gbt_timetz_compress(PG_FUNCTION_ARGS);
Datum gbt_time_union(PG_FUNCTION_ARGS);
Datum gbt_time_picksplit(PG_FUNCTION_ARGS);
Datum gbt_time_consistent(PG_FUNCTION_ARGS);
+Datum gbt_time_distance(PG_FUNCTION_ARGS);
Datum gbt_timetz_consistent(PG_FUNCTION_ARGS);
Datum gbt_time_penalty(PG_FUNCTION_ARGS);
Datum gbt_time_same(PG_FUNCTION_ARGS);
@@ -112,6 +114,19 @@ gbt_timekey_cmp(const void *a, const void *b)
return res;
}
+static float8
+gbt_time_dist(const void *a, const void *b)
+{
+ const TimeADT *aa = (const TimeADT *) a;
+ const TimeADT *bb = (const TimeADT *) b;
+ Interval *i;
+
+ i = DatumGetIntervalP(DirectFunctionCall2(time_mi_time,
+ TimeADTGetDatumFast(*aa),
+ TimeADTGetDatumFast(*bb)));
+ return (float8) Abs(INTERVAL_TO_SEC(i));
+}
+
static const gbtree_ninfo tinfo =
{
@@ -122,10 +137,24 @@ static const gbtree_ninfo tinfo =
gbt_timeeq,
gbt_timele,
gbt_timelt,
- gbt_timekey_cmp
+ gbt_timekey_cmp,
+ gbt_time_dist
};
+PG_FUNCTION_INFO_V1(time_dist);
+Datum time_dist(PG_FUNCTION_ARGS);
+Datum
+time_dist(PG_FUNCTION_ARGS)
+{
+ Datum diff = DirectFunctionCall2(time_mi_time,
+ PG_GETARG_DATUM(0),
+ PG_GETARG_DATUM(1));
+
+ PG_RETURN_INTERVAL_P(abs_interval(DatumGetIntervalP(diff)));
+}
+
+
/**************************************************
* time ops
**************************************************/
@@ -196,6 +225,24 @@ gbt_time_consistent(PG_FUNCTION_ARGS)
);
}
+Datum
+gbt_time_distance(PG_FUNCTION_ARGS)
+{
+ GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+ TimeADT query = PG_GETARG_TIMEADT(1);
+
+ /* Oid subtype = PG_GETARG_OID(3); */
+ timeKEY *kkk = (timeKEY *) DatumGetPointer(entry->key);
+ GBT_NUMKEY_R key;
+
+ key.lower = (GBT_NUMKEY *) &kkk->lower;
+ key.upper = (GBT_NUMKEY *) &kkk->upper;
+
+ PG_RETURN_FLOAT8(
+ gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo)
+ );
+}
+
Datum
gbt_timetz_consistent(PG_FUNCTION_ARGS)
{
diff --git a/contrib/btree_gist/btree_ts.c b/contrib/btree_gist/btree_ts.c
index 2b13d14ad19..9a0ec07a1e7 100644
--- a/contrib/btree_gist/btree_ts.c
+++ b/contrib/btree_gist/btree_ts.c
@@ -3,6 +3,7 @@
*/
#include "btree_gist.h"
#include "btree_utils_num.h"
+#include "utils/builtins.h"
#include "utils/datetime.h"
typedef struct
@@ -19,7 +20,9 @@ PG_FUNCTION_INFO_V1(gbt_tstz_compress);
PG_FUNCTION_INFO_V1(gbt_ts_union);
PG_FUNCTION_INFO_V1(gbt_ts_picksplit);
PG_FUNCTION_INFO_V1(gbt_ts_consistent);
+PG_FUNCTION_INFO_V1(gbt_ts_distance);
PG_FUNCTION_INFO_V1(gbt_tstz_consistent);
+PG_FUNCTION_INFO_V1(gbt_tstz_distance);
PG_FUNCTION_INFO_V1(gbt_ts_penalty);
PG_FUNCTION_INFO_V1(gbt_ts_same);
@@ -28,7 +31,9 @@ Datum gbt_tstz_compress(PG_FUNCTION_ARGS);
Datum gbt_ts_union(PG_FUNCTION_ARGS);
Datum gbt_ts_picksplit(PG_FUNCTION_ARGS);
Datum gbt_ts_consistent(PG_FUNCTION_ARGS);
+Datum gbt_ts_distance(PG_FUNCTION_ARGS);
Datum gbt_tstz_consistent(PG_FUNCTION_ARGS);
+Datum gbt_tstz_distance(PG_FUNCTION_ARGS);
Datum gbt_ts_penalty(PG_FUNCTION_ARGS);
Datum gbt_ts_same(PG_FUNCTION_ARGS);
@@ -110,6 +115,22 @@ gbt_tskey_cmp(const void *a, const void *b)
return res;
}
+static float8
+gbt_ts_dist(const void *a, const void *b)
+{
+ const Timestamp *aa = (const Timestamp *) a;
+ const Timestamp *bb = (const Timestamp *) b;
+ Interval *i;
+
+ if (TIMESTAMP_NOT_FINITE(*aa) || TIMESTAMP_NOT_FINITE(*bb))
+ return get_float8_infinity();
+
+ i = DatumGetIntervalP(DirectFunctionCall2(timestamp_mi,
+ TimestampGetDatumFast(*aa),
+ TimestampGetDatumFast(*bb)));
+ return (float8) Abs(INTERVAL_TO_SEC(i));
+}
+
static const gbtree_ninfo tinfo =
{
@@ -120,10 +141,71 @@ static const gbtree_ninfo tinfo =
gbt_tseq,
gbt_tsle,
gbt_tslt,
- gbt_tskey_cmp
+ gbt_tskey_cmp,
+ gbt_ts_dist
};
+PG_FUNCTION_INFO_V1(ts_dist);
+Datum ts_dist(PG_FUNCTION_ARGS);
+Datum
+ts_dist(PG_FUNCTION_ARGS)
+{
+ Timestamp a = PG_GETARG_TIMESTAMP(0);
+ Timestamp b = PG_GETARG_TIMESTAMP(1);
+ Interval *r;
+
+ if (TIMESTAMP_NOT_FINITE(a) || TIMESTAMP_NOT_FINITE(b))
+ {
+ Interval *p = palloc(sizeof(Interval));
+
+ p->day = INT_MAX;
+ p->month = INT_MAX;
+#ifdef HAVE_INT64_TIMESTAMP
+ p->time = INT64CONST(0x7FFFFFFFFFFFFFFF);
+#else
+ p->time = DBL_MAX;
+#endif
+ PG_RETURN_INTERVAL_P(p);
+ }
+ else
+
+ r = DatumGetIntervalP(DirectFunctionCall2(timestamp_mi,
+ PG_GETARG_DATUM(0),
+ PG_GETARG_DATUM(1)));
+ PG_RETURN_INTERVAL_P( abs_interval(r) );
+}
+
+PG_FUNCTION_INFO_V1(tstz_dist);
+Datum tstz_dist(PG_FUNCTION_ARGS);
+Datum
+tstz_dist(PG_FUNCTION_ARGS)
+{
+ TimestampTz a = PG_GETARG_TIMESTAMPTZ(0);
+ TimestampTz b = PG_GETARG_TIMESTAMPTZ(1);
+ Interval *r;
+
+ if (TIMESTAMP_NOT_FINITE(a) || TIMESTAMP_NOT_FINITE(b))
+ {
+ Interval *p = palloc(sizeof(Interval));
+
+ p->day = INT_MAX;
+ p->month = INT_MAX;
+#ifdef HAVE_INT64_TIMESTAMP
+ p->time = INT64CONST(0x7FFFFFFFFFFFFFFF);
+#else
+ p->time = DBL_MAX;
+#endif
+ PG_RETURN_INTERVAL_P(p);
+ }
+
+ r = DatumGetIntervalP(DirectFunctionCall2(timestamp_mi,
+ PG_GETARG_DATUM(0),
+ PG_GETARG_DATUM(1)));
+ PG_RETURN_INTERVAL_P( abs_interval(r) );
+}
+
+
/**************************************************
* timestamp ops
**************************************************/
@@ -213,6 +295,24 @@ gbt_ts_consistent(PG_FUNCTION_ARGS)
);
}
+Datum
+gbt_ts_distance(PG_FUNCTION_ARGS)
+{
+ GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+ Timestamp query = PG_GETARG_TIMESTAMP(1);
+
+ /* Oid subtype = PG_GETARG_OID(3); */
+ tsKEY *kkk = (tsKEY *) DatumGetPointer(entry->key);
+ GBT_NUMKEY_R key;
+
+ key.lower = (GBT_NUMKEY *) &kkk->lower;
+ key.upper = (GBT_NUMKEY *) &kkk->upper;
+
+ PG_RETURN_FLOAT8(
+ gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo)
+ );
+}
+
Datum
gbt_tstz_consistent(PG_FUNCTION_ARGS)
{
@@ -238,6 +338,26 @@ gbt_tstz_consistent(PG_FUNCTION_ARGS)
);
}
+Datum
+gbt_tstz_distance(PG_FUNCTION_ARGS)
+{
+ GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+ TimestampTz query = PG_GETARG_TIMESTAMPTZ(1);
+
+ /* Oid subtype = PG_GETARG_OID(3); */
+ char *kkk = (char *) DatumGetPointer(entry->key);
+ GBT_NUMKEY_R key;
+ Timestamp qqq;
+
+ key.lower = (GBT_NUMKEY *) &kkk[0];
+ key.upper = (GBT_NUMKEY *) &kkk[MAXALIGN(tinfo.size)];
+ qqq = tstz_to_ts_gmt(query);
+
+ PG_RETURN_FLOAT8(
+ gbt_num_distance(&key, (void *) &qqq, GIST_LEAF(entry), &tinfo)
+ );
+}
+
Datum
gbt_ts_union(PG_FUNCTION_ARGS)
diff --git a/contrib/btree_gist/btree_utils_num.c b/contrib/btree_gist/btree_utils_num.c
index 0df22f21338..17440a191b2 100644
--- a/contrib/btree_gist/btree_utils_num.c
+++ b/contrib/btree_gist/btree_utils_num.c
@@ -188,16 +188,13 @@ gbt_num_bin_union(Datum *u, GBT_NUMKEY *e, const gbtree_ninfo *tinfo)
*/
bool
-gbt_num_consistent(
- const GBT_NUMKEY_R *key,
+gbt_num_consistent(const GBT_NUMKEY_R *key,
const void *query,
const StrategyNumber *strategy,
bool is_leaf,
- const gbtree_ninfo *tinfo
-)
+ const gbtree_ninfo *tinfo)
{
-
- bool retval = FALSE;
+ bool retval;
switch (*strategy)
{
@@ -214,7 +211,7 @@ gbt_num_consistent(
if (is_leaf)
retval = (*tinfo->f_eq) (query, key->lower);
else
- retval = (*tinfo->f_le) (key->lower, query) && (*tinfo->f_le) (query, key->upper);
+ retval = ((*tinfo->f_le) (key->lower, query) && (*tinfo->f_le) (query, key->upper)) ? true : false;
break;
case BTGreaterStrategyNumber:
if (is_leaf)
@@ -226,17 +223,43 @@ gbt_num_consistent(
retval = (*tinfo->f_le) (query, key->upper);
break;
case BtreeGistNotEqualStrategyNumber:
- retval = ! ((*tinfo->f_eq) (query, key->lower) &&
- (*tinfo->f_eq) (query, key->upper));
+ retval = (! ((*tinfo->f_eq) (query, key->lower) &&
+ (*tinfo->f_eq) (query, key->upper))) ? true : false;
break;
default:
- retval = FALSE;
+ retval = false;
}
return (retval);
}
+/*
+** The GiST distance method (for KNN-Gist)
+*/
+
+float8
+gbt_num_distance(const GBT_NUMKEY_R *key,
+ const void *query,
+ bool is_leaf,
+ const gbtree_ninfo *tinfo)
+{
+ float8 retval;
+
+ if (tinfo->f_dist == NULL)
+ elog(ERROR, "KNN search is not supported for btree_gist type %d",
+ (int) tinfo->t);
+ if ( tinfo->f_le(query, key->lower) )
+ retval = tinfo->f_dist(query, key->lower);
+ else if ( tinfo->f_ge(query, key->upper) )
+ retval = tinfo->f_dist(query, key->upper);
+ else
+ retval = 0.0;
+
+ return retval;
+}
+
+
GIST_SPLITVEC *
gbt_num_picksplit(const GistEntryVector *entryvec, GIST_SPLITVEC *v,
const gbtree_ninfo *tinfo)
diff --git a/contrib/btree_gist/btree_utils_num.h b/contrib/btree_gist/btree_utils_num.h
index 091784bd5a1..243d3b5cb99 100644
--- a/contrib/btree_gist/btree_utils_num.h
+++ b/contrib/btree_gist/btree_utils_num.h
@@ -40,24 +40,25 @@ typedef struct
/* Methods */
- bool (*f_gt) (const void *, const void *); /* greater then */
- bool (*f_ge) (const void *, const void *); /* greater equal */
+ bool (*f_gt) (const void *, const void *); /* greater than */
+ bool (*f_ge) (const void *, const void *); /* greater or equal */
bool (*f_eq) (const void *, const void *); /* equal */
- bool (*f_le) (const void *, const void *); /* less equal */
- bool (*f_lt) (const void *, const void *); /* less then */
+ bool (*f_le) (const void *, const void *); /* less or equal */
+ bool (*f_lt) (const void *, const void *); /* less than */
int (*f_cmp) (const void *, const void *); /* key compare function */
+ float8 (*f_dist) (const void *, const void *); /* key distance function */
} gbtree_ninfo;
/*
* Numeric btree functions
-*/
+ */
/*
* Note: The factor 0.49 in following macro avoids floating point overflows
-*/
+ */
#define penalty_num(result,olower,oupper,nlower,nupper) do { \
double tmp = 0.0F; \
(*(result)) = 0.0F; \
@@ -91,11 +92,37 @@ typedef struct
(ivp)->month * (30.0 * SECS_PER_DAY))
#endif
+#define GET_FLOAT_DISTANCE(t, arg1, arg2) Abs( ((float8) *((const t *) (arg1))) - ((float8) *((const t *) (arg2))) )
+
+#define SAMESIGN(a,b) (((a) < 0) == ((b) < 0))
+
+/*
+ * check to see if a float4/8 val has underflowed or overflowed
+ * borrowed from src/backend/utils/adt/float.c
+ */
+#define CHECKFLOATVAL(val, inf_is_valid, zero_is_valid) \
+do { \
+ if (isinf(val) && !(inf_is_valid)) \
+ ereport(ERROR, \
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), \
+ errmsg("value out of range: overflow"))); \
+ \
+ if ((val) == 0.0 && !(zero_is_valid)) \
+ ereport(ERROR, \
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), \
+ errmsg("value out of range: underflow"))); \
+} while(0)
+
+
+extern Interval *abs_interval(Interval *a);
extern bool gbt_num_consistent(const GBT_NUMKEY_R *key, const void *query,
const StrategyNumber *strategy, bool is_leaf,
const gbtree_ninfo *tinfo);
+extern float8 gbt_num_distance(const GBT_NUMKEY_R *key, const void *query,
+ bool is_leaf, const gbtree_ninfo *tinfo);
+
extern GIST_SPLITVEC *gbt_num_picksplit(const GistEntryVector *entryvec, GIST_SPLITVEC *v,
const gbtree_ninfo *tinfo);
diff --git a/contrib/btree_gist/expected/cash.out b/contrib/btree_gist/expected/cash.out
index 2beb8cd92dc..a4100d844e7 100644
--- a/contrib/btree_gist/expected/cash.out
+++ b/contrib/btree_gist/expected/cash.out
@@ -32,6 +32,14 @@ SELECT count(*) FROM moneytmp WHERE a > '22649.64';
253
(1 row)
+SELECT a, a <-> '21472.79' FROM moneytmp ORDER BY a <-> '21472.79' LIMIT 3;
+ a | ?column?
+------------+----------
+ $21,472.79 | $0.00
+ $21,469.25 | $3.54
+ $21,915.01 | $442.22
+(3 rows)
+
CREATE INDEX moneyidx ON moneytmp USING gist ( a );
SET enable_seqscan=off;
SELECT count(*) FROM moneytmp WHERE a < '22649.64'::money;
@@ -64,3 +72,20 @@ SELECT count(*) FROM moneytmp WHERE a > '22649.64'::money;
253
(1 row)
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '21472.79' FROM moneytmp ORDER BY a <-> '21472.79' LIMIT 3;
+ QUERY PLAN
+-----------------------------------------------
+ Limit
+ -> Index Scan using moneyidx on moneytmp
+ Order By: (a <-> '$21,472.79'::money)
+(3 rows)
+
+SELECT a, a <-> '21472.79' FROM moneytmp ORDER BY a <-> '21472.79' LIMIT 3;
+ a | ?column?
+------------+----------
+ $21,472.79 | $0.00
+ $21,469.25 | $3.54
+ $21,915.01 | $442.22
+(3 rows)
+
diff --git a/contrib/btree_gist/expected/date.out b/contrib/btree_gist/expected/date.out
index f2082cf391a..4a360bea6d6 100644
--- a/contrib/btree_gist/expected/date.out
+++ b/contrib/btree_gist/expected/date.out
@@ -32,6 +32,14 @@ SELECT count(*) FROM datetmp WHERE a > '2001-02-13';
313
(1 row)
+SELECT a, a <-> '2001-02-13' FROM datetmp ORDER BY a <-> '2001-02-13' LIMIT 3;
+ a | ?column?
+------------+----------
+ 02-13-2001 | 0
+ 02-11-2001 | 2
+ 03-24-2001 | 39
+(3 rows)
+
CREATE INDEX dateidx ON datetmp USING gist ( a );
SET enable_seqscan=off;
SELECT count(*) FROM datetmp WHERE a < '2001-02-13'::date;
@@ -64,3 +72,20 @@ SELECT count(*) FROM datetmp WHERE a > '2001-02-13'::date;
313
(1 row)
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '2001-02-13' FROM datetmp ORDER BY a <-> '2001-02-13' LIMIT 3;
+ QUERY PLAN
+----------------------------------------------
+ Limit
+ -> Index Scan using dateidx on datetmp
+ Order By: (a <-> '02-13-2001'::date)
+(3 rows)
+
+SELECT a, a <-> '2001-02-13' FROM datetmp ORDER BY a <-> '2001-02-13' LIMIT 3;
+ a | ?column?
+------------+----------
+ 02-13-2001 | 0
+ 02-11-2001 | 2
+ 03-24-2001 | 39
+(3 rows)
+
diff --git a/contrib/btree_gist/expected/float4.out b/contrib/btree_gist/expected/float4.out
index c7f65c8d7fc..1695f7805a0 100644
--- a/contrib/btree_gist/expected/float4.out
+++ b/contrib/btree_gist/expected/float4.out
@@ -32,6 +32,14 @@ SELECT count(*) FROM float4tmp WHERE a > -179.0;
302
(1 row)
+SELECT a, a <-> '-179.0' FROM float4tmp ORDER BY a <-> '-179.0' LIMIT 3;
+ a | ?column?
+----------+----------
+ -179 | 0
+ -189.024 | 10.0239
+ -158.177 | 20.8226
+(3 rows)
+
CREATE INDEX float4idx ON float4tmp USING gist ( a );
SET enable_seqscan=off;
SELECT count(*) FROM float4tmp WHERE a < -179.0::float4;
@@ -64,3 +72,20 @@ SELECT count(*) FROM float4tmp WHERE a > -179.0::float4;
302
(1 row)
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '-179.0' FROM float4tmp ORDER BY a <-> '-179.0' LIMIT 3;
+ QUERY PLAN
+-----------------------------------------------
+ Limit
+ -> Index Scan using float4idx on float4tmp
+ Order By: (a <-> (-179)::real)
+(3 rows)
+
+SELECT a, a <-> '-179.0' FROM float4tmp ORDER BY a <-> '-179.0' LIMIT 3;
+ a | ?column?
+----------+----------
+ -179 | 0
+ -189.024 | 10.0239
+ -158.177 | 20.8226
+(3 rows)
+
diff --git a/contrib/btree_gist/expected/float8.out b/contrib/btree_gist/expected/float8.out
index 4598ac87a2c..7d2228b7973 100644
--- a/contrib/btree_gist/expected/float8.out
+++ b/contrib/btree_gist/expected/float8.out
@@ -32,6 +32,14 @@ SELECT count(*) FROM float8tmp WHERE a > -1890.0;
306
(1 row)
+SELECT a, a <-> '-1890.0' FROM float8tmp ORDER BY a <-> '-1890.0' LIMIT 3;
+ a | ?column?
+--------------+------------
+ -1890 | 0
+ -2003.634512 | 113.634512
+ -1769.73634 | 120.26366
+(3 rows)
+
CREATE INDEX float8idx ON float8tmp USING gist ( a );
SET enable_seqscan=off;
SELECT count(*) FROM float8tmp WHERE a < -1890.0::float8;
@@ -64,3 +72,20 @@ SELECT count(*) FROM float8tmp WHERE a > -1890.0::float8;
306
(1 row)
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '-1890.0' FROM float8tmp ORDER BY a <-> '-1890.0' LIMIT 3;
+ QUERY PLAN
+-----------------------------------------------------
+ Limit
+ -> Index Scan using float8idx on float8tmp
+ Order By: (a <-> (-1890)::double precision)
+(3 rows)
+
+SELECT a, a <-> '-1890.0' FROM float8tmp ORDER BY a <-> '-1890.0' LIMIT 3;
+ a | ?column?
+--------------+------------
+ -1890 | 0
+ -2003.634512 | 113.634512
+ -1769.73634 | 120.26366
+(3 rows)
+
diff --git a/contrib/btree_gist/expected/int2.out b/contrib/btree_gist/expected/int2.out
index a82819c26a1..b1cc3b14b25 100644
--- a/contrib/btree_gist/expected/int2.out
+++ b/contrib/btree_gist/expected/int2.out
@@ -32,6 +32,14 @@ SELECT count(*) FROM int2tmp WHERE a > 237;
248
(1 row)
+SELECT a, a <-> '237' FROM int2tmp ORDER BY a <-> '237' LIMIT 3;
+ a | ?column?
+-----+----------
+ 237 | 0
+ 232 | 5
+ 228 | 9
+(3 rows)
+
CREATE INDEX int2idx ON int2tmp USING gist ( a );
SET enable_seqscan=off;
SELECT count(*) FROM int2tmp WHERE a < 237::int2;
@@ -64,3 +72,20 @@ SELECT count(*) FROM int2tmp WHERE a > 237::int2;
248
(1 row)
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '237' FROM int2tmp ORDER BY a <-> '237' LIMIT 3;
+ QUERY PLAN
+-------------------------------------------
+ Limit
+ -> Index Scan using int2idx on int2tmp
+ Order By: (a <-> 237::smallint)
+(3 rows)
+
+SELECT a, a <-> '237' FROM int2tmp ORDER BY a <-> '237' LIMIT 3;
+ a | ?column?
+-----+----------
+ 237 | 0
+ 232 | 5
+ 228 | 9
+(3 rows)
+
diff --git a/contrib/btree_gist/expected/int4.out b/contrib/btree_gist/expected/int4.out
index d4ac0e15135..41bed1f6e34 100644
--- a/contrib/btree_gist/expected/int4.out
+++ b/contrib/btree_gist/expected/int4.out
@@ -32,6 +32,14 @@ SELECT count(*) FROM int4tmp WHERE a > 237;
248
(1 row)
+SELECT a, a <-> '237' FROM int4tmp ORDER BY a <-> '237' LIMIT 3;
+ a | ?column?
+-----+----------
+ 237 | 0
+ 232 | 5
+ 228 | 9
+(3 rows)
+
CREATE INDEX int4idx ON int4tmp USING gist ( a );
SET enable_seqscan=off;
SELECT count(*) FROM int4tmp WHERE a < 237::int4;
@@ -64,3 +72,20 @@ SELECT count(*) FROM int4tmp WHERE a > 237::int4;
248
(1 row)
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '237' FROM int4tmp ORDER BY a <-> '237' LIMIT 3;
+ QUERY PLAN
+-------------------------------------------
+ Limit
+ -> Index Scan using int4idx on int4tmp
+ Order By: (a <-> 237)
+(3 rows)
+
+SELECT a, a <-> '237' FROM int4tmp ORDER BY a <-> '237' LIMIT 3;
+ a | ?column?
+-----+----------
+ 237 | 0
+ 232 | 5
+ 228 | 9
+(3 rows)
+
diff --git a/contrib/btree_gist/expected/int8.out b/contrib/btree_gist/expected/int8.out
index 1da484525b5..ff0af4a5fb8 100644
--- a/contrib/btree_gist/expected/int8.out
+++ b/contrib/btree_gist/expected/int8.out
@@ -32,6 +32,14 @@ SELECT count(*) FROM int8tmp WHERE a > 464571291354841;
270
(1 row)
+SELECT a, a <-> '464571291354841' FROM int8tmp ORDER BY a <-> '464571291354841' LIMIT 3;
+ a | ?column?
+-----------------+----------------
+ 464571291354841 | 0
+ 457257666629329 | 7313624725512
+ 478227196042750 | 13655904687909
+(3 rows)
+
CREATE INDEX int8idx ON int8tmp USING gist ( a );
SET enable_seqscan=off;
SELECT count(*) FROM int8tmp WHERE a < 464571291354841::int8;
@@ -64,3 +72,20 @@ SELECT count(*) FROM int8tmp WHERE a > 464571291354841::int8;
270
(1 row)
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '464571291354841' FROM int8tmp ORDER BY a <-> '464571291354841' LIMIT 3;
+ QUERY PLAN
+---------------------------------------------------
+ Limit
+ -> Index Scan using int8idx on int8tmp
+ Order By: (a <-> 464571291354841::bigint)
+(3 rows)
+
+SELECT a, a <-> '464571291354841' FROM int8tmp ORDER BY a <-> '464571291354841' LIMIT 3;
+ a | ?column?
+-----------------+----------------
+ 464571291354841 | 0
+ 457257666629329 | 7313624725512
+ 478227196042750 | 13655904687909
+(3 rows)
+
diff --git a/contrib/btree_gist/expected/interval.out b/contrib/btree_gist/expected/interval.out
index 4c78e21346c..6955251a045 100644
--- a/contrib/btree_gist/expected/interval.out
+++ b/contrib/btree_gist/expected/interval.out
@@ -32,6 +32,14 @@ SELECT count(*) FROM intervaltmp WHERE a > '199 days 21:21:23';
270
(1 row)
+SELECT a, a <-> '199 days 21:21:23' FROM intervaltmp ORDER BY a <-> '199 days 21:21:23' LIMIT 3;
+ a | ?column?
+-------------------------------------+--------------------------------------
+ @ 199 days 21 hours 21 mins 23 secs | @ 0
+ @ 183 days 6 hours 52 mins 48 secs | @ 16 days 14 hours 28 mins 35 secs
+ @ 220 days 19 hours 5 mins 42 secs | @ 21 days -2 hours -15 mins -41 secs
+(3 rows)
+
CREATE INDEX intervalidx ON intervaltmp USING gist ( a );
SET enable_seqscan=off;
SELECT count(*) FROM intervaltmp WHERE a < '199 days 21:21:23'::interval;
@@ -64,3 +72,20 @@ SELECT count(*) FROM intervaltmp WHERE a > '199 days 21:21:23'::interval;
270
(1 row)
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '199 days 21:21:23' FROM intervaltmp ORDER BY a <-> '199 days 21:21:23' LIMIT 3;
+ QUERY PLAN
+---------------------------------------------------------------------------
+ Limit
+ -> Index Scan using intervalidx on intervaltmp
+ Order By: (a <-> '@ 199 days 21 hours 21 mins 23 secs'::interval)
+(3 rows)
+
+SELECT a, a <-> '199 days 21:21:23' FROM intervaltmp ORDER BY a <-> '199 days 21:21:23' LIMIT 3;
+ a | ?column?
+-------------------------------------+--------------------------------------
+ @ 199 days 21 hours 21 mins 23 secs | @ 0
+ @ 183 days 6 hours 52 mins 48 secs | @ 16 days 14 hours 28 mins 35 secs
+ @ 220 days 19 hours 5 mins 42 secs | @ 21 days -2 hours -15 mins -41 secs
+(3 rows)
+
diff --git a/contrib/btree_gist/expected/time.out b/contrib/btree_gist/expected/time.out
index 015a67f6a17..1b9da4e192a 100644
--- a/contrib/btree_gist/expected/time.out
+++ b/contrib/btree_gist/expected/time.out
@@ -32,6 +32,14 @@ SELECT count(*) FROM timetmp WHERE a > '10:57:11';
292
(1 row)
+SELECT a, a <-> '10:57:11' FROM timetmp ORDER BY a <-> '10:57:11' LIMIT 3;
+ a | ?column?
+----------+-----------------
+ 10:57:11 | @ 0
+ 10:57:10 | @ 1 sec
+ 10:55:32 | @ 1 min 39 secs
+(3 rows)
+
CREATE INDEX timeidx ON timetmp USING gist ( a );
SET enable_seqscan=off;
SELECT count(*) FROM timetmp WHERE a < '10:57:11'::time;
@@ -64,3 +72,20 @@ SELECT count(*) FROM timetmp WHERE a > '10:57:11'::time;
292
(1 row)
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '10:57:11' FROM timetmp ORDER BY a <-> '10:57:11' LIMIT 3;
+ QUERY PLAN
+--------------------------------------------------------------
+ Limit
+ -> Index Scan using timeidx on timetmp
+ Order By: (a <-> '10:57:11'::time without time zone)
+(3 rows)
+
+SELECT a, a <-> '10:57:11' FROM timetmp ORDER BY a <-> '10:57:11' LIMIT 3;
+ a | ?column?
+----------+-----------------
+ 10:57:11 | @ 0
+ 10:57:10 | @ 1 sec
+ 10:55:32 | @ 1 min 39 secs
+(3 rows)
+
diff --git a/contrib/btree_gist/expected/timestamp.out b/contrib/btree_gist/expected/timestamp.out
index dc53895ca21..cc3624f0843 100644
--- a/contrib/btree_gist/expected/timestamp.out
+++ b/contrib/btree_gist/expected/timestamp.out
@@ -32,6 +32,14 @@ SELECT count(*) FROM timestamptmp WHERE a > '2004-10-26 08:55:08';
289
(1 row)
+SELECT a, a <-> '2004-10-26 08:55:08' FROM timestamptmp ORDER BY a <-> '2004-10-26 08:55:08' LIMIT 3;
+ a | ?column?
+--------------------------+------------------------------------
+ Tue Oct 26 08:55:08 2004 | @ 0
+ Sun Oct 31 06:35:03 2004 | @ 4 days 21 hours 39 mins 55 secs
+ Mon Nov 29 20:12:43 2004 | @ 34 days 11 hours 17 mins 35 secs
+(3 rows)
+
CREATE INDEX timestampidx ON timestamptmp USING gist ( a );
SET enable_seqscan=off;
SELECT count(*) FROM timestamptmp WHERE a < '2004-10-26 08:55:08'::timestamp;
@@ -64,3 +72,20 @@ SELECT count(*) FROM timestamptmp WHERE a > '2004-10-26 08:55:08'::timestamp;
289
(1 row)
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '2004-10-26 08:55:08' FROM timestamptmp ORDER BY a <-> '2004-10-26 08:55:08' LIMIT 3;
+ QUERY PLAN
+-----------------------------------------------------------------------------------
+ Limit
+ -> Index Scan using timestampidx on timestamptmp
+ Order By: (a <-> 'Tue Oct 26 08:55:08 2004'::timestamp without time zone)
+(3 rows)
+
+SELECT a, a <-> '2004-10-26 08:55:08' FROM timestamptmp ORDER BY a <-> '2004-10-26 08:55:08' LIMIT 3;
+ a | ?column?
+--------------------------+------------------------------------
+ Tue Oct 26 08:55:08 2004 | @ 0
+ Sun Oct 31 06:35:03 2004 | @ 4 days 21 hours 39 mins 55 secs
+ Mon Nov 29 20:12:43 2004 | @ 34 days 11 hours 17 mins 35 secs
+(3 rows)
+
diff --git a/contrib/btree_gist/expected/timestamptz.out b/contrib/btree_gist/expected/timestamptz.out
index 391705f0dbe..88d2404c44b 100644
--- a/contrib/btree_gist/expected/timestamptz.out
+++ b/contrib/btree_gist/expected/timestamptz.out
@@ -92,6 +92,14 @@ SELECT count(*) FROM timestamptztmp WHERE a > '2018-12-18 10:59:54 GMT+4';
157
(1 row)
+SELECT a, a <-> '2018-12-18 10:59:54 GMT+2' FROM timestamptztmp ORDER BY a <-> '2018-12-18 10:59:54 GMT+2' LIMIT 3;
+ a | ?column?
+------------------------------+-----------------------------------
+ Tue Dec 18 05:59:54 2018 PST | @ 1 hour
+ Thu Jan 10 03:01:34 2019 PST | @ 22 days 22 hours 1 min 40 secs
+ Thu Jan 24 12:28:12 2019 PST | @ 37 days 7 hours 28 mins 18 secs
+(3 rows)
+
CREATE INDEX timestamptzidx ON timestamptztmp USING gist ( a );
SET enable_seqscan=off;
SELECT count(*) FROM timestamptztmp WHERE a < '2018-12-18 10:59:54 GMT+3'::timestamptz;
@@ -184,3 +192,20 @@ SELECT count(*) FROM timestamptztmp WHERE a > '2018-12-18 10:59:54 GMT+4'::time
157
(1 row)
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '2018-12-18 10:59:54 GMT+2' FROM timestamptztmp ORDER BY a <-> '2018-12-18 10:59:54 GMT+2' LIMIT 3;
+ QUERY PLAN
+------------------------------------------------------------------------------------
+ Limit
+ -> Index Scan using timestamptzidx on timestamptztmp
+ Order By: (a <-> 'Tue Dec 18 04:59:54 2018 PST'::timestamp with time zone)
+(3 rows)
+
+SELECT a, a <-> '2018-12-18 10:59:54 GMT+2' FROM timestamptztmp ORDER BY a <-> '2018-12-18 10:59:54 GMT+2' LIMIT 3;
+ a | ?column?
+------------------------------+-----------------------------------
+ Tue Dec 18 05:59:54 2018 PST | @ 1 hour
+ Thu Jan 10 03:01:34 2019 PST | @ 22 days 22 hours 1 min 40 secs
+ Thu Jan 24 12:28:12 2019 PST | @ 37 days 7 hours 28 mins 18 secs
+(3 rows)
+
diff --git a/contrib/btree_gist/sql/cash.sql b/contrib/btree_gist/sql/cash.sql
index 5313e8f6965..0e037984e1b 100644
--- a/contrib/btree_gist/sql/cash.sql
+++ b/contrib/btree_gist/sql/cash.sql
@@ -16,6 +16,8 @@ SELECT count(*) FROM moneytmp WHERE a >= '22649.64';
SELECT count(*) FROM moneytmp WHERE a > '22649.64';
+SELECT a, a <-> '21472.79' FROM moneytmp ORDER BY a <-> '21472.79' LIMIT 3;
+
CREATE INDEX moneyidx ON moneytmp USING gist ( a );
SET enable_seqscan=off;
@@ -29,3 +31,7 @@ SELECT count(*) FROM moneytmp WHERE a = '22649.64'::money;
SELECT count(*) FROM moneytmp WHERE a >= '22649.64'::money;
SELECT count(*) FROM moneytmp WHERE a > '22649.64'::money;
+
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '21472.79' FROM moneytmp ORDER BY a <-> '21472.79' LIMIT 3;
+SELECT a, a <-> '21472.79' FROM moneytmp ORDER BY a <-> '21472.79' LIMIT 3;
diff --git a/contrib/btree_gist/sql/date.sql b/contrib/btree_gist/sql/date.sql
index f3b8166a6f0..f969ef0a08c 100644
--- a/contrib/btree_gist/sql/date.sql
+++ b/contrib/btree_gist/sql/date.sql
@@ -16,6 +16,8 @@ SELECT count(*) FROM datetmp WHERE a >= '2001-02-13';
SELECT count(*) FROM datetmp WHERE a > '2001-02-13';
+SELECT a, a <-> '2001-02-13' FROM datetmp ORDER BY a <-> '2001-02-13' LIMIT 3;
+
CREATE INDEX dateidx ON datetmp USING gist ( a );
SET enable_seqscan=off;
@@ -29,3 +31,7 @@ SELECT count(*) FROM datetmp WHERE a = '2001-02-13'::date;
SELECT count(*) FROM datetmp WHERE a >= '2001-02-13'::date;
SELECT count(*) FROM datetmp WHERE a > '2001-02-13'::date;
+
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '2001-02-13' FROM datetmp ORDER BY a <-> '2001-02-13' LIMIT 3;
+SELECT a, a <-> '2001-02-13' FROM datetmp ORDER BY a <-> '2001-02-13' LIMIT 3;
diff --git a/contrib/btree_gist/sql/float4.sql b/contrib/btree_gist/sql/float4.sql
index fb4b726d223..3da1ce953c8 100644
--- a/contrib/btree_gist/sql/float4.sql
+++ b/contrib/btree_gist/sql/float4.sql
@@ -16,6 +16,8 @@ SELECT count(*) FROM float4tmp WHERE a >= -179.0;
SELECT count(*) FROM float4tmp WHERE a > -179.0;
+SELECT a, a <-> '-179.0' FROM float4tmp ORDER BY a <-> '-179.0' LIMIT 3;
+
CREATE INDEX float4idx ON float4tmp USING gist ( a );
SET enable_seqscan=off;
@@ -29,3 +31,7 @@ SELECT count(*) FROM float4tmp WHERE a = -179.0::float4;
SELECT count(*) FROM float4tmp WHERE a >= -179.0::float4;
SELECT count(*) FROM float4tmp WHERE a > -179.0::float4;
+
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '-179.0' FROM float4tmp ORDER BY a <-> '-179.0' LIMIT 3;
+SELECT a, a <-> '-179.0' FROM float4tmp ORDER BY a <-> '-179.0' LIMIT 3;
diff --git a/contrib/btree_gist/sql/float8.sql b/contrib/btree_gist/sql/float8.sql
index f8bd12efa13..e1e819b37f9 100644
--- a/contrib/btree_gist/sql/float8.sql
+++ b/contrib/btree_gist/sql/float8.sql
@@ -16,6 +16,8 @@ SELECT count(*) FROM float8tmp WHERE a >= -1890.0;
SELECT count(*) FROM float8tmp WHERE a > -1890.0;
+SELECT a, a <-> '-1890.0' FROM float8tmp ORDER BY a <-> '-1890.0' LIMIT 3;
+
CREATE INDEX float8idx ON float8tmp USING gist ( a );
SET enable_seqscan=off;
@@ -29,3 +31,7 @@ SELECT count(*) FROM float8tmp WHERE a = -1890.0::float8;
SELECT count(*) FROM float8tmp WHERE a >= -1890.0::float8;
SELECT count(*) FROM float8tmp WHERE a > -1890.0::float8;
+
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '-1890.0' FROM float8tmp ORDER BY a <-> '-1890.0' LIMIT 3;
+SELECT a, a <-> '-1890.0' FROM float8tmp ORDER BY a <-> '-1890.0' LIMIT 3;
diff --git a/contrib/btree_gist/sql/int2.sql b/contrib/btree_gist/sql/int2.sql
index 80ca6ac37cc..988518795fc 100644
--- a/contrib/btree_gist/sql/int2.sql
+++ b/contrib/btree_gist/sql/int2.sql
@@ -16,6 +16,8 @@ SELECT count(*) FROM int2tmp WHERE a >= 237;
SELECT count(*) FROM int2tmp WHERE a > 237;
+SELECT a, a <-> '237' FROM int2tmp ORDER BY a <-> '237' LIMIT 3;
+
CREATE INDEX int2idx ON int2tmp USING gist ( a );
SET enable_seqscan=off;
@@ -29,3 +31,7 @@ SELECT count(*) FROM int2tmp WHERE a = 237::int2;
SELECT count(*) FROM int2tmp WHERE a >= 237::int2;
SELECT count(*) FROM int2tmp WHERE a > 237::int2;
+
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '237' FROM int2tmp ORDER BY a <-> '237' LIMIT 3;
+SELECT a, a <-> '237' FROM int2tmp ORDER BY a <-> '237' LIMIT 3;
diff --git a/contrib/btree_gist/sql/int4.sql b/contrib/btree_gist/sql/int4.sql
index 31307d3610d..659ab5ee24b 100644
--- a/contrib/btree_gist/sql/int4.sql
+++ b/contrib/btree_gist/sql/int4.sql
@@ -16,6 +16,8 @@ SELECT count(*) FROM int4tmp WHERE a >= 237;
SELECT count(*) FROM int4tmp WHERE a > 237;
+SELECT a, a <-> '237' FROM int4tmp ORDER BY a <-> '237' LIMIT 3;
+
CREATE INDEX int4idx ON int4tmp USING gist ( a );
SET enable_seqscan=off;
@@ -29,3 +31,7 @@ SELECT count(*) FROM int4tmp WHERE a = 237::int4;
SELECT count(*) FROM int4tmp WHERE a >= 237::int4;
SELECT count(*) FROM int4tmp WHERE a > 237::int4;
+
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '237' FROM int4tmp ORDER BY a <-> '237' LIMIT 3;
+SELECT a, a <-> '237' FROM int4tmp ORDER BY a <-> '237' LIMIT 3;
diff --git a/contrib/btree_gist/sql/int8.sql b/contrib/btree_gist/sql/int8.sql
index 747bdca1ec9..51e55e9c14b 100644
--- a/contrib/btree_gist/sql/int8.sql
+++ b/contrib/btree_gist/sql/int8.sql
@@ -16,6 +16,8 @@ SELECT count(*) FROM int8tmp WHERE a >= 464571291354841;
SELECT count(*) FROM int8tmp WHERE a > 464571291354841;
+SELECT a, a <-> '464571291354841' FROM int8tmp ORDER BY a <-> '464571291354841' LIMIT 3;
+
CREATE INDEX int8idx ON int8tmp USING gist ( a );
SET enable_seqscan=off;
@@ -29,3 +31,7 @@ SELECT count(*) FROM int8tmp WHERE a = 464571291354841::int8;
SELECT count(*) FROM int8tmp WHERE a >= 464571291354841::int8;
SELECT count(*) FROM int8tmp WHERE a > 464571291354841::int8;
+
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '464571291354841' FROM int8tmp ORDER BY a <-> '464571291354841' LIMIT 3;
+SELECT a, a <-> '464571291354841' FROM int8tmp ORDER BY a <-> '464571291354841' LIMIT 3;
diff --git a/contrib/btree_gist/sql/interval.sql b/contrib/btree_gist/sql/interval.sql
index 561e3d92ff9..0f8b0315203 100644
--- a/contrib/btree_gist/sql/interval.sql
+++ b/contrib/btree_gist/sql/interval.sql
@@ -16,6 +16,8 @@ SELECT count(*) FROM intervaltmp WHERE a >= '199 days 21:21:23';
SELECT count(*) FROM intervaltmp WHERE a > '199 days 21:21:23';
+SELECT a, a <-> '199 days 21:21:23' FROM intervaltmp ORDER BY a <-> '199 days 21:21:23' LIMIT 3;
+
CREATE INDEX intervalidx ON intervaltmp USING gist ( a );
SET enable_seqscan=off;
@@ -29,3 +31,7 @@ SELECT count(*) FROM intervaltmp WHERE a = '199 days 21:21:23'::interval;
SELECT count(*) FROM intervaltmp WHERE a >= '199 days 21:21:23'::interval;
SELECT count(*) FROM intervaltmp WHERE a > '199 days 21:21:23'::interval;
+
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '199 days 21:21:23' FROM intervaltmp ORDER BY a <-> '199 days 21:21:23' LIMIT 3;
+SELECT a, a <-> '199 days 21:21:23' FROM intervaltmp ORDER BY a <-> '199 days 21:21:23' LIMIT 3;
diff --git a/contrib/btree_gist/sql/time.sql b/contrib/btree_gist/sql/time.sql
index 3329ee64da3..6104e7f61c8 100644
--- a/contrib/btree_gist/sql/time.sql
+++ b/contrib/btree_gist/sql/time.sql
@@ -16,6 +16,8 @@ SELECT count(*) FROM timetmp WHERE a >= '10:57:11';
SELECT count(*) FROM timetmp WHERE a > '10:57:11';
+SELECT a, a <-> '10:57:11' FROM timetmp ORDER BY a <-> '10:57:11' LIMIT 3;
+
CREATE INDEX timeidx ON timetmp USING gist ( a );
SET enable_seqscan=off;
@@ -29,3 +31,7 @@ SELECT count(*) FROM timetmp WHERE a = '10:57:11'::time;
SELECT count(*) FROM timetmp WHERE a >= '10:57:11'::time;
SELECT count(*) FROM timetmp WHERE a > '10:57:11'::time;
+
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '10:57:11' FROM timetmp ORDER BY a <-> '10:57:11' LIMIT 3;
+SELECT a, a <-> '10:57:11' FROM timetmp ORDER BY a <-> '10:57:11' LIMIT 3;
diff --git a/contrib/btree_gist/sql/timestamp.sql b/contrib/btree_gist/sql/timestamp.sql
index 25e942874eb..95effebfc47 100644
--- a/contrib/btree_gist/sql/timestamp.sql
+++ b/contrib/btree_gist/sql/timestamp.sql
@@ -16,6 +16,8 @@ SELECT count(*) FROM timestamptmp WHERE a >= '2004-10-26 08:55:08';
SELECT count(*) FROM timestamptmp WHERE a > '2004-10-26 08:55:08';
+SELECT a, a <-> '2004-10-26 08:55:08' FROM timestamptmp ORDER BY a <-> '2004-10-26 08:55:08' LIMIT 3;
+
CREATE INDEX timestampidx ON timestamptmp USING gist ( a );
SET enable_seqscan=off;
@@ -29,3 +31,7 @@ SELECT count(*) FROM timestamptmp WHERE a = '2004-10-26 08:55:08'::timestamp;
SELECT count(*) FROM timestamptmp WHERE a >= '2004-10-26 08:55:08'::timestamp;
SELECT count(*) FROM timestamptmp WHERE a > '2004-10-26 08:55:08'::timestamp;
+
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '2004-10-26 08:55:08' FROM timestamptmp ORDER BY a <-> '2004-10-26 08:55:08' LIMIT 3;
+SELECT a, a <-> '2004-10-26 08:55:08' FROM timestamptmp ORDER BY a <-> '2004-10-26 08:55:08' LIMIT 3;
diff --git a/contrib/btree_gist/sql/timestamptz.sql b/contrib/btree_gist/sql/timestamptz.sql
index 371233bc53a..f70caa4a649 100644
--- a/contrib/btree_gist/sql/timestamptz.sql
+++ b/contrib/btree_gist/sql/timestamptz.sql
@@ -37,7 +37,7 @@ SELECT count(*) FROM timestamptztmp WHERE a >= '2018-12-18 10:59:54 GMT+4';
SELECT count(*) FROM timestamptztmp WHERE a > '2018-12-18 10:59:54 GMT+4';
-
+SELECT a, a <-> '2018-12-18 10:59:54 GMT+2' FROM timestamptztmp ORDER BY a <-> '2018-12-18 10:59:54 GMT+2' LIMIT 3;
CREATE INDEX timestamptzidx ON timestamptztmp USING gist ( a );
@@ -74,3 +74,7 @@ SELECT count(*) FROM timestamptztmp WHERE a = '2018-12-18 10:59:54 GMT+4'::time
SELECT count(*) FROM timestamptztmp WHERE a >= '2018-12-18 10:59:54 GMT+4'::timestamptz;
SELECT count(*) FROM timestamptztmp WHERE a > '2018-12-18 10:59:54 GMT+4'::timestamptz;
+
+EXPLAIN (COSTS OFF)
+SELECT a, a <-> '2018-12-18 10:59:54 GMT+2' FROM timestamptztmp ORDER BY a <-> '2018-12-18 10:59:54 GMT+2' LIMIT 3;
+SELECT a, a <-> '2018-12-18 10:59:54 GMT+2' FROM timestamptztmp ORDER BY a <-> '2018-12-18 10:59:54 GMT+2' LIMIT 3;
diff --git a/doc/src/sgml/btree-gist.sgml b/doc/src/sgml/btree-gist.sgml
index 931acda95f9..af3f707bb9c 100644
--- a/doc/src/sgml/btree-gist.sgml
+++ b/doc/src/sgml/btree-gist.sgml
@@ -8,7 +8,7 @@
- btree_gist> provides sample GiST operator classes that
+ btree_gist> provides GiST index operator classes that
implement B-tree equivalent behavior for the data types
int2>, int4>, int8>, float4>,
float8>, numeric>, timestamp with time zone>,
@@ -23,18 +23,34 @@
In general, these operator classes will not outperform the equivalent
standard B-tree index methods, and they lack one major feature of the
standard B-tree code: the ability to enforce uniqueness. However,
- they are useful for GiST testing and as a base for developing other
- GiST operator classes.
+ they provide some other features that are not available with a B-tree
+ index, as described below. Also, these operator classes are useful
+ when a multi-column GiST index is needed, wherein some of the columns
+ are of data types that are only indexable with GiST but other columns
+ are just simple data types. Lastly, these operator classes are useful for
+ GiST testing and as a base for developing other GiST operator classes.
- In addition to the typical btree search operators, btree_gist also
- provides search operators for <> (not
+ In addition to the typical B-tree search operators, btree_gist>
+ also provides index support for <> (not
equals
). This may be useful in combination with an
exclusion constraint,
as described below.
+
+ Also, for data types for which there is a natural distance metric,
+ btree_gist> defines a distance operator <->>,
+ and provides GiST index support for nearest-neighbor searches using
+ this operator. Distance operators are provided for
+ int2>, int4>, int8>, float4>,
+ float8>, timestamp with time zone>,
+ timestamp without time zone>,
+ time without time zone>, date>, interval>,
+ oid>, and money>.
+
+
Example Usage
@@ -48,6 +64,8 @@ CREATE TABLE test (a int4);
CREATE INDEX testidx ON test USING gist (a);
-- query
SELECT * FROM test WHERE a < 10;
+-- nearest-neighbor search: find the ten entries closest to "42"
+SELECT *, a <-> 42 AS dist FROM test ORDER BY a <-> 42 LIMIT 10;