LCOV - code coverage report
Current view: top level - contrib/pg_trgm - trgm_gist.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 79.8 % 431 344
Test Date: 2026-07-26 08:15:28 Functions: 87.5 % 32 28
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 58.0 % 250 145

             Branch data     Line data    Source code
       1                 :             : /*
       2                 :             :  * contrib/pg_trgm/trgm_gist.c
       3                 :             :  */
       4                 :             : #include "postgres.h"
       5                 :             : 
       6                 :             : #include "access/reloptions.h"
       7                 :             : #include "access/stratnum.h"
       8                 :             : #include "fmgr.h"
       9                 :             : #include "port/pg_bitutils.h"
      10                 :             : #include "trgm.h"
      11                 :             : #include "varatt.h"
      12                 :             : 
      13                 :             : /* gist_trgm_ops opclass options */
      14                 :             : typedef struct
      15                 :             : {
      16                 :             :     int32       vl_len_;        /* varlena header (do not touch directly!) */
      17                 :             :     int         siglen;         /* signature length in bytes */
      18                 :             : } TrgmGistOptions;
      19                 :             : 
      20                 :             : #define GET_SIGLEN()            (PG_HAS_OPCLASS_OPTIONS() ? \
      21                 :             :                                  ((TrgmGistOptions *) PG_GET_OPCLASS_OPTIONS())->siglen : \
      22                 :             :                                  SIGLEN_DEFAULT)
      23                 :             : 
      24                 :             : typedef struct
      25                 :             : {
      26                 :             :     /* most recent inputs to gtrgm_consistent */
      27                 :             :     StrategyNumber strategy;
      28                 :             :     text       *query;
      29                 :             :     /* extracted trigrams for query */
      30                 :             :     TRGM       *trigrams;
      31                 :             :     /* if a regex operator, the extracted graph */
      32                 :             :     TrgmPackedGraph *graph;
      33                 :             : 
      34                 :             :     /*
      35                 :             :      * The "query" and "trigrams" are stored in the same palloc block as this
      36                 :             :      * cache struct, at MAXALIGN'ed offsets.  The graph however isn't.
      37                 :             :      */
      38                 :             : } gtrgm_consistent_cache;
      39                 :             : 
      40                 :             : #define GETENTRY(vec,pos) ((TRGM *) DatumGetPointer((vec)->vector[(pos)].key))
      41                 :             : 
      42                 :             : 
      43                 :           1 : PG_FUNCTION_INFO_V1(gtrgm_in);
      44                 :           1 : PG_FUNCTION_INFO_V1(gtrgm_out);
      45                 :           5 : PG_FUNCTION_INFO_V1(gtrgm_compress);
      46                 :           5 : PG_FUNCTION_INFO_V1(gtrgm_decompress);
      47                 :           5 : PG_FUNCTION_INFO_V1(gtrgm_consistent);
      48                 :           5 : PG_FUNCTION_INFO_V1(gtrgm_distance);
      49                 :           5 : PG_FUNCTION_INFO_V1(gtrgm_union);
      50                 :           5 : PG_FUNCTION_INFO_V1(gtrgm_same);
      51                 :           5 : PG_FUNCTION_INFO_V1(gtrgm_penalty);
      52                 :           5 : PG_FUNCTION_INFO_V1(gtrgm_picksplit);
      53                 :           5 : PG_FUNCTION_INFO_V1(gtrgm_options);
      54                 :             : 
      55                 :             : 
      56                 :             : Datum
      57                 :           0 : gtrgm_in(PG_FUNCTION_ARGS)
      58                 :             : {
      59         [ #  # ]:           0 :     ereport(ERROR,
      60                 :             :             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
      61                 :             :              errmsg("cannot accept a value of type %s", "gtrgm")));
      62                 :             : 
      63                 :             :     PG_RETURN_VOID();           /* keep compiler quiet */
      64                 :             : }
      65                 :             : 
      66                 :             : Datum
      67                 :           0 : gtrgm_out(PG_FUNCTION_ARGS)
      68                 :             : {
      69         [ #  # ]:           0 :     ereport(ERROR,
      70                 :             :             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
      71                 :             :              errmsg("cannot display a value of type %s", "gtrgm")));
      72                 :             : 
      73                 :             :     PG_RETURN_VOID();           /* keep compiler quiet */
      74                 :             : }
      75                 :             : 
      76                 :             : static TRGM *
      77                 :       28116 : gtrgm_alloc(bool isalltrue, int siglen, BITVECP sign)
      78                 :             : {
      79         [ -  + ]:       28116 :     int         flag = SIGNKEY | (isalltrue ? ALLISTRUE : 0);
      80   [ -  +  +  - ]:       28116 :     int         size = CALCGTSIZE(flag, siglen);
      81                 :       28116 :     TRGM       *res = palloc(size);
      82                 :             : 
      83                 :       28116 :     SET_VARSIZE(res, size);
      84                 :       28116 :     res->flag = flag;
      85                 :             : 
      86         [ +  - ]:       28116 :     if (!isalltrue)
      87                 :             :     {
      88         [ +  + ]:       28116 :         if (sign)
      89                 :         554 :             memcpy(GETSIGN(res), sign, siglen);
      90                 :             :         else
      91                 :       27562 :             memset(GETSIGN(res), 0, siglen);
      92                 :             :     }
      93                 :             : 
      94                 :       28116 :     return res;
      95                 :             : }
      96                 :             : 
      97                 :             : static void
      98                 :       47422 : makesign(BITVECP sign, TRGM *a, int siglen)
      99                 :             : {
     100                 :             :     int32       k,
     101                 :       47422 :                 len = ARRNELEM(a);
     102                 :       47422 :     trgm       *ptr = GETARR(a);
     103                 :       47422 :     int32       tmp = 0;
     104                 :             : 
     105   [ +  +  +  +  :       47422 :     MemSet(sign, 0, siglen);
          +  -  -  +  -  
                      - ]
     106                 :       47422 :     SETBIT(sign, SIGLENBIT(siglen));    /* set last unused bit */
     107         [ +  + ]:      466998 :     for (k = 0; k < len; k++)
     108                 :             :     {
     109                 :      419576 :         CPTRGM(&tmp, ptr + k);
     110                 :      419576 :         HASH(sign, tmp, siglen);
     111                 :             :     }
     112                 :       47422 : }
     113                 :             : 
     114                 :             : Datum
     115                 :       27850 : gtrgm_compress(PG_FUNCTION_ARGS)
     116                 :             : {
     117                 :       27850 :     GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
     118         [ +  - ]:       27850 :     int         siglen = GET_SIGLEN();
     119                 :       27850 :     GISTENTRY  *retval = entry;
     120                 :             : 
     121         [ +  + ]:       27850 :     if (entry->leafkey)
     122                 :             :     {                           /* trgm */
     123                 :             :         TRGM       *res;
     124                 :       24452 :         text       *val = DatumGetTextPP(entry->key);
     125                 :             : 
     126                 :       24452 :         res = generate_trgm(VARDATA_ANY(val), VARSIZE_ANY_EXHDR(val));
     127                 :       24452 :         retval = palloc_object(GISTENTRY);
     128                 :       24452 :         gistentryinit(*retval, PointerGetDatum(res),
     129                 :             :                       entry->rel, entry->page,
     130                 :             :                       entry->offset, false);
     131                 :             :     }
     132         [ +  - ]:        3398 :     else if (ISSIGNKEY(DatumGetPointer(entry->key)) &&
     133         [ +  - ]:        3398 :              !ISALLTRUE(DatumGetPointer(entry->key)))
     134                 :             :     {
     135                 :             :         int32       i;
     136                 :             :         TRGM       *res;
     137                 :        3398 :         BITVECP     sign = GETSIGN(DatumGetPointer(entry->key));
     138                 :             : 
     139         [ +  - ]:        3652 :         LOOPBYTE(siglen)
     140                 :             :         {
     141         [ +  + ]:        3652 :             if ((sign[i] & 0xff) != 0xff)
     142                 :        3398 :                 PG_RETURN_POINTER(retval);
     143                 :             :         }
     144                 :             : 
     145                 :           0 :         res = gtrgm_alloc(true, siglen, sign);
     146                 :           0 :         retval = palloc_object(GISTENTRY);
     147                 :           0 :         gistentryinit(*retval, PointerGetDatum(res),
     148                 :             :                       entry->rel, entry->page,
     149                 :             :                       entry->offset, false);
     150                 :             :     }
     151                 :       24452 :     PG_RETURN_POINTER(retval);
     152                 :             : }
     153                 :             : 
     154                 :             : Datum
     155                 :     1353453 : gtrgm_decompress(PG_FUNCTION_ARGS)
     156                 :             : {
     157                 :     1353453 :     GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
     158                 :             :     GISTENTRY  *retval;
     159                 :             :     text       *key;
     160                 :             : 
     161                 :     1353453 :     key = DatumGetTextPP(entry->key);
     162                 :             : 
     163         [ -  + ]:     1353453 :     if (key != (text *) DatumGetPointer(entry->key))
     164                 :             :     {
     165                 :             :         /* need to pass back the decompressed item */
     166                 :           0 :         retval = palloc_object(GISTENTRY);
     167                 :           0 :         gistentryinit(*retval, PointerGetDatum(key),
     168                 :             :                       entry->rel, entry->page, entry->offset, entry->leafkey);
     169                 :           0 :         PG_RETURN_POINTER(retval);
     170                 :             :     }
     171                 :             :     else
     172                 :             :     {
     173                 :             :         /* we can return the entry as-is */
     174                 :     1353453 :         PG_RETURN_POINTER(entry);
     175                 :             :     }
     176                 :             : }
     177                 :             : 
     178                 :             : static int32
     179                 :         643 : cnt_sml_sign_common(TRGM *qtrg, BITVECP sign, int siglen)
     180                 :             : {
     181                 :         643 :     int32       count = 0;
     182                 :             :     int32       k,
     183                 :         643 :                 len = ARRNELEM(qtrg);
     184                 :         643 :     trgm       *ptr = GETARR(qtrg);
     185                 :         643 :     int32       tmp = 0;
     186                 :             : 
     187         [ +  + ]:        5883 :     for (k = 0; k < len; k++)
     188                 :             :     {
     189                 :        5240 :         CPTRGM(&tmp, ptr + k);
     190                 :        5240 :         count += GETBIT(sign, HASHVAL(tmp, siglen));
     191                 :             :     }
     192                 :             : 
     193                 :         643 :     return count;
     194                 :             : }
     195                 :             : 
     196                 :             : Datum
     197                 :       37414 : gtrgm_consistent(PG_FUNCTION_ARGS)
     198                 :             : {
     199                 :       37414 :     GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
     200                 :       37414 :     text       *query = PG_GETARG_TEXT_P(1);
     201                 :       37414 :     StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
     202                 :             : #ifdef NOT_USED
     203                 :             :     Oid         subtype = PG_GETARG_OID(3);
     204                 :             : #endif
     205                 :       37414 :     bool       *recheck = (bool *) PG_GETARG_POINTER(4);
     206         [ +  - ]:       37414 :     int         siglen = GET_SIGLEN();
     207                 :       37414 :     TRGM       *key = (TRGM *) DatumGetPointer(entry->key);
     208                 :             :     TRGM       *qtrg;
     209                 :             :     bool        res;
     210                 :       37414 :     Size        querysize = VARSIZE(query);
     211                 :             :     gtrgm_consistent_cache *cache;
     212                 :             :     double      nlimit;
     213                 :             : 
     214                 :             :     /*
     215                 :             :      * We keep the extracted trigrams in cache, because trigram extraction is
     216                 :             :      * relatively CPU-expensive.  When trying to reuse a cached value, check
     217                 :             :      * strategy number not just query itself, because trigram extraction
     218                 :             :      * depends on strategy.
     219                 :             :      *
     220                 :             :      * The cached structure is a single palloc chunk containing the
     221                 :             :      * gtrgm_consistent_cache header, then the input query (4-byte length
     222                 :             :      * word, uncompressed, starting at a MAXALIGN boundary), then the TRGM
     223                 :             :      * value (also starting at a MAXALIGN boundary).  However we don't try to
     224                 :             :      * include the regex graph (if any) in that struct.  (XXX currently, this
     225                 :             :      * approach can leak regex graphs across index rescans.  Not clear if
     226                 :             :      * that's worth fixing.)
     227                 :             :      */
     228                 :       37414 :     cache = (gtrgm_consistent_cache *) fcinfo->flinfo->fn_extra;
     229         [ +  + ]:       37414 :     if (cache == NULL ||
     230   [ +  -  +  - ]:       74716 :         cache->strategy != strategy ||
     231                 :       37358 :         VARSIZE(cache->query) != querysize ||
     232         [ -  + ]:       37358 :         memcmp(cache->query, query, querysize) != 0)
     233                 :             :     {
     234                 :             :         gtrgm_consistent_cache *newcache;
     235                 :          56 :         TrgmPackedGraph *graph = NULL;
     236                 :             :         Size        qtrgsize;
     237                 :             : 
     238   [ +  +  +  - ]:          56 :         switch (strategy)
     239                 :             :         {
     240                 :          28 :             case SimilarityStrategyNumber:
     241                 :             :             case WordSimilarityStrategyNumber:
     242                 :             :             case StrictWordSimilarityStrategyNumber:
     243                 :             :             case EqualStrategyNumber:
     244                 :          28 :                 qtrg = generate_trgm(VARDATA(query),
     245                 :          28 :                                      querysize - VARHDRSZ);
     246                 :          28 :                 break;
     247                 :           7 :             case ILikeStrategyNumber:
     248                 :             : #ifndef IGNORECASE
     249                 :             :                 elog(ERROR, "cannot handle ~~* with case-sensitive trigrams");
     250                 :             : #endif
     251                 :             :                 pg_fallthrough;
     252                 :             :             case LikeStrategyNumber:
     253                 :           7 :                 qtrg = generate_wildcard_trgm(VARDATA(query),
     254                 :           7 :                                               querysize - VARHDRSZ);
     255                 :           7 :                 break;
     256                 :          21 :             case RegExpICaseStrategyNumber:
     257                 :             : #ifndef IGNORECASE
     258                 :             :                 elog(ERROR, "cannot handle ~* with case-sensitive trigrams");
     259                 :             : #endif
     260                 :             :                 pg_fallthrough;
     261                 :             :             case RegExpStrategyNumber:
     262                 :          21 :                 qtrg = createTrgmNFA(query, PG_GET_COLLATION(),
     263                 :          21 :                                      &graph, fcinfo->flinfo->fn_mcxt);
     264                 :             :                 /* just in case an empty array is returned ... */
     265   [ +  +  -  + ]:          21 :                 if (qtrg && ARRNELEM(qtrg) <= 0)
     266                 :             :                 {
     267                 :           0 :                     pfree(qtrg);
     268                 :           0 :                     qtrg = NULL;
     269                 :             :                 }
     270                 :          21 :                 break;
     271                 :           0 :             default:
     272         [ #  # ]:           0 :                 elog(ERROR, "unrecognized strategy number: %d", strategy);
     273                 :             :                 qtrg = NULL;    /* keep compiler quiet */
     274                 :             :                 break;
     275                 :             :         }
     276                 :             : 
     277         [ +  + ]:          56 :         qtrgsize = qtrg ? VARSIZE(qtrg) : 0;
     278                 :             : 
     279                 :             :         newcache = (gtrgm_consistent_cache *)
     280                 :          56 :             MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
     281                 :             :                                MAXALIGN(sizeof(gtrgm_consistent_cache)) +
     282                 :          56 :                                MAXALIGN(querysize) +
     283                 :             :                                qtrgsize);
     284                 :             : 
     285                 :          56 :         newcache->strategy = strategy;
     286                 :          56 :         newcache->query = (text *)
     287                 :             :             ((char *) newcache + MAXALIGN(sizeof(gtrgm_consistent_cache)));
     288                 :          56 :         memcpy(newcache->query, query, querysize);
     289         [ +  + ]:          56 :         if (qtrg)
     290                 :             :         {
     291                 :          52 :             newcache->trigrams = (TRGM *)
     292                 :          52 :                 ((char *) newcache->query + MAXALIGN(querysize));
     293                 :          52 :             memcpy((char *) newcache->trigrams, qtrg, qtrgsize);
     294                 :             :             /* release qtrg in case it was made in fn_mcxt */
     295                 :          52 :             pfree(qtrg);
     296                 :             :         }
     297                 :             :         else
     298                 :           4 :             newcache->trigrams = NULL;
     299                 :          56 :         newcache->graph = graph;
     300                 :             : 
     301         [ -  + ]:          56 :         if (cache)
     302                 :           0 :             pfree(cache);
     303                 :          56 :         fcinfo->flinfo->fn_extra = newcache;
     304                 :          56 :         cache = newcache;
     305                 :             :     }
     306                 :             : 
     307                 :       37414 :     qtrg = cache->trigrams;
     308                 :             : 
     309   [ +  +  +  - ]:       37414 :     switch (strategy)
     310                 :             :     {
     311                 :       35012 :         case SimilarityStrategyNumber:
     312                 :             :         case WordSimilarityStrategyNumber:
     313                 :             :         case StrictWordSimilarityStrategyNumber:
     314                 :             : 
     315                 :             :             /*
     316                 :             :              * Similarity search is exact. (Strict) word similarity search is
     317                 :             :              * inexact
     318                 :             :              */
     319                 :       35012 :             *recheck = (strategy != SimilarityStrategyNumber);
     320                 :             : 
     321                 :       35012 :             nlimit = index_strategy_get_limit(strategy);
     322                 :             : 
     323         [ +  + ]:       35012 :             if (GIST_LEAF(entry))
     324                 :             :             {                   /* all leafs contains orig trgm */
     325                 :       34408 :                 double      tmpsml = cnt_sml(qtrg, key, *recheck);
     326                 :             : 
     327                 :       34408 :                 res = (tmpsml >= nlimit);
     328                 :             :             }
     329         [ -  + ]:         604 :             else if (ISALLTRUE(key))
     330                 :             :             {                   /* non-leaf contains signature */
     331                 :           0 :                 res = true;
     332                 :             :             }
     333                 :             :             else
     334                 :             :             {                   /* non-leaf contains signature */
     335                 :         604 :                 int32       count = cnt_sml_sign_common(qtrg, GETSIGN(key), siglen);
     336                 :         604 :                 int32       len = ARRNELEM(qtrg);
     337                 :             : 
     338         [ -  + ]:         604 :                 if (len == 0)
     339                 :           0 :                     res = false;
     340                 :             :                 else
     341                 :         604 :                     res = (((((float8) count) / ((float8) len))) >= nlimit);
     342                 :             :             }
     343                 :       35012 :             break;
     344                 :         190 :         case ILikeStrategyNumber:
     345                 :             : #ifndef IGNORECASE
     346                 :             :             elog(ERROR, "cannot handle ~~* with case-sensitive trigrams");
     347                 :             : #endif
     348                 :             :             pg_fallthrough;
     349                 :             :         case LikeStrategyNumber:
     350                 :             :         case EqualStrategyNumber:
     351                 :             :             /* Wildcard and equal search are inexact */
     352                 :         190 :             *recheck = true;
     353                 :             : 
     354                 :             :             /*
     355                 :             :              * Check if all the extracted trigrams can be present in child
     356                 :             :              * nodes.
     357                 :             :              */
     358         [ +  - ]:         190 :             if (GIST_LEAF(entry))
     359                 :             :             {                   /* all leafs contains orig trgm */
     360                 :         190 :                 res = trgm_contained_by(qtrg, key);
     361                 :             :             }
     362         [ #  # ]:           0 :             else if (ISALLTRUE(key))
     363                 :             :             {                   /* non-leaf contains signature */
     364                 :           0 :                 res = true;
     365                 :             :             }
     366                 :             :             else
     367                 :             :             {                   /* non-leaf contains signature */
     368                 :             :                 int32       k,
     369                 :           0 :                             tmp = 0,
     370                 :           0 :                             len = ARRNELEM(qtrg);
     371                 :           0 :                 trgm       *ptr = GETARR(qtrg);
     372                 :           0 :                 BITVECP     sign = GETSIGN(key);
     373                 :             : 
     374                 :           0 :                 res = true;
     375         [ #  # ]:           0 :                 for (k = 0; k < len; k++)
     376                 :             :                 {
     377                 :           0 :                     CPTRGM(&tmp, ptr + k);
     378         [ #  # ]:           0 :                     if (!GETBIT(sign, HASHVAL(tmp, siglen)))
     379                 :             :                     {
     380                 :           0 :                         res = false;
     381                 :           0 :                         break;
     382                 :             :                     }
     383                 :             :                 }
     384                 :             :             }
     385                 :         190 :             break;
     386                 :        2212 :         case RegExpICaseStrategyNumber:
     387                 :             : #ifndef IGNORECASE
     388                 :             :             elog(ERROR, "cannot handle ~* with case-sensitive trigrams");
     389                 :             : #endif
     390                 :             :             pg_fallthrough;
     391                 :             :         case RegExpStrategyNumber:
     392                 :             :             /* Regexp search is inexact */
     393                 :        2212 :             *recheck = true;
     394                 :             : 
     395                 :             :             /* Check regex match as much as we can with available info */
     396         [ +  + ]:        2212 :             if (qtrg)
     397                 :             :             {
     398         [ +  + ]:        2172 :                 if (GIST_LEAF(entry))
     399                 :             :                 {               /* all leafs contains orig trgm */
     400                 :             :                     bool       *check;
     401                 :             : 
     402                 :        2150 :                     check = trgm_presence_map(qtrg, key);
     403                 :        2150 :                     res = trigramsMatchGraph(cache->graph, check);
     404                 :        2150 :                     pfree(check);
     405                 :             :                 }
     406         [ -  + ]:          22 :                 else if (ISALLTRUE(key))
     407                 :             :                 {               /* non-leaf contains signature */
     408                 :           0 :                     res = true;
     409                 :             :                 }
     410                 :             :                 else
     411                 :             :                 {               /* non-leaf contains signature */
     412                 :             :                     int32       k,
     413                 :          22 :                                 tmp = 0,
     414                 :          22 :                                 len = ARRNELEM(qtrg);
     415                 :          22 :                     trgm       *ptr = GETARR(qtrg);
     416                 :          22 :                     BITVECP     sign = GETSIGN(key);
     417                 :             :                     bool       *check;
     418                 :             : 
     419                 :             :                     /*
     420                 :             :                      * GETBIT() tests may give false positives, due to limited
     421                 :             :                      * size of the sign array.  But since trigramsMatchGraph()
     422                 :             :                      * implements a monotone boolean function, false positives
     423                 :             :                      * in the check array can't lead to false negative answer.
     424                 :             :                      * So we can apply trigramsMatchGraph despite uncertainty,
     425                 :             :                      * and that usefully improves the quality of the search.
     426                 :             :                      */
     427                 :          22 :                     check = (bool *) palloc(len * sizeof(bool));
     428         [ +  + ]:        5566 :                     for (k = 0; k < len; k++)
     429                 :             :                     {
     430                 :        5544 :                         CPTRGM(&tmp, ptr + k);
     431                 :        5544 :                         check[k] = GETBIT(sign, HASHVAL(tmp, siglen));
     432                 :             :                     }
     433                 :          22 :                     res = trigramsMatchGraph(cache->graph, check);
     434                 :          22 :                     pfree(check);
     435                 :             :                 }
     436                 :             :             }
     437                 :             :             else
     438                 :             :             {
     439                 :             :                 /* trigram-free query must be rechecked everywhere */
     440                 :          40 :                 res = true;
     441                 :             :             }
     442                 :        2212 :             break;
     443                 :           0 :         default:
     444         [ #  # ]:           0 :             elog(ERROR, "unrecognized strategy number: %d", strategy);
     445                 :             :             res = false;        /* keep compiler quiet */
     446                 :             :             break;
     447                 :             :     }
     448                 :             : 
     449                 :       37414 :     PG_RETURN_BOOL(res);
     450                 :             : }
     451                 :             : 
     452                 :             : Datum
     453                 :        2860 : gtrgm_distance(PG_FUNCTION_ARGS)
     454                 :             : {
     455                 :        2860 :     GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
     456                 :        2860 :     text       *query = PG_GETARG_TEXT_P(1);
     457                 :        2860 :     StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
     458                 :             : #ifdef NOT_USED
     459                 :             :     Oid         subtype = PG_GETARG_OID(3);
     460                 :             : #endif
     461                 :        2860 :     bool       *recheck = (bool *) PG_GETARG_POINTER(4);
     462         [ +  - ]:        2860 :     int         siglen = GET_SIGLEN();
     463                 :        2860 :     TRGM       *key = (TRGM *) DatumGetPointer(entry->key);
     464                 :             :     TRGM       *qtrg;
     465                 :             :     float8      res;
     466                 :        2860 :     Size        querysize = VARSIZE(query);
     467                 :        2860 :     char       *cache = (char *) fcinfo->flinfo->fn_extra;
     468                 :             : 
     469                 :             :     /*
     470                 :             :      * Cache the generated trigrams across multiple calls with the same query.
     471                 :             :      */
     472   [ +  +  +  - ]:        5716 :     if (cache == NULL ||
     473                 :        2856 :         VARSIZE(cache) != querysize ||
     474         [ -  + ]:        2856 :         memcmp(cache, query, querysize) != 0)
     475                 :             :     {
     476                 :             :         char       *newcache;
     477                 :             : 
     478                 :           4 :         qtrg = generate_trgm(VARDATA(query), querysize - VARHDRSZ);
     479                 :             : 
     480                 :           4 :         newcache = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
     481                 :           4 :                                       MAXALIGN(querysize) +
     482                 :           4 :                                       VARSIZE(qtrg));
     483                 :             : 
     484                 :           4 :         memcpy(newcache, query, querysize);
     485                 :           4 :         memcpy(newcache + MAXALIGN(querysize), qtrg, VARSIZE(qtrg));
     486                 :             : 
     487         [ -  + ]:           4 :         if (cache)
     488                 :           0 :             pfree(cache);
     489                 :           4 :         fcinfo->flinfo->fn_extra = newcache;
     490                 :           4 :         cache = newcache;
     491                 :             :     }
     492                 :             : 
     493                 :        2860 :     qtrg = (TRGM *) (cache + MAXALIGN(querysize));
     494                 :             : 
     495         [ +  - ]:        2860 :     switch (strategy)
     496                 :             :     {
     497                 :        2860 :         case DistanceStrategyNumber:
     498                 :             :         case WordDistanceStrategyNumber:
     499                 :             :         case StrictWordDistanceStrategyNumber:
     500                 :             :             /* Only plain trigram distance is exact */
     501                 :        2860 :             *recheck = (strategy != DistanceStrategyNumber);
     502         [ +  + ]:        2860 :             if (GIST_LEAF(entry))
     503                 :             :             {                   /* all leafs contains orig trgm */
     504                 :             : 
     505                 :             :                 /*
     506                 :             :                  * Prevent gcc optimizing the sml variable using volatile
     507                 :             :                  * keyword. Otherwise res can differ from the
     508                 :             :                  * word_similarity_dist_op() function.
     509                 :             :                  */
     510                 :        2821 :                 float4 volatile sml = cnt_sml(qtrg, key, *recheck);
     511                 :             : 
     512                 :        2821 :                 res = 1.0 - sml;
     513                 :             :             }
     514         [ -  + ]:          39 :             else if (ISALLTRUE(key))
     515                 :             :             {                   /* all leafs contains orig trgm */
     516                 :           0 :                 res = 0.0;
     517                 :             :             }
     518                 :             :             else
     519                 :             :             {                   /* non-leaf contains signature */
     520                 :          39 :                 int32       count = cnt_sml_sign_common(qtrg, GETSIGN(key), siglen);
     521                 :          39 :                 int32       len = ARRNELEM(qtrg);
     522                 :             : 
     523         [ +  - ]:          39 :                 res = (len == 0) ? -1.0 : 1.0 - ((float8) count) / ((float8) len);
     524                 :             :             }
     525                 :        2860 :             break;
     526                 :           0 :         default:
     527         [ #  # ]:           0 :             elog(ERROR, "unrecognized strategy number: %d", strategy);
     528                 :             :             res = 0;            /* keep compiler quiet */
     529                 :             :             break;
     530                 :             :     }
     531                 :             : 
     532                 :        2860 :     PG_RETURN_FLOAT8(res);
     533                 :             : }
     534                 :             : 
     535                 :             : static int32
     536                 :       55124 : unionkey(BITVECP sbase, TRGM *add, int siglen)
     537                 :             : {
     538         [ +  + ]:       55124 :     if (ISSIGNKEY(add))
     539                 :             :     {
     540                 :             :         int32       i;
     541                 :       27562 :         BITVECP     sadd = GETSIGN(add);
     542                 :             : 
     543         [ -  + ]:       27562 :         if (ISALLTRUE(add))
     544                 :           0 :             return 1;
     545                 :             : 
     546         [ +  + ]:     6519050 :         LOOPBYTE(siglen)
     547                 :     6491488 :             sbase[i] |= sadd[i];
     548                 :             :     }
     549                 :             :     else
     550                 :             :     {
     551                 :       27562 :         trgm       *ptr = GETARR(add);
     552                 :       27562 :         int32       tmp = 0;
     553                 :             : 
     554         [ +  + ]:      275653 :         for (unsigned i = 0; i < ARRNELEM(add); i++)
     555                 :             :         {
     556                 :      248091 :             CPTRGM(&tmp, ptr + i);
     557                 :      248091 :             HASH(sbase, tmp, siglen);
     558                 :             :         }
     559                 :             :     }
     560                 :       55124 :     return 0;
     561                 :             : }
     562                 :             : 
     563                 :             : 
     564                 :             : Datum
     565                 :       27562 : gtrgm_union(PG_FUNCTION_ARGS)
     566                 :             : {
     567                 :       27562 :     GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
     568                 :       27562 :     int32       len = entryvec->n;
     569                 :       27562 :     int        *size = (int *) PG_GETARG_POINTER(1);
     570         [ +  - ]:       27562 :     int         siglen = GET_SIGLEN();
     571                 :             :     int32       i;
     572                 :       27562 :     TRGM       *result = gtrgm_alloc(false, siglen, NULL);
     573                 :       27562 :     BITVECP     base = GETSIGN(result);
     574                 :             : 
     575         [ +  + ]:       82686 :     for (i = 0; i < len; i++)
     576                 :             :     {
     577         [ -  + ]:       55124 :         if (unionkey(base, GETENTRY(entryvec, i), siglen))
     578                 :             :         {
     579                 :           0 :             result->flag = ALLISTRUE;
     580                 :           0 :             SET_VARSIZE(result, CALCGTSIZE(ALLISTRUE, siglen));
     581                 :           0 :             break;
     582                 :             :         }
     583                 :             :     }
     584                 :             : 
     585                 :       27562 :     *size = VARSIZE(result);
     586                 :             : 
     587                 :       27562 :     PG_RETURN_POINTER(result);
     588                 :             : }
     589                 :             : 
     590                 :             : Datum
     591                 :       27562 : gtrgm_same(PG_FUNCTION_ARGS)
     592                 :             : {
     593                 :       27562 :     TRGM       *a = (TRGM *) PG_GETARG_POINTER(0);
     594                 :       27562 :     TRGM       *b = (TRGM *) PG_GETARG_POINTER(1);
     595                 :       27562 :     bool       *result = (bool *) PG_GETARG_POINTER(2);
     596         [ +  - ]:       27562 :     int         siglen = GET_SIGLEN();
     597                 :             : 
     598         [ +  - ]:       27562 :     if (ISSIGNKEY(a))
     599                 :             :     {                           /* then b also ISSIGNKEY */
     600   [ -  +  -  - ]:       27562 :         if (ISALLTRUE(a) && ISALLTRUE(b))
     601                 :           0 :             *result = true;
     602         [ -  + ]:       27562 :         else if (ISALLTRUE(a))
     603                 :           0 :             *result = false;
     604         [ -  + ]:       27562 :         else if (ISALLTRUE(b))
     605                 :           0 :             *result = false;
     606                 :             :         else
     607                 :             :         {
     608                 :             :             int32       i;
     609                 :       27562 :             BITVECP     sa = GETSIGN(a),
     610                 :       27562 :                         sb = GETSIGN(b);
     611                 :             : 
     612                 :       27562 :             *result = true;
     613         [ +  + ]:     3117649 :             LOOPBYTE(siglen)
     614                 :             :             {
     615         [ +  + ]:     3092931 :                 if (sa[i] != sb[i])
     616                 :             :                 {
     617                 :        2844 :                     *result = false;
     618                 :        2844 :                     break;
     619                 :             :                 }
     620                 :             :             }
     621                 :             :         }
     622                 :             :     }
     623                 :             :     else
     624                 :             :     {                           /* a and b ISARRKEY */
     625                 :           0 :         int32       lena = ARRNELEM(a),
     626                 :           0 :                     lenb = ARRNELEM(b);
     627                 :             : 
     628         [ #  # ]:           0 :         if (lena != lenb)
     629                 :           0 :             *result = false;
     630                 :             :         else
     631                 :             :         {
     632                 :           0 :             trgm       *ptra = GETARR(a),
     633                 :           0 :                        *ptrb = GETARR(b);
     634                 :             :             int32       i;
     635                 :             : 
     636                 :           0 :             *result = true;
     637         [ #  # ]:           0 :             for (i = 0; i < lena; i++)
     638         [ #  # ]:           0 :                 if (CMPTRGM(ptra + i, ptrb + i))
     639                 :             :                 {
     640                 :           0 :                     *result = false;
     641                 :           0 :                     break;
     642                 :             :                 }
     643                 :             :         }
     644                 :             :     }
     645                 :             : 
     646                 :       27562 :     PG_RETURN_POINTER(result);
     647                 :             : }
     648                 :             : 
     649                 :             : static int32
     650                 :           0 : sizebitvec(BITVECP sign, int siglen)
     651                 :             : {
     652                 :           0 :     return pg_popcount(sign, siglen);
     653                 :             : }
     654                 :             : 
     655                 :             : static int
     656                 :     4897550 : hemdistsign(BITVECP a, BITVECP b, int siglen)
     657                 :             : {
     658                 :             :     int         i,
     659                 :             :                 diff,
     660                 :     4897550 :                 dist = 0;
     661                 :             : 
     662         [ +  + ]:   336644238 :     LOOPBYTE(siglen)
     663                 :             :     {
     664                 :   331746688 :         diff = (unsigned char) (a[i] ^ b[i]);
     665                 :             :         /* Using the popcount functions here isn't likely to win */
     666                 :   331746688 :         dist += pg_number_of_ones[diff];
     667                 :             :     }
     668                 :     4897550 :     return dist;
     669                 :             : }
     670                 :             : 
     671                 :             : static int
     672                 :           0 : hemdist(TRGM *a, TRGM *b, int siglen)
     673                 :             : {
     674         [ #  # ]:           0 :     if (ISALLTRUE(a))
     675                 :             :     {
     676         [ #  # ]:           0 :         if (ISALLTRUE(b))
     677                 :           0 :             return 0;
     678                 :             :         else
     679                 :           0 :             return SIGLENBIT(siglen) - sizebitvec(GETSIGN(b), siglen);
     680                 :             :     }
     681         [ #  # ]:           0 :     else if (ISALLTRUE(b))
     682                 :           0 :         return SIGLENBIT(siglen) - sizebitvec(GETSIGN(a), siglen);
     683                 :             : 
     684                 :           0 :     return hemdistsign(GETSIGN(a), GETSIGN(b), siglen);
     685                 :             : }
     686                 :             : 
     687                 :             : Datum
     688                 :     1186614 : gtrgm_penalty(PG_FUNCTION_ARGS)
     689                 :             : {
     690                 :     1186614 :     GISTENTRY  *origentry = (GISTENTRY *) PG_GETARG_POINTER(0); /* always ISSIGNKEY */
     691                 :     1186614 :     GISTENTRY  *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
     692                 :     1186614 :     float      *penalty = (float *) PG_GETARG_POINTER(2);
     693         [ +  - ]:     1186614 :     int         siglen = GET_SIGLEN();
     694                 :     1186614 :     TRGM       *origval = (TRGM *) DatumGetPointer(origentry->key);
     695                 :     1186614 :     TRGM       *newval = (TRGM *) DatumGetPointer(newentry->key);
     696                 :     1186614 :     BITVECP     orig = GETSIGN(origval);
     697                 :             : 
     698                 :     1186614 :     *penalty = 0.0;
     699                 :             : 
     700         [ +  - ]:     1186614 :     if (ISARRKEY(newval))
     701                 :             :     {
     702                 :     1186614 :         char       *cache = (char *) fcinfo->flinfo->fn_extra;
     703                 :     1186614 :         TRGM       *cachedVal = NULL;
     704                 :     1186614 :         Size        newvalsize = VARSIZE(newval);
     705                 :             :         BITVECP     sign;
     706                 :             : 
     707         [ +  + ]:     1186614 :         if (cache != NULL)
     708                 :     1186608 :             cachedVal = (TRGM *) (cache + MAXALIGN(siglen));
     709                 :             : 
     710                 :             :         /*
     711                 :             :          * Cache the sign data across multiple calls with the same newval.
     712                 :             :          */
     713   [ +  +  +  + ]:     2373222 :         if (cache == NULL ||
     714                 :     1186608 :             VARSIZE(cachedVal) != newvalsize ||
     715         [ +  + ]:     1185581 :             memcmp(cachedVal, newval, newvalsize) != 0)
     716                 :             :         {
     717                 :             :             char       *newcache;
     718                 :             : 
     719                 :        3763 :             newcache = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
     720                 :        3763 :                                           MAXALIGN(siglen) +
     721                 :             :                                           newvalsize);
     722                 :             : 
     723                 :        3763 :             makesign((BITVECP) newcache, newval, siglen);
     724                 :             : 
     725                 :        3763 :             cachedVal = (TRGM *) (newcache + MAXALIGN(siglen));
     726                 :        3763 :             memcpy(cachedVal, newval, newvalsize);
     727                 :             : 
     728         [ +  + ]:        3763 :             if (cache)
     729                 :        3757 :                 pfree(cache);
     730                 :        3763 :             fcinfo->flinfo->fn_extra = newcache;
     731                 :        3763 :             cache = newcache;
     732                 :             :         }
     733                 :             : 
     734                 :     1186614 :         sign = (BITVECP) cache;
     735                 :             : 
     736         [ -  + ]:     1186614 :         if (ISALLTRUE(origval))
     737                 :           0 :             *penalty = ((float) (SIGLENBIT(siglen) - sizebitvec(sign, siglen))) / (float) (SIGLENBIT(siglen) + 1);
     738                 :             :         else
     739                 :     1186614 :             *penalty = hemdistsign(sign, orig, siglen);
     740                 :             :     }
     741                 :             :     else
     742                 :           0 :         *penalty = hemdist(origval, newval, siglen);
     743                 :     1186614 :     PG_RETURN_POINTER(penalty);
     744                 :             : }
     745                 :             : 
     746                 :             : typedef struct
     747                 :             : {
     748                 :             :     bool        allistrue;
     749                 :             :     BITVECP     sign;
     750                 :             : } CACHESIGN;
     751                 :             : 
     752                 :             : static void
     753                 :       43879 : fillcache(CACHESIGN *item, TRGM *key, BITVECP sign, int siglen)
     754                 :             : {
     755                 :       43879 :     item->allistrue = false;
     756                 :       43879 :     item->sign = sign;
     757         [ +  + ]:       43879 :     if (ISARRKEY(key))
     758                 :       43659 :         makesign(item->sign, key, siglen);
     759         [ -  + ]:         220 :     else if (ISALLTRUE(key))
     760                 :           0 :         item->allistrue = true;
     761                 :             :     else
     762                 :         220 :         memcpy(item->sign, GETSIGN(key), siglen);
     763                 :       43879 : }
     764                 :             : 
     765                 :             : #define WISH_F(a,b,c) (double)( -(double)(((a)-(b))*((a)-(b))*((a)-(b)))*(c) )
     766                 :             : typedef struct
     767                 :             : {
     768                 :             :     OffsetNumber pos;
     769                 :             :     int32       cost;
     770                 :             : } SPLITCOST;
     771                 :             : 
     772                 :             : static int
     773                 :       49162 : comparecost(const void *a, const void *b)
     774                 :             : {
     775         [ +  + ]:       49162 :     if (((const SPLITCOST *) a)->cost == ((const SPLITCOST *) b)->cost)
     776                 :       43994 :         return 0;
     777                 :             :     else
     778         [ +  + ]:        5168 :         return (((const SPLITCOST *) a)->cost > ((const SPLITCOST *) b)->cost) ? 1 : -1;
     779                 :             : }
     780                 :             : 
     781                 :             : 
     782                 :             : static int
     783                 :     3624286 : hemdistcache(CACHESIGN *a, CACHESIGN *b, int siglen)
     784                 :             : {
     785         [ -  + ]:     3624286 :     if (a->allistrue)
     786                 :             :     {
     787         [ #  # ]:           0 :         if (b->allistrue)
     788                 :           0 :             return 0;
     789                 :             :         else
     790                 :           0 :             return SIGLENBIT(siglen) - sizebitvec(b->sign, siglen);
     791                 :             :     }
     792         [ -  + ]:     3624286 :     else if (b->allistrue)
     793                 :           0 :         return SIGLENBIT(siglen) - sizebitvec(a->sign, siglen);
     794                 :             : 
     795                 :     3624286 :     return hemdistsign(a->sign, b->sign, siglen);
     796                 :             : }
     797                 :             : 
     798                 :             : Datum
     799                 :         277 : gtrgm_picksplit(PG_FUNCTION_ARGS)
     800                 :             : {
     801                 :         277 :     GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
     802                 :         277 :     OffsetNumber maxoff = entryvec->n - 1;
     803                 :         277 :     GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
     804         [ +  - ]:         277 :     int         siglen = GET_SIGLEN();
     805                 :             :     OffsetNumber k,
     806                 :             :                 j;
     807                 :             :     TRGM       *datum_l,
     808                 :             :                *datum_r;
     809                 :             :     BITVECP     union_l,
     810                 :             :                 union_r;
     811                 :             :     int32       size_alpha,
     812                 :             :                 size_beta;
     813                 :             :     int32       size_waste,
     814                 :         277 :                 waste = -1;
     815                 :             :     int32       nbytes;
     816                 :         277 :     OffsetNumber seed_1 = 0,
     817                 :         277 :                 seed_2 = 0;
     818                 :             :     OffsetNumber *left,
     819                 :             :                *right;
     820                 :             :     BITVECP     ptr;
     821                 :             :     int         i;
     822                 :             :     CACHESIGN  *cache;
     823                 :             :     char       *cache_sign;
     824                 :             :     SPLITCOST  *costvector;
     825                 :             : 
     826                 :             :     /* cache the sign data for each existing item */
     827                 :         277 :     cache = palloc_array(CACHESIGN, maxoff + 1);
     828                 :         277 :     cache_sign = palloc(siglen * (maxoff + 1));
     829                 :             : 
     830         [ +  + ]:       44156 :     for (k = FirstOffsetNumber; k <= maxoff; k = OffsetNumberNext(k))
     831                 :       43879 :         fillcache(&cache[k], GETENTRY(entryvec, k), &cache_sign[siglen * k],
     832                 :             :                   siglen);
     833                 :             : 
     834                 :             :     /* now find the two furthest-apart items */
     835         [ +  + ]:       43879 :     for (k = FirstOffsetNumber; k < maxoff; k = OffsetNumberNext(k))
     836                 :             :     {
     837         [ +  + ]:     3580130 :         for (j = OffsetNumberNext(k); j <= maxoff; j = OffsetNumberNext(j))
     838                 :             :         {
     839                 :     3536528 :             size_waste = hemdistcache(&(cache[j]), &(cache[k]), siglen);
     840         [ +  + ]:     3536528 :             if (size_waste > waste)
     841                 :             :             {
     842                 :         458 :                 waste = size_waste;
     843                 :         458 :                 seed_1 = k;
     844                 :         458 :                 seed_2 = j;
     845                 :             :             }
     846                 :             :         }
     847                 :             :     }
     848                 :             : 
     849                 :             :     /* just in case we didn't make a selection ... */
     850   [ +  -  -  + ]:         277 :     if (seed_1 == 0 || seed_2 == 0)
     851                 :             :     {
     852                 :           0 :         seed_1 = 1;
     853                 :           0 :         seed_2 = 2;
     854                 :             :     }
     855                 :             : 
     856                 :             :     /* initialize the result vectors */
     857                 :         277 :     nbytes = maxoff * sizeof(OffsetNumber);
     858                 :         277 :     v->spl_left = left = (OffsetNumber *) palloc(nbytes);
     859                 :         277 :     v->spl_right = right = (OffsetNumber *) palloc(nbytes);
     860                 :         277 :     v->spl_nleft = 0;
     861                 :         277 :     v->spl_nright = 0;
     862                 :             : 
     863                 :             :     /* form initial .. */
     864                 :         277 :     datum_l = gtrgm_alloc(cache[seed_1].allistrue, siglen, cache[seed_1].sign);
     865                 :         277 :     datum_r = gtrgm_alloc(cache[seed_2].allistrue, siglen, cache[seed_2].sign);
     866                 :             : 
     867                 :         277 :     union_l = GETSIGN(datum_l);
     868                 :         277 :     union_r = GETSIGN(datum_r);
     869                 :             : 
     870                 :             :     /* sort before ... */
     871                 :         277 :     costvector = palloc_array(SPLITCOST, maxoff);
     872         [ +  + ]:       44156 :     for (j = FirstOffsetNumber; j <= maxoff; j = OffsetNumberNext(j))
     873                 :             :     {
     874                 :       43879 :         costvector[j - 1].pos = j;
     875                 :       43879 :         size_alpha = hemdistcache(&(cache[seed_1]), &(cache[j]), siglen);
     876                 :       43879 :         size_beta = hemdistcache(&(cache[seed_2]), &(cache[j]), siglen);
     877                 :       43879 :         costvector[j - 1].cost = abs(size_alpha - size_beta);
     878                 :             :     }
     879                 :         277 :     qsort(costvector, maxoff, sizeof(SPLITCOST), comparecost);
     880                 :             : 
     881         [ +  + ]:       44156 :     for (k = 0; k < maxoff; k++)
     882                 :             :     {
     883                 :       43879 :         j = costvector[k].pos;
     884         [ +  + ]:       43879 :         if (j == seed_1)
     885                 :             :         {
     886                 :         277 :             *left++ = j;
     887                 :         277 :             v->spl_nleft++;
     888                 :         277 :             continue;
     889                 :             :         }
     890         [ +  + ]:       43602 :         else if (j == seed_2)
     891                 :             :         {
     892                 :         277 :             *right++ = j;
     893                 :         277 :             v->spl_nright++;
     894                 :         277 :             continue;
     895                 :             :         }
     896                 :             : 
     897   [ +  -  -  + ]:       43325 :         if (ISALLTRUE(datum_l) || cache[j].allistrue)
     898                 :             :         {
     899   [ #  #  #  # ]:           0 :             if (ISALLTRUE(datum_l) && cache[j].allistrue)
     900                 :           0 :                 size_alpha = 0;
     901                 :             :             else
     902                 :           0 :                 size_alpha = SIGLENBIT(siglen) -
     903         [ #  # ]:           0 :                     sizebitvec((cache[j].allistrue) ? GETSIGN(datum_l) :
     904                 :           0 :                                GETSIGN(cache[j].sign),
     905                 :             :                                siglen);
     906                 :             :         }
     907                 :             :         else
     908                 :       43325 :             size_alpha = hemdistsign(cache[j].sign, GETSIGN(datum_l), siglen);
     909                 :             : 
     910   [ +  -  -  + ]:       43325 :         if (ISALLTRUE(datum_r) || cache[j].allistrue)
     911                 :             :         {
     912   [ #  #  #  # ]:           0 :             if (ISALLTRUE(datum_r) && cache[j].allistrue)
     913                 :           0 :                 size_beta = 0;
     914                 :             :             else
     915                 :           0 :                 size_beta = SIGLENBIT(siglen) -
     916         [ #  # ]:           0 :                     sizebitvec((cache[j].allistrue) ? GETSIGN(datum_r) :
     917                 :           0 :                                GETSIGN(cache[j].sign),
     918                 :             :                                siglen);
     919                 :             :         }
     920                 :             :         else
     921                 :       43325 :             size_beta = hemdistsign(cache[j].sign, GETSIGN(datum_r), siglen);
     922                 :             : 
     923         [ +  + ]:       43325 :         if (size_alpha < size_beta + WISH_F(v->spl_nleft, v->spl_nright, 0.1))
     924                 :             :         {
     925   [ +  -  -  + ]:       21547 :             if (ISALLTRUE(datum_l) || cache[j].allistrue)
     926                 :             :             {
     927         [ #  # ]:           0 :                 if (!ISALLTRUE(datum_l))
     928                 :           0 :                     memset(GETSIGN(datum_l), 0xff, siglen);
     929                 :             :             }
     930                 :             :             else
     931                 :             :             {
     932                 :       21547 :                 ptr = cache[j].sign;
     933         [ +  + ]:     2239799 :                 LOOPBYTE(siglen)
     934                 :     2218252 :                     union_l[i] |= ptr[i];
     935                 :             :             }
     936                 :       21547 :             *left++ = j;
     937                 :       21547 :             v->spl_nleft++;
     938                 :             :         }
     939                 :             :         else
     940                 :             :         {
     941   [ +  -  -  + ]:       21778 :             if (ISALLTRUE(datum_r) || cache[j].allistrue)
     942                 :             :             {
     943         [ #  # ]:           0 :                 if (!ISALLTRUE(datum_r))
     944                 :           0 :                     memset(GETSIGN(datum_r), 0xff, siglen);
     945                 :             :             }
     946                 :             :             else
     947                 :             :             {
     948                 :       21778 :                 ptr = cache[j].sign;
     949         [ +  + ]:     2234754 :                 LOOPBYTE(siglen)
     950                 :     2212976 :                     union_r[i] |= ptr[i];
     951                 :             :             }
     952                 :       21778 :             *right++ = j;
     953                 :       21778 :             v->spl_nright++;
     954                 :             :         }
     955                 :             :     }
     956                 :             : 
     957                 :         277 :     v->spl_ldatum = PointerGetDatum(datum_l);
     958                 :         277 :     v->spl_rdatum = PointerGetDatum(datum_r);
     959                 :             : 
     960                 :         277 :     PG_RETURN_POINTER(v);
     961                 :             : }
     962                 :             : 
     963                 :             : Datum
     964                 :          31 : gtrgm_options(PG_FUNCTION_ARGS)
     965                 :             : {
     966                 :          31 :     local_relopts *relopts = (local_relopts *) PG_GETARG_POINTER(0);
     967                 :             : 
     968                 :          31 :     init_local_reloptions(relopts, sizeof(TrgmGistOptions));
     969                 :          31 :     add_local_int_reloption(relopts, "siglen",
     970                 :             :                             "signature length in bytes",
     971                 :             :                             SIGLEN_DEFAULT, 1, SIGLEN_MAX,
     972                 :             :                             offsetof(TrgmGistOptions, siglen));
     973                 :             : 
     974                 :          31 :     PG_RETURN_VOID();
     975                 :             : }
        

Generated by: LCOV version 2.0-1