diff -c -r -N contrib.orig/pg_trgm/expected/pg_trgm.out contrib/pg_trgm/expected/pg_trgm.out
*** contrib.orig/pg_trgm/expected/pg_trgm.out	2009-12-30 15:36:27.000000000 +0300
--- contrib/pg_trgm/expected/pg_trgm.out	2009-12-30 15:44:18.000000000 +0300
***************
*** 1187,1192 ****
--- 1187,1199 ----
   qwertyu0988 | 0.333333
  (1 row)
  
+ select t <-> 'q0987wertyu0988', t from test_trgm order by t <-> 'q0987wertyu0988' limit 2;
+  ?column? |      t      
+ ----------+-------------
+  0.411765 | qwertyu0988
+       0.5 | qwertyu0987
+ (2 rows)
+ 
  create index trgm_idx on test_trgm using gist (t gist_trgm_ops);
  set enable_seqscan=off;
  select t,similarity(t,'qwertyu0988') as sml from test_trgm where t % 'qwertyu0988' order by sml desc, t;
***************
*** 2315,2320 ****
--- 2322,2343 ----
   qwertyu0988 | 0.333333
  (1 row)
  
+ explain (costs off)
+ select t <-> 'q0987wertyu0988', t from test_trgm order by t <-> 'q0987wertyu0988' limit 2;
+                      QUERY PLAN                     
+ ----------------------------------------------------
+  Limit
+    ->  Index Scan using trgm_idx on test_trgm
+          Sort Cond: (t <-> 'q0987wertyu0988'::text)
+ (3 rows)
+ 
+ select t <-> 'q0987wertyu0988', t from test_trgm order by t <-> 'q0987wertyu0988' limit 2;
+  ?column? |      t      
+ ----------+-------------
+  0.411765 | qwertyu0988
+       0.5 | qwertyu0987
+ (2 rows)
+ 
  drop index trgm_idx;
  create index trgm_idx on test_trgm using gin (t gin_trgm_ops);
  set enable_seqscan=off;
diff -c -r -N contrib.orig/pg_trgm/pg_trgm.sql.in contrib/pg_trgm/pg_trgm.sql.in
*** contrib.orig/pg_trgm/pg_trgm.sql.in	2009-12-30 15:36:27.000000000 +0300
--- contrib/pg_trgm/pg_trgm.sql.in	2009-12-30 15:44:18.000000000 +0300
***************
*** 37,42 ****
--- 37,54 ----
          JOIN = contjoinsel
  );
  
+ CREATE OR REPLACE FUNCTION similarity_dist(text,text)
+ RETURNS float4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT STABLE;
+ 
+ CREATE OPERATOR <-> (
+         LEFTARG = text,
+         RIGHTARG = text,
+         PROCEDURE = similarity_dist,
+         COMMUTATOR = '<->'
+ );
+ 
  -- gist key
  CREATE OR REPLACE FUNCTION gtrgm_in(cstring)
  RETURNS gtrgm
***************
*** 56,62 ****
  
  -- support functions for gist
  CREATE OR REPLACE FUNCTION gtrgm_consistent(internal,text,int,oid,internal)
! RETURNS bool
  AS 'MODULE_PATHNAME'
  LANGUAGE C IMMUTABLE STRICT;
   
--- 68,74 ----
  
  -- support functions for gist
  CREATE OR REPLACE FUNCTION gtrgm_consistent(internal,text,int,oid,internal)
! RETURNS float8
  AS 'MODULE_PATHNAME'
  LANGUAGE C IMMUTABLE STRICT;
   
***************
*** 95,100 ****
--- 107,113 ----
  FOR TYPE text USING gist
  AS
          OPERATOR        1       % (text, text),
+         OPERATOR        2       <-> (text, text),
          FUNCTION        1       gtrgm_consistent (internal, text, int, oid, internal),
          FUNCTION        2       gtrgm_union (bytea, internal),
          FUNCTION        3       gtrgm_compress (internal),
diff -c -r -N contrib.orig/pg_trgm/sql/pg_trgm.sql contrib/pg_trgm/sql/pg_trgm.sql
*** contrib.orig/pg_trgm/sql/pg_trgm.sql	2009-12-30 15:36:27.000000000 +0300
--- contrib/pg_trgm/sql/pg_trgm.sql	2009-12-30 15:44:18.000000000 +0300
***************
*** 26,31 ****
--- 26,32 ----
  select t,similarity(t,'qwertyu0988') as sml from test_trgm where t % 'qwertyu0988' order by sml desc, t;
  select t,similarity(t,'gwertyu0988') as sml from test_trgm where t % 'gwertyu0988' order by sml desc, t;
  select t,similarity(t,'gwertyu1988') as sml from test_trgm where t % 'gwertyu1988' order by sml desc, t;
