11/*
22 * contrib/pg_trgm/trgm_gist.c
33 */
4+ #include "postgres.h"
5+
46#include "trgm.h"
57
68#include "access/gist.h"
79#include "access/itup.h"
10+ #include "access/skey.h"
811#include "access/tuptoaster.h"
912#include "storage/bufpage.h"
1013#include "utils/array.h"
1114#include "utils/builtins.h"
1215
16+
1317PG_FUNCTION_INFO_V1 (gtrgm_in );
1418Datum gtrgm_in (PG_FUNCTION_ARGS );
1519
@@ -25,6 +29,9 @@ Datumgtrgm_decompress(PG_FUNCTION_ARGS);
2529PG_FUNCTION_INFO_V1 (gtrgm_consistent );
2630Datum gtrgm_consistent (PG_FUNCTION_ARGS );
2731
32+ PG_FUNCTION_INFO_V1 (gtrgm_distance );
33+ Datum gtrgm_distance (PG_FUNCTION_ARGS );
34+
2835PG_FUNCTION_INFO_V1 (gtrgm_union );
2936Datum gtrgm_union (PG_FUNCTION_ARGS );
3037
@@ -159,18 +166,35 @@ gtrgm_decompress(PG_FUNCTION_ARGS)
159166}
160167}
161168
169+ static int4
170+ cnt_sml_sign_common (TRGM * qtrg ,BITVECP sign )
171+ {
172+ int4 count = 0 ;
173+ int4 k ,
174+ len = ARRNELEM (qtrg );
175+ trgm * ptr = GETARR (qtrg );
176+ int4 tmp = 0 ;
177+
178+ for (k = 0 ;k < len ;k ++ )
179+ {
180+ CPTRGM (((char * )& tmp ),ptr + k );
181+ count += GETBIT (sign ,HASHVAL (tmp ));
182+ }
183+
184+ return count ;
185+ }
186+
162187Datum
163188gtrgm_consistent (PG_FUNCTION_ARGS )
164189{
165190GISTENTRY * entry = (GISTENTRY * )PG_GETARG_POINTER (0 );
166191text * query = PG_GETARG_TEXT_P (1 );
167-
168- /* StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2); */
192+ StrategyNumber strategy = (StrategyNumber )PG_GETARG_UINT16 (2 );
169193/* Oidsubtype = PG_GETARG_OID(3); */
170194bool * recheck = (bool * )PG_GETARG_POINTER (4 );
171195TRGM * key = (TRGM * )DatumGetPointer (entry -> key );
172196TRGM * qtrg ;
173- bool res = false ;
197+ bool res ;
174198char * cache = (char * )fcinfo -> flinfo -> fn_extra ;
175199
176200/* All cases served by this function are exact */
@@ -193,39 +217,95 @@ gtrgm_consistent(PG_FUNCTION_ARGS)
193217
194218qtrg = (TRGM * ) (cache + MAXALIGN (VARSIZE (query )));
195219
196- if (GIST_LEAF (entry ))
197- {/* all leafs contains orig trgm */
198- float4 tmpsml = cnt_sml (key ,qtrg );
220+ switch (strategy )
221+ {
222+ case SimilarityStrategyNumber :
223+ if (GIST_LEAF (entry ))
224+ {/* all leafs contains orig trgm */
225+ float4 tmpsml = cnt_sml (key ,qtrg );
199226
200- /* strange bug at freebsd 5.2.1 and gcc 3.3.3 */
201- res = (* (int * )& tmpsml == * (int * )& trgm_limit || tmpsml > trgm_limit ) ? true : false;
227+ /* strange bug at freebsd 5.2.1 and gcc 3.3.3 */
228+ res = (* (int * )& tmpsml == * (int * )& trgm_limit || tmpsml > trgm_limit ) ? true : false;
229+ }
230+ else if (ISALLTRUE (key ))
231+ {/* non-leaf contains signature */
232+ res = true;
233+ }
234+ else
235+ {/* non-leaf contains signature */
236+ int4 count = cnt_sml_sign_common (qtrg ,GETSIGN (key ));
237+ int4 len = ARRNELEM (qtrg );
238+
239+ if (len == 0 )
240+ res = false;
241+ else
242+ res = (((((float8 )count ) / ((float8 )len ))) >=trgm_limit ) ? true : false;
243+ }
244+ break ;
245+ default :
246+ elog (ERROR ,"unrecognized strategy number: %d" ,strategy );
247+ res = false;/* keep compiler quiet */
248+ break ;
202249}
203- else if (ISALLTRUE (key ))
204- {/* non-leaf contains signature */
205- res = true;
250+
251+ PG_RETURN_BOOL (res );
252+ }
253+
254+ Datum
255+ gtrgm_distance (PG_FUNCTION_ARGS )
256+ {
257+ GISTENTRY * entry = (GISTENTRY * )PG_GETARG_POINTER (0 );
258+ text * query = PG_GETARG_TEXT_P (1 );
259+ StrategyNumber strategy = (StrategyNumber )PG_GETARG_UINT16 (2 );
260+ /* Oidsubtype = PG_GETARG_OID(3); */
261+ TRGM * key = (TRGM * )DatumGetPointer (entry -> key );
262+ TRGM * qtrg ;
263+ float8 res ;
264+ char * cache = (char * )fcinfo -> flinfo -> fn_extra ;
265+
266+ if (cache == NULL || VARSIZE (cache )!= VARSIZE (query )|| memcmp (cache ,query ,VARSIZE (query ))!= 0 )
267+ {
268+ qtrg = generate_trgm (VARDATA (query ),VARSIZE (query )- VARHDRSZ );
269+
270+ if (cache )
271+ pfree (cache );
272+
273+ fcinfo -> flinfo -> fn_extra = MemoryContextAlloc (fcinfo -> flinfo -> fn_mcxt ,
274+ MAXALIGN (VARSIZE (query ))+ VARSIZE (qtrg ));
275+ cache = (char * )fcinfo -> flinfo -> fn_extra ;
276+
277+ memcpy (cache ,query ,VARSIZE (query ));
278+ memcpy (cache + MAXALIGN (VARSIZE (query )),qtrg ,VARSIZE (qtrg ));
206279}
207- else
208- {/* non-leaf contains signature */
209- int4 count = 0 ;
210- int4 k ,
211- len = ARRNELEM (qtrg );
212- trgm * ptr = GETARR (qtrg );
213- BITVECP sign = GETSIGN (key );
214- int4 tmp = 0 ;
215280
216- for (k = 0 ;k < len ;k ++ )
217- {
218- CPTRGM (((char * )& tmp ),ptr + k );
219- count += GETBIT (sign ,HASHVAL (tmp ));
220- }
221- #ifdef DIVUNION
222- res = (len == count ) ? true : ((((((float4 )count ) / ((float4 ) (len - count )))) >=trgm_limit ) ? true : false);
223- #else
224- res = (len == 0 ) ? false : ((((((float4 )count ) / ((float4 )len ))) >=trgm_limit ) ? true : false);
225- #endif
281+ qtrg = (TRGM * ) (cache + MAXALIGN (VARSIZE (query )));
282+
283+ switch (strategy )
284+ {
285+ case DistanceStrategyNumber :
286+ if (GIST_LEAF (entry ))
287+ {/* all leafs contains orig trgm */
288+ res = 1.0 - cnt_sml (key ,qtrg );
289+ }
290+ else if (ISALLTRUE (key ))
291+ {/* all leafs contains orig trgm */
292+ res = 0.0 ;
293+ }
294+ else
295+ {/* non-leaf contains signature */
296+ int4 count = cnt_sml_sign_common (qtrg ,GETSIGN (key ));
297+ int4 len = ARRNELEM (qtrg );
298+
299+ res = (len == 0 ) ?-1.0 :1.0 - ((float8 )count ) / ((float8 )len );
300+ }
301+ break ;
302+ default :
303+ elog (ERROR ,"unrecognized strategy number: %d" ,strategy );
304+ res = 0 ;/* keep compiler quiet */
305+ break ;
226306}
227307
228- PG_RETURN_BOOL (res );
308+ PG_RETURN_FLOAT8 (res );
229309}
230310
231311static int4