@@ -190,54 +190,63 @@ gtrgm_consistent(PG_FUNCTION_ARGS)
190190 TRGM * key = (TRGM * ) DatumGetPointer (entry -> key );
191191 TRGM * qtrg ;
192192 bool res ;
193+ Size querysize = VARSIZE (query );
193194 char * cache = (char * ) fcinfo -> flinfo -> fn_extra ,
194- * cacheContents = cache + MAXALIGN (sizeof (StrategyNumber ));
195+ * cachedQuery = cache + MAXALIGN (sizeof (StrategyNumber ));
195196
196197 /*
197198 * Store both the strategy number and extracted trigrams in cache, because
198199 * trigram extraction is relatively CPU-expensive. We must include
199200 * strategy number because trigram extraction depends on strategy.
201+ *
202+ * The cached structure contains the strategy number, then the input
203+ * query (starting at a MAXALIGN boundary), then the TRGM value (also
204+ * starting at a MAXALIGN boundary).
200205 */
201- if (cache == NULL || strategy != * ((StrategyNumber * ) cache ) ||
202- VARSIZE (cacheContents ) != VARSIZE (query ) ||
203- memcmp (cacheContents , query , VARSIZE (query )) != 0 )
206+ if (cache == NULL ||
207+ strategy != * ((StrategyNumber * ) cache ) ||
208+ VARSIZE (cachedQuery ) != querysize ||
209+ memcmp (cachedQuery , query , querysize ) != 0 )
204210 {
211+ char * newcache ;
212+
205213 switch (strategy )
206214 {
207215 case SimilarityStrategyNumber :
208- qtrg = generate_trgm (VARDATA (query ), VARSIZE (query ) - VARHDRSZ );
216+ qtrg = generate_trgm (VARDATA (query ),
217+ querysize - VARHDRSZ );
209218 break ;
210219 case ILikeStrategyNumber :
211220#ifndef IGNORECASE
212221 elog (ERROR , "cannot handle ~~* with case-sensitive trigrams" );
213222#endif
214223 /* FALL THRU */
215224 case LikeStrategyNumber :
216- qtrg = generate_wildcard_trgm (VARDATA (query ), VARSIZE (query ) - VARHDRSZ );
225+ qtrg = generate_wildcard_trgm (VARDATA (query ),
226+ querysize - VARHDRSZ );
217227 break ;
218228 default :
219229 elog (ERROR , "unrecognized strategy number: %d" , strategy );
220230 qtrg = NULL ; /* keep compiler quiet */
221231 break ;
222232 }
223233
234+ newcache = MemoryContextAlloc (fcinfo -> flinfo -> fn_mcxt ,
235+ MAXALIGN (sizeof (StrategyNumber )) +
236+ MAXALIGN (querysize ) +
237+ VARSIZE (qtrg ));
238+ cachedQuery = newcache + MAXALIGN (sizeof (StrategyNumber ));
239+
240+ * ((StrategyNumber * ) newcache ) = strategy ;
241+ memcpy (cachedQuery , query , querysize );
242+ memcpy (cachedQuery + MAXALIGN (querysize ), qtrg , VARSIZE (qtrg ));
243+
224244 if (cache )
225245 pfree (cache );
226-
227- fcinfo -> flinfo -> fn_extra =
228- MemoryContextAlloc (fcinfo -> flinfo -> fn_mcxt ,
229- MAXALIGN (sizeof (StrategyNumber )) +
230- MAXALIGN (VARSIZE (query )) +
231- VARSIZE (qtrg ));
232- cache = (char * ) fcinfo -> flinfo -> fn_extra ;
233- cacheContents = cache + MAXALIGN (sizeof (StrategyNumber ));
234-
235- * ((StrategyNumber * ) cache ) = strategy ;
236- memcpy (cacheContents , query , VARSIZE (query ));
237- memcpy (cacheContents + MAXALIGN (VARSIZE (query )), qtrg , VARSIZE (qtrg ));
246+ fcinfo -> flinfo -> fn_extra = newcache ;
238247 }
239248
240- qtrg = (TRGM * ) (cacheContents + MAXALIGN (VARSIZE ( query ) ));
249+ qtrg = (TRGM * ) (cachedQuery + MAXALIGN (querysize ));
241250
242251 switch (strategy )
243252 {
@@ -328,24 +337,35 @@ gtrgm_distance(PG_FUNCTION_ARGS)
328337 TRGM * key = (TRGM * ) DatumGetPointer (entry -> key );
329338 TRGM * qtrg ;
330339 float8 res ;
340+ Size querysize = VARSIZE (query );
331341 char * cache = (char * ) fcinfo -> flinfo -> fn_extra ;
332342
333- if (cache == NULL || VARSIZE (cache ) != VARSIZE (query ) || memcmp (cache , query , VARSIZE (query )) != 0 )
343+ /*
344+ * Cache the generated trigrams across multiple calls with the same
345+ * query.
346+ */
347+ if (cache == NULL ||
348+ VARSIZE (cache ) != querysize ||
349+ memcmp (cache , query , querysize ) != 0 )
334350 {
335- qtrg = generate_trgm ( VARDATA ( query ), VARSIZE ( query ) - VARHDRSZ ) ;
351+ char * newcache ;
336352
337- if (cache )
338- pfree (cache );
353+ qtrg = generate_trgm (VARDATA (query ), querysize - VARHDRSZ );
354+
355+ newcache = MemoryContextAlloc (fcinfo -> flinfo -> fn_mcxt ,
356+ MAXALIGN (querysize ) +
357+ VARSIZE (qtrg ));
339358
340- fcinfo -> flinfo -> fn_extra = MemoryContextAlloc (fcinfo -> flinfo -> fn_mcxt ,
341- MAXALIGN (VARSIZE (query )) + VARSIZE (qtrg ));
342- cache = (char * ) fcinfo -> flinfo -> fn_extra ;
359+ memcpy (newcache , query , querysize );
360+ memcpy (newcache + MAXALIGN (querysize ), qtrg , VARSIZE (qtrg ));
343361
344- memcpy (cache , query , VARSIZE (query ));
345- memcpy (cache + MAXALIGN (VARSIZE (query )), qtrg , VARSIZE (qtrg ));
362+ if (cache )
363+ pfree (cache );
364+ fcinfo -> flinfo -> fn_extra = newcache ;
365+ cache = newcache ;
346366 }
347367
348- qtrg = (TRGM * ) (cache + MAXALIGN (VARSIZE ( query ) ));
368+ qtrg = (TRGM * ) (cache + MAXALIGN (querysize ));
349369
350370 switch (strategy )
351371 {
@@ -552,9 +572,36 @@ gtrgm_penalty(PG_FUNCTION_ARGS)
552572
553573 if (ISARRKEY (newval ))
554574 {
555- BITVEC sign ;
575+ char * cache = (char * ) fcinfo -> flinfo -> fn_extra ;
576+ TRGM * cachedVal = (TRGM * ) (cache + MAXALIGN (sizeof (BITVEC )));
577+ Size newvalsize = VARSIZE (newval );
578+ BITVECP sign ;
579+
580+ /*
581+ * Cache the sign data across multiple calls with the same newval.
582+ */
583+ if (cache == NULL ||
584+ VARSIZE (cachedVal ) != newvalsize ||
585+ memcmp (cachedVal , newval , newvalsize ) != 0 )
586+ {
587+ char * newcache ;
588+
589+ newcache = MemoryContextAlloc (fcinfo -> flinfo -> fn_mcxt ,
590+ MAXALIGN (sizeof (BITVEC )) +
591+ newvalsize );
592+
593+ makesign ((BITVECP ) newcache , newval );
556594
557- makesign (sign , newval );
595+ cachedVal = (TRGM * ) (newcache + MAXALIGN (sizeof (BITVEC )));
596+ memcpy (cachedVal , newval , newvalsize );
597+
598+ if (cache )
599+ pfree (cache );
600+ fcinfo -> flinfo -> fn_extra = newcache ;
601+ cache = newcache ;
602+ }
603+
604+ sign = (BITVECP ) cache ;
558605
559606 if (ISALLTRUE (origval ))
560607 * penalty = ((float ) (SIGLENBIT - sizebitvec (sign ))) / (float ) (SIGLENBIT + 1 );
@@ -643,20 +690,16 @@ gtrgm_picksplit(PG_FUNCTION_ARGS)
643690 CACHESIGN * cache ;
644691 SPLITCOST * costvector ;
645692
646- nbytes = (maxoff + 2 ) * sizeof (OffsetNumber );
647- v -> spl_left = (OffsetNumber * ) palloc (nbytes );
648- v -> spl_right = (OffsetNumber * ) palloc (nbytes );
649-
693+ /* cache the sign data for each existing item */
650694 cache = (CACHESIGN * ) palloc (sizeof (CACHESIGN ) * (maxoff + 2 ));
651- fillcache (& cache [FirstOffsetNumber ], GETENTRY (entryvec , FirstOffsetNumber ));
695+ for (k = FirstOffsetNumber ; k <= maxoff ; k = OffsetNumberNext (k ))
696+ fillcache (& cache [k ], GETENTRY (entryvec , k ));
652697
698+ /* now find the two furthest-apart items */
653699 for (k = FirstOffsetNumber ; k < maxoff ; k = OffsetNumberNext (k ))
654700 {
655701 for (j = OffsetNumberNext (k ); j <= maxoff ; j = OffsetNumberNext (j ))
656702 {
657- if (k == FirstOffsetNumber )
658- fillcache (& cache [j ], GETENTRY (entryvec , j ));
659-
660703 size_waste = hemdistcache (& (cache [j ]), & (cache [k ]));
661704 if (size_waste > waste )
662705 {
@@ -667,17 +710,20 @@ gtrgm_picksplit(PG_FUNCTION_ARGS)
667710 }
668711 }
669712
670- left = v -> spl_left ;
671- v -> spl_nleft = 0 ;
672- right = v -> spl_right ;
673- v -> spl_nright = 0 ;
674-
713+ /* just in case we didn't make a selection ... */
675714 if (seed_1 == 0 || seed_2 == 0 )
676715 {
677716 seed_1 = 1 ;
678717 seed_2 = 2 ;
679718 }
680719
720+ /* initialize the result vectors */
721+ nbytes = (maxoff + 2 ) * sizeof (OffsetNumber );
722+ v -> spl_left = left = (OffsetNumber * ) palloc (nbytes );
723+ v -> spl_right = right = (OffsetNumber * ) palloc (nbytes );
724+ v -> spl_nleft = 0 ;
725+ v -> spl_nright = 0 ;
726+
681727 /* form initial .. */
682728 if (cache [seed_1 ].allistrue )
683729 {
0 commit comments