+ select t <-> 'q0987wertyu0988', t from test_trgm order by t <-> 'q0987wertyu0988' limit 2;
  
  create index trgm_idx on test_trgm using gist (t gist_trgm_ops);
  set enable_seqscan=off;
***************
*** 33,38 ****
--- 34,42 ----
  select t,similarity(t,'qwertyu0988') as sml from test_trgm where t % 'qwertyu0988' order by sml desc, t;
  select t,similarity(t,'gwertyu0988') as sml from test_trgm where t % 'gwertyu0988' order by sml desc, t;
  select t,similarity(t,'gwertyu1988') as sml from test_trgm where t % 'gwertyu1988' order by sml desc, t;
+ explain (costs off)
+ select t <-> 'q0987wertyu0988', t from test_trgm order by t <-> 'q0987wertyu0988' limit 2;
+ select t <-> 'q0987wertyu0988', t from test_trgm order by t <-> 'q0987wertyu0988' limit 2;
  
  drop index trgm_idx;
  create index trgm_idx on test_trgm using gin (t gin_trgm_ops);
diff -c -r -N contrib.orig/pg_trgm/trgm_gist.c contrib/pg_trgm/trgm_gist.c
*** contrib.orig/pg_trgm/trgm_gist.c	2009-12-30 15:36:27.000000000 +0300
--- contrib/pg_trgm/trgm_gist.c	2009-12-30 15:44:18.000000000 +0300
***************
*** 5,10 ****
--- 5,11 ----
  
  #include "access/gist.h"
  #include "access/itup.h"
+ #include "access/skey.h"
  #include "access/tuptoaster.h"
  #include "storage/bufpage.h"
  #include "utils/array.h"
***************
*** 159,176 ****
  	}
  }
  
  Datum
  gtrgm_consistent(PG_FUNCTION_ARGS)
  {
  	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
  	text	   *query = PG_GETARG_TEXT_P(1);
! 
! 	/* StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2); */
  	/* Oid		subtype = PG_GETARG_OID(3); */
  	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
  	TRGM	   *key = (TRGM *) DatumGetPointer(entry->key);
  	TRGM	   *qtrg;
! 	bool		res = false;
  	char	   *cache = (char *) fcinfo->flinfo->fn_extra;
  
  	/* All cases served by this function are exact */
--- 160,197 ----
  	}
  }
  
+ #define	SimilarityStrategyNumber	1
+ #define	DistanceStrategyNumber		2
+ 
+ static int4
+ cnt_sml_sign_common(TRGM *qtrg, BITVECP sign)
+ {
+ 	int4		count = 0;
+ 	int4		k,
+ 				len = ARRNELEM(qtrg);
+ 	trgm	   *ptr = GETARR(qtrg);
+ 	int4		tmp = 0;
+ 
+ 	for (k = 0; k < len; k++)
+ 	{
+ 		CPTRGM(((char *) &tmp), ptr + k);
+ 		count += GETBIT(sign, HASHVAL(tmp));
+ 	}
+ 
+ 	return count;
+ }
+ 
  Datum
  gtrgm_consistent(PG_FUNCTION_ARGS)
  {
  	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
  	text	   *query = PG_GETARG_TEXT_P(1);
! 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
  	/* Oid		subtype = PG_GETARG_OID(3); */
  	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
  	TRGM	   *key = (TRGM *) DatumGetPointer(entry->key);
  	TRGM	   *qtrg;
! 	float8		res;
  	char	   *cache = (char *) fcinfo->flinfo->fn_extra;
  
  	/* All cases served by this function are exact */
***************
*** 193,231 ****
  
  	qtrg = (TRGM *) (cache + MAXALIGN(VARSIZE(query)));
  
! 	if (GIST_LEAF(entry))
! 	{							/* all leafs contains orig trgm */
! 		float4		tmpsml = cnt_sml(key, qtrg);
  
! 		/* strange bug at freebsd 5.2.1 and gcc 3.3.3 */
! 		res = (*(int *) &tmpsml == *(int *) &trgm_limit || tmpsml > trgm_limit) ? true : false;
! 	}
! 	else if (ISALLTRUE(key))
! 	{							/* non-leaf contains signature */
! 		res = true;
! 	}
! 	else
! 	{							/* non-leaf contains signature */
! 		int4		count = 0;
! 		int4		k,
! 					len = ARRNELEM(qtrg);
! 		trgm	   *ptr = GETARR(qtrg);
! 		BITVECP		sign = GETSIGN(key);
! 		int4		tmp = 0;
  
! 		for (k = 0; k < len; k++)
! 		{
! 			CPTRGM(((char *) &tmp), ptr + k);
! 			count += GETBIT(sign, HASHVAL(tmp));
! 		}
! #ifdef DIVUNION
! 		res = (len == count) ? true : ((((((float4) count) / ((float4) (len - count)))) >= trgm_limit) ? true : false);
! #else
! 		res = (len == 0) ? false : ((((((float4) count) / ((float4) len))) >= trgm_limit) ? true : false);
! #endif
  	}
  
! 	PG_RETURN_BOOL(res);
  }
  
  static int4
