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-03 19:57:34 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                 :       28147 : gtrgm_alloc(bool isalltrue, int siglen, BITVECP sign)
      78                 :             : {
      79         [ -  + ]:       28147 :     int         flag = SIGNKEY | (isalltrue ? ALLISTRUE : 0);
      80   [ -  +  +  - ]:       28147 :     int         size = CALCGTSIZE(flag, siglen);
      81                 :       28147 :     TRGM       *res = palloc(size);
      82                 :             : 
      83                 :       28147 :     SET_VARSIZE(res, size);
      84                 :       28147 :     res->flag = flag;
      85                 :             : 
      86         [ +  - ]:       28147 :     if (!isalltrue)
      87                 :             :     {
      88         [ +  + ]:       28147 :         if (sign)
      89                 :         562 :             memcpy(GETSIGN(res), sign, siglen);
      90                 :             :         else
      91                 :       27585 :             memset(GETSIGN(res), 0, siglen);
      92                 :             :     }
      93                 :             : 
      94                 :       28147 :     return res;
      95                 :             : }
      96                 :             : 
      97                 :             : static void
      98                 :       47725 : makesign(BITVECP sign, TRGM *a, int siglen)
      99                 :             : {
     100                 :             :     int32       k,
     101                 :       47725 :                 len = ARRNELEM(a);
     102                 :       47725 :     trgm       *ptr = GETARR(a);
     103                 :       47725 :     int32       tmp = 0;
     104                 :             : 
     105   [ +  +  +  +  :       47725 :     MemSet(sign, 0, siglen);
          +  -  -  +  -  
                      - ]
     106                 :       47725 :     SETBIT(sign, SIGLENBIT(siglen));    /* set last unused bit */
     107         [ +  + ]:      470226 :     for (k = 0; k < len; k++)
     108                 :             :     {
     109                 :      422501 :         CPTRGM(&tmp, ptr + k);
     110                 :      422501 :         HASH(sign, tmp, siglen);
     111                 :             :     }
     112                 :       47725 : }
     113                 :             : 
     114                 :             : Datum
     115                 :       27844 : gtrgm_compress(PG_FUNCTION_ARGS)
     116                 :             : {
     117                 :       27844 :     GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
     118         [ +  - ]:       27844 :     int         siglen = GET_SIGLEN();
     119                 :       27844 :     GISTENTRY  *retval = entry;
     120                 :             : 
     121         [ +  + ]:       27844 :     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         [ +  - ]:        3392 :     else if (ISSIGNKEY(DatumGetPointer(entry->key)) &&
     133         [ +  - ]:        3392 :              !ISALLTRUE(DatumGetPointer(entry->key)))
     134                 :             :     {
     135                 :             :         int32       i;
     136                 :             :         TRGM       *res;
     137                 :        3392 :         BITVECP     sign = GETSIGN(DatumGetPointer(entry->key));
     138                 :             : 
     139         [ +  - ]:        3665 :         LOOPBYTE(siglen)
     140                 :             :         {
     141         [ +  + ]:        3665 :             if ((sign[i] & 0xff) != 0xff)
     142                 :        3392 :                 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                 :     1352673 : gtrgm_decompress(PG_FUNCTION_ARGS)
     156                 :             : {
     157                 :     1352673 :     GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
     158                 :             :     GISTENTRY  *retval;
     159                 :             :     text       *key;
     160                 :             : 
     161                 :     1352673 :     key = DatumGetTextPP(entry->key);
     162                 :             : 
     163         [ -  + ]:     1352673 :     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                 :     1352673 :         PG_RETURN_POINTER(entry);
     175                 :             :     }
     176                 :             : }
     177                 :             : 
     178                 :             : static int32
     179                 :         645 : cnt_sml_sign_common(TRGM *qtrg, BITVECP sign, int siglen)
     180                 :             : {
     181                 :         645 :     int32       count = 0;
     182                 :             :     int32       k,
     183                 :         645 :                 len = ARRNELEM(qtrg);
     184                 :         645 :     trgm       *ptr = GETARR(qtrg);
     185                 :         645 :     int32       tmp = 0;
     186                 :             : 
     187         [ +  + ]:        5909 :     for (k = 0; k < len; k++)
     188                 :             :     {
     189                 :        5264 :         CPTRGM(&tmp, ptr + k);
     190                 :        5264 :         count += GETBIT(sign, HASHVAL(tmp, siglen));
     191                 :             :     }
     192                 :             : 
     193                 :         645 :     return count;
     194                 :             : }
     195                 :             : 
     196                 :             : Datum
     197                 :       37404 : gtrgm_consistent(PG_FUNCTION_ARGS)
     198                 :             : {
     199                 :       37404 :     GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
     200                 :       37404 :     text       *query = PG_GETARG_TEXT_P(1);
     201                 :       37404 :     StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
     202                 :             : #ifdef NOT_USED
     203                 :             :     Oid         subtype = PG_GETARG_OID(3);
     204                 :             : #endif
     205                 :       37404 :     bool       *recheck = (bool *) PG_GETARG_POINTER(4);
     206         [ +  - ]:       37404 :     int         siglen = GET_SIGLEN();
     207                 :       37404 :     TRGM       *key = (TRGM *) DatumGetPointer(entry->key);
     208                 :             :     TRGM       *qtrg;
     209                 :             :     bool        res;
     210                 :       37404 :     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                 :       37404 :     cache = (gtrgm_consistent_cache *) fcinfo->flinfo->fn_extra;
     229         [ +  + ]:       37404 :     if (cache == NULL ||
     230   [ +  -  +  - ]:       74696 :         cache->strategy != strategy ||
     231                 :       37348 :         VARSIZE(cache->query) != querysize ||
     232         [ -  + ]:       37348 :         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                 :       37404 :     qtrg = cache->trigrams;
     308                 :             : 
     309   [ +  +  +  - ]:       37404 :     switch (strategy)
     310                 :             :     {
     311                 :       35002 :         case SimilarityStrategyNumber:
     312                 :             :         case WordSimilarityStrategyNumber:
     313                 :             :         case StrictWordSimilarityStrategyNumber:
     314                 :             : 
     315                 :             :             /*
     316                 :             :              * Similarity search is exact. (Strict) word similarity search is
     317                 :             :              * inexact
     318                 :             :              */
     319                 :       35002 :             *recheck = (strategy != SimilarityStrategyNumber);
     320                 :             : 
     321                 :       35002 :             nlimit = index_strategy_get_limit(strategy);
     322                 :             : 
     323         [ +  + ]:       35002 :             if (GIST_LEAF(entry))
     324                 :             :             {                   /* all leafs contains orig trgm */
     325                 :       34396 :                 double      tmpsml = cnt_sml(qtrg, key, *recheck);
     326                 :             : 
     327                 :       34396 :                 res = (tmpsml >= nlimit);
     328                 :             :             }
     329         [ -  + ]:         606 :             else if (ISALLTRUE(key))
     330                 :             :             {                   /* non-leaf contains signature */
     331                 :           0 :                 res = true;
     332                 :             :             }
     333                 :             :             else
     334                 :             :             {                   /* non-leaf contains signature */
     335                 :         606 :                 int32       count = cnt_sml_sign_common(qtrg, GETSIGN(key), siglen);
     336                 :         606 :                 int32       len = ARRNELEM(qtrg);
     337                 :             : 
     338         [ -  + ]:         606 :                 if (len == 0)
     339                 :           0 :                     res = false;
     340                 :             :                 else
     341                 :         606 :                     res = (((((float8) count) / ((float8) len))) >= nlimit);
     342                 :             :             }
     343                 :       35002 :             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                 :       37404 :     PG_RETURN_BOOL(res);
     450                 :             : }
     451                 :             : 
     452                 :             : Datum
     453                 :        2980 : gtrgm_distance(PG_FUNCTION_ARGS)
     454                 :             : {
     455                 :        2980 :     GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
     456                 :        2980 :     text       *query = PG_GETARG_TEXT_P(1);
     457                 :        2980 :     StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
     458                 :             : #ifdef NOT_USED
     459                 :             :     Oid         subtype = PG_GETARG_OID(3);
     460                 :             : #endif
     461                 :        2980 :     bool       *recheck = (bool *) PG_GETARG_POINTER(4);
     462         [ +  - ]:        2980 :     int         siglen = GET_SIGLEN();
     463                 :        2980 :     TRGM       *key = (TRGM *) DatumGetPointer(entry->key);
     464                 :             :     TRGM       *qtrg;
     465                 :             :     float8      res;
     466                 :        2980 :     Size        querysize = VARSIZE(query);
     467                 :        2980 :     char       *cache = (char *) fcinfo->flinfo->fn_extra;
     468                 :             : 
     469                 :             :     /*
     470                 :             :      * Cache the generated trigrams across multiple calls with the same query.
     471                 :             :      */
     472   [ +  +  +  - ]:        5956 :     if (cache == NULL ||
     473                 :        2976 :         VARSIZE(cache) != querysize ||
     474         [ -  + ]:        2976 :         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                 :        2980 :     qtrg = (TRGM *) (cache + MAXALIGN(querysize));
     494                 :             : 
     495         [ +  - ]:        2980 :     switch (strategy)
     496                 :             :     {
     497                 :        2980 :         case DistanceStrategyNumber:
     498                 :             :         case WordDistanceStrategyNumber:
     499                 :             :         case StrictWordDistanceStrategyNumber:
     500                 :             :             /* Only plain trigram distance is exact */
     501                 :        2980 :             *recheck = (strategy != DistanceStrategyNumber);
     502         [ +  + ]:        2980 :             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                 :        2941 :                 float4 volatile sml = cnt_sml(qtrg, key, *recheck);
     511                 :             : 
     512                 :        2941 :                 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                 :        2980 :             break;
     526                 :           0 :         default:
     527         [ #  # ]:           0 :             elog(ERROR, "unrecognized strategy number: %d", strategy);
     528                 :             :             res = 0;            /* keep compiler quiet */
     529                 :             :             break;
     530                 :             :     }
     531                 :             : 
     532                 :        2980 :     PG_RETURN_FLOAT8(res);
     533                 :             : }
     534                 :             : 
     535                 :             : static int32
     536                 :       55170 : unionkey(BITVECP sbase, TRGM *add, int siglen)
     537                 :             : {
     538                 :             :     int32       i;
     539                 :             : 
     540         [ +  + ]:       55170 :     if (ISSIGNKEY(add))
     541                 :             :     {
     542                 :       27585 :         BITVECP     sadd = GETSIGN(add);
     543                 :             : 
     544         [ -  + ]:       27585 :         if (ISALLTRUE(add))
     545                 :           0 :             return 1;
     546                 :             : 
     547         [ +  + ]:     6539469 :         LOOPBYTE(siglen)
     548                 :     6511884 :             sbase[i] |= sadd[i];
     549                 :             :     }
     550                 :             :     else
     551                 :             :     {
     552                 :       27585 :         trgm       *ptr = GETARR(add);
     553                 :       27585 :         int32       tmp = 0;
     554                 :             : 
     555         [ +  + ]:      275913 :         for (i = 0; i < ARRNELEM(add); i++)
     556                 :             :         {
     557                 :      248328 :             CPTRGM(&tmp, ptr + i);
     558                 :      248328 :             HASH(sbase, tmp, siglen);
     559                 :             :         }
     560                 :             :     }
     561                 :       55170 :     return 0;
     562                 :             : }
     563                 :             : 
     564                 :             : 
     565                 :             : Datum
     566                 :       27585 : gtrgm_union(PG_FUNCTION_ARGS)
     567                 :             : {
     568                 :       27585 :     GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
     569                 :       27585 :     int32       len = entryvec->n;
     570                 :       27585 :     int        *size = (int *) PG_GETARG_POINTER(1);
     571         [ +  - ]:       27585 :     int         siglen = GET_SIGLEN();
     572                 :             :     int32       i;
     573                 :       27585 :     TRGM       *result = gtrgm_alloc(false, siglen, NULL);
     574                 :       27585 :     BITVECP     base = GETSIGN(result);
     575                 :             : 
     576         [ +  + ]:       82755 :     for (i = 0; i < len; i++)
     577                 :             :     {
     578         [ -  + ]:       55170 :         if (unionkey(base, GETENTRY(entryvec, i), siglen))
     579                 :             :         {
     580                 :           0 :             result->flag = ALLISTRUE;
     581                 :           0 :             SET_VARSIZE(result, CALCGTSIZE(ALLISTRUE, siglen));
     582                 :           0 :             break;
     583                 :             :         }
     584                 :             :     }
     585                 :             : 
     586                 :       27585 :     *size = VARSIZE(result);
     587                 :             : 
     588                 :       27585 :     PG_RETURN_POINTER(result);
     589                 :             : }
     590                 :             : 
     591                 :             : Datum
     592                 :       27585 : gtrgm_same(PG_FUNCTION_ARGS)
     593                 :             : {
     594                 :       27585 :     TRGM       *a = (TRGM *) PG_GETARG_POINTER(0);
     595                 :       27585 :     TRGM       *b = (TRGM *) PG_GETARG_POINTER(1);
     596                 :       27585 :     bool       *result = (bool *) PG_GETARG_POINTER(2);
     597         [ +  - ]:       27585 :     int         siglen = GET_SIGLEN();
     598                 :             : 
     599         [ +  - ]:       27585 :     if (ISSIGNKEY(a))
     600                 :             :     {                           /* then b also ISSIGNKEY */
     601   [ -  +  -  - ]:       27585 :         if (ISALLTRUE(a) && ISALLTRUE(b))
     602                 :           0 :             *result = true;
     603         [ -  + ]:       27585 :         else if (ISALLTRUE(a))
     604                 :           0 :             *result = false;
     605         [ -  + ]:       27585 :         else if (ISALLTRUE(b))
     606                 :           0 :             *result = false;
     607                 :             :         else
     608                 :             :         {
     609                 :             :             int32       i;
     610                 :       27585 :             BITVECP     sa = GETSIGN(a),
     611                 :       27585 :                         sb = GETSIGN(b);
     612                 :             : 
     613                 :       27585 :             *result = true;
     614         [ +  + ]:     3178851 :             LOOPBYTE(siglen)
     615                 :             :             {
     616         [ +  + ]:     3154096 :                 if (sa[i] != sb[i])
     617                 :             :                 {
     618                 :        2830 :                     *result = false;
     619                 :        2830 :                     break;
     620                 :             :                 }
     621                 :             :             }
     622                 :             :         }
     623                 :             :     }
     624                 :             :     else
     625                 :             :     {                           /* a and b ISARRKEY */
     626                 :           0 :         int32       lena = ARRNELEM(a),
     627                 :           0 :                     lenb = ARRNELEM(b);
     628                 :             : 
     629         [ #  # ]:           0 :         if (lena != lenb)
     630                 :           0 :             *result = false;
     631                 :             :         else
     632                 :             :         {
     633                 :           0 :             trgm       *ptra = GETARR(a),
     634                 :           0 :                        *ptrb = GETARR(b);
     635                 :             :             int32       i;
     636                 :             : 
     637                 :           0 :             *result = true;
     638         [ #  # ]:           0 :             for (i = 0; i < lena; i++)
     639         [ #  # ]:           0 :                 if (CMPTRGM(ptra + i, ptrb + i))
     640                 :             :                 {
     641                 :           0 :                     *result = false;
     642                 :           0 :                     break;
     643                 :             :                 }
     644                 :             :         }
     645                 :             :     }
     646                 :             : 
     647                 :       27585 :     PG_RETURN_POINTER(result);
     648                 :             : }
     649                 :             : 
     650                 :             : static int32
     651                 :           0 : sizebitvec(BITVECP sign, int siglen)
     652                 :             : {
     653                 :           0 :     return pg_popcount(sign, siglen);
     654                 :             : }
     655                 :             : 
     656                 :             : static int
     657                 :     4920467 : hemdistsign(BITVECP a, BITVECP b, int siglen)
     658                 :             : {
     659                 :             :     int         i,
     660                 :             :                 diff,
     661                 :     4920467 :                 dist = 0;
     662                 :             : 
     663         [ +  + ]:   353074375 :     LOOPBYTE(siglen)
     664                 :             :     {
     665                 :   348153908 :         diff = (unsigned char) (a[i] ^ b[i]);
     666                 :             :         /* Using the popcount functions here isn't likely to win */
     667                 :   348153908 :         dist += pg_number_of_ones[diff];
     668                 :             :     }
     669                 :     4920467 :     return dist;
     670                 :             : }
     671                 :             : 
     672                 :             : static int
     673                 :           0 : hemdist(TRGM *a, TRGM *b, int siglen)
     674                 :             : {
     675         [ #  # ]:           0 :     if (ISALLTRUE(a))
     676                 :             :     {
     677         [ #  # ]:           0 :         if (ISALLTRUE(b))
     678                 :           0 :             return 0;
     679                 :             :         else
     680                 :           0 :             return SIGLENBIT(siglen) - sizebitvec(GETSIGN(b), siglen);
     681                 :             :     }
     682         [ #  # ]:           0 :     else if (ISALLTRUE(b))
     683                 :           0 :         return SIGLENBIT(siglen) - sizebitvec(GETSIGN(a), siglen);
     684                 :             : 
     685                 :           0 :     return hemdistsign(GETSIGN(a), GETSIGN(b), siglen);
     686                 :             : }
     687                 :             : 
     688                 :             : Datum
     689                 :     1185344 : gtrgm_penalty(PG_FUNCTION_ARGS)
     690                 :             : {
     691                 :     1185344 :     GISTENTRY  *origentry = (GISTENTRY *) PG_GETARG_POINTER(0); /* always ISSIGNKEY */
     692                 :     1185344 :     GISTENTRY  *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
     693                 :     1185344 :     float      *penalty = (float *) PG_GETARG_POINTER(2);
     694         [ +  - ]:     1185344 :     int         siglen = GET_SIGLEN();
     695                 :     1185344 :     TRGM       *origval = (TRGM *) DatumGetPointer(origentry->key);
     696                 :     1185344 :     TRGM       *newval = (TRGM *) DatumGetPointer(newentry->key);
     697                 :     1185344 :     BITVECP     orig = GETSIGN(origval);
     698                 :             : 
     699                 :     1185344 :     *penalty = 0.0;
     700                 :             : 
     701         [ +  - ]:     1185344 :     if (ISARRKEY(newval))
     702                 :             :     {
     703                 :     1185344 :         char       *cache = (char *) fcinfo->flinfo->fn_extra;
     704                 :     1185344 :         TRGM       *cachedVal = NULL;
     705                 :     1185344 :         Size        newvalsize = VARSIZE(newval);
     706                 :             :         BITVECP     sign;
     707                 :             : 
     708         [ +  + ]:     1185344 :         if (cache != NULL)
     709                 :     1185338 :             cachedVal = (TRGM *) (cache + MAXALIGN(siglen));
     710                 :             : 
     711                 :             :         /*
     712                 :             :          * Cache the sign data across multiple calls with the same newval.
     713                 :             :          */
     714   [ +  +  +  + ]:     2370682 :         if (cache == NULL ||
     715                 :     1185338 :             VARSIZE(cachedVal) != newvalsize ||
     716         [ +  + ]:     1184311 :             memcmp(cachedVal, newval, newvalsize) != 0)
     717                 :             :         {
     718                 :             :             char       *newcache;
     719                 :             : 
     720                 :        3763 :             newcache = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
     721                 :        3763 :                                           MAXALIGN(siglen) +
     722                 :             :                                           newvalsize);
     723                 :             : 
     724                 :        3763 :             makesign((BITVECP) newcache, newval, siglen);
     725                 :             : 
     726                 :        3763 :             cachedVal = (TRGM *) (newcache + MAXALIGN(siglen));
     727                 :        3763 :             memcpy(cachedVal, newval, newvalsize);
     728                 :             : 
     729         [ +  + ]:        3763 :             if (cache)
     730                 :        3757 :                 pfree(cache);
     731                 :        3763 :             fcinfo->flinfo->fn_extra = newcache;
     732                 :        3763 :             cache = newcache;
     733                 :             :         }
     734                 :             : 
     735                 :     1185344 :         sign = (BITVECP) cache;
     736                 :             : 
     737         [ -  + ]:     1185344 :         if (ISALLTRUE(origval))
     738                 :           0 :             *penalty = ((float) (SIGLENBIT(siglen) - sizebitvec(sign, siglen))) / (float) (SIGLENBIT(siglen) + 1);
     739                 :             :         else
     740                 :     1185344 :             *penalty = hemdistsign(sign, orig, siglen);
     741                 :             :     }
     742                 :             :     else
     743                 :           0 :         *penalty = hemdist(origval, newval, siglen);
     744                 :     1185344 :     PG_RETURN_POINTER(penalty);
     745                 :             : }
     746                 :             : 
     747                 :             : typedef struct
     748                 :             : {
     749                 :             :     bool        allistrue;
     750                 :             :     BITVECP     sign;
     751                 :             : } CACHESIGN;
     752                 :             : 
     753                 :             : static void
     754                 :       44190 : fillcache(CACHESIGN *item, TRGM *key, BITVECP sign, int siglen)
     755                 :             : {
     756                 :       44190 :     item->allistrue = false;
     757                 :       44190 :     item->sign = sign;
     758         [ +  + ]:       44190 :     if (ISARRKEY(key))
     759                 :       43962 :         makesign(item->sign, key, siglen);
     760         [ -  + ]:         228 :     else if (ISALLTRUE(key))
     761                 :           0 :         item->allistrue = true;
     762                 :             :     else
     763                 :         228 :         memcpy(item->sign, GETSIGN(key), siglen);
     764                 :       44190 : }
     765                 :             : 
     766                 :             : #define WISH_F(a,b,c) (double)( -(double)(((a)-(b))*((a)-(b))*((a)-(b)))*(c) )
     767                 :             : typedef struct
     768                 :             : {
     769                 :             :     OffsetNumber pos;
     770                 :             :     int32       cost;
     771                 :             : } SPLITCOST;
     772                 :             : 
     773                 :             : static int
     774                 :       49536 : comparecost(const void *a, const void *b)
     775                 :             : {
     776         [ +  + ]:       49536 :     if (((const SPLITCOST *) a)->cost == ((const SPLITCOST *) b)->cost)
     777                 :       44323 :         return 0;
     778                 :             :     else
     779         [ +  + ]:        5213 :         return (((const SPLITCOST *) a)->cost > ((const SPLITCOST *) b)->cost) ? 1 : -1;
     780                 :             : }
     781                 :             : 
     782                 :             : 
     783                 :             : static int
     784                 :     3647867 : hemdistcache(CACHESIGN *a, CACHESIGN *b, int siglen)
     785                 :             : {
     786         [ -  + ]:     3647867 :     if (a->allistrue)
     787                 :             :     {
     788         [ #  # ]:           0 :         if (b->allistrue)
     789                 :           0 :             return 0;
     790                 :             :         else
     791                 :           0 :             return SIGLENBIT(siglen) - sizebitvec(b->sign, siglen);
     792                 :             :     }
     793         [ -  + ]:     3647867 :     else if (b->allistrue)
     794                 :           0 :         return SIGLENBIT(siglen) - sizebitvec(a->sign, siglen);
     795                 :             : 
     796                 :     3647867 :     return hemdistsign(a->sign, b->sign, siglen);
     797                 :             : }
     798                 :             : 
     799                 :             : Datum
     800                 :         281 : gtrgm_picksplit(PG_FUNCTION_ARGS)
     801                 :             : {
     802                 :         281 :     GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
     803                 :         281 :     OffsetNumber maxoff = entryvec->n - 1;
     804                 :         281 :     GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
     805         [ +  - ]:         281 :     int         siglen = GET_SIGLEN();
     806                 :             :     OffsetNumber k,
     807                 :             :                 j;
     808                 :             :     TRGM       *datum_l,
     809                 :             :                *datum_r;
     810                 :             :     BITVECP     union_l,
     811                 :             :                 union_r;
     812                 :             :     int32       size_alpha,
     813                 :             :                 size_beta;
     814                 :             :     int32       size_waste,
     815                 :         281 :                 waste = -1;
     816                 :             :     int32       nbytes;
     817                 :         281 :     OffsetNumber seed_1 = 0,
     818                 :         281 :                 seed_2 = 0;
     819                 :             :     OffsetNumber *left,
     820                 :             :                *right;
     821                 :             :     BITVECP     ptr;
     822                 :             :     int         i;
     823                 :             :     CACHESIGN  *cache;
     824                 :             :     char       *cache_sign;
     825                 :             :     SPLITCOST  *costvector;
     826                 :             : 
     827                 :             :     /* cache the sign data for each existing item */
     828                 :         281 :     cache = palloc_array(CACHESIGN, maxoff + 1);
     829                 :         281 :     cache_sign = palloc(siglen * (maxoff + 1));
     830                 :             : 
     831         [ +  + ]:       44471 :     for (k = FirstOffsetNumber; k <= maxoff; k = OffsetNumberNext(k))
     832                 :       44190 :         fillcache(&cache[k], GETENTRY(entryvec, k), &cache_sign[siglen * k],
     833                 :             :                   siglen);
     834                 :             : 
     835                 :             :     /* now find the two furthest-apart items */
     836         [ +  + ]:       44190 :     for (k = FirstOffsetNumber; k < maxoff; k = OffsetNumberNext(k))
     837                 :             :     {
     838         [ +  + ]:     3603396 :         for (j = OffsetNumberNext(k); j <= maxoff; j = OffsetNumberNext(j))
     839                 :             :         {
     840                 :     3559487 :             size_waste = hemdistcache(&(cache[j]), &(cache[k]), siglen);
     841         [ +  + ]:     3559487 :             if (size_waste > waste)
     842                 :             :             {
     843                 :         481 :                 waste = size_waste;
     844                 :         481 :                 seed_1 = k;
     845                 :         481 :                 seed_2 = j;
     846                 :             :             }
     847                 :             :         }
     848                 :             :     }
     849                 :             : 
     850                 :             :     /* just in case we didn't make a selection ... */
     851   [ +  -  -  + ]:         281 :     if (seed_1 == 0 || seed_2 == 0)
     852                 :             :     {
     853                 :           0 :         seed_1 = 1;
     854                 :           0 :         seed_2 = 2;
     855                 :             :     }
     856                 :             : 
     857                 :             :     /* initialize the result vectors */
     858                 :         281 :     nbytes = maxoff * sizeof(OffsetNumber);
     859                 :         281 :     v->spl_left = left = (OffsetNumber *) palloc(nbytes);
     860                 :         281 :     v->spl_right = right = (OffsetNumber *) palloc(nbytes);
     861                 :         281 :     v->spl_nleft = 0;
     862                 :         281 :     v->spl_nright = 0;
     863                 :             : 
     864                 :             :     /* form initial .. */
     865                 :         281 :     datum_l = gtrgm_alloc(cache[seed_1].allistrue, siglen, cache[seed_1].sign);
     866                 :         281 :     datum_r = gtrgm_alloc(cache[seed_2].allistrue, siglen, cache[seed_2].sign);
     867                 :             : 
     868                 :         281 :     union_l = GETSIGN(datum_l);
     869                 :         281 :     union_r = GETSIGN(datum_r);
     870                 :             : 
     871                 :             :     /* sort before ... */
     872                 :         281 :     costvector = palloc_array(SPLITCOST, maxoff);
     873         [ +  + ]:       44471 :     for (j = FirstOffsetNumber; j <= maxoff; j = OffsetNumberNext(j))
     874                 :             :     {
     875                 :       44190 :         costvector[j - 1].pos = j;
     876                 :       44190 :         size_alpha = hemdistcache(&(cache[seed_1]), &(cache[j]), siglen);
     877                 :       44190 :         size_beta = hemdistcache(&(cache[seed_2]), &(cache[j]), siglen);
     878                 :       44190 :         costvector[j - 1].cost = abs(size_alpha - size_beta);
     879                 :             :     }
     880                 :         281 :     qsort(costvector, maxoff, sizeof(SPLITCOST), comparecost);
     881                 :             : 
     882         [ +  + ]:       44471 :     for (k = 0; k < maxoff; k++)
     883                 :             :     {
     884                 :       44190 :         j = costvector[k].pos;
     885         [ +  + ]:       44190 :         if (j == seed_1)
     886                 :             :         {
     887                 :         281 :             *left++ = j;
     888                 :         281 :             v->spl_nleft++;
     889                 :         281 :             continue;
     890                 :             :         }
     891         [ +  + ]:       43909 :         else if (j == seed_2)
     892                 :             :         {
     893                 :         281 :             *right++ = j;
     894                 :         281 :             v->spl_nright++;
     895                 :         281 :             continue;
     896                 :             :         }
     897                 :             : 
     898   [ +  -  -  + ]:       43628 :         if (ISALLTRUE(datum_l) || cache[j].allistrue)
     899                 :             :         {
     900   [ #  #  #  # ]:           0 :             if (ISALLTRUE(datum_l) && cache[j].allistrue)
     901                 :           0 :                 size_alpha = 0;
     902                 :             :             else
     903                 :           0 :                 size_alpha = SIGLENBIT(siglen) -
     904         [ #  # ]:           0 :                     sizebitvec((cache[j].allistrue) ? GETSIGN(datum_l) :
     905                 :           0 :                                GETSIGN(cache[j].sign),
     906                 :             :                                siglen);
     907                 :             :         }
     908                 :             :         else
     909                 :       43628 :             size_alpha = hemdistsign(cache[j].sign, GETSIGN(datum_l), siglen);
     910                 :             : 
     911   [ +  -  -  + ]:       43628 :         if (ISALLTRUE(datum_r) || cache[j].allistrue)
     912                 :             :         {
     913   [ #  #  #  # ]:           0 :             if (ISALLTRUE(datum_r) && cache[j].allistrue)
     914                 :           0 :                 size_beta = 0;
     915                 :             :             else
     916                 :           0 :                 size_beta = SIGLENBIT(siglen) -
     917         [ #  # ]:           0 :                     sizebitvec((cache[j].allistrue) ? GETSIGN(datum_r) :
     918                 :           0 :                                GETSIGN(cache[j].sign),
     919                 :             :                                siglen);
     920                 :             :         }
     921                 :             :         else
     922                 :       43628 :             size_beta = hemdistsign(cache[j].sign, GETSIGN(datum_r), siglen);
     923                 :             : 
     924         [ +  + ]:       43628 :         if (size_alpha < size_beta + WISH_F(v->spl_nleft, v->spl_nright, 0.1))
     925                 :             :         {
     926   [ +  -  -  + ]:       21708 :             if (ISALLTRUE(datum_l) || cache[j].allistrue)
     927                 :             :             {
     928         [ #  # ]:           0 :                 if (!ISALLTRUE(datum_l))
     929                 :           0 :                     memset(GETSIGN(datum_l), 0xff, siglen);
     930                 :             :             }
     931                 :             :             else
     932                 :             :             {
     933                 :       21708 :                 ptr = cache[j].sign;
     934         [ +  + ]:     2372672 :                 LOOPBYTE(siglen)
     935                 :     2350964 :                     union_l[i] |= ptr[i];
     936                 :             :             }
     937                 :       21708 :             *left++ = j;
     938                 :       21708 :             v->spl_nleft++;
     939                 :             :         }
     940                 :             :         else
     941                 :             :         {
     942   [ +  -  -  + ]:       21920 :             if (ISALLTRUE(datum_r) || cache[j].allistrue)
     943                 :             :             {
     944         [ #  # ]:           0 :                 if (!ISALLTRUE(datum_r))
     945                 :           0 :                     memset(GETSIGN(datum_r), 0xff, siglen);
     946                 :             :             }
     947                 :             :             else
     948                 :             :             {
     949                 :       21920 :                 ptr = cache[j].sign;
     950         [ +  + ]:     2357320 :                 LOOPBYTE(siglen)
     951                 :     2335400 :                     union_r[i] |= ptr[i];
     952                 :             :             }
     953                 :       21920 :             *right++ = j;
     954                 :       21920 :             v->spl_nright++;
     955                 :             :         }
     956                 :             :     }
     957                 :             : 
     958                 :         281 :     v->spl_ldatum = PointerGetDatum(datum_l);
     959                 :         281 :     v->spl_rdatum = PointerGetDatum(datum_r);
     960                 :             : 
     961                 :         281 :     PG_RETURN_POINTER(v);
     962                 :             : }
     963                 :             : 
     964                 :             : Datum
     965                 :          31 : gtrgm_options(PG_FUNCTION_ARGS)
     966                 :             : {
     967                 :          31 :     local_relopts *relopts = (local_relopts *) PG_GETARG_POINTER(0);
     968                 :             : 
     969                 :          31 :     init_local_reloptions(relopts, sizeof(TrgmGistOptions));
     970                 :          31 :     add_local_int_reloption(relopts, "siglen",
     971                 :             :                             "signature length in bytes",
     972                 :             :                             SIGLEN_DEFAULT, 1, SIGLEN_MAX,
     973                 :             :                             offsetof(TrgmGistOptions, siglen));
     974                 :             : 
     975                 :          31 :     PG_RETURN_VOID();
     976                 :             : }
        

Generated by: LCOV version 2.0-1