diff --git a/contrib/btree_gist/btree_cash.c b/contrib/btree_gist/btree_cash.c index bfda21b058c4933ec90dc6ac7d06bca8de2fd6ad..7938a70f17a120c1e181df0804b558b6608bef22 100644 --- a/contrib/btree_gist/btree_cash.c +++ b/contrib/btree_gist/btree_cash.c @@ -18,6 +18,7 @@ PG_FUNCTION_INFO_V1(gbt_cash_compress); PG_FUNCTION_INFO_V1(gbt_cash_union); PG_FUNCTION_INFO_V1(gbt_cash_picksplit); PG_FUNCTION_INFO_V1(gbt_cash_consistent); +PG_FUNCTION_INFO_V1(gbt_cash_distance); PG_FUNCTION_INFO_V1(gbt_cash_penalty); PG_FUNCTION_INFO_V1(gbt_cash_same); @@ -25,6 +26,7 @@ Datum gbt_cash_compress(PG_FUNCTION_ARGS); Datum gbt_cash_union(PG_FUNCTION_ARGS); Datum gbt_cash_picksplit(PG_FUNCTION_ARGS); Datum gbt_cash_consistent(PG_FUNCTION_ARGS); +Datum gbt_cash_distance(PG_FUNCTION_ARGS); Datum gbt_cash_penalty(PG_FUNCTION_ARGS); Datum gbt_cash_same(PG_FUNCTION_ARGS); @@ -71,6 +73,12 @@ gbt_cashkey_cmp(const void *a, const void *b) return (ia->lower > ib->lower) ? 1 : -1; } +static float8 +gbt_cash_dist(const void *a, const void *b) +{ + return GET_FLOAT_DISTANCE(Cash, a, b); +} + static const gbtree_ninfo tinfo = { @@ -81,10 +89,33 @@ static const gbtree_ninfo tinfo = gbt_casheq, gbt_cashle, gbt_cashlt, - gbt_cashkey_cmp + gbt_cashkey_cmp, + gbt_cash_dist }; +PG_FUNCTION_INFO_V1(cash_dist); +Datum cash_dist(PG_FUNCTION_ARGS); +Datum +cash_dist(PG_FUNCTION_ARGS) +{ + Cash a = PG_GETARG_CASH(0); + Cash b = PG_GETARG_CASH(1); + Cash r; + Cash ra; + + r = a - b; + ra = Abs(r); + + /* Overflow check. */ + if (ra < 0 || (!SAMESIGN(a, b) && !SAMESIGN(r, a))) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("money out of range"))); + + PG_RETURN_CASH(ra); +} + /************************************************** * Cash ops **************************************************/ @@ -124,6 +155,25 @@ gbt_cash_consistent(PG_FUNCTION_ARGS) } +Datum +gbt_cash_distance(PG_FUNCTION_ARGS) +{ + GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); + Cash query = PG_GETARG_CASH(1); + + /* Oid subtype = PG_GETARG_OID(3); */ + cashKEY *kkk = (cashKEY *) DatumGetPointer(entry->key); + GBT_NUMKEY_R key; + + key.lower = (GBT_NUMKEY *) &kkk->lower; + key.upper = (GBT_NUMKEY *) &kkk->upper; + + PG_RETURN_FLOAT8( + gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo) + ); +} + + Datum gbt_cash_union(PG_FUNCTION_ARGS) { diff --git a/contrib/btree_gist/btree_date.c b/contrib/btree_gist/btree_date.c index 11904af2573f5f05ab416b5efaa0fa0e3424b459..ccd7e2ad3f383a3fef458454b3bbe5a05fb1cca7 100644 --- a/contrib/btree_gist/btree_date.c +++ b/contrib/btree_gist/btree_date.c @@ -18,6 +18,7 @@ PG_FUNCTION_INFO_V1(gbt_date_compress); PG_FUNCTION_INFO_V1(gbt_date_union); PG_FUNCTION_INFO_V1(gbt_date_picksplit); PG_FUNCTION_INFO_V1(gbt_date_consistent); +PG_FUNCTION_INFO_V1(gbt_date_distance); PG_FUNCTION_INFO_V1(gbt_date_penalty); PG_FUNCTION_INFO_V1(gbt_date_same); @@ -25,6 +26,7 @@ Datum gbt_date_compress(PG_FUNCTION_ARGS); Datum gbt_date_union(PG_FUNCTION_ARGS); Datum gbt_date_picksplit(PG_FUNCTION_ARGS); Datum gbt_date_consistent(PG_FUNCTION_ARGS); +Datum gbt_date_distance(PG_FUNCTION_ARGS); Datum gbt_date_penalty(PG_FUNCTION_ARGS); Datum gbt_date_same(PG_FUNCTION_ARGS); @@ -84,6 +86,17 @@ gbt_datekey_cmp(const void *a, const void *b) return res; } +static float8 +gdb_date_dist(const void *a, const void *b) +{ + /* we assume the difference can't overflow */ + Datum diff = DirectFunctionCall2(date_mi, + DateADTGetDatum(*((const DateADT *) a)), + DateADTGetDatum(*((const DateADT *) b))); + + return (float8) Abs(DatumGetInt32(diff)); +} + static const gbtree_ninfo tinfo = { @@ -94,10 +107,25 @@ static const gbtree_ninfo tinfo = gbt_dateeq, gbt_datele, gbt_datelt, - gbt_datekey_cmp + gbt_datekey_cmp, + gdb_date_dist }; +PG_FUNCTION_INFO_V1(date_dist); +Datum date_dist(PG_FUNCTION_ARGS); +Datum +date_dist(PG_FUNCTION_ARGS) +{ + /* we assume the difference can't overflow */ + Datum diff = DirectFunctionCall2(date_mi, + PG_GETARG_DATUM(0), + PG_GETARG_DATUM(1)); + + PG_RETURN_INT32(Abs(DatumGetInt32(diff))); +} + + /************************************************** * date ops **************************************************/ @@ -139,6 +167,25 @@ gbt_date_consistent(PG_FUNCTION_ARGS) } +Datum +gbt_date_distance(PG_FUNCTION_ARGS) +{ + GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); + DateADT query = PG_GETARG_DATEADT(1); + + /* Oid subtype = PG_GETARG_OID(3); */ + dateKEY *kkk = (dateKEY *) DatumGetPointer(entry->key); + GBT_NUMKEY_R key; + + key.lower = (GBT_NUMKEY *) &kkk->lower; + key.upper = (GBT_NUMKEY *) &kkk->upper; + + PG_RETURN_FLOAT8( + gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo) + ); +} + + Datum gbt_date_union(PG_FUNCTION_ARGS) { diff --git a/contrib/btree_gist/btree_float4.c b/contrib/btree_gist/btree_float4.c index 4cfeddfc6870e43e88a04fbd90bb60881c4625a6..932a941f889e4b9d3e91fd4f58ad7654221c7187 100644 --- a/contrib/btree_gist/btree_float4.c +++ b/contrib/btree_gist/btree_float4.c @@ -17,6 +17,7 @@ PG_FUNCTION_INFO_V1(gbt_float4_compress); PG_FUNCTION_INFO_V1(gbt_float4_union); PG_FUNCTION_INFO_V1(gbt_float4_picksplit); PG_FUNCTION_INFO_V1(gbt_float4_consistent); +PG_FUNCTION_INFO_V1(gbt_float4_distance); PG_FUNCTION_INFO_V1(gbt_float4_penalty); PG_FUNCTION_INFO_V1(gbt_float4_same); @@ -24,6 +25,7 @@ Datum gbt_float4_compress(PG_FUNCTION_ARGS); Datum gbt_float4_union(PG_FUNCTION_ARGS); Datum gbt_float4_picksplit(PG_FUNCTION_ARGS); Datum gbt_float4_consistent(PG_FUNCTION_ARGS); +Datum gbt_float4_distance(PG_FUNCTION_ARGS); Datum gbt_float4_penalty(PG_FUNCTION_ARGS); Datum gbt_float4_same(PG_FUNCTION_ARGS); @@ -70,6 +72,12 @@ gbt_float4key_cmp(const void *a, const void *b) return (ia->lower > ib->lower) ? 1 : -1; } +static float8 +gbt_float4_dist(const void *a, const void *b) +{ + return GET_FLOAT_DISTANCE(float4, a, b); +} + static const gbtree_ninfo tinfo = { @@ -80,10 +88,27 @@ static const gbtree_ninfo tinfo = gbt_float4eq, gbt_float4le, gbt_float4lt, - gbt_float4key_cmp + gbt_float4key_cmp, + gbt_float4_dist }; +PG_FUNCTION_INFO_V1(float4_dist); +Datum float4_dist(PG_FUNCTION_ARGS); +Datum +float4_dist(PG_FUNCTION_ARGS) +{ + float4 a = PG_GETARG_FLOAT4(0); + float4 b = PG_GETARG_FLOAT4(1); + float4 r; + + r = a - b; + CHECKFLOATVAL(r, isinf(a) || isinf(b), true); + + PG_RETURN_FLOAT4( Abs(r) ); +} + + /************************************************** * float4 ops **************************************************/ @@ -123,6 +148,25 @@ gbt_float4_consistent(PG_FUNCTION_ARGS) } +Datum +gbt_float4_distance(PG_FUNCTION_ARGS) +{ + GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); + float4 query = PG_GETARG_FLOAT4(1); + + /* Oid subtype = PG_GETARG_OID(3); */ + float4KEY *kkk = (float4KEY *) DatumGetPointer(entry->key); + GBT_NUMKEY_R key; + + key.lower = (GBT_NUMKEY *) &kkk->lower; + key.upper = (GBT_NUMKEY *) &kkk->upper; + + PG_RETURN_FLOAT8( + gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo) + ); +} + + Datum gbt_float4_union(PG_FUNCTION_ARGS) { diff --git a/contrib/btree_gist/btree_float8.c b/contrib/btree_gist/btree_float8.c index 1386983272c6647e01bce75e1241f52a028dfa07..0c39980ba1e0ee456c05a0d7644364b5b11bd8b2 100644 --- a/contrib/btree_gist/btree_float8.c +++ b/contrib/btree_gist/btree_float8.c @@ -17,6 +17,7 @@ PG_FUNCTION_INFO_V1(gbt_float8_compress); PG_FUNCTION_INFO_V1(gbt_float8_union); PG_FUNCTION_INFO_V1(gbt_float8_picksplit); PG_FUNCTION_INFO_V1(gbt_float8_consistent); +PG_FUNCTION_INFO_V1(gbt_float8_distance); PG_FUNCTION_INFO_V1(gbt_float8_penalty); PG_FUNCTION_INFO_V1(gbt_float8_same); @@ -24,6 +25,7 @@ Datum gbt_float8_compress(PG_FUNCTION_ARGS); Datum gbt_float8_union(PG_FUNCTION_ARGS); Datum gbt_float8_picksplit(PG_FUNCTION_ARGS); Datum gbt_float8_consistent(PG_FUNCTION_ARGS); +Datum gbt_float8_distance(PG_FUNCTION_ARGS); Datum gbt_float8_penalty(PG_FUNCTION_ARGS); Datum gbt_float8_same(PG_FUNCTION_ARGS); @@ -71,6 +73,19 @@ gbt_float8key_cmp(const void *a, const void *b) return (ia->lower > ib->lower) ? 1 : -1; } +static float8 +gbt_float8_dist(const void *a, const void *b) +{ + float8 arg1 = *(const float8 *)a; + float8 arg2 = *(const float8 *)b; + float8 r; + + r = arg1 - arg2; + CHECKFLOATVAL(r, isinf(arg1) || isinf(arg2), true); + + return Abs(r); +} + static const gbtree_ninfo tinfo = { @@ -81,10 +96,26 @@ static const gbtree_ninfo tinfo = gbt_float8eq, gbt_float8le, gbt_float8lt, - gbt_float8key_cmp + gbt_float8key_cmp, + gbt_float8_dist }; +PG_FUNCTION_INFO_V1(float8_dist); +Datum float8_dist(PG_FUNCTION_ARGS); +Datum +float8_dist(PG_FUNCTION_ARGS) +{ + float8 a = PG_GETARG_FLOAT8(0); + float8 b = PG_GETARG_FLOAT8(1); + float8 r; + + r = a - b; + CHECKFLOATVAL(r, isinf(a) || isinf(b), true); + + PG_RETURN_FLOAT8( Abs(r) ); +} + /************************************************** * float8 ops **************************************************/ @@ -124,6 +155,25 @@ gbt_float8_consistent(PG_FUNCTION_ARGS) } +Datum +gbt_float8_distance(PG_FUNCTION_ARGS) +{ + GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); + float8 query = PG_GETARG_FLOAT8(1); + + /* Oid subtype = PG_GETARG_OID(3); */ + float8KEY *kkk = (float8KEY *) DatumGetPointer(entry->key); + GBT_NUMKEY_R key; + + key.lower = (GBT_NUMKEY *) &kkk->lower; + key.upper = (GBT_NUMKEY *) &kkk->upper; + + PG_RETURN_FLOAT8( + gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo) + ); +} + + Datum gbt_float8_union(PG_FUNCTION_ARGS) { diff --git a/contrib/btree_gist/btree_gist--1.0.sql b/contrib/btree_gist/btree_gist--1.0.sql index 1ea5fa2db418d06f991f362a956fec07ccfba9e9..dd428995c185a09519ed65433081752b83b71bb7 100644 --- a/contrib/btree_gist/btree_gist--1.0.sql +++ b/contrib/btree_gist/btree_gist--1.0.sql @@ -81,6 +81,151 @@ CREATE TYPE gbtreekey_var ( STORAGE = EXTENDED ); +--distance operators + +CREATE FUNCTION cash_dist(money, money) +RETURNS money +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR <-> ( + LEFTARG = money, + RIGHTARG = money, + PROCEDURE = cash_dist, + COMMUTATOR = '<->' +); + +CREATE FUNCTION date_dist(date, date) +RETURNS int4 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR <-> ( + LEFTARG = date, + RIGHTARG = date, + PROCEDURE = date_dist, + COMMUTATOR = '<->' +); + +CREATE FUNCTION float4_dist(float4, float4) +RETURNS float4 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR <-> ( + LEFTARG = float4, + RIGHTARG = float4, + PROCEDURE = float4_dist, + COMMUTATOR = '<->' +); + +CREATE FUNCTION float8_dist(float8, float8) +RETURNS float8 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR <-> ( + LEFTARG = float8, + RIGHTARG = float8, + PROCEDURE = float8_dist, + COMMUTATOR = '<->' +); + +CREATE FUNCTION int2_dist(int2, int2) +RETURNS int2 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR <-> ( + LEFTARG = int2, + RIGHTARG = int2, + PROCEDURE = int2_dist, + COMMUTATOR = '<->' +); + +CREATE FUNCTION int4_dist(int4, int4) +RETURNS int4 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR <-> ( + LEFTARG = int4, + RIGHTARG = int4, + PROCEDURE = int4_dist, + COMMUTATOR = '<->' +); + +CREATE FUNCTION int8_dist(int8, int8) +RETURNS int8 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR <-> ( + LEFTARG = int8, + RIGHTARG = int8, + PROCEDURE = int8_dist, + COMMUTATOR = '<->' +); + +CREATE FUNCTION interval_dist(interval, interval) +RETURNS interval +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR <-> ( + LEFTARG = interval, + RIGHTARG = interval, + PROCEDURE = interval_dist, + COMMUTATOR = '<->' +); + +CREATE FUNCTION oid_dist(oid, oid) +RETURNS oid +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR <-> ( + LEFTARG = oid, + RIGHTARG = oid, + PROCEDURE = oid_dist, + COMMUTATOR = '<->' +); + +CREATE FUNCTION time_dist(time, time) +RETURNS interval +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR <-> ( + LEFTARG = time, + RIGHTARG = time, + PROCEDURE = time_dist, + COMMUTATOR = '<->' +); + +CREATE FUNCTION ts_dist(timestamp, timestamp) +RETURNS interval +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR <-> ( + LEFTARG = timestamp, + RIGHTARG = timestamp, + PROCEDURE = ts_dist, + COMMUTATOR = '<->' +); + +CREATE FUNCTION tstz_dist(timestamptz, timestamptz) +RETURNS interval +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR <-> ( + LEFTARG = timestamptz, + RIGHTARG = timestamptz, + PROCEDURE = tstz_dist, + COMMUTATOR = '<->' +); -- @@ -96,6 +241,11 @@ RETURNS bool AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT; +CREATE FUNCTION gbt_oid_distance(internal,oid,int2,oid) +RETURNS float8 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + CREATE FUNCTION gbt_oid_compress(internal) RETURNS internal AS 'MODULE_PATHNAME' @@ -154,7 +304,9 @@ AS -- that's the only state that can be reproduced during an upgrade from 9.0. ALTER OPERATOR FAMILY gist_oid_ops USING gist ADD - OPERATOR 6 <> (oid, oid) ; + OPERATOR 6 <> (oid, oid) , + OPERATOR 15 <-> (oid, oid) FOR ORDER BY pg_catalog.oid_ops , + FUNCTION 8 (oid, oid) gbt_oid_distance (internal, oid, int2, oid) ; -- @@ -170,6 +322,11 @@ RETURNS bool AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT; +CREATE FUNCTION gbt_int2_distance(internal,int2,int2,oid) +RETURNS float8 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + CREATE FUNCTION gbt_int2_compress(internal) RETURNS internal AS 'MODULE_PATHNAME' @@ -214,7 +371,9 @@ AS STORAGE gbtreekey4; ALTER OPERATOR FAMILY gist_int2_ops USING gist ADD - OPERATOR 6 <> (int2, int2) ; + OPERATOR 6 <> (int2, int2) , + OPERATOR 15 <-> (int2, int2) FOR ORDER BY pg_catalog.integer_ops , + FUNCTION 8 (int2, int2) gbt_int2_distance (internal, int2, int2, oid) ; -- @@ -230,6 +389,11 @@ RETURNS bool AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT; +CREATE FUNCTION gbt_int4_distance(internal,int4,int2,oid) +RETURNS float8 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + CREATE FUNCTION gbt_int4_compress(internal) RETURNS internal AS 'MODULE_PATHNAME' @@ -274,7 +438,9 @@ AS STORAGE gbtreekey8; ALTER OPERATOR FAMILY gist_int4_ops USING gist ADD - OPERATOR 6 <> (int4, int4) ; + OPERATOR 6 <> (int4, int4) , + OPERATOR 15 <-> (int4, int4) FOR ORDER BY pg_catalog.integer_ops , + FUNCTION 8 (int4, int4) gbt_int4_distance (internal, int4, int2, oid) ; -- @@ -290,6 +456,11 @@ RETURNS bool AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT; +CREATE FUNCTION gbt_int8_distance(internal,int8,int2,oid) +RETURNS float8 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + CREATE FUNCTION gbt_int8_compress(internal) RETURNS internal AS 'MODULE_PATHNAME' @@ -334,7 +505,9 @@ AS STORAGE gbtreekey16; ALTER OPERATOR FAMILY gist_int8_ops USING gist ADD - OPERATOR 6 <> (int8, int8) ; + OPERATOR 6 <> (int8, int8) , + OPERATOR 15 <-> (int8, int8) FOR ORDER BY pg_catalog.integer_ops , + FUNCTION 8 (int8, int8) gbt_int8_distance (internal, int8, int2, oid) ; -- @@ -350,6 +523,11 @@ RETURNS bool AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT; +CREATE FUNCTION gbt_float4_distance(internal,float4,int2,oid) +RETURNS float8 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + CREATE FUNCTION gbt_float4_compress(internal) RETURNS internal AS 'MODULE_PATHNAME' @@ -394,7 +572,9 @@ AS STORAGE gbtreekey8; ALTER OPERATOR FAMILY gist_float4_ops USING gist ADD - OPERATOR 6 <> (float4, float4) ; + OPERATOR 6 <> (float4, float4) , + OPERATOR 15 <-> (float4, float4) FOR ORDER BY pg_catalog.float_ops , + FUNCTION 8 (float4, float4) gbt_float4_distance (internal, float4, int2, oid) ; -- @@ -410,6 +590,11 @@ RETURNS bool AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT; +CREATE FUNCTION gbt_float8_distance(internal,float8,int2,oid) +RETURNS float8 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + CREATE FUNCTION gbt_float8_compress(internal) RETURNS internal AS 'MODULE_PATHNAME' @@ -454,7 +639,9 @@ AS STORAGE gbtreekey16; ALTER OPERATOR FAMILY gist_float8_ops USING gist ADD - OPERATOR 6 <> (float8, float8) ; + OPERATOR 6 <> (float8, float8) , + OPERATOR 15 <-> (float8, float8) FOR ORDER BY pg_catalog.float_ops , + FUNCTION 8 (float8, float8) gbt_float8_distance (internal, float8, int2, oid) ; -- @@ -470,11 +657,21 @@ RETURNS bool AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT; +CREATE FUNCTION gbt_ts_distance(internal,timestamp,int2,oid) +RETURNS float8 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + CREATE FUNCTION gbt_tstz_consistent(internal,timestamptz,int2,oid,internal) RETURNS bool AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT; +CREATE FUNCTION gbt_tstz_distance(internal,timestamptz,int2,oid) +RETURNS float8 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + CREATE FUNCTION gbt_ts_compress(internal) RETURNS internal AS 'MODULE_PATHNAME' @@ -524,7 +721,9 @@ AS STORAGE gbtreekey16; ALTER OPERATOR FAMILY gist_timestamp_ops USING gist ADD - OPERATOR 6 <> (timestamp, timestamp) ; + OPERATOR 6 <> (timestamp, timestamp) , + OPERATOR 15 <-> (timestamp, timestamp) FOR ORDER BY pg_catalog.interval_ops , + FUNCTION 8 (timestamp, timestamp) gbt_ts_distance (internal, timestamp, int2, oid) ; -- Create the operator class @@ -546,7 +745,9 @@ AS STORAGE gbtreekey16; ALTER OPERATOR FAMILY gist_timestamptz_ops USING gist ADD - OPERATOR 6 <> (timestamptz, timestamptz) ; + OPERATOR 6 <> (timestamptz, timestamptz) , + OPERATOR 15 <-> (timestamptz, timestamptz) FOR ORDER BY pg_catalog.interval_ops , + FUNCTION 8 (timestamptz, timestamptz) gbt_tstz_distance (internal, timestamptz, int2, oid) ; -- @@ -562,6 +763,11 @@ RETURNS bool AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT; +CREATE FUNCTION gbt_time_distance(internal,time,int2,oid) +RETURNS float8 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + CREATE FUNCTION gbt_timetz_consistent(internal,timetz,int2,oid,internal) RETURNS bool AS 'MODULE_PATHNAME' @@ -616,7 +822,9 @@ AS STORAGE gbtreekey16; ALTER OPERATOR FAMILY gist_time_ops USING gist ADD - OPERATOR 6 <> (time, time) ; + OPERATOR 6 <> (time, time) , + OPERATOR 15 <-> (time, time) FOR ORDER BY pg_catalog.interval_ops , + FUNCTION 8 (time, time) gbt_time_distance (internal, time, int2, oid) ; CREATE OPERATOR CLASS gist_timetz_ops @@ -653,6 +861,11 @@ RETURNS bool AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT; +CREATE FUNCTION gbt_date_distance(internal,date,int2,oid) +RETURNS float8 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + CREATE FUNCTION gbt_date_compress(internal) RETURNS internal AS 'MODULE_PATHNAME' @@ -697,7 +910,9 @@ AS STORAGE gbtreekey8; ALTER OPERATOR FAMILY gist_date_ops USING gist ADD - OPERATOR 6 <> (date, date) ; + OPERATOR 6 <> (date, date) , + OPERATOR 15 <-> (date, date) FOR ORDER BY pg_catalog.integer_ops , + FUNCTION 8 (date, date) gbt_date_distance (internal, date, int2, oid) ; -- @@ -713,6 +928,11 @@ RETURNS bool AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT; +CREATE FUNCTION gbt_intv_distance(internal,interval,int2,oid) +RETURNS float8 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + CREATE FUNCTION gbt_intv_compress(internal) RETURNS internal AS 'MODULE_PATHNAME' @@ -762,7 +982,9 @@ AS STORAGE gbtreekey32; ALTER OPERATOR FAMILY gist_interval_ops USING gist ADD - OPERATOR 6 <> (interval, interval) ; + OPERATOR 6 <> (interval, interval) , + OPERATOR 15 <-> (interval, interval) FOR ORDER BY pg_catalog.interval_ops , + FUNCTION 8 (interval, interval) gbt_intv_distance (internal, interval, int2, oid) ; -- @@ -778,6 +1000,11 @@ RETURNS bool AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT; +CREATE FUNCTION gbt_cash_distance(internal,money,int2,oid) +RETURNS float8 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + CREATE FUNCTION gbt_cash_compress(internal) RETURNS internal AS 'MODULE_PATHNAME' @@ -822,7 +1049,9 @@ AS STORAGE gbtreekey16; ALTER OPERATOR FAMILY gist_cash_ops USING gist ADD - OPERATOR 6 <> (money, money) ; + OPERATOR 6 <> (money, money) , + OPERATOR 15 <-> (money, money) FOR ORDER BY pg_catalog.money_ops , + FUNCTION 8 (money, money) gbt_cash_distance (internal, money, int2, oid) ; -- diff --git a/contrib/btree_gist/btree_gist--unpackaged--1.0.sql b/contrib/btree_gist/btree_gist--unpackaged--1.0.sql index d8631d6bc267e0c4814b95dc2f02bc0ccfec2660..00252bf7c380a999e4f67e3a45c4a53f40d7b20c 100644 --- a/contrib/btree_gist/btree_gist--unpackaged--1.0.sql +++ b/contrib/btree_gist/btree_gist--unpackaged--1.0.sql @@ -171,46 +171,282 @@ ALTER EXTENSION btree_gist ADD operator class gist_inet_ops using gist; ALTER EXTENSION btree_gist ADD operator family gist_cidr_ops using gist; ALTER EXTENSION btree_gist ADD operator class gist_cidr_ops using gist; + +-- Add functions and operators that are new in 9.1 + +--distance operators + +CREATE FUNCTION cash_dist(money, money) +RETURNS money +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR <-> ( + LEFTARG = money, + RIGHTARG = money, + PROCEDURE = cash_dist, + COMMUTATOR = '<->' +); + +CREATE FUNCTION date_dist(date, date) +RETURNS int4 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR <-> ( + LEFTARG = date, + RIGHTARG = date, + PROCEDURE = date_dist, + COMMUTATOR = '<->' +); + +CREATE FUNCTION float4_dist(float4, float4) +RETURNS float4 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR <-> ( + LEFTARG = float4, + RIGHTARG = float4, + PROCEDURE = float4_dist, + COMMUTATOR = '<->' +); + +CREATE FUNCTION float8_dist(float8, float8) +RETURNS float8 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR <-> ( + LEFTARG = float8, + RIGHTARG = float8, + PROCEDURE = float8_dist, + COMMUTATOR = '<->' +); + +CREATE FUNCTION int2_dist(int2, int2) +RETURNS int2 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR <-> ( + LEFTARG = int2, + RIGHTARG = int2, + PROCEDURE = int2_dist, + COMMUTATOR = '<->' +); + +CREATE FUNCTION int4_dist(int4, int4) +RETURNS int4 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR <-> ( + LEFTARG = int4, + RIGHTARG = int4, + PROCEDURE = int4_dist, + COMMUTATOR = '<->' +); + +CREATE FUNCTION int8_dist(int8, int8) +RETURNS int8 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR <-> ( + LEFTARG = int8, + RIGHTARG = int8, + PROCEDURE = int8_dist, + COMMUTATOR = '<->' +); + +CREATE FUNCTION interval_dist(interval, interval) +RETURNS interval +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR <-> ( + LEFTARG = interval, + RIGHTARG = interval, + PROCEDURE = interval_dist, + COMMUTATOR = '<->' +); + +CREATE FUNCTION oid_dist(oid, oid) +RETURNS oid +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR <-> ( + LEFTARG = oid, + RIGHTARG = oid, + PROCEDURE = oid_dist, + COMMUTATOR = '<->' +); + +CREATE FUNCTION time_dist(time, time) +RETURNS interval +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR <-> ( + LEFTARG = time, + RIGHTARG = time, + PROCEDURE = time_dist, + COMMUTATOR = '<->' +); + +CREATE FUNCTION ts_dist(timestamp, timestamp) +RETURNS interval +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR <-> ( + LEFTARG = timestamp, + RIGHTARG = timestamp, + PROCEDURE = ts_dist, + COMMUTATOR = '<->' +); + +CREATE FUNCTION tstz_dist(timestamptz, timestamptz) +RETURNS interval +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR <-> ( + LEFTARG = timestamptz, + RIGHTARG = timestamptz, + PROCEDURE = tstz_dist, + COMMUTATOR = '<->' +); + +-- Support functions for distance operators + +CREATE FUNCTION gbt_oid_distance(internal,oid,int2,oid) +RETURNS float8 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION gbt_int2_distance(internal,int2,int2,oid) +RETURNS float8 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION gbt_int4_distance(internal,int4,int2,oid) +RETURNS float8 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION gbt_int8_distance(internal,int8,int2,oid) +RETURNS float8 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION gbt_float4_distance(internal,float4,int2,oid) +RETURNS float8 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION gbt_float8_distance(internal,float8,int2,oid) +RETURNS float8 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION gbt_ts_distance(internal,timestamp,int2,oid) +RETURNS float8 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION gbt_tstz_distance(internal,timestamptz,int2,oid) +RETURNS float8 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION gbt_time_distance(internal,time,int2,oid) +RETURNS float8 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION gbt_date_distance(internal,date,int2,oid) +RETURNS float8 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION gbt_intv_distance(internal,interval,int2,oid) +RETURNS float8 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION gbt_cash_distance(internal,money,int2,oid) +RETURNS float8 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + + -- Add new-in-9.1 stuff to the operator classes. ALTER OPERATOR FAMILY gist_oid_ops USING gist ADD - OPERATOR 6 <> (oid, oid) ; + OPERATOR 6 <> (oid, oid) , + OPERATOR 15 <-> (oid, oid) FOR ORDER BY pg_catalog.oid_ops , + FUNCTION 8 (oid, oid) gbt_oid_distance (internal, oid, int2, oid) ; ALTER OPERATOR FAMILY gist_int2_ops USING gist ADD - OPERATOR 6 <> (int2, int2) ; + OPERATOR 6 <> (int2, int2) , + OPERATOR 15 <-> (int2, int2) FOR ORDER BY pg_catalog.integer_ops , + FUNCTION 8 (int2, int2) gbt_int2_distance (internal, int2, int2, oid) ; ALTER OPERATOR FAMILY gist_int4_ops USING gist ADD - OPERATOR 6 <> (int4, int4) ; + OPERATOR 6 <> (int4, int4) , + OPERATOR 15 <-> (int4, int4) FOR ORDER BY pg_catalog.integer_ops , + FUNCTION 8 (int4, int4) gbt_int4_distance (internal, int4, int2, oid) ; ALTER OPERATOR FAMILY gist_int8_ops USING gist ADD - OPERATOR 6 <> (int8, int8) ; + OPERATOR 6 <> (int8, int8) , + OPERATOR 15 <-> (int8, int8) FOR ORDER BY pg_catalog.integer_ops , + FUNCTION 8 (int8, int8) gbt_int8_distance (internal, int8, int2, oid) ; ALTER OPERATOR FAMILY gist_float4_ops USING gist ADD - OPERATOR 6 <> (float4, float4) ; + OPERATOR 6 <> (float4, float4) , + OPERATOR 15 <-> (float4, float4) FOR ORDER BY pg_catalog.float_ops , + FUNCTION 8 (float4, float4) gbt_float4_distance (internal, float4, int2, oid) ; ALTER OPERATOR FAMILY gist_float8_ops USING gist ADD - OPERATOR 6 <> (float8, float8) ; + OPERATOR 6 <> (float8, float8) , + OPERATOR 15 <-> (float8, float8) FOR ORDER BY pg_catalog.float_ops , + FUNCTION 8 (float8, float8) gbt_float8_distance (internal, float8, int2, oid) ; ALTER OPERATOR FAMILY gist_timestamp_ops USING gist ADD - OPERATOR 6 <> (timestamp, timestamp) ; + OPERATOR 6 <> (timestamp, timestamp) , + OPERATOR 15 <-> (timestamp, timestamp) FOR ORDER BY pg_catalog.interval_ops , + FUNCTION 8 (timestamp, timestamp) gbt_ts_distance (internal, timestamp, int2, oid) ; ALTER OPERATOR FAMILY gist_timestamptz_ops USING gist ADD - OPERATOR 6 <> (timestamptz, timestamptz) ; + OPERATOR 6 <> (timestamptz, timestamptz) , + OPERATOR 15 <-> (timestamptz, timestamptz) FOR ORDER BY pg_catalog.interval_ops , + FUNCTION 8 (timestamptz, timestamptz) gbt_tstz_distance (internal, timestamptz, int2, oid) ; ALTER OPERATOR FAMILY gist_time_ops USING gist ADD - OPERATOR 6 <> (time, time) ; + OPERATOR 6 <> (time, time) , + OPERATOR 15 <-> (time, time) FOR ORDER BY pg_catalog.interval_ops , + FUNCTION 8 (time, time) gbt_time_distance (internal, time, int2, oid) ; ALTER OPERATOR FAMILY gist_timetz_ops USING gist ADD OPERATOR 6 <> (timetz, timetz) ; ALTER OPERATOR FAMILY gist_date_ops USING gist ADD - OPERATOR 6 <> (date, date) ; + OPERATOR 6 <> (date, date) , + OPERATOR 15 <-> (date, date) FOR ORDER BY pg_catalog.integer_ops , + FUNCTION 8 (date, date) gbt_date_distance (internal, date, int2, oid) ; ALTER OPERATOR FAMILY gist_interval_ops USING gist ADD - OPERATOR 6 <> (interval, interval) ; + OPERATOR 6 <> (interval, interval) , + OPERATOR 15 <-> (interval, interval) FOR ORDER BY pg_catalog.interval_ops , + FUNCTION 8 (interval, interval) gbt_intv_distance (internal, interval, int2, oid) ; ALTER OPERATOR FAMILY gist_cash_ops USING gist ADD - OPERATOR 6 <> (money, money) ; + OPERATOR 6 <> (money, money) , + OPERATOR 15 <-> (money, money) FOR ORDER BY pg_catalog.money_ops , + FUNCTION 8 (money, money) gbt_cash_distance (internal, money, int2, oid) ; ALTER OPERATOR FAMILY gist_macaddr_ops USING gist ADD OPERATOR 6 <> (macaddr, macaddr) ; diff --git a/contrib/btree_gist/btree_inet.c b/contrib/btree_gist/btree_inet.c index dcc934d1562c2ebc6951c103758d670107327a83..690a01cbc7a2b6c264608c8dab94398c1a828fa0 100644 --- a/contrib/btree_gist/btree_inet.c +++ b/contrib/btree_gist/btree_inet.c @@ -84,7 +84,8 @@ static const gbtree_ninfo tinfo = gbt_ineteq, gbt_inetle, gbt_inetlt, - gbt_inetkey_cmp + gbt_inetkey_cmp, + NULL }; diff --git a/contrib/btree_gist/btree_int2.c b/contrib/btree_gist/btree_int2.c index 2e981174520c832865d8c2967487dbc4764cbf4f..c06d170a5e1af5c272fff56d0d775bdc47ed5ffc 100644 --- a/contrib/btree_gist/btree_int2.c +++ b/contrib/btree_gist/btree_int2.c @@ -17,6 +17,7 @@ PG_FUNCTION_INFO_V1(gbt_int2_compress); PG_FUNCTION_INFO_V1(gbt_int2_union); PG_FUNCTION_INFO_V1(gbt_int2_picksplit); PG_FUNCTION_INFO_V1(gbt_int2_consistent); +PG_FUNCTION_INFO_V1(gbt_int2_distance); PG_FUNCTION_INFO_V1(gbt_int2_penalty); PG_FUNCTION_INFO_V1(gbt_int2_same); @@ -24,6 +25,7 @@ Datum gbt_int2_compress(PG_FUNCTION_ARGS); Datum gbt_int2_union(PG_FUNCTION_ARGS); Datum gbt_int2_picksplit(PG_FUNCTION_ARGS); Datum gbt_int2_consistent(PG_FUNCTION_ARGS); +Datum gbt_int2_distance(PG_FUNCTION_ARGS); Datum gbt_int2_penalty(PG_FUNCTION_ARGS); Datum gbt_int2_same(PG_FUNCTION_ARGS); @@ -70,6 +72,12 @@ gbt_int2key_cmp(const void *a, const void *b) return (ia->lower > ib->lower) ? 1 : -1; } +static float8 +gbt_int2_dist(const void *a, const void *b) +{ + return GET_FLOAT_DISTANCE(int2, a, b); +} + static const gbtree_ninfo tinfo = { @@ -80,12 +88,32 @@ static const gbtree_ninfo tinfo = gbt_int2eq, gbt_int2le, gbt_int2lt, - gbt_int2key_cmp + gbt_int2key_cmp, + gbt_int2_dist }; +PG_FUNCTION_INFO_V1(int2_dist); +Datum int2_dist(PG_FUNCTION_ARGS); +Datum +int2_dist(PG_FUNCTION_ARGS) +{ + int2 a = PG_GETARG_INT16(0); + int2 b = PG_GETARG_INT16(1); + int2 r; + int2 ra; + + r = a - b; + ra = Abs(r); + /* Overflow check. */ + if (ra < 0 || (!SAMESIGN(a, b) && !SAMESIGN(r, a))) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("smallint out of range"))); + PG_RETURN_INT16(ra); +} /************************************************** @@ -127,6 +155,25 @@ gbt_int2_consistent(PG_FUNCTION_ARGS) } +Datum +gbt_int2_distance(PG_FUNCTION_ARGS) +{ + GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); + int16 query = PG_GETARG_INT16(1); + + /* Oid subtype = PG_GETARG_OID(3); */ + int16KEY *kkk = (int16KEY *) DatumGetPointer(entry->key); + GBT_NUMKEY_R key; + + key.lower = (GBT_NUMKEY *) &kkk->lower; + key.upper = (GBT_NUMKEY *) &kkk->upper; + + PG_RETURN_FLOAT8( + gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo) + ); +} + + Datum gbt_int2_union(PG_FUNCTION_ARGS) { diff --git a/contrib/btree_gist/btree_int4.c b/contrib/btree_gist/btree_int4.c index 678d653fd0b399d04a79447ab72ea7c4ef1d35f4..ef7af524e76bdfab212fd332b8bd3b0778237ba6 100644 --- a/contrib/btree_gist/btree_int4.c +++ b/contrib/btree_gist/btree_int4.c @@ -17,6 +17,7 @@ PG_FUNCTION_INFO_V1(gbt_int4_compress); PG_FUNCTION_INFO_V1(gbt_int4_union); PG_FUNCTION_INFO_V1(gbt_int4_picksplit); PG_FUNCTION_INFO_V1(gbt_int4_consistent); +PG_FUNCTION_INFO_V1(gbt_int4_distance); PG_FUNCTION_INFO_V1(gbt_int4_penalty); PG_FUNCTION_INFO_V1(gbt_int4_same); @@ -24,6 +25,7 @@ Datum gbt_int4_compress(PG_FUNCTION_ARGS); Datum gbt_int4_union(PG_FUNCTION_ARGS); Datum gbt_int4_picksplit(PG_FUNCTION_ARGS); Datum gbt_int4_consistent(PG_FUNCTION_ARGS); +Datum gbt_int4_distance(PG_FUNCTION_ARGS); Datum gbt_int4_penalty(PG_FUNCTION_ARGS); Datum gbt_int4_same(PG_FUNCTION_ARGS); @@ -71,6 +73,12 @@ gbt_int4key_cmp(const void *a, const void *b) return (ia->lower > ib->lower) ? 1 : -1; } +static float8 +gbt_int4_dist(const void *a, const void *b) +{ + return GET_FLOAT_DISTANCE(int4, a, b); +} + static const gbtree_ninfo tinfo = { @@ -81,10 +89,34 @@ static const gbtree_ninfo tinfo = gbt_int4eq, gbt_int4le, gbt_int4lt, - gbt_int4key_cmp + gbt_int4key_cmp, + gbt_int4_dist }; +PG_FUNCTION_INFO_V1(int4_dist); +Datum int4_dist(PG_FUNCTION_ARGS); +Datum +int4_dist(PG_FUNCTION_ARGS) +{ + int4 a = PG_GETARG_INT32(0); + int4 b = PG_GETARG_INT32(1); + int4 r; + int4 ra; + + r = a - b; + ra = Abs(r); + + /* Overflow check. */ + if (ra < 0 || (!SAMESIGN(a, b) && !SAMESIGN(r, a))) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("integer out of range"))); + + PG_RETURN_INT32(ra); +} + + /************************************************** * int32 ops **************************************************/ @@ -124,6 +156,25 @@ gbt_int4_consistent(PG_FUNCTION_ARGS) } +Datum +gbt_int4_distance(PG_FUNCTION_ARGS) +{ + GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); + int32 query = PG_GETARG_INT32(1); + + /* Oid subtype = PG_GETARG_OID(3); */ + int32KEY *kkk = (int32KEY *) DatumGetPointer(entry->key); + GBT_NUMKEY_R key; + + key.lower = (GBT_NUMKEY *) &kkk->lower; + key.upper = (GBT_NUMKEY *) &kkk->upper; + + PG_RETURN_FLOAT8( + gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo) + ); +} + + Datum gbt_int4_union(PG_FUNCTION_ARGS) { diff --git a/contrib/btree_gist/btree_int8.c b/contrib/btree_gist/btree_int8.c index 8afa5b0af24dbcd3a1345785c523b6c81c21fb7c..1f14d82891d8c47cd59487d2fd8a1d41a4054e96 100644 --- a/contrib/btree_gist/btree_int8.c +++ b/contrib/btree_gist/btree_int8.c @@ -17,6 +17,7 @@ PG_FUNCTION_INFO_V1(gbt_int8_compress); PG_FUNCTION_INFO_V1(gbt_int8_union); PG_FUNCTION_INFO_V1(gbt_int8_picksplit); PG_FUNCTION_INFO_V1(gbt_int8_consistent); +PG_FUNCTION_INFO_V1(gbt_int8_distance); PG_FUNCTION_INFO_V1(gbt_int8_penalty); PG_FUNCTION_INFO_V1(gbt_int8_same); @@ -24,6 +25,7 @@ Datum gbt_int8_compress(PG_FUNCTION_ARGS); Datum gbt_int8_union(PG_FUNCTION_ARGS); Datum gbt_int8_picksplit(PG_FUNCTION_ARGS); Datum gbt_int8_consistent(PG_FUNCTION_ARGS); +Datum gbt_int8_distance(PG_FUNCTION_ARGS); Datum gbt_int8_penalty(PG_FUNCTION_ARGS); Datum gbt_int8_same(PG_FUNCTION_ARGS); @@ -71,6 +73,12 @@ gbt_int8key_cmp(const void *a, const void *b) return (ia->lower > ib->lower) ? 1 : -1; } +static float8 +gbt_int8_dist(const void *a, const void *b) +{ + return GET_FLOAT_DISTANCE(int64, a, b); +} + static const gbtree_ninfo tinfo = { @@ -81,10 +89,34 @@ static const gbtree_ninfo tinfo = gbt_int8eq, gbt_int8le, gbt_int8lt, - gbt_int8key_cmp + gbt_int8key_cmp, + gbt_int8_dist }; +PG_FUNCTION_INFO_V1(int8_dist); +Datum int8_dist(PG_FUNCTION_ARGS); +Datum +int8_dist(PG_FUNCTION_ARGS) +{ + int64 a = PG_GETARG_INT64(0); + int64 b = PG_GETARG_INT64(1); + int64 r; + int64 ra; + + r = a - b; + ra = Abs(r); + + /* Overflow check. */ + if (ra < 0 || (!SAMESIGN(a, b) && !SAMESIGN(r, a))) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("bigint out of range"))); + + PG_RETURN_INT64(ra); +} + + /************************************************** * int64 ops **************************************************/ @@ -124,6 +156,25 @@ gbt_int8_consistent(PG_FUNCTION_ARGS) } +Datum +gbt_int8_distance(PG_FUNCTION_ARGS) +{ + GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); + int64 query = PG_GETARG_INT64(1); + + /* Oid subtype = PG_GETARG_OID(3); */ + int64KEY *kkk = (int64KEY *) DatumGetPointer(entry->key); + GBT_NUMKEY_R key; + + key.lower = (GBT_NUMKEY *) &kkk->lower; + key.upper = (GBT_NUMKEY *) &kkk->upper; + + PG_RETURN_FLOAT8( + gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo) + ); +} + + Datum gbt_int8_union(PG_FUNCTION_ARGS) { diff --git a/contrib/btree_gist/btree_interval.c b/contrib/btree_gist/btree_interval.c index 0715346f234c544099c9c813a0900e31fa3b723e..5195284afa1be65f3a66acf779d7a1a6c99236f6 100644 --- a/contrib/btree_gist/btree_interval.c +++ b/contrib/btree_gist/btree_interval.c @@ -20,6 +20,7 @@ PG_FUNCTION_INFO_V1(gbt_intv_decompress); PG_FUNCTION_INFO_V1(gbt_intv_union); PG_FUNCTION_INFO_V1(gbt_intv_picksplit); PG_FUNCTION_INFO_V1(gbt_intv_consistent); +PG_FUNCTION_INFO_V1(gbt_intv_distance); PG_FUNCTION_INFO_V1(gbt_intv_penalty); PG_FUNCTION_INFO_V1(gbt_intv_same); @@ -28,6 +29,7 @@ Datum gbt_intv_decompress(PG_FUNCTION_ARGS); Datum gbt_intv_union(PG_FUNCTION_ARGS); Datum gbt_intv_picksplit(PG_FUNCTION_ARGS); Datum gbt_intv_consistent(PG_FUNCTION_ARGS); +Datum gbt_intv_distance(PG_FUNCTION_ARGS); Datum gbt_intv_penalty(PG_FUNCTION_ARGS); Datum gbt_intv_same(PG_FUNCTION_ARGS); @@ -83,6 +85,12 @@ intr2num(const Interval *i) return INTERVAL_TO_SEC(i); } +static float8 +gbt_intv_dist(const void *a, const void *b) +{ + return (float8)Abs(intr2num((Interval*)a) - intr2num((Interval*)b)); +} + /* * INTERVALSIZE should be the actual size-on-disk of an Interval, as shown * in pg_type. This might be less than sizeof(Interval) if the compiler @@ -99,10 +107,38 @@ static const gbtree_ninfo tinfo = gbt_intveq, gbt_intvle, gbt_intvlt, - gbt_intvkey_cmp + gbt_intvkey_cmp, + gbt_intv_dist }; +Interval * +abs_interval(Interval *a) +{ + static Interval zero = {0, 0, 0}; + + if (DatumGetBool(DirectFunctionCall2(interval_lt, + IntervalPGetDatum(a), + IntervalPGetDatum(&zero)))) + a = DatumGetIntervalP(DirectFunctionCall1(interval_um, + IntervalPGetDatum(a))); + + return a; +} + +PG_FUNCTION_INFO_V1(interval_dist); +Datum interval_dist(PG_FUNCTION_ARGS); +Datum +interval_dist(PG_FUNCTION_ARGS) +{ + Datum diff = DirectFunctionCall2(interval_mi, + PG_GETARG_DATUM(0), + PG_GETARG_DATUM(1)); + + PG_RETURN_INTERVAL_P(abs_interval(DatumGetIntervalP(diff))); +} + + /************************************************** * interval ops **************************************************/ @@ -190,6 +226,25 @@ gbt_intv_consistent(PG_FUNCTION_ARGS) } +Datum +gbt_intv_distance(PG_FUNCTION_ARGS) +{ + GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); + Interval *query = PG_GETARG_INTERVAL_P(1); + + /* Oid subtype = PG_GETARG_OID(3); */ + intvKEY *kkk = (intvKEY *) DatumGetPointer(entry->key); + GBT_NUMKEY_R key; + + key.lower = (GBT_NUMKEY *) &kkk->lower; + key.upper = (GBT_NUMKEY *) &kkk->upper; + + PG_RETURN_FLOAT8( + gbt_num_distance(&key, (void *) query, GIST_LEAF(entry), &tinfo) + ); +} + + Datum gbt_intv_union(PG_FUNCTION_ARGS) { diff --git a/contrib/btree_gist/btree_macaddr.c b/contrib/btree_gist/btree_macaddr.c index fb440c3f198fadfa99b1c29feff23495eadd673b..aa150e26a23d244c7b98a6d760da54c54ff33303 100644 --- a/contrib/btree_gist/btree_macaddr.c +++ b/contrib/btree_gist/btree_macaddr.c @@ -84,7 +84,8 @@ static const gbtree_ninfo tinfo = gbt_macadeq, gbt_macadle, gbt_macadlt, - gbt_macadkey_cmp + gbt_macadkey_cmp, + NULL }; diff --git a/contrib/btree_gist/btree_oid.c b/contrib/btree_gist/btree_oid.c index 4927448258fe31e02deab0be790791daac89aacd..c81dd31799eb9a2f61b86ab29d2f05adc8a2db31 100644 --- a/contrib/btree_gist/btree_oid.c +++ b/contrib/btree_gist/btree_oid.c @@ -17,6 +17,7 @@ PG_FUNCTION_INFO_V1(gbt_oid_compress); PG_FUNCTION_INFO_V1(gbt_oid_union); PG_FUNCTION_INFO_V1(gbt_oid_picksplit); PG_FUNCTION_INFO_V1(gbt_oid_consistent); +PG_FUNCTION_INFO_V1(gbt_oid_distance); PG_FUNCTION_INFO_V1(gbt_oid_penalty); PG_FUNCTION_INFO_V1(gbt_oid_same); @@ -24,6 +25,7 @@ Datum gbt_oid_compress(PG_FUNCTION_ARGS); Datum gbt_oid_union(PG_FUNCTION_ARGS); Datum gbt_oid_picksplit(PG_FUNCTION_ARGS); Datum gbt_oid_consistent(PG_FUNCTION_ARGS); +Datum gbt_oid_distance(PG_FUNCTION_ARGS); Datum gbt_oid_penalty(PG_FUNCTION_ARGS); Datum gbt_oid_same(PG_FUNCTION_ARGS); @@ -71,6 +73,18 @@ gbt_oidkey_cmp(const void *a, const void *b) return (ia->lower > ib->lower) ? 1 : -1; } +static float8 +gbt_oid_dist(const void *a, const void *b) +{ + Oid aa = *(const Oid *) a; + Oid bb = *(const Oid *) b; + + if (aa < bb) + return (float8) (bb - aa); + else + return (float8) (aa - bb); +} + static const gbtree_ninfo tinfo = { @@ -81,10 +95,28 @@ static const gbtree_ninfo tinfo = gbt_oideq, gbt_oidle, gbt_oidlt, - gbt_oidkey_cmp + gbt_oidkey_cmp, + gbt_oid_dist }; +PG_FUNCTION_INFO_V1(oid_dist); +Datum oid_dist(PG_FUNCTION_ARGS); +Datum +oid_dist(PG_FUNCTION_ARGS) +{ + Oid a = PG_GETARG_OID(0); + Oid b = PG_GETARG_OID(1); + Oid res; + + if (a < b) + res = b - a; + else + res = a - b; + PG_RETURN_OID(res); +} + + /************************************************** * Oid ops **************************************************/ @@ -124,6 +156,25 @@ gbt_oid_consistent(PG_FUNCTION_ARGS) } +Datum +gbt_oid_distance(PG_FUNCTION_ARGS) +{ + GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); + Oid query = PG_GETARG_OID(1); + + /* Oid subtype = PG_GETARG_OID(3); */ + oidKEY *kkk = (oidKEY *) DatumGetPointer(entry->key); + GBT_NUMKEY_R key; + + key.lower = (GBT_NUMKEY *) &kkk->lower; + key.upper = (GBT_NUMKEY *) &kkk->upper; + + PG_RETURN_FLOAT8( + gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo) + ); +} + + Datum gbt_oid_union(PG_FUNCTION_ARGS) { diff --git a/contrib/btree_gist/btree_time.c b/contrib/btree_gist/btree_time.c index 01163e906ad921e53a67da840a0977a27a89c46c..44f6923409f4b6a6fb1682751deae1507f76c5be 100644 --- a/contrib/btree_gist/btree_time.c +++ b/contrib/btree_gist/btree_time.c @@ -20,6 +20,7 @@ PG_FUNCTION_INFO_V1(gbt_timetz_compress); PG_FUNCTION_INFO_V1(gbt_time_union); PG_FUNCTION_INFO_V1(gbt_time_picksplit); PG_FUNCTION_INFO_V1(gbt_time_consistent); +PG_FUNCTION_INFO_V1(gbt_time_distance); PG_FUNCTION_INFO_V1(gbt_timetz_consistent); PG_FUNCTION_INFO_V1(gbt_time_penalty); PG_FUNCTION_INFO_V1(gbt_time_same); @@ -29,6 +30,7 @@ Datum gbt_timetz_compress(PG_FUNCTION_ARGS); Datum gbt_time_union(PG_FUNCTION_ARGS); Datum gbt_time_picksplit(PG_FUNCTION_ARGS); Datum gbt_time_consistent(PG_FUNCTION_ARGS); +Datum gbt_time_distance(PG_FUNCTION_ARGS); Datum gbt_timetz_consistent(PG_FUNCTION_ARGS); Datum gbt_time_penalty(PG_FUNCTION_ARGS); Datum gbt_time_same(PG_FUNCTION_ARGS); @@ -112,6 +114,19 @@ gbt_timekey_cmp(const void *a, const void *b) return res; } +static float8 +gbt_time_dist(const void *a, const void *b) +{ + const TimeADT *aa = (const TimeADT *) a; + const TimeADT *bb = (const TimeADT *) b; + Interval *i; + + i = DatumGetIntervalP(DirectFunctionCall2(time_mi_time, + TimeADTGetDatumFast(*aa), + TimeADTGetDatumFast(*bb))); + return (float8) Abs(INTERVAL_TO_SEC(i)); +} + static const gbtree_ninfo tinfo = { @@ -122,10 +137,24 @@ static const gbtree_ninfo tinfo = gbt_timeeq, gbt_timele, gbt_timelt, - gbt_timekey_cmp + gbt_timekey_cmp, + gbt_time_dist }; +PG_FUNCTION_INFO_V1(time_dist); +Datum time_dist(PG_FUNCTION_ARGS); +Datum +time_dist(PG_FUNCTION_ARGS) +{ + Datum diff = DirectFunctionCall2(time_mi_time, + PG_GETARG_DATUM(0), + PG_GETARG_DATUM(1)); + + PG_RETURN_INTERVAL_P(abs_interval(DatumGetIntervalP(diff))); +} + + /************************************************** * time ops **************************************************/ @@ -196,6 +225,24 @@ gbt_time_consistent(PG_FUNCTION_ARGS) ); } +Datum +gbt_time_distance(PG_FUNCTION_ARGS) +{ + GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); + TimeADT query = PG_GETARG_TIMEADT(1); + + /* Oid subtype = PG_GETARG_OID(3); */ + timeKEY *kkk = (timeKEY *) DatumGetPointer(entry->key); + GBT_NUMKEY_R key; + + key.lower = (GBT_NUMKEY *) &kkk->lower; + key.upper = (GBT_NUMKEY *) &kkk->upper; + + PG_RETURN_FLOAT8( + gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo) + ); +} + Datum gbt_timetz_consistent(PG_FUNCTION_ARGS) { diff --git a/contrib/btree_gist/btree_ts.c b/contrib/btree_gist/btree_ts.c index 2b13d14ad19f1f804d492f4a6f8b05290f00c391..9a0ec07a1e742bf4003ee5b0a5f1b7ce2ef40d72 100644 --- a/contrib/btree_gist/btree_ts.c +++ b/contrib/btree_gist/btree_ts.c @@ -3,6 +3,7 @@ */ #include "btree_gist.h" #include "btree_utils_num.h" +#include "utils/builtins.h" #include "utils/datetime.h" typedef struct @@ -19,7 +20,9 @@ PG_FUNCTION_INFO_V1(gbt_tstz_compress); PG_FUNCTION_INFO_V1(gbt_ts_union); PG_FUNCTION_INFO_V1(gbt_ts_picksplit); PG_FUNCTION_INFO_V1(gbt_ts_consistent); +PG_FUNCTION_INFO_V1(gbt_ts_distance); PG_FUNCTION_INFO_V1(gbt_tstz_consistent); +PG_FUNCTION_INFO_V1(gbt_tstz_distance); PG_FUNCTION_INFO_V1(gbt_ts_penalty); PG_FUNCTION_INFO_V1(gbt_ts_same); @@ -28,7 +31,9 @@ Datum gbt_tstz_compress(PG_FUNCTION_ARGS); Datum gbt_ts_union(PG_FUNCTION_ARGS); Datum gbt_ts_picksplit(PG_FUNCTION_ARGS); Datum gbt_ts_consistent(PG_FUNCTION_ARGS); +Datum gbt_ts_distance(PG_FUNCTION_ARGS); Datum gbt_tstz_consistent(PG_FUNCTION_ARGS); +Datum gbt_tstz_distance(PG_FUNCTION_ARGS); Datum gbt_ts_penalty(PG_FUNCTION_ARGS); Datum gbt_ts_same(PG_FUNCTION_ARGS); @@ -110,6 +115,22 @@ gbt_tskey_cmp(const void *a, const void *b) return res; } +static float8 +gbt_ts_dist(const void *a, const void *b) +{ + const Timestamp *aa = (const Timestamp *) a; + const Timestamp *bb = (const Timestamp *) b; + Interval *i; + + if (TIMESTAMP_NOT_FINITE(*aa) || TIMESTAMP_NOT_FINITE(*bb)) + return get_float8_infinity(); + + i = DatumGetIntervalP(DirectFunctionCall2(timestamp_mi, + TimestampGetDatumFast(*aa), + TimestampGetDatumFast(*bb))); + return (float8) Abs(INTERVAL_TO_SEC(i)); +} + static const gbtree_ninfo tinfo = { @@ -120,10 +141,71 @@ static const gbtree_ninfo tinfo = gbt_tseq, gbt_tsle, gbt_tslt, - gbt_tskey_cmp + gbt_tskey_cmp, + gbt_ts_dist }; +PG_FUNCTION_INFO_V1(ts_dist); +Datum ts_dist(PG_FUNCTION_ARGS); +Datum +ts_dist(PG_FUNCTION_ARGS) +{ + Timestamp a = PG_GETARG_TIMESTAMP(0); + Timestamp b = PG_GETARG_TIMESTAMP(1); + Interval *r; + + if (TIMESTAMP_NOT_FINITE(a) || TIMESTAMP_NOT_FINITE(b)) + { + Interval *p = palloc(sizeof(Interval)); + + p->day = INT_MAX; + p->month = INT_MAX; +#ifdef HAVE_INT64_TIMESTAMP + p->time = INT64CONST(0x7FFFFFFFFFFFFFFF); +#else + p->time = DBL_MAX; +#endif + PG_RETURN_INTERVAL_P(p); + } + else + + r = DatumGetIntervalP(DirectFunctionCall2(timestamp_mi, + PG_GETARG_DATUM(0), + PG_GETARG_DATUM(1))); + PG_RETURN_INTERVAL_P( abs_interval(r) ); +} + +PG_FUNCTION_INFO_V1(tstz_dist); +Datum tstz_dist(PG_FUNCTION_ARGS); +Datum +tstz_dist(PG_FUNCTION_ARGS) +{ + TimestampTz a = PG_GETARG_TIMESTAMPTZ(0); + TimestampTz b = PG_GETARG_TIMESTAMPTZ(1); + Interval *r; + + if (TIMESTAMP_NOT_FINITE(a) || TIMESTAMP_NOT_FINITE(b)) + { + Interval *p = palloc(sizeof(Interval)); + + p->day = INT_MAX; + p->month = INT_MAX; +#ifdef HAVE_INT64_TIMESTAMP + p->time = INT64CONST(0x7FFFFFFFFFFFFFFF); +#else + p->time = DBL_MAX; +#endif + PG_RETURN_INTERVAL_P(p); + } + + r = DatumGetIntervalP(DirectFunctionCall2(timestamp_mi, + PG_GETARG_DATUM(0), + PG_GETARG_DATUM(1))); + PG_RETURN_INTERVAL_P( abs_interval(r) ); +} + + /************************************************** * timestamp ops **************************************************/ @@ -213,6 +295,24 @@ gbt_ts_consistent(PG_FUNCTION_ARGS) ); } +Datum +gbt_ts_distance(PG_FUNCTION_ARGS) +{ + GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); + Timestamp query = PG_GETARG_TIMESTAMP(1); + + /* Oid subtype = PG_GETARG_OID(3); */ + tsKEY *kkk = (tsKEY *) DatumGetPointer(entry->key); + GBT_NUMKEY_R key; + + key.lower = (GBT_NUMKEY *) &kkk->lower; + key.upper = (GBT_NUMKEY *) &kkk->upper; + + PG_RETURN_FLOAT8( + gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo) + ); +} + Datum gbt_tstz_consistent(PG_FUNCTION_ARGS) { @@ -238,6 +338,26 @@ gbt_tstz_consistent(PG_FUNCTION_ARGS) ); } +Datum +gbt_tstz_distance(PG_FUNCTION_ARGS) +{ + GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); + TimestampTz query = PG_GETARG_TIMESTAMPTZ(1); + + /* Oid subtype = PG_GETARG_OID(3); */ + char *kkk = (char *) DatumGetPointer(entry->key); + GBT_NUMKEY_R key; + Timestamp qqq; + + key.lower = (GBT_NUMKEY *) &kkk[0]; + key.upper = (GBT_NUMKEY *) &kkk[MAXALIGN(tinfo.size)]; + qqq = tstz_to_ts_gmt(query); + + PG_RETURN_FLOAT8( + gbt_num_distance(&key, (void *) &qqq, GIST_LEAF(entry), &tinfo) + ); +} + Datum gbt_ts_union(PG_FUNCTION_ARGS) diff --git a/contrib/btree_gist/btree_utils_num.c b/contrib/btree_gist/btree_utils_num.c index 0df22f21338ad62f24831f9cdbc9591bb2e7bac8..17440a191b271a57afe3e445a3f522a3ead39a69 100644 --- a/contrib/btree_gist/btree_utils_num.c +++ b/contrib/btree_gist/btree_utils_num.c @@ -188,16 +188,13 @@ gbt_num_bin_union(Datum *u, GBT_NUMKEY *e, const gbtree_ninfo *tinfo) */ bool -gbt_num_consistent( - const GBT_NUMKEY_R *key, +gbt_num_consistent(const GBT_NUMKEY_R *key, const void *query, const StrategyNumber *strategy, bool is_leaf, - const gbtree_ninfo *tinfo -) + const gbtree_ninfo *tinfo) { - - bool retval = FALSE; + bool retval; switch (*strategy) { @@ -214,7 +211,7 @@ gbt_num_consistent( if (is_leaf) retval = (*tinfo->f_eq) (query, key->lower); else - retval = (*tinfo->f_le) (key->lower, query) && (*tinfo->f_le) (query, key->upper); + retval = ((*tinfo->f_le) (key->lower, query) && (*tinfo->f_le) (query, key->upper)) ? true : false; break; case BTGreaterStrategyNumber: if (is_leaf) @@ -226,17 +223,43 @@ gbt_num_consistent( retval = (*tinfo->f_le) (query, key->upper); break; case BtreeGistNotEqualStrategyNumber: - retval = ! ((*tinfo->f_eq) (query, key->lower) && - (*tinfo->f_eq) (query, key->upper)); + retval = (! ((*tinfo->f_eq) (query, key->lower) && + (*tinfo->f_eq) (query, key->upper))) ? true : false; break; default: - retval = FALSE; + retval = false; } return (retval); } +/* +** The GiST distance method (for KNN-Gist) +*/ + +float8 +gbt_num_distance(const GBT_NUMKEY_R *key, + const void *query, + bool is_leaf, + const gbtree_ninfo *tinfo) +{ + float8 retval; + + if (tinfo->f_dist == NULL) + elog(ERROR, "KNN search is not supported for btree_gist type %d", + (int) tinfo->t); + if ( tinfo->f_le(query, key->lower) ) + retval = tinfo->f_dist(query, key->lower); + else if ( tinfo->f_ge(query, key->upper) ) + retval = tinfo->f_dist(query, key->upper); + else + retval = 0.0; + + return retval; +} + + GIST_SPLITVEC * gbt_num_picksplit(const GistEntryVector *entryvec, GIST_SPLITVEC *v, const gbtree_ninfo *tinfo) diff --git a/contrib/btree_gist/btree_utils_num.h b/contrib/btree_gist/btree_utils_num.h index 091784bd5a17160f1d7eefb99785b94cfbcce117..243d3b5cb99087a3c166c922c72031c5bc3cac39 100644 --- a/contrib/btree_gist/btree_utils_num.h +++ b/contrib/btree_gist/btree_utils_num.h @@ -40,24 +40,25 @@ typedef struct /* Methods */ - bool (*f_gt) (const void *, const void *); /* greater then */ - bool (*f_ge) (const void *, const void *); /* greater equal */ + bool (*f_gt) (const void *, const void *); /* greater than */ + bool (*f_ge) (const void *, const void *); /* greater or equal */ bool (*f_eq) (const void *, const void *); /* equal */ - bool (*f_le) (const void *, const void *); /* less equal */ - bool (*f_lt) (const void *, const void *); /* less then */ + bool (*f_le) (const void *, const void *); /* less or equal */ + bool (*f_lt) (const void *, const void *); /* less than */ int (*f_cmp) (const void *, const void *); /* key compare function */ + float8 (*f_dist) (const void *, const void *); /* key distance function */ } gbtree_ninfo; /* * Numeric btree functions -*/ + */ /* * Note: The factor 0.49 in following macro avoids floating point overflows -*/ + */ #define penalty_num(result,olower,oupper,nlower,nupper) do { \ double tmp = 0.0F; \ (*(result)) = 0.0F; \ @@ -91,11 +92,37 @@ typedef struct (ivp)->month * (30.0 * SECS_PER_DAY)) #endif +#define GET_FLOAT_DISTANCE(t, arg1, arg2) Abs( ((float8) *((const t *) (arg1))) - ((float8) *((const t *) (arg2))) ) + +#define SAMESIGN(a,b) (((a) < 0) == ((b) < 0)) + +/* + * check to see if a float4/8 val has underflowed or overflowed + * borrowed from src/backend/utils/adt/float.c + */ +#define CHECKFLOATVAL(val, inf_is_valid, zero_is_valid) \ +do { \ + if (isinf(val) && !(inf_is_valid)) \ + ereport(ERROR, \ + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), \ + errmsg("value out of range: overflow"))); \ + \ + if ((val) == 0.0 && !(zero_is_valid)) \ + ereport(ERROR, \ + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), \ + errmsg("value out of range: underflow"))); \ +} while(0) + + +extern Interval *abs_interval(Interval *a); extern bool gbt_num_consistent(const GBT_NUMKEY_R *key, const void *query, const StrategyNumber *strategy, bool is_leaf, const gbtree_ninfo *tinfo); +extern float8 gbt_num_distance(const GBT_NUMKEY_R *key, const void *query, + bool is_leaf, const gbtree_ninfo *tinfo); + extern GIST_SPLITVEC *gbt_num_picksplit(const GistEntryVector *entryvec, GIST_SPLITVEC *v, const gbtree_ninfo *tinfo); diff --git a/contrib/btree_gist/expected/cash.out b/contrib/btree_gist/expected/cash.out index 2beb8cd92dcb98b562fcbe300c5a220ee09e7d1c..a4100d844e74724165fcbebc92bb42eacc5b54af 100644 --- a/contrib/btree_gist/expected/cash.out +++ b/contrib/btree_gist/expected/cash.out @@ -32,6 +32,14 @@ SELECT count(*) FROM moneytmp WHERE a > '22649.64'; 253 (1 row) +SELECT a, a <-> '21472.79' FROM moneytmp ORDER BY a <-> '21472.79' LIMIT 3; + a | ?column? +------------+---------- + $21,472.79 | $0.00 + $21,469.25 | $3.54 + $21,915.01 | $442.22 +(3 rows) + CREATE INDEX moneyidx ON moneytmp USING gist ( a ); SET enable_seqscan=off; SELECT count(*) FROM moneytmp WHERE a < '22649.64'::money; @@ -64,3 +72,20 @@ SELECT count(*) FROM moneytmp WHERE a > '22649.64'::money; 253 (1 row) +EXPLAIN (COSTS OFF) +SELECT a, a <-> '21472.79' FROM moneytmp ORDER BY a <-> '21472.79' LIMIT 3; + QUERY PLAN +----------------------------------------------- + Limit + -> Index Scan using moneyidx on moneytmp + Order By: (a <-> '$21,472.79'::money) +(3 rows) + +SELECT a, a <-> '21472.79' FROM moneytmp ORDER BY a <-> '21472.79' LIMIT 3; + a | ?column? +------------+---------- + $21,472.79 | $0.00 + $21,469.25 | $3.54 + $21,915.01 | $442.22 +(3 rows) + diff --git a/contrib/btree_gist/expected/date.out b/contrib/btree_gist/expected/date.out index f2082cf391afa923af4cbaefa6a46acf0bec377d..4a360bea6d6c66b50c256a2b06673e8d1b35153b 100644 --- a/contrib/btree_gist/expected/date.out +++ b/contrib/btree_gist/expected/date.out @@ -32,6 +32,14 @@ SELECT count(*) FROM datetmp WHERE a > '2001-02-13'; 313 (1 row) +SELECT a, a <-> '2001-02-13' FROM datetmp ORDER BY a <-> '2001-02-13' LIMIT 3; + a | ?column? +------------+---------- + 02-13-2001 | 0 + 02-11-2001 | 2 + 03-24-2001 | 39 +(3 rows) + CREATE INDEX dateidx ON datetmp USING gist ( a ); SET enable_seqscan=off; SELECT count(*) FROM datetmp WHERE a < '2001-02-13'::date; @@ -64,3 +72,20 @@ SELECT count(*) FROM datetmp WHERE a > '2001-02-13'::date; 313 (1 row) +EXPLAIN (COSTS OFF) +SELECT a, a <-> '2001-02-13' FROM datetmp ORDER BY a <-> '2001-02-13' LIMIT 3; + QUERY PLAN +---------------------------------------------- + Limit + -> Index Scan using dateidx on datetmp + Order By: (a <-> '02-13-2001'::date) +(3 rows) + +SELECT a, a <-> '2001-02-13' FROM datetmp ORDER BY a <-> '2001-02-13' LIMIT 3; + a | ?column? +------------+---------- + 02-13-2001 | 0 + 02-11-2001 | 2 + 03-24-2001 | 39 +(3 rows) + diff --git a/contrib/btree_gist/expected/float4.out b/contrib/btree_gist/expected/float4.out index c7f65c8d7fc4448004f3a01e1489ab70ffd38b11..1695f7805a0c6dd0dab1bf1d54cfe171682911b1 100644 --- a/contrib/btree_gist/expected/float4.out +++ b/contrib/btree_gist/expected/float4.out @@ -32,6 +32,14 @@ SELECT count(*) FROM float4tmp WHERE a > -179.0; 302 (1 row) +SELECT a, a <-> '-179.0' FROM float4tmp ORDER BY a <-> '-179.0' LIMIT 3; + a | ?column? +----------+---------- + -179 | 0 + -189.024 | 10.0239 + -158.177 | 20.8226 +(3 rows) + CREATE INDEX float4idx ON float4tmp USING gist ( a ); SET enable_seqscan=off; SELECT count(*) FROM float4tmp WHERE a < -179.0::float4; @@ -64,3 +72,20 @@ SELECT count(*) FROM float4tmp WHERE a > -179.0::float4; 302 (1 row) +EXPLAIN (COSTS OFF) +SELECT a, a <-> '-179.0' FROM float4tmp ORDER BY a <-> '-179.0' LIMIT 3; + QUERY PLAN +----------------------------------------------- + Limit + -> Index Scan using float4idx on float4tmp + Order By: (a <-> (-179)::real) +(3 rows) + +SELECT a, a <-> '-179.0' FROM float4tmp ORDER BY a <-> '-179.0' LIMIT 3; + a | ?column? +----------+---------- + -179 | 0 + -189.024 | 10.0239 + -158.177 | 20.8226 +(3 rows) + diff --git a/contrib/btree_gist/expected/float8.out b/contrib/btree_gist/expected/float8.out index 4598ac87a2c811135727a641fcca69c349daddb7..7d2228b797390d1b1333d09f97a7153f21d09f50 100644 --- a/contrib/btree_gist/expected/float8.out +++ b/contrib/btree_gist/expected/float8.out @@ -32,6 +32,14 @@ SELECT count(*) FROM float8tmp WHERE a > -1890.0; 306 (1 row) +SELECT a, a <-> '-1890.0' FROM float8tmp ORDER BY a <-> '-1890.0' LIMIT 3; + a | ?column? +--------------+------------ + -1890 | 0 + -2003.634512 | 113.634512 + -1769.73634 | 120.26366 +(3 rows) + CREATE INDEX float8idx ON float8tmp USING gist ( a ); SET enable_seqscan=off; SELECT count(*) FROM float8tmp WHERE a < -1890.0::float8; @@ -64,3 +72,20 @@ SELECT count(*) FROM float8tmp WHERE a > -1890.0::float8; 306 (1 row) +EXPLAIN (COSTS OFF) +SELECT a, a <-> '-1890.0' FROM float8tmp ORDER BY a <-> '-1890.0' LIMIT 3; + QUERY PLAN +----------------------------------------------------- + Limit + -> Index Scan using float8idx on float8tmp + Order By: (a <-> (-1890)::double precision) +(3 rows) + +SELECT a, a <-> '-1890.0' FROM float8tmp ORDER BY a <-> '-1890.0' LIMIT 3; + a | ?column? +--------------+------------ + -1890 | 0 + -2003.634512 | 113.634512 + -1769.73634 | 120.26366 +(3 rows) + diff --git a/contrib/btree_gist/expected/int2.out b/contrib/btree_gist/expected/int2.out index a82819c26a19c997f2ede59b1ae8583507507543..b1cc3b14b252c0b89e02b21df8dcc0ead3598a71 100644 --- a/contrib/btree_gist/expected/int2.out +++ b/contrib/btree_gist/expected/int2.out @@ -32,6 +32,14 @@ SELECT count(*) FROM int2tmp WHERE a > 237; 248 (1 row) +SELECT a, a <-> '237' FROM int2tmp ORDER BY a <-> '237' LIMIT 3; + a | ?column? +-----+---------- + 237 | 0 + 232 | 5 + 228 | 9 +(3 rows) + CREATE INDEX int2idx ON int2tmp USING gist ( a ); SET enable_seqscan=off; SELECT count(*) FROM int2tmp WHERE a < 237::int2; @@ -64,3 +72,20 @@ SELECT count(*) FROM int2tmp WHERE a > 237::int2; 248 (1 row) +EXPLAIN (COSTS OFF) +SELECT a, a <-> '237' FROM int2tmp ORDER BY a <-> '237' LIMIT 3; + QUERY PLAN +------------------------------------------- + Limit + -> Index Scan using int2idx on int2tmp + Order By: (a <-> 237::smallint) +(3 rows) + +SELECT a, a <-> '237' FROM int2tmp ORDER BY a <-> '237' LIMIT 3; + a | ?column? +-----+---------- + 237 | 0 + 232 | 5 + 228 | 9 +(3 rows) + diff --git a/contrib/btree_gist/expected/int4.out b/contrib/btree_gist/expected/int4.out index d4ac0e15135fdb7b4c4c77f11ec8663ddc50464c..41bed1f6e348d9b0acd91b25db38d80555b0865d 100644 --- a/contrib/btree_gist/expected/int4.out +++ b/contrib/btree_gist/expected/int4.out @@ -32,6 +32,14 @@ SELECT count(*) FROM int4tmp WHERE a > 237; 248 (1 row) +SELECT a, a <-> '237' FROM int4tmp ORDER BY a <-> '237' LIMIT 3; + a | ?column? +-----+---------- + 237 | 0 + 232 | 5 + 228 | 9 +(3 rows) + CREATE INDEX int4idx ON int4tmp USING gist ( a ); SET enable_seqscan=off; SELECT count(*) FROM int4tmp WHERE a < 237::int4; @@ -64,3 +72,20 @@ SELECT count(*) FROM int4tmp WHERE a > 237::int4; 248 (1 row) +EXPLAIN (COSTS OFF) +SELECT a, a <-> '237' FROM int4tmp ORDER BY a <-> '237' LIMIT 3; + QUERY PLAN +------------------------------------------- + Limit + -> Index Scan using int4idx on int4tmp + Order By: (a <-> 237) +(3 rows) + +SELECT a, a <-> '237' FROM int4tmp ORDER BY a <-> '237' LIMIT 3; + a | ?column? +-----+---------- + 237 | 0 + 232 | 5 + 228 | 9 +(3 rows) + diff --git a/contrib/btree_gist/expected/int8.out b/contrib/btree_gist/expected/int8.out index 1da484525b511e6c8081f80e1479258d10e65e67..ff0af4a5fb8d8f3bbd7e7997b1a887221ba2f656 100644 --- a/contrib/btree_gist/expected/int8.out +++ b/contrib/btree_gist/expected/int8.out @@ -32,6 +32,14 @@ SELECT count(*) FROM int8tmp WHERE a > 464571291354841; 270 (1 row) +SELECT a, a <-> '464571291354841' FROM int8tmp ORDER BY a <-> '464571291354841' LIMIT 3; + a | ?column? +-----------------+---------------- + 464571291354841 | 0 + 457257666629329 | 7313624725512 + 478227196042750 | 13655904687909 +(3 rows) + CREATE INDEX int8idx ON int8tmp USING gist ( a ); SET enable_seqscan=off; SELECT count(*) FROM int8tmp WHERE a < 464571291354841::int8; @@ -64,3 +72,20 @@ SELECT count(*) FROM int8tmp WHERE a > 464571291354841::int8; 270 (1 row) +EXPLAIN (COSTS OFF) +SELECT a, a <-> '464571291354841' FROM int8tmp ORDER BY a <-> '464571291354841' LIMIT 3; + QUERY PLAN +--------------------------------------------------- + Limit + -> Index Scan using int8idx on int8tmp + Order By: (a <-> 464571291354841::bigint) +(3 rows) + +SELECT a, a <-> '464571291354841' FROM int8tmp ORDER BY a <-> '464571291354841' LIMIT 3; + a | ?column? +-----------------+---------------- + 464571291354841 | 0 + 457257666629329 | 7313624725512 + 478227196042750 | 13655904687909 +(3 rows) + diff --git a/contrib/btree_gist/expected/interval.out b/contrib/btree_gist/expected/interval.out index 4c78e21346c2ad5239dbddcafa353bb31a19bad3..6955251a0451bac1ec77e41730a630621be2ea59 100644 --- a/contrib/btree_gist/expected/interval.out +++ b/contrib/btree_gist/expected/interval.out @@ -32,6 +32,14 @@ SELECT count(*) FROM intervaltmp WHERE a > '199 days 21:21:23'; 270 (1 row) +SELECT a, a <-> '199 days 21:21:23' FROM intervaltmp ORDER BY a <-> '199 days 21:21:23' LIMIT 3; + a | ?column? +-------------------------------------+-------------------------------------- + @ 199 days 21 hours 21 mins 23 secs | @ 0 + @ 183 days 6 hours 52 mins 48 secs | @ 16 days 14 hours 28 mins 35 secs + @ 220 days 19 hours 5 mins 42 secs | @ 21 days -2 hours -15 mins -41 secs +(3 rows) + CREATE INDEX intervalidx ON intervaltmp USING gist ( a ); SET enable_seqscan=off; SELECT count(*) FROM intervaltmp WHERE a < '199 days 21:21:23'::interval; @@ -64,3 +72,20 @@ SELECT count(*) FROM intervaltmp WHERE a > '199 days 21:21:23'::interval; 270 (1 row) +EXPLAIN (COSTS OFF) +SELECT a, a <-> '199 days 21:21:23' FROM intervaltmp ORDER BY a <-> '199 days 21:21:23' LIMIT 3; + QUERY PLAN +--------------------------------------------------------------------------- + Limit + -> Index Scan using intervalidx on intervaltmp + Order By: (a <-> '@ 199 days 21 hours 21 mins 23 secs'::interval) +(3 rows) + +SELECT a, a <-> '199 days 21:21:23' FROM intervaltmp ORDER BY a <-> '199 days 21:21:23' LIMIT 3; + a | ?column? +-------------------------------------+-------------------------------------- + @ 199 days 21 hours 21 mins 23 secs | @ 0 + @ 183 days 6 hours 52 mins 48 secs | @ 16 days 14 hours 28 mins 35 secs + @ 220 days 19 hours 5 mins 42 secs | @ 21 days -2 hours -15 mins -41 secs +(3 rows) + diff --git a/contrib/btree_gist/expected/time.out b/contrib/btree_gist/expected/time.out index 015a67f6a17d7e166117dd53587b78ec3c28554c..1b9da4e192a14cb4d212ff5de046f9de57b3efc7 100644 --- a/contrib/btree_gist/expected/time.out +++ b/contrib/btree_gist/expected/time.out @@ -32,6 +32,14 @@ SELECT count(*) FROM timetmp WHERE a > '10:57:11'; 292 (1 row) +SELECT a, a <-> '10:57:11' FROM timetmp ORDER BY a <-> '10:57:11' LIMIT 3; + a | ?column? +----------+----------------- + 10:57:11 | @ 0 + 10:57:10 | @ 1 sec + 10:55:32 | @ 1 min 39 secs +(3 rows) + CREATE INDEX timeidx ON timetmp USING gist ( a ); SET enable_seqscan=off; SELECT count(*) FROM timetmp WHERE a < '10:57:11'::time; @@ -64,3 +72,20 @@ SELECT count(*) FROM timetmp WHERE a > '10:57:11'::time; 292 (1 row) +EXPLAIN (COSTS OFF) +SELECT a, a <-> '10:57:11' FROM timetmp ORDER BY a <-> '10:57:11' LIMIT 3; + QUERY PLAN +-------------------------------------------------------------- + Limit + -> Index Scan using timeidx on timetmp + Order By: (a <-> '10:57:11'::time without time zone) +(3 rows) + +SELECT a, a <-> '10:57:11' FROM timetmp ORDER BY a <-> '10:57:11' LIMIT 3; + a | ?column? +----------+----------------- + 10:57:11 | @ 0 + 10:57:10 | @ 1 sec + 10:55:32 | @ 1 min 39 secs +(3 rows) + diff --git a/contrib/btree_gist/expected/timestamp.out b/contrib/btree_gist/expected/timestamp.out index dc53895ca2110e7e998042b35d0d561eb72232a6..cc3624f084320415549a4ba83fa7e2c12f86f9de 100644 --- a/contrib/btree_gist/expected/timestamp.out +++ b/contrib/btree_gist/expected/timestamp.out @@ -32,6 +32,14 @@ SELECT count(*) FROM timestamptmp WHERE a > '2004-10-26 08:55:08'; 289 (1 row) +SELECT a, a <-> '2004-10-26 08:55:08' FROM timestamptmp ORDER BY a <-> '2004-10-26 08:55:08' LIMIT 3; + a | ?column? +--------------------------+------------------------------------ + Tue Oct 26 08:55:08 2004 | @ 0 + Sun Oct 31 06:35:03 2004 | @ 4 days 21 hours 39 mins 55 secs + Mon Nov 29 20:12:43 2004 | @ 34 days 11 hours 17 mins 35 secs +(3 rows) + CREATE INDEX timestampidx ON timestamptmp USING gist ( a ); SET enable_seqscan=off; SELECT count(*) FROM timestamptmp WHERE a < '2004-10-26 08:55:08'::timestamp; @@ -64,3 +72,20 @@ SELECT count(*) FROM timestamptmp WHERE a > '2004-10-26 08:55:08'::timestamp; 289 (1 row) +EXPLAIN (COSTS OFF) +SELECT a, a <-> '2004-10-26 08:55:08' FROM timestamptmp ORDER BY a <-> '2004-10-26 08:55:08' LIMIT 3; + QUERY PLAN +----------------------------------------------------------------------------------- + Limit + -> Index Scan using timestampidx on timestamptmp + Order By: (a <-> 'Tue Oct 26 08:55:08 2004'::timestamp without time zone) +(3 rows) + +SELECT a, a <-> '2004-10-26 08:55:08' FROM timestamptmp ORDER BY a <-> '2004-10-26 08:55:08' LIMIT 3; + a | ?column? +--------------------------+------------------------------------ + Tue Oct 26 08:55:08 2004 | @ 0 + Sun Oct 31 06:35:03 2004 | @ 4 days 21 hours 39 mins 55 secs + Mon Nov 29 20:12:43 2004 | @ 34 days 11 hours 17 mins 35 secs +(3 rows) + diff --git a/contrib/btree_gist/expected/timestamptz.out b/contrib/btree_gist/expected/timestamptz.out index 391705f0dbefa970a5c31eed7c8ecf8716333e61..88d2404c44b3b417517bcf189522ff6870948215 100644 --- a/contrib/btree_gist/expected/timestamptz.out +++ b/contrib/btree_gist/expected/timestamptz.out @@ -92,6 +92,14 @@ SELECT count(*) FROM timestamptztmp WHERE a > '2018-12-18 10:59:54 GMT+4'; 157 (1 row) +SELECT a, a <-> '2018-12-18 10:59:54 GMT+2' FROM timestamptztmp ORDER BY a <-> '2018-12-18 10:59:54 GMT+2' LIMIT 3; + a | ?column? +------------------------------+----------------------------------- + Tue Dec 18 05:59:54 2018 PST | @ 1 hour + Thu Jan 10 03:01:34 2019 PST | @ 22 days 22 hours 1 min 40 secs + Thu Jan 24 12:28:12 2019 PST | @ 37 days 7 hours 28 mins 18 secs +(3 rows) + CREATE INDEX timestamptzidx ON timestamptztmp USING gist ( a ); SET enable_seqscan=off; SELECT count(*) FROM timestamptztmp WHERE a < '2018-12-18 10:59:54 GMT+3'::timestamptz; @@ -184,3 +192,20 @@ SELECT count(*) FROM timestamptztmp WHERE a > '2018-12-18 10:59:54 GMT+4'::time 157 (1 row) +EXPLAIN (COSTS OFF) +SELECT a, a <-> '2018-12-18 10:59:54 GMT+2' FROM timestamptztmp ORDER BY a <-> '2018-12-18 10:59:54 GMT+2' LIMIT 3; + QUERY PLAN +------------------------------------------------------------------------------------ + Limit + -> Index Scan using timestamptzidx on timestamptztmp + Order By: (a <-> 'Tue Dec 18 04:59:54 2018 PST'::timestamp with time zone) +(3 rows) + +SELECT a, a <-> '2018-12-18 10:59:54 GMT+2' FROM timestamptztmp ORDER BY a <-> '2018-12-18 10:59:54 GMT+2' LIMIT 3; + a | ?column? +------------------------------+----------------------------------- + Tue Dec 18 05:59:54 2018 PST | @ 1 hour + Thu Jan 10 03:01:34 2019 PST | @ 22 days 22 hours 1 min 40 secs + Thu Jan 24 12:28:12 2019 PST | @ 37 days 7 hours 28 mins 18 secs +(3 rows) + diff --git a/contrib/btree_gist/sql/cash.sql b/contrib/btree_gist/sql/cash.sql index 5313e8f69652bdbbc61a8027260c295c53e8f86f..0e037984e1b6a90e00822888110cbfb5aed2beb2 100644 --- a/contrib/btree_gist/sql/cash.sql +++ b/contrib/btree_gist/sql/cash.sql @@ -16,6 +16,8 @@ SELECT count(*) FROM moneytmp WHERE a >= '22649.64'; SELECT count(*) FROM moneytmp WHERE a > '22649.64'; +SELECT a, a <-> '21472.79' FROM moneytmp ORDER BY a <-> '21472.79' LIMIT 3; + CREATE INDEX moneyidx ON moneytmp USING gist ( a ); SET enable_seqscan=off; @@ -29,3 +31,7 @@ SELECT count(*) FROM moneytmp WHERE a = '22649.64'::money; SELECT count(*) FROM moneytmp WHERE a >= '22649.64'::money; SELECT count(*) FROM moneytmp WHERE a > '22649.64'::money; + +EXPLAIN (COSTS OFF) +SELECT a, a <-> '21472.79' FROM moneytmp ORDER BY a <-> '21472.79' LIMIT 3; +SELECT a, a <-> '21472.79' FROM moneytmp ORDER BY a <-> '21472.79' LIMIT 3; diff --git a/contrib/btree_gist/sql/date.sql b/contrib/btree_gist/sql/date.sql index f3b8166a6f0220ddd58b5e55d8495452c329129e..f969ef0a08cb37aaa7fe9745f9642263db6d95e3 100644 --- a/contrib/btree_gist/sql/date.sql +++ b/contrib/btree_gist/sql/date.sql @@ -16,6 +16,8 @@ SELECT count(*) FROM datetmp WHERE a >= '2001-02-13'; SELECT count(*) FROM datetmp WHERE a > '2001-02-13'; +SELECT a, a <-> '2001-02-13' FROM datetmp ORDER BY a <-> '2001-02-13' LIMIT 3; + CREATE INDEX dateidx ON datetmp USING gist ( a ); SET enable_seqscan=off; @@ -29,3 +31,7 @@ SELECT count(*) FROM datetmp WHERE a = '2001-02-13'::date; SELECT count(*) FROM datetmp WHERE a >= '2001-02-13'::date; SELECT count(*) FROM datetmp WHERE a > '2001-02-13'::date; + +EXPLAIN (COSTS OFF) +SELECT a, a <-> '2001-02-13' FROM datetmp ORDER BY a <-> '2001-02-13' LIMIT 3; +SELECT a, a <-> '2001-02-13' FROM datetmp ORDER BY a <-> '2001-02-13' LIMIT 3; diff --git a/contrib/btree_gist/sql/float4.sql b/contrib/btree_gist/sql/float4.sql index fb4b726d22301bc2f08ad49bb37f4091ba2f6669..3da1ce953c8d1471d49236d65e4ab88c447c5460 100644 --- a/contrib/btree_gist/sql/float4.sql +++ b/contrib/btree_gist/sql/float4.sql @@ -16,6 +16,8 @@ SELECT count(*) FROM float4tmp WHERE a >= -179.0; SELECT count(*) FROM float4tmp WHERE a > -179.0; +SELECT a, a <-> '-179.0' FROM float4tmp ORDER BY a <-> '-179.0' LIMIT 3; + CREATE INDEX float4idx ON float4tmp USING gist ( a ); SET enable_seqscan=off; @@ -29,3 +31,7 @@ SELECT count(*) FROM float4tmp WHERE a = -179.0::float4; SELECT count(*) FROM float4tmp WHERE a >= -179.0::float4; SELECT count(*) FROM float4tmp WHERE a > -179.0::float4; + +EXPLAIN (COSTS OFF) +SELECT a, a <-> '-179.0' FROM float4tmp ORDER BY a <-> '-179.0' LIMIT 3; +SELECT a, a <-> '-179.0' FROM float4tmp ORDER BY a <-> '-179.0' LIMIT 3; diff --git a/contrib/btree_gist/sql/float8.sql b/contrib/btree_gist/sql/float8.sql index f8bd12efa139a4f274f429c59da699579d0ff050..e1e819b37f98c18c50b6eb1eb00752d6ef5fe695 100644 --- a/contrib/btree_gist/sql/float8.sql +++ b/contrib/btree_gist/sql/float8.sql @@ -16,6 +16,8 @@ SELECT count(*) FROM float8tmp WHERE a >= -1890.0; SELECT count(*) FROM float8tmp WHERE a > -1890.0; +SELECT a, a <-> '-1890.0' FROM float8tmp ORDER BY a <-> '-1890.0' LIMIT 3; + CREATE INDEX float8idx ON float8tmp USING gist ( a ); SET enable_seqscan=off; @@ -29,3 +31,7 @@ SELECT count(*) FROM float8tmp WHERE a = -1890.0::float8; SELECT count(*) FROM float8tmp WHERE a >= -1890.0::float8; SELECT count(*) FROM float8tmp WHERE a > -1890.0::float8; + +EXPLAIN (COSTS OFF) +SELECT a, a <-> '-1890.0' FROM float8tmp ORDER BY a <-> '-1890.0' LIMIT 3; +SELECT a, a <-> '-1890.0' FROM float8tmp ORDER BY a <-> '-1890.0' LIMIT 3; diff --git a/contrib/btree_gist/sql/int2.sql b/contrib/btree_gist/sql/int2.sql index 80ca6ac37cc8d5d9994f07bd9e551f316e65b38e..988518795fc5631c04e82768c6dcc88f275ebcda 100644 --- a/contrib/btree_gist/sql/int2.sql +++ b/contrib/btree_gist/sql/int2.sql @@ -16,6 +16,8 @@ SELECT count(*) FROM int2tmp WHERE a >= 237; SELECT count(*) FROM int2tmp WHERE a > 237; +SELECT a, a <-> '237' FROM int2tmp ORDER BY a <-> '237' LIMIT 3; + CREATE INDEX int2idx ON int2tmp USING gist ( a ); SET enable_seqscan=off; @@ -29,3 +31,7 @@ SELECT count(*) FROM int2tmp WHERE a = 237::int2; SELECT count(*) FROM int2tmp WHERE a >= 237::int2; SELECT count(*) FROM int2tmp WHERE a > 237::int2; + +EXPLAIN (COSTS OFF) +SELECT a, a <-> '237' FROM int2tmp ORDER BY a <-> '237' LIMIT 3; +SELECT a, a <-> '237' FROM int2tmp ORDER BY a <-> '237' LIMIT 3; diff --git a/contrib/btree_gist/sql/int4.sql b/contrib/btree_gist/sql/int4.sql index 31307d3610dc42ded469b10ef6532702b6cca604..659ab5ee24bbc6d18a5a82d283570d911ca58a1f 100644 --- a/contrib/btree_gist/sql/int4.sql +++ b/contrib/btree_gist/sql/int4.sql @@ -16,6 +16,8 @@ SELECT count(*) FROM int4tmp WHERE a >= 237; SELECT count(*) FROM int4tmp WHERE a > 237; +SELECT a, a <-> '237' FROM int4tmp ORDER BY a <-> '237' LIMIT 3; + CREATE INDEX int4idx ON int4tmp USING gist ( a ); SET enable_seqscan=off; @@ -29,3 +31,7 @@ SELECT count(*) FROM int4tmp WHERE a = 237::int4; SELECT count(*) FROM int4tmp WHERE a >= 237::int4; SELECT count(*) FROM int4tmp WHERE a > 237::int4; + +EXPLAIN (COSTS OFF) +SELECT a, a <-> '237' FROM int4tmp ORDER BY a <-> '237' LIMIT 3; +SELECT a, a <-> '237' FROM int4tmp ORDER BY a <-> '237' LIMIT 3; diff --git a/contrib/btree_gist/sql/int8.sql b/contrib/btree_gist/sql/int8.sql index 747bdca1ec97f60d786bf8df4786253f3fc580ed..51e55e9c14b87b7c081b69a0f7ec4ba8ebc5757f 100644 --- a/contrib/btree_gist/sql/int8.sql +++ b/contrib/btree_gist/sql/int8.sql @@ -16,6 +16,8 @@ SELECT count(*) FROM int8tmp WHERE a >= 464571291354841; SELECT count(*) FROM int8tmp WHERE a > 464571291354841; +SELECT a, a <-> '464571291354841' FROM int8tmp ORDER BY a <-> '464571291354841' LIMIT 3; + CREATE INDEX int8idx ON int8tmp USING gist ( a ); SET enable_seqscan=off; @@ -29,3 +31,7 @@ SELECT count(*) FROM int8tmp WHERE a = 464571291354841::int8; SELECT count(*) FROM int8tmp WHERE a >= 464571291354841::int8; SELECT count(*) FROM int8tmp WHERE a > 464571291354841::int8; + +EXPLAIN (COSTS OFF) +SELECT a, a <-> '464571291354841' FROM int8tmp ORDER BY a <-> '464571291354841' LIMIT 3; +SELECT a, a <-> '464571291354841' FROM int8tmp ORDER BY a <-> '464571291354841' LIMIT 3; diff --git a/contrib/btree_gist/sql/interval.sql b/contrib/btree_gist/sql/interval.sql index 561e3d92ff971139cf98cc6dc69cbf2273b27d8d..0f8b03152035e6316c16e690492567bc0dd2a113 100644 --- a/contrib/btree_gist/sql/interval.sql +++ b/contrib/btree_gist/sql/interval.sql @@ -16,6 +16,8 @@ SELECT count(*) FROM intervaltmp WHERE a >= '199 days 21:21:23'; SELECT count(*) FROM intervaltmp WHERE a > '199 days 21:21:23'; +SELECT a, a <-> '199 days 21:21:23' FROM intervaltmp ORDER BY a <-> '199 days 21:21:23' LIMIT 3; + CREATE INDEX intervalidx ON intervaltmp USING gist ( a ); SET enable_seqscan=off; @@ -29,3 +31,7 @@ SELECT count(*) FROM intervaltmp WHERE a = '199 days 21:21:23'::interval; SELECT count(*) FROM intervaltmp WHERE a >= '199 days 21:21:23'::interval; SELECT count(*) FROM intervaltmp WHERE a > '199 days 21:21:23'::interval; + +EXPLAIN (COSTS OFF) +SELECT a, a <-> '199 days 21:21:23' FROM intervaltmp ORDER BY a <-> '199 days 21:21:23' LIMIT 3; +SELECT a, a <-> '199 days 21:21:23' FROM intervaltmp ORDER BY a <-> '199 days 21:21:23' LIMIT 3; diff --git a/contrib/btree_gist/sql/time.sql b/contrib/btree_gist/sql/time.sql index 3329ee64da33c930bd6224695f7477d8f01c9645..6104e7f61c8e28ca6dfeca1735a916ce456a0f42 100644 --- a/contrib/btree_gist/sql/time.sql +++ b/contrib/btree_gist/sql/time.sql @@ -16,6 +16,8 @@ SELECT count(*) FROM timetmp WHERE a >= '10:57:11'; SELECT count(*) FROM timetmp WHERE a > '10:57:11'; +SELECT a, a <-> '10:57:11' FROM timetmp ORDER BY a <-> '10:57:11' LIMIT 3; + CREATE INDEX timeidx ON timetmp USING gist ( a ); SET enable_seqscan=off; @@ -29,3 +31,7 @@ SELECT count(*) FROM timetmp WHERE a = '10:57:11'::time; SELECT count(*) FROM timetmp WHERE a >= '10:57:11'::time; SELECT count(*) FROM timetmp WHERE a > '10:57:11'::time; + +EXPLAIN (COSTS OFF) +SELECT a, a <-> '10:57:11' FROM timetmp ORDER BY a <-> '10:57:11' LIMIT 3; +SELECT a, a <-> '10:57:11' FROM timetmp ORDER BY a <-> '10:57:11' LIMIT 3; diff --git a/contrib/btree_gist/sql/timestamp.sql b/contrib/btree_gist/sql/timestamp.sql index 25e942874eb86371d49ca6778c2b94eca829d4b7..95effebfc47a7fbf9d9896d7f2e17c37c2107be2 100644 --- a/contrib/btree_gist/sql/timestamp.sql +++ b/contrib/btree_gist/sql/timestamp.sql @@ -16,6 +16,8 @@ SELECT count(*) FROM timestamptmp WHERE a >= '2004-10-26 08:55:08'; SELECT count(*) FROM timestamptmp WHERE a > '2004-10-26 08:55:08'; +SELECT a, a <-> '2004-10-26 08:55:08' FROM timestamptmp ORDER BY a <-> '2004-10-26 08:55:08' LIMIT 3; + CREATE INDEX timestampidx ON timestamptmp USING gist ( a ); SET enable_seqscan=off; @@ -29,3 +31,7 @@ SELECT count(*) FROM timestamptmp WHERE a = '2004-10-26 08:55:08'::timestamp; SELECT count(*) FROM timestamptmp WHERE a >= '2004-10-26 08:55:08'::timestamp; SELECT count(*) FROM timestamptmp WHERE a > '2004-10-26 08:55:08'::timestamp; + +EXPLAIN (COSTS OFF) +SELECT a, a <-> '2004-10-26 08:55:08' FROM timestamptmp ORDER BY a <-> '2004-10-26 08:55:08' LIMIT 3; +SELECT a, a <-> '2004-10-26 08:55:08' FROM timestamptmp ORDER BY a <-> '2004-10-26 08:55:08' LIMIT 3; diff --git a/contrib/btree_gist/sql/timestamptz.sql b/contrib/btree_gist/sql/timestamptz.sql index 371233bc53a5704e5d54de31de5c357e149d67f4..f70caa4a6492c19d53572ee38520c9e6bd5a6b2d 100644 --- a/contrib/btree_gist/sql/timestamptz.sql +++ b/contrib/btree_gist/sql/timestamptz.sql @@ -37,7 +37,7 @@ SELECT count(*) FROM timestamptztmp WHERE a >= '2018-12-18 10:59:54 GMT+4'; SELECT count(*) FROM timestamptztmp WHERE a > '2018-12-18 10:59:54 GMT+4'; - +SELECT a, a <-> '2018-12-18 10:59:54 GMT+2' FROM timestamptztmp ORDER BY a <-> '2018-12-18 10:59:54 GMT+2' LIMIT 3; CREATE INDEX timestamptzidx ON timestamptztmp USING gist ( a ); @@ -74,3 +74,7 @@ SELECT count(*) FROM timestamptztmp WHERE a = '2018-12-18 10:59:54 GMT+4'::time SELECT count(*) FROM timestamptztmp WHERE a >= '2018-12-18 10:59:54 GMT+4'::timestamptz; SELECT count(*) FROM timestamptztmp WHERE a > '2018-12-18 10:59:54 GMT+4'::timestamptz; + +EXPLAIN (COSTS OFF) +SELECT a, a <-> '2018-12-18 10:59:54 GMT+2' FROM timestamptztmp ORDER BY a <-> '2018-12-18 10:59:54 GMT+2' LIMIT 3; +SELECT a, a <-> '2018-12-18 10:59:54 GMT+2' FROM timestamptztmp ORDER BY a <-> '2018-12-18 10:59:54 GMT+2' LIMIT 3; diff --git a/doc/src/sgml/btree-gist.sgml b/doc/src/sgml/btree-gist.sgml index 931acda95f9db9523f3905e732129dc42d2b0735..af3f707bb9c73c6876f12b9772a8fbb25dd0a8db 100644 --- a/doc/src/sgml/btree-gist.sgml +++ b/doc/src/sgml/btree-gist.sgml @@ -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><></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> @@ -48,6 +64,8 @@ CREATE TABLE test (a int4); CREATE INDEX testidx ON test USING gist (a); -- query SELECT * FROM test WHERE a < 10; +-- nearest-neighbor search: find the ten entries closest to "42" +SELECT *, a <-> 42 AS dist FROM test ORDER BY a <-> 42 LIMIT 10; </programlisting> <para>