--- 214,266 ----
  
  	qtrg = (TRGM *) (cache + MAXALIGN(VARSIZE(query)));
  
! 	switch(strategy)
! 	{
! 		case SimilarityStrategyNumber:
! 			if (GIST_LEAF(entry))
! 			{							/* all leafs contains orig trgm */
! 				float4      tmpsml = cnt_sml(key, qtrg);
  
! 				/* strange bug at freebsd 5.2.1 and gcc 3.3.3 */
! 				res = (*(int *) &tmpsml == *(int *) &trgm_limit || tmpsml > trgm_limit) ? 0.0 : -1.0;
! 			}
! 			else if (ISALLTRUE(key))
! 			{							/* non-leaf contains signature */
! 				res = 0.0; /*true!*/
! 			}
! 			else
! 			{							/* non-leaf contains signature */
! 				int4 count = cnt_sml_sign_common(qtrg, GETSIGN(key));
! 				int4 len = ARRNELEM(qtrg);
! 
! 				if (len == 0)
! 					res = -1.0;
! 				else
! 					res = (((((float8) count) / ((float8) len))) >= trgm_limit) ? 0.0 : -1.0;
! 			}
! 			break;
! 		case DistanceStrategyNumber:
! 			if (GIST_LEAF(entry))
! 			{							/* all leafs contains orig trgm */
! 				res = 1.0 - cnt_sml(key, qtrg);
! 			}
! 			else if (ISALLTRUE(key))
! 			{							/* all leafs contains orig trgm */
! 				res = 0.0; 
! 			}
! 			else
! 			{							/* non-leaf contains signature */
! 				int4 count = cnt_sml_sign_common(qtrg, GETSIGN(key));
! 				int4 len = ARRNELEM(qtrg);
  
! 				res = (len == 0) ? -1.0 : 1.0 - ((float8) count) / ((float8) len);
! 			}
! 			break;
! 		default:
! 			elog(ERROR, "Unknown strategy number: %d", strategy);
  	}
  
! 	PG_RETURN_FLOAT8(res);
  }
  
  static int4
diff -c -r -N contrib.orig/pg_trgm/trgm_op.c contrib/pg_trgm/trgm_op.c
*** contrib.orig/pg_trgm/trgm_op.c	2009-12-30 15:36:27.000000000 +0300
--- contrib/pg_trgm/trgm_op.c	2009-12-30 15:44:18.000000000 +0300
***************
*** 359,364 ****
--- 359,377 ----
  	PG_RETURN_FLOAT4(res);
  }
  
+ PG_FUNCTION_INFO_V1(similarity_dist);
+ Datum		similarity_dist(PG_FUNCTION_ARGS);
+ Datum
+ similarity_dist(PG_FUNCTION_ARGS)
+ {
+ 	float4		res = DatumGetFloat4(DirectFunctionCall2(
+ 														 similarity,
+ 														 PG_GETARG_DATUM(0),
+ 														 PG_GETARG_DATUM(1)
+ 														 ));
+ 	PG_RETURN_FLOAT4( 1.0 - res );
+ }
+ 
  PG_FUNCTION_INFO_V1(similarity_op);
  Datum		similarity_op(PG_FUNCTION_ARGS);
  Datum
diff -c -r -N contrib.orig/pg_trgm/uninstall_pg_trgm.sql contrib/pg_trgm/uninstall_pg_trgm.sql
*** contrib.orig/pg_trgm/uninstall_pg_trgm.sql	2009-12-30 15:36:27.000000000 +0300
--- contrib/pg_trgm/uninstall_pg_trgm.sql	2009-12-30 15:44:18.000000000 +0300
***************
*** 33,38 ****
--- 33,42 ----
  
  DROP FUNCTION similarity_op(text,text);
  
+ DROP OPERATOR <-> (text, text);
+ 
+ DROP FUNCTION similarity_dist(text,text);
+ 
  DROP FUNCTION similarity(text,text);
  
  DROP FUNCTION show_trgm(text);
