Add KNNGIST support to contrib/btree_gist.

This extends GiST's support for nearest-neighbor searches to many of the
standard data types.

Teodor Sigaev
This commit is contained in:
Tom Lane 2011-03-02 14:43:24 -05:00
parent 6094c242d1
commit 8436489c81
40 changed files with 1546 additions and 59 deletions

View File

@ -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)
{

View File

@ -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)
{

View File

@ -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)
{

View File

@ -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)
{

View File

@ -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) ;
--

View File

@ -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) ;

View File

@ -84,7 +84,8 @@ static const gbtree_ninfo tinfo =
gbt_ineteq,
gbt_inetle,
gbt_inetlt,
gbt_inetkey_cmp
gbt_inetkey_cmp,
NULL
};

View File

@ -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)
{

View File

@ -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)
{

View File

@ -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)
{

View File

@ -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)
{

View File

@ -84,7 +84,8 @@ static const gbtree_ninfo tinfo =
gbt_macadeq,
gbt_macadle,
gbt_macadlt,
gbt_macadkey_cmp
gbt_macadkey_cmp,
NULL
};

View File

@ -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)
{

View File

@ -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)
{

View File

@ -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)

View File

@ -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)

View File

@ -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);

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -8,7 +8,7 @@
</indexterm>
<para>
<filename>btree_gist</> provides sample GiST operator classes that
<filename>btree_gist</> provides GiST index operator classes that
implement B-tree equivalent behavior for the data types
<type>int2</>, <type>int4</>, <type>int8</>, <type>float4</>,
<type>float8</>, <type>numeric</>, <type>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.
</para>
<para>
In addition to the typical btree search operators, btree_gist also
provides search operators for <literal>&lt;&gt;</literal> (<quote>not
In addition to the typical B-tree search operators, <filename>btree_gist</>
also provides index support for <literal>&lt;&gt;</literal> (<quote>not
equals</quote>). This may be useful in combination with an
<link linkend="SQL-CREATETABLE-EXCLUDE">exclusion constraint</link>,
as described below.
</para>
<para>
Also, for data types for which there is a natural distance metric,
<filename>btree_gist</> defines a distance operator <literal>&lt;-&gt;</>,
and provides GiST index support for nearest-neighbor searches using
this operator. Distance operators are provided for
<type>int2</>, <type>int4</>, <type>int8</>, <type>float4</>,
<type>float8</>, <type>timestamp with time zone</>,
<type>timestamp without time zone</>,
<type>time without time zone</>, <type>date</>, <type>interval</>,
<type>oid</>, and <type>money</>.
</para>
<sect2>
<title>Example Usage</title>
@ -48,6 +64,8 @@ CREATE TABLE test (a int4);
CREATE INDEX testidx ON test USING gist (a);
-- query
SELECT * FROM test WHERE a &lt; 10;
-- nearest-neighbor search: find the ten entries closest to "42"
SELECT *, a &lt;-&gt; 42 AS dist FROM test ORDER BY a &lt;-&gt; 42 LIMIT 10;
</programlisting>
<para>