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);
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);
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 =
{
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
**************************************************/
}
+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)
{
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);
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);
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 =
{
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
**************************************************/
}
+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)
{
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);
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);
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 =
{
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
**************************************************/
}
+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)
{
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);
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);
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 =
{
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
**************************************************/
}
+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)
{
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 = '<->'
+);
--
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'
-- 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) ;
--
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'
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) ;
--
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'
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) ;
--
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'
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) ;
--
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'
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) ;
--
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'
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) ;
--
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'
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
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) ;
--
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'
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
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'
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) ;
--
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'
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) ;
--
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'
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) ;
--
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) ;
gbt_ineteq,
gbt_inetle,
gbt_inetlt,
- gbt_inetkey_cmp
+ gbt_inetkey_cmp,
+ NULL
};
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);
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);
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 =
{
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);
+}
/**************************************************
}
+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)
{
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);
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);
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 =
{
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
**************************************************/
}
+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)
{
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);
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);
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 =
{
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
**************************************************/
}
+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)
{
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);
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);
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
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
**************************************************/
}
+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)
{
gbt_macadeq,
gbt_macadle,
gbt_macadlt,
- gbt_macadkey_cmp
+ gbt_macadkey_cmp,
+ NULL
};
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);
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);
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 =
{
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
**************************************************/
}
+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)
{
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);
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);
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 =
{
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
**************************************************/
);
}
+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)
{
*/
#include "btree_gist.h"
#include "btree_utils_num.h"
+#include "utils/builtins.h"
#include "utils/datetime.h"
typedef struct
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);
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);
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 =
{
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
**************************************************/
);
}
+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)
{
);
}
+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)
*/
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)
{
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)
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)
/* 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; \
(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);
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;
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)
+
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;
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)
+
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;
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)
+
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;
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)
+
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;
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)
+
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;
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)
+
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;
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)
+
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;
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)
+
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;
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)
+
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;
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)
+
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;
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)
+
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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 );
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;
</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</>,
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><></literal> (<quote>not
+ In addition to the typical B-tree search operators, <filename>btree_gist</>
+ also provides index support for <literal><></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><-></>,
+ 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>
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;
</programlisting>
<para>