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 @@ Datum gtrgm_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{
165190 GISTENTRY * entry = (GISTENTRY * ) PG_GETARG_POINTER (0 );
166191 text * query = PG_GETARG_TEXT_P (1 );
167-
168- /* StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2); */
192+ StrategyNumber strategy = (StrategyNumber ) PG_GETARG_UINT16 (2 );
169193 /* Oid subtype = PG_GETARG_OID(3); */
170194 bool * recheck = (bool * ) PG_GETARG_POINTER (4 );
171195 TRGM * key = (TRGM * ) DatumGetPointer (entry -> key );
172196 TRGM * qtrg ;
173- bool res = false ;
197+ bool res ;
174198 char * 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
194218 qtrg = (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+ /* Oid subtype = 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
0 commit comments