LCOV - differential code coverage report
Current view: top level - contrib/pg_trgm - trgm_gist.c (source / functions) Coverage Total Hit UNC UIC UBC GIC GNC CBC EUB ECB DUB DCB
Current: 0e5ff9b9b45a657aea12440478dc002e9b01f138 vs 0123ce131fca454009439dfa3b2266d1d40737d7 Lines: 79.8 % 431 344 2 85 3 341 2 3
Current Date: 2026-03-14 14:10:32 -0400 Functions: 87.5 % 32 28 4 5 23
Baseline: lcov-20260315-024220-baseline Branches: 58.0 % 250 145 2 103 4 141 11 7
Baseline Date: 2026-03-14 15:27:56 +0100 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(30,360] days: 75.0 % 8 6 2 3 3
(360..) days: 79.9 % 423 338 85 338
Function coverage date bins:
(360..) days: 87.5 % 32 28 4 5 23
Branch coverage date bins:
(30,360] days: 100.0 % 2 2 2
(360..) days: 53.8 % 266 143 2 103 4 139 11 7

 Age         Owner                    Branch data    TLA  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                 :                : 
 7958 teodor@sigaev.ru           43                 :CBC           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);
 5580 tgl@sss.pgh.pa.us          48                 :              5 : PG_FUNCTION_INFO_V1(gtrgm_distance);
 7958 teodor@sigaev.ru           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);
 2176 akorotkov@postgresql       53                 :              5 : PG_FUNCTION_INFO_V1(gtrgm_options);
                                 54                 :                : 
                                 55                 :                : 
                                 56                 :                : Datum
 7958 teodor@sigaev.ru           57                 :UBC           0 : gtrgm_in(PG_FUNCTION_ARGS)
                                 58                 :                : {
 1191 tgl@sss.pgh.pa.us          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
 7958 teodor@sigaev.ru           67                 :              0 : gtrgm_out(PG_FUNCTION_ARGS)
                                 68                 :                : {
 1191 tgl@sss.pgh.pa.us          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 *
 2176 akorotkov@postgresql       77                 :CBC       28153 : gtrgm_alloc(bool isalltrue, int siglen, BITVECP sign)
                                 78                 :                : {
                                 79         [ -  + ]:          28153 :     int         flag = SIGNKEY | (isalltrue ? ALLISTRUE : 0);
                                 80   [ -  +  +  - ]:          28153 :     int         size = CALCGTSIZE(flag, siglen);
                                 81                 :          28153 :     TRGM       *res = palloc(size);
                                 82                 :                : 
                                 83                 :          28153 :     SET_VARSIZE(res, size);
                                 84                 :          28153 :     res->flag = flag;
                                 85                 :                : 
                                 86         [ +  - ]:          28153 :     if (!isalltrue)
                                 87                 :                :     {
                                 88         [ +  + ]:          28153 :         if (sign)
                                 89                 :            556 :             memcpy(GETSIGN(res), sign, siglen);
                                 90                 :                :         else
                                 91                 :          27597 :             memset(GETSIGN(res), 0, siglen);
                                 92                 :                :     }
                                 93                 :                : 
                                 94                 :          28153 :     return res;
                                 95                 :                : }
                                 96                 :                : 
                                 97                 :                : static void
                                 98                 :          47653 : makesign(BITVECP sign, TRGM *a, int siglen)
                                 99                 :                : {
                                100                 :                :     int32       k,
 7958 teodor@sigaev.ru          101                 :          47653 :                 len = ARRNELEM(a);
                                102                 :          47653 :     trgm       *ptr = GETARR(a);
 5011 peter_e@gmx.net           103                 :          47653 :     int32       tmp = 0;
                                104                 :                : 
 1132 peter@eisentraut.org      105   [ +  +  +  +  :          47653 :     MemSet(sign, 0, siglen);
                                     +  -  -  +  -  
                                                 - ]
 2176 akorotkov@postgresql      106                 :          47653 :     SETBIT(sign, SIGLENBIT(siglen));    /* set last unused bit */
 7868 bruce@momjian.us          107         [ +  + ]:         468207 :     for (k = 0; k < len; k++)
                                108                 :                :     {
  388 peter@eisentraut.org      109                 :         420554 :         CPTRGM(&tmp, ptr + k);
 2176 akorotkov@postgresql      110                 :         420554 :         HASH(sign, tmp, siglen);
                                111                 :                :     }
 7958 teodor@sigaev.ru          112                 :          47653 : }
                                113                 :                : 
                                114                 :                : Datum
                                115                 :          27789 : gtrgm_compress(PG_FUNCTION_ARGS)
                                116                 :                : {
                                117                 :          27789 :     GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 1949 akorotkov@postgresql      118         [ +  - ]:          27789 :     int         siglen = GET_SIGLEN();
 7958 teodor@sigaev.ru          119                 :          27789 :     GISTENTRY  *retval = entry;
                                120                 :                : 
                                121         [ +  + ]:          27789 :     if (entry->leafkey)
                                122                 :                :     {                           /* trgm */
                                123                 :                :         TRGM       *res;
 3290 noah@leadboat.com         124                 :          24452 :         text       *val = DatumGetTextPP(entry->key);
                                125                 :                : 
                                126   [ -  +  -  -  :          24452 :         res = generate_trgm(VARDATA_ANY(val), VARSIZE_ANY_EXHDR(val));
                                     -  -  -  -  +  
                                           -  +  - ]
  100 michael@paquier.xyz       127                 :GNC       24452 :         retval = palloc_object(GISTENTRY);
 7958 teodor@sigaev.ru          128                 :CBC       24452 :         gistentryinit(*retval, PointerGetDatum(res),
                                129                 :                :                       entry->rel, entry->page,
                                130                 :                :                       entry->offset, false);
                                131                 :                :     }
                                132         [ +  - ]:           3337 :     else if (ISSIGNKEY(DatumGetPointer(entry->key)) &&
                                133         [ +  - ]:           3337 :              !ISALLTRUE(DatumGetPointer(entry->key)))
                                134                 :                :     {
                                135                 :                :         int32       i;
                                136                 :                :         TRGM       *res;
                                137                 :           3337 :         BITVECP     sign = GETSIGN(DatumGetPointer(entry->key));
                                138                 :                : 
 2176 akorotkov@postgresql      139         [ +  - ]:           3596 :         LOOPBYTE(siglen)
                                140                 :                :         {
 6694 bruce@momjian.us          141         [ +  + ]:           3596 :             if ((sign[i] & 0xff) != 0xff)
                                142                 :           3337 :                 PG_RETURN_POINTER(retval);
                                143                 :                :         }
                                144                 :                : 
 2176 akorotkov@postgresql      145                 :UBC           0 :         res = gtrgm_alloc(true, siglen, sign);
  100 michael@paquier.xyz       146                 :UNC           0 :         retval = palloc_object(GISTENTRY);
 7958 teodor@sigaev.ru          147                 :UBC           0 :         gistentryinit(*retval, PointerGetDatum(res),
                                148                 :                :                       entry->rel, entry->page,
                                149                 :                :                       entry->offset, false);
                                150                 :                :     }
 7958 teodor@sigaev.ru          151                 :CBC       24452 :     PG_RETURN_POINTER(retval);
                                152                 :                : }
                                153                 :                : 
                                154                 :                : Datum
                                155                 :        1362561 : gtrgm_decompress(PG_FUNCTION_ARGS)
                                156                 :                : {
 6918 tgl@sss.pgh.pa.us         157                 :        1362561 :     GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
                                158                 :                :     GISTENTRY  *retval;
                                159                 :                :     text       *key;
                                160                 :                : 
 3290 noah@leadboat.com         161                 :        1362561 :     key = DatumGetTextPP(entry->key);
                                162                 :                : 
 6918 tgl@sss.pgh.pa.us         163         [ -  + ]:        1362561 :     if (key != (text *) DatumGetPointer(entry->key))
                                164                 :                :     {
                                165                 :                :         /* need to pass back the decompressed item */
  100 michael@paquier.xyz       166                 :UNC           0 :         retval = palloc_object(GISTENTRY);
 6918 tgl@sss.pgh.pa.us         167                 :UBC           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 */
 6918 tgl@sss.pgh.pa.us         174                 :CBC     1362561 :         PG_RETURN_POINTER(entry);
                                175                 :                :     }
                                176                 :                : }
                                177                 :                : 
                                178                 :                : static int32
 2176 akorotkov@postgresql      179                 :            642 : cnt_sml_sign_common(TRGM *qtrg, BITVECP sign, int siglen)
                                180                 :                : {
 5011 peter_e@gmx.net           181                 :            642 :     int32       count = 0;
                                182                 :                :     int32       k,
 5580 tgl@sss.pgh.pa.us         183                 :            642 :                 len = ARRNELEM(qtrg);
                                184                 :            642 :     trgm       *ptr = GETARR(qtrg);
 5011 peter_e@gmx.net           185                 :            642 :     int32       tmp = 0;
                                186                 :                : 
 5580 tgl@sss.pgh.pa.us         187         [ +  + ]:           5866 :     for (k = 0; k < len; k++)
                                188                 :                :     {
  388 peter@eisentraut.org      189                 :           5224 :         CPTRGM(&tmp, ptr + k);
 2176 akorotkov@postgresql      190                 :           5224 :         count += GETBIT(sign, HASHVAL(tmp, siglen));
                                191                 :                :     }
                                192                 :                : 
 5580 tgl@sss.pgh.pa.us         193                 :            642 :     return count;
                                194                 :                : }
                                195                 :                : 
                                196                 :                : Datum
 7958 teodor@sigaev.ru          197                 :          37638 : gtrgm_consistent(PG_FUNCTION_ARGS)
                                198                 :                : {
 6544 tgl@sss.pgh.pa.us         199                 :          37638 :     GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
                                200                 :          37638 :     text       *query = PG_GETARG_TEXT_P(1);
 5580                           201                 :          37638 :     StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
                                202                 :                : #ifdef NOT_USED
                                203                 :                :     Oid         subtype = PG_GETARG_OID(3);
                                204                 :                : #endif
 6544                           205                 :          37638 :     bool       *recheck = (bool *) PG_GETARG_POINTER(4);
 1949 akorotkov@postgresql      206         [ +  - ]:          37638 :     int         siglen = GET_SIGLEN();
 6544 tgl@sss.pgh.pa.us         207                 :          37638 :     TRGM       *key = (TRGM *) DatumGetPointer(entry->key);
                                208                 :                :     TRGM       *qtrg;
                                209                 :                :     bool        res;
 5280                           210                 :          37638 :     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                 :                :      */
 4722                           228                 :          37638 :     cache = (gtrgm_consistent_cache *) fcinfo->flinfo->fn_extra;
 5280                           229         [ +  + ]:          37638 :     if (cache == NULL ||
 4722                           230   [ +  -  +  - ]:          75164 :         cache->strategy != strategy ||
                                231         [ +  - ]:          37582 :         VARSIZE(cache->query) != querysize ||
  396 peter@eisentraut.org      232         [ -  + ]:          37582 :         memcmp(cache->query, query, querysize) != 0)
                                233                 :                :     {
                                234                 :                :         gtrgm_consistent_cache *newcache;
 4722 tgl@sss.pgh.pa.us         235                 :             56 :         TrgmPackedGraph *graph = NULL;
                                236                 :                :         Size        qtrgsize;
                                237                 :                : 
 5522                           238   [ +  +  +  - ]:             56 :         switch (strategy)
                                239                 :                :         {
                                240                 :             28 :             case SimilarityStrategyNumber:
                                241                 :                :             case WordSimilarityStrategyNumber:
                                242                 :                :             case StrictWordSimilarityStrategyNumber:
                                243                 :                :             case EqualStrategyNumber:
 5280                           244                 :             28 :                 qtrg = generate_trgm(VARDATA(query),
                                245                 :             28 :                                      querysize - VARHDRSZ);
 5522                           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:
 5280                           253                 :              7 :                 qtrg = generate_wildcard_trgm(VARDATA(query),
                                254                 :              7 :                                               querysize - VARHDRSZ);
 5522                           255                 :              7 :                 break;
 4722                           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                 :                :                 {
 4722 tgl@sss.pgh.pa.us         267                 :UBC           0 :                     pfree(qtrg);
                                268                 :              0 :                     qtrg = NULL;
                                269                 :                :                 }
 4722 tgl@sss.pgh.pa.us         270                 :CBC          21 :                 break;
 5522 tgl@sss.pgh.pa.us         271                 :UBC           0 :             default:
                                272         [ #  # ]:              0 :                 elog(ERROR, "unrecognized strategy number: %d", strategy);
                                273                 :                :                 qtrg = NULL;    /* keep compiler quiet */
                                274                 :                :                 break;
                                275                 :                :         }
                                276                 :                : 
 4722 tgl@sss.pgh.pa.us         277         [ +  + ]:CBC          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)));
  396 peter@eisentraut.org      288                 :             56 :         memcpy(newcache->query, query, querysize);
 4722 tgl@sss.pgh.pa.us         289         [ +  + ]:             56 :         if (qtrg)
                                290                 :                :         {
                                291                 :             52 :             newcache->trigrams = (TRGM *)
                                292                 :             52 :                 ((char *) newcache->query + MAXALIGN(querysize));
  396 peter@eisentraut.org      293                 :             52 :             memcpy((char *) newcache->trigrams, qtrg, qtrgsize);
                                294                 :                :             /* release qtrg in case it was made in fn_mcxt */
 4722 tgl@sss.pgh.pa.us         295                 :             52 :             pfree(qtrg);
                                296                 :                :         }
                                297                 :                :         else
                                298                 :              4 :             newcache->trigrams = NULL;
                                299                 :             56 :         newcache->graph = graph;
                                300                 :                : 
 6456 teodor@sigaev.ru          301         [ -  + ]:             56 :         if (cache)
 6456 teodor@sigaev.ru          302                 :UBC           0 :             pfree(cache);
  472 peter@eisentraut.org      303                 :CBC          56 :         fcinfo->flinfo->fn_extra = newcache;
 4722 tgl@sss.pgh.pa.us         304                 :             56 :         cache = newcache;
                                305                 :                :     }
                                306                 :                : 
                                307                 :          37638 :     qtrg = cache->trigrams;
                                308                 :                : 
 5580                           309   [ +  +  +  - ]:          37638 :     switch (strategy)
                                310                 :                :     {
                                311                 :          35236 :         case SimilarityStrategyNumber:
                                312                 :                :         case WordSimilarityStrategyNumber:
                                313                 :                :         case StrictWordSimilarityStrategyNumber:
                                314                 :                : 
                                315                 :                :             /*
                                316                 :                :              * Similarity search is exact. (Strict) word similarity search is
                                317                 :                :              * inexact
                                318                 :                :              */
 2916 teodor@sigaev.ru          319                 :          35236 :             *recheck = (strategy != SimilarityStrategyNumber);
                                320                 :                : 
                                321                 :          35236 :             nlimit = index_strategy_get_limit(strategy);
                                322                 :                : 
 5580 tgl@sss.pgh.pa.us         323         [ +  + ]:          35236 :             if (GIST_LEAF(entry))
                                324                 :                :             {                   /* all leafs contains orig trgm */
 3555                           325                 :          34632 :                 double      tmpsml = cnt_sml(qtrg, key, *recheck);
                                326                 :                : 
                                327                 :          34632 :                 res = (tmpsml >= nlimit);
                                328                 :                :             }
 5580                           329         [ -  + ]:            604 :             else if (ISALLTRUE(key))
                                330                 :                :             {                   /* non-leaf contains signature */
 5580 tgl@sss.pgh.pa.us         331                 :UBC           0 :                 res = true;
                                332                 :                :             }
                                333                 :                :             else
                                334                 :                :             {                   /* non-leaf contains signature */
 2176 akorotkov@postgresql      335                 :CBC         604 :                 int32       count = cnt_sml_sign_common(qtrg, GETSIGN(key), siglen);
 5011 peter_e@gmx.net           336                 :            604 :                 int32       len = ARRNELEM(qtrg);
                                337                 :                : 
 5580 tgl@sss.pgh.pa.us         338         [ -  + ]:            604 :                 if (len == 0)
 5580 tgl@sss.pgh.pa.us         339                 :UBC           0 :                     res = false;
                                340                 :                :                 else
 3651 teodor@sigaev.ru          341                 :CBC         604 :                     res = (((((float8) count) / ((float8) len))) >= nlimit);
                                342                 :                :             }
 5580 tgl@sss.pgh.pa.us         343                 :          35236 :             break;
 5522                           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                 :                :             }
 5522 tgl@sss.pgh.pa.us         362         [ #  # ]:UBC           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,
 5453 bruce@momjian.us          369                 :              0 :                             tmp = 0,
                                370                 :              0 :                             len = ARRNELEM(qtrg);
                                371                 :              0 :                 trgm       *ptr = GETARR(qtrg);
                                372                 :              0 :                 BITVECP     sign = GETSIGN(key);
                                373                 :                : 
 5522 tgl@sss.pgh.pa.us         374                 :              0 :                 res = true;
                                375         [ #  # ]:              0 :                 for (k = 0; k < len; k++)
                                376                 :                :                 {
  388 peter@eisentraut.org      377                 :              0 :                     CPTRGM(&tmp, ptr + k);
 2176 akorotkov@postgresql      378         [ #  # ]:              0 :                     if (!GETBIT(sign, HASHVAL(tmp, siglen)))
                                379                 :                :                     {
 5522 tgl@sss.pgh.pa.us         380                 :              0 :                         res = false;
                                381                 :              0 :                         break;
                                382                 :                :                     }
                                383                 :                :                 }
                                384                 :                :             }
 5522 tgl@sss.pgh.pa.us         385                 :CBC         190 :             break;
 4722                           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 */
 4722 tgl@sss.pgh.pa.us         408                 :UBC           0 :                     res = true;
                                409                 :                :                 }
                                410                 :                :                 else
                                411                 :                :                 {               /* non-leaf contains signature */
                                412                 :                :                     int32       k,
 4722 tgl@sss.pgh.pa.us         413                 :CBC          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                 :                :                      */
 4717                           427                 :             22 :                     check = (bool *) palloc(len * sizeof(bool));
 4722                           428         [ +  + ]:           5566 :                     for (k = 0; k < len; k++)
                                429                 :                :                     {
  388 peter@eisentraut.org      430                 :           5544 :                         CPTRGM(&tmp, ptr + k);
 2176 akorotkov@postgresql      431                 :           5544 :                         check[k] = GETBIT(sign, HASHVAL(tmp, siglen));
                                432                 :                :                     }
 4717 tgl@sss.pgh.pa.us         433                 :             22 :                     res = trigramsMatchGraph(cache->graph, check);
                                434                 :             22 :                     pfree(check);
                                435                 :                :                 }
                                436                 :                :             }
                                437                 :                :             else
                                438                 :                :             {
                                439                 :                :                 /* trigram-free query must be rechecked everywhere */
 4722                           440                 :             40 :                 res = true;
                                441                 :                :             }
                                442                 :           2212 :             break;
 5580 tgl@sss.pgh.pa.us         443                 :UBC           0 :         default:
                                444         [ #  # ]:              0 :             elog(ERROR, "unrecognized strategy number: %d", strategy);
                                445                 :                :             res = false;        /* keep compiler quiet */
                                446                 :                :             break;
                                447                 :                :     }
                                448                 :                : 
 5580 tgl@sss.pgh.pa.us         449                 :CBC       37638 :     PG_RETURN_BOOL(res);
                                450                 :                : }
                                451                 :                : 
                                452                 :                : Datum
                                453                 :           2864 : gtrgm_distance(PG_FUNCTION_ARGS)
                                454                 :                : {
                                455                 :           2864 :     GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
                                456                 :           2864 :     text       *query = PG_GETARG_TEXT_P(1);
                                457                 :           2864 :     StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
                                458                 :                : #ifdef NOT_USED
                                459                 :                :     Oid         subtype = PG_GETARG_OID(3);
                                460                 :                : #endif
 3651 teodor@sigaev.ru          461                 :           2864 :     bool       *recheck = (bool *) PG_GETARG_POINTER(4);
 1949 akorotkov@postgresql      462         [ +  - ]:           2864 :     int         siglen = GET_SIGLEN();
 5580 tgl@sss.pgh.pa.us         463                 :           2864 :     TRGM       *key = (TRGM *) DatumGetPointer(entry->key);
                                464                 :                :     TRGM       *qtrg;
                                465                 :                :     float8      res;
 5280                           466                 :           2864 :     Size        querysize = VARSIZE(query);
 5580                           467                 :           2864 :     char       *cache = (char *) fcinfo->flinfo->fn_extra;
                                468                 :                : 
                                469                 :                :     /*
                                470                 :                :      * Cache the generated trigrams across multiple calls with the same query.
                                471                 :                :      */
 5280                           472   [ +  +  +  - ]:           5724 :     if (cache == NULL ||
                                473         [ +  - ]:           2860 :         VARSIZE(cache) != querysize ||
                                474         [ -  + ]:           2860 :         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)
 5280 tgl@sss.pgh.pa.us         488                 :UBC           0 :             pfree(cache);
 5280 tgl@sss.pgh.pa.us         489                 :CBC           4 :         fcinfo->flinfo->fn_extra = newcache;
                                490                 :              4 :         cache = newcache;
                                491                 :                :     }
                                492                 :                : 
                                493                 :           2864 :     qtrg = (TRGM *) (cache + MAXALIGN(querysize));
                                494                 :                : 
 5580                           495         [ +  - ]:           2864 :     switch (strategy)
                                496                 :                :     {
                                497                 :           2864 :         case DistanceStrategyNumber:
                                498                 :                :         case WordDistanceStrategyNumber:
                                499                 :                :         case StrictWordDistanceStrategyNumber:
                                500                 :                :             /* Only plain trigram distance is exact */
 2916 teodor@sigaev.ru          501                 :           2864 :             *recheck = (strategy != DistanceStrategyNumber);
 5580 tgl@sss.pgh.pa.us         502         [ +  + ]:           2864 :             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                 :                :                  */
 3651 teodor@sigaev.ru          510                 :           2826 :                 float4 volatile sml = cnt_sml(qtrg, key, *recheck);
                                511                 :                : 
                                512                 :           2826 :                 res = 1.0 - sml;
                                513                 :                :             }
 5580 tgl@sss.pgh.pa.us         514         [ -  + ]:             38 :             else if (ISALLTRUE(key))
                                515                 :                :             {                   /* all leafs contains orig trgm */
 5580 tgl@sss.pgh.pa.us         516                 :UBC           0 :                 res = 0.0;
                                517                 :                :             }
                                518                 :                :             else
                                519                 :                :             {                   /* non-leaf contains signature */
 2176 akorotkov@postgresql      520                 :CBC          38 :                 int32       count = cnt_sml_sign_common(qtrg, GETSIGN(key), siglen);
 5011 peter_e@gmx.net           521                 :             38 :                 int32       len = ARRNELEM(qtrg);
                                522                 :                : 
 5580 tgl@sss.pgh.pa.us         523         [ +  - ]:             38 :                 res = (len == 0) ? -1.0 : 1.0 - ((float8) count) / ((float8) len);
                                524                 :                :             }
                                525                 :           2864 :             break;
 5580 tgl@sss.pgh.pa.us         526                 :UBC           0 :         default:
                                527         [ #  # ]:              0 :             elog(ERROR, "unrecognized strategy number: %d", strategy);
                                528                 :                :             res = 0;            /* keep compiler quiet */
                                529                 :                :             break;
                                530                 :                :     }
                                531                 :                : 
 5580 tgl@sss.pgh.pa.us         532                 :CBC        2864 :     PG_RETURN_FLOAT8(res);
                                533                 :                : }
                                534                 :                : 
                                535                 :                : static int32
 2176 akorotkov@postgresql      536                 :          55194 : unionkey(BITVECP sbase, TRGM *add, int siglen)
                                537                 :                : {
                                538                 :                :     int32       i;
                                539                 :                : 
 7958 teodor@sigaev.ru          540         [ +  + ]:          55194 :     if (ISSIGNKEY(add))
                                541                 :                :     {
                                542                 :          27597 :         BITVECP     sadd = GETSIGN(add);
                                543                 :                : 
                                544         [ -  + ]:          27597 :         if (ISALLTRUE(add))
 7958 teodor@sigaev.ru          545                 :UBC           0 :             return 1;
                                546                 :                : 
 2176 akorotkov@postgresql      547         [ +  + ]:CBC     6507433 :         LOOPBYTE(siglen)
 6694 bruce@momjian.us          548                 :        6479836 :             sbase[i] |= sadd[i];
                                549                 :                :     }
                                550                 :                :     else
                                551                 :                :     {
 7958 teodor@sigaev.ru          552                 :          27597 :         trgm       *ptr = GETARR(add);
 5011 peter_e@gmx.net           553                 :          27597 :         int32       tmp = 0;
                                554                 :                : 
 7868 bruce@momjian.us          555         [ +  + ]:         275985 :         for (i = 0; i < ARRNELEM(add); i++)
                                556                 :                :         {
  388 peter@eisentraut.org      557                 :         248388 :             CPTRGM(&tmp, ptr + i);
 2176 akorotkov@postgresql      558                 :         248388 :             HASH(sbase, tmp, siglen);
                                559                 :                :         }
                                560                 :                :     }
 7958 teodor@sigaev.ru          561                 :          55194 :     return 0;
                                562                 :                : }
                                563                 :                : 
                                564                 :                : 
                                565                 :                : Datum
                                566                 :          27597 : gtrgm_union(PG_FUNCTION_ARGS)
                                567                 :                : {
 7868 bruce@momjian.us          568                 :          27597 :     GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
 5011 peter_e@gmx.net           569                 :          27597 :     int32       len = entryvec->n;
 7958 teodor@sigaev.ru          570                 :          27597 :     int        *size = (int *) PG_GETARG_POINTER(1);
 1949 akorotkov@postgresql      571         [ +  - ]:          27597 :     int         siglen = GET_SIGLEN();
                                572                 :                :     int32       i;
 2176                           573                 :          27597 :     TRGM       *result = gtrgm_alloc(false, siglen, NULL);
                                574                 :          27597 :     BITVECP     base = GETSIGN(result);
                                575                 :                : 
 7958 teodor@sigaev.ru          576         [ +  + ]:          82791 :     for (i = 0; i < len; i++)
                                577                 :                :     {
 2176 akorotkov@postgresql      578         [ -  + ]:          55194 :         if (unionkey(base, GETENTRY(entryvec, i), siglen))
                                579                 :                :         {
 2176 akorotkov@postgresql      580                 :UBC           0 :             result->flag = ALLISTRUE;
                                581                 :              0 :             SET_VARSIZE(result, CALCGTSIZE(ALLISTRUE, siglen));
 7958 teodor@sigaev.ru          582                 :              0 :             break;
                                583                 :                :         }
                                584                 :                :     }
                                585                 :                : 
 2176 akorotkov@postgresql      586                 :CBC       27597 :     *size = VARSIZE(result);
                                587                 :                : 
 7958 teodor@sigaev.ru          588                 :          27597 :     PG_RETURN_POINTER(result);
                                589                 :                : }
                                590                 :                : 
                                591                 :                : Datum
                                592                 :          27597 : gtrgm_same(PG_FUNCTION_ARGS)
                                593                 :                : {
 7868 bruce@momjian.us          594                 :          27597 :     TRGM       *a = (TRGM *) PG_GETARG_POINTER(0);
                                595                 :          27597 :     TRGM       *b = (TRGM *) PG_GETARG_POINTER(1);
 7958 teodor@sigaev.ru          596                 :          27597 :     bool       *result = (bool *) PG_GETARG_POINTER(2);
 1949 akorotkov@postgresql      597         [ +  - ]:          27597 :     int         siglen = GET_SIGLEN();
                                598                 :                : 
 7958 teodor@sigaev.ru          599         [ +  - ]:          27597 :     if (ISSIGNKEY(a))
                                600                 :                :     {                           /* then b also ISSIGNKEY */
                                601   [ -  +  -  - ]:          27597 :         if (ISALLTRUE(a) && ISALLTRUE(b))
 7958 teodor@sigaev.ru          602                 :UBC           0 :             *result = true;
 7958 teodor@sigaev.ru          603         [ -  + ]:CBC       27597 :         else if (ISALLTRUE(a))
 7958 teodor@sigaev.ru          604                 :UBC           0 :             *result = false;
 7958 teodor@sigaev.ru          605         [ -  + ]:CBC       27597 :         else if (ISALLTRUE(b))
 7958 teodor@sigaev.ru          606                 :UBC           0 :             *result = false;
                                607                 :                :         else
                                608                 :                :         {
                                609                 :                :             int32       i;
 7958 teodor@sigaev.ru          610                 :CBC       27597 :             BITVECP     sa = GETSIGN(a),
                                611                 :          27597 :                         sb = GETSIGN(b);
                                612                 :                : 
                                613                 :          27597 :             *result = true;
 2176 akorotkov@postgresql      614         [ +  + ]:        3185253 :             LOOPBYTE(siglen)
                                615                 :                :             {
 6694 bruce@momjian.us          616         [ +  + ]:        3160437 :                 if (sa[i] != sb[i])
                                617                 :                :                 {
                                618                 :           2781 :                     *result = false;
                                619                 :           2781 :                     break;
                                620                 :                :                 }
                                621                 :                :             }
                                622                 :                :         }
                                623                 :                :     }
                                624                 :                :     else
                                625                 :                :     {                           /* a and b ISARRKEY */
 5011 peter_e@gmx.net           626                 :UBC           0 :         int32       lena = ARRNELEM(a),
 7958 teodor@sigaev.ru          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++)
 7868 bruce@momjian.us          639         [ #  # ]:              0 :                 if (CMPTRGM(ptra + i, ptrb + i))
                                640                 :                :                 {
 7958 teodor@sigaev.ru          641                 :              0 :                     *result = false;
                                642                 :              0 :                     break;
                                643                 :                :                 }
                                644                 :                :         }
                                645                 :                :     }
                                646                 :                : 
 7958 teodor@sigaev.ru          647                 :CBC       27597 :     PG_RETURN_POINTER(result);
                                648                 :                : }
                                649                 :                : 
                                650                 :                : static int32
 2176 akorotkov@postgresql      651                 :UBC           0 : sizebitvec(BITVECP sign, int siglen)
                                652                 :                : {
                                653                 :              0 :     return pg_popcount(sign, siglen);
                                654                 :                : }
                                655                 :                : 
                                656                 :                : static int
 2176 akorotkov@postgresql      657                 :CBC     4929506 : hemdistsign(BITVECP a, BITVECP b, int siglen)
                                658                 :                : {
                                659                 :                :     int         i,
                                660                 :                :                 diff,
 7868 bruce@momjian.us          661                 :        4929506 :                 dist = 0;
                                662                 :                : 
 2176 akorotkov@postgresql      663         [ +  + ]:      337023450 :     LOOPBYTE(siglen)
                                664                 :                :     {
 6694 bruce@momjian.us          665                 :      332093944 :         diff = (unsigned char) (a[i] ^ b[i]);
                                666                 :                :         /* Using the popcount functions here isn't likely to win */
 2585 tgl@sss.pgh.pa.us         667                 :      332093944 :         dist += pg_number_of_ones[diff];
                                668                 :                :     }
 7958 teodor@sigaev.ru          669                 :        4929506 :     return dist;
                                670                 :                : }
                                671                 :                : 
                                672                 :                : static int
 2176 akorotkov@postgresql      673                 :UBC           0 : hemdist(TRGM *a, TRGM *b, int siglen)
                                674                 :                : {
 7868 bruce@momjian.us          675         [ #  # ]:              0 :     if (ISALLTRUE(a))
                                676                 :                :     {
 7958 teodor@sigaev.ru          677         [ #  # ]:              0 :         if (ISALLTRUE(b))
                                678                 :              0 :             return 0;
                                679                 :                :         else
 2176 akorotkov@postgresql      680                 :              0 :             return SIGLENBIT(siglen) - sizebitvec(GETSIGN(b), siglen);
                                681                 :                :     }
 7868 bruce@momjian.us          682         [ #  # ]:              0 :     else if (ISALLTRUE(b))
 2176 akorotkov@postgresql      683                 :              0 :         return SIGLENBIT(siglen) - sizebitvec(GETSIGN(a), siglen);
                                684                 :                : 
                                685                 :              0 :     return hemdistsign(GETSIGN(a), GETSIGN(b), siglen);
                                686                 :                : }
                                687                 :                : 
                                688                 :                : Datum
 7958 teodor@sigaev.ru          689                 :CBC     1195158 : gtrgm_penalty(PG_FUNCTION_ARGS)
                                690                 :                : {
                                691                 :        1195158 :     GISTENTRY  *origentry = (GISTENTRY *) PG_GETARG_POINTER(0); /* always ISSIGNKEY */
                                692                 :        1195158 :     GISTENTRY  *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
                                693                 :        1195158 :     float      *penalty = (float *) PG_GETARG_POINTER(2);
 1949 akorotkov@postgresql      694         [ +  - ]:        1195158 :     int         siglen = GET_SIGLEN();
 7868 bruce@momjian.us          695                 :        1195158 :     TRGM       *origval = (TRGM *) DatumGetPointer(origentry->key);
                                696                 :        1195158 :     TRGM       *newval = (TRGM *) DatumGetPointer(newentry->key);
 7958 teodor@sigaev.ru          697                 :        1195158 :     BITVECP     orig = GETSIGN(origval);
                                698                 :                : 
                                699                 :        1195158 :     *penalty = 0.0;
                                700                 :                : 
 7868 bruce@momjian.us          701         [ +  - ]:        1195158 :     if (ISARRKEY(newval))
                                702                 :                :     {
 5280 tgl@sss.pgh.pa.us         703                 :        1195158 :         char       *cache = (char *) fcinfo->flinfo->fn_extra;
   39 john.naylor@postgres      704                 :        1195158 :         TRGM       *cachedVal = NULL;
 5280 tgl@sss.pgh.pa.us         705                 :        1195158 :         Size        newvalsize = VARSIZE(newval);
                                706                 :                :         BITVECP     sign;
                                707                 :                : 
   39 john.naylor@postgres      708         [ +  + ]:        1195158 :         if (cache != NULL)
                                709                 :        1195152 :             cachedVal = (TRGM *) (cache + MAXALIGN(siglen));
                                710                 :                : 
                                711                 :                :         /*
                                712                 :                :          * Cache the sign data across multiple calls with the same newval.
                                713                 :                :          */
 5280 tgl@sss.pgh.pa.us         714   [ +  +  +  + ]:        2390310 :         if (cache == NULL ||
                                715         [ +  + ]:        1195152 :             VARSIZE(cachedVal) != newvalsize ||
                                716         [ +  + ]:        1194125 :             memcmp(cachedVal, newval, newvalsize) != 0)
                                717                 :                :         {
                                718                 :                :             char       *newcache;
                                719                 :                : 
                                720                 :           3763 :             newcache = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
 2176 akorotkov@postgresql      721                 :           3763 :                                           MAXALIGN(siglen) +
                                722                 :                :                                           newvalsize);
                                723                 :                : 
                                724                 :           3763 :             makesign((BITVECP) newcache, newval, siglen);
                                725                 :                : 
                                726                 :           3763 :             cachedVal = (TRGM *) (newcache + MAXALIGN(siglen));
 5280 tgl@sss.pgh.pa.us         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                 :        1195158 :         sign = (BITVECP) cache;
                                736                 :                : 
 7868 bruce@momjian.us          737         [ -  + ]:        1195158 :         if (ISALLTRUE(origval))
 2176 akorotkov@postgresql      738                 :UBC           0 :             *penalty = ((float) (SIGLENBIT(siglen) - sizebitvec(sign, siglen))) / (float) (SIGLENBIT(siglen) + 1);
                                739                 :                :         else
 2176 akorotkov@postgresql      740                 :CBC     1195158 :             *penalty = hemdistsign(sign, orig, siglen);
                                741                 :                :     }
                                742                 :                :     else
 2176 akorotkov@postgresql      743                 :UBC           0 :         *penalty = hemdist(origval, newval, siglen);
 7958 teodor@sigaev.ru          744                 :CBC     1195158 :     PG_RETURN_POINTER(penalty);
                                745                 :                : }
                                746                 :                : 
                                747                 :                : typedef struct
                                748                 :                : {
                                749                 :                :     bool        allistrue;
                                750                 :                :     BITVECP     sign;
                                751                 :                : } CACHESIGN;
                                752                 :                : 
                                753                 :                : static void
 2176 akorotkov@postgresql      754                 :          44110 : fillcache(CACHESIGN *item, TRGM *key, BITVECP sign, int siglen)
                                755                 :                : {
 7958 teodor@sigaev.ru          756                 :          44110 :     item->allistrue = false;
 2176 akorotkov@postgresql      757                 :          44110 :     item->sign = sign;
 7958 teodor@sigaev.ru          758         [ +  + ]:          44110 :     if (ISARRKEY(key))
 2176 akorotkov@postgresql      759                 :          43890 :         makesign(item->sign, key, siglen);
 7958 teodor@sigaev.ru          760         [ -  + ]:            220 :     else if (ISALLTRUE(key))
 7958 teodor@sigaev.ru          761                 :UBC           0 :         item->allistrue = true;
                                762                 :                :     else
 1132 peter@eisentraut.org      763                 :CBC         220 :         memcpy(item->sign, GETSIGN(key), siglen);
 7958 teodor@sigaev.ru          764                 :          44110 : }
                                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                 :          49063 : comparecost(const void *a, const void *b)
                                775                 :                : {
 5299 peter_e@gmx.net           776         [ +  + ]:          49063 :     if (((const SPLITCOST *) a)->cost == ((const SPLITCOST *) b)->cost)
 7958 teodor@sigaev.ru          777                 :          44213 :         return 0;
                                778                 :                :     else
 5299 peter_e@gmx.net           779         [ +  + ]:           4850 :         return (((const SPLITCOST *) a)->cost > ((const SPLITCOST *) b)->cost) ? 1 : -1;
                                780                 :                : }
                                781                 :                : 
                                782                 :                : 
                                783                 :                : static int
 2176 akorotkov@postgresql      784                 :        3647240 : hemdistcache(CACHESIGN *a, CACHESIGN *b, int siglen)
                                785                 :                : {
 7868 bruce@momjian.us          786         [ -  + ]:        3647240 :     if (a->allistrue)
                                787                 :                :     {
 7958 teodor@sigaev.ru          788         [ #  # ]:UBC           0 :         if (b->allistrue)
                                789                 :              0 :             return 0;
                                790                 :                :         else
 2176 akorotkov@postgresql      791                 :              0 :             return SIGLENBIT(siglen) - sizebitvec(b->sign, siglen);
                                792                 :                :     }
 7868 bruce@momjian.us          793         [ -  + ]:CBC     3647240 :     else if (b->allistrue)
 2176 akorotkov@postgresql      794                 :UBC           0 :         return SIGLENBIT(siglen) - sizebitvec(a->sign, siglen);
                                795                 :                : 
 2176 akorotkov@postgresql      796                 :CBC     3647240 :     return hemdistsign(a->sign, b->sign, siglen);
                                797                 :                : }
                                798                 :                : 
                                799                 :                : Datum
 7958 teodor@sigaev.ru          800                 :            278 : gtrgm_picksplit(PG_FUNCTION_ARGS)
                                801                 :                : {
 7868 bruce@momjian.us          802                 :            278 :     GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
 1949 rhodiumtoad@postgres      803                 :            278 :     OffsetNumber maxoff = entryvec->n - 1;
 7958 teodor@sigaev.ru          804                 :            278 :     GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
 1949 akorotkov@postgresql      805         [ +  - ]:            278 :     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,
 7958 teodor@sigaev.ru          815                 :            278 :                 waste = -1;
                                816                 :                :     int32       nbytes;
                                817                 :            278 :     OffsetNumber seed_1 = 0,
                                818                 :            278 :                 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 */
  100 michael@paquier.xyz       828                 :GNC         278 :     cache = palloc_array(CACHESIGN, maxoff + 1);
 1949 rhodiumtoad@postgres      829                 :CBC         278 :     cache_sign = palloc(siglen * (maxoff + 1));
                                830                 :                : 
 5280 tgl@sss.pgh.pa.us         831         [ +  + ]:          44388 :     for (k = FirstOffsetNumber; k <= maxoff; k = OffsetNumberNext(k))
 2176 akorotkov@postgresql      832                 :          44110 :         fillcache(&cache[k], GETENTRY(entryvec, k), &cache_sign[siglen * k],
                                833                 :                :                   siglen);
                                834                 :                : 
                                835                 :                :     /* now find the two furthest-apart items */
 7868 bruce@momjian.us          836         [ +  + ]:          44110 :     for (k = FirstOffsetNumber; k < maxoff; k = OffsetNumberNext(k))
                                837                 :                :     {
                                838         [ +  + ]:        3602852 :         for (j = OffsetNumberNext(k); j <= maxoff; j = OffsetNumberNext(j))
                                839                 :                :         {
 2176 akorotkov@postgresql      840                 :        3559020 :             size_waste = hemdistcache(&(cache[j]), &(cache[k]), siglen);
 7868 bruce@momjian.us          841         [ +  + ]:        3559020 :             if (size_waste > waste)
                                842                 :                :             {
 7958 teodor@sigaev.ru          843                 :            466 :                 waste = size_waste;
                                844                 :            466 :                 seed_1 = k;
                                845                 :            466 :                 seed_2 = j;
                                846                 :                :             }
                                847                 :                :         }
                                848                 :                :     }
                                849                 :                : 
                                850                 :                :     /* just in case we didn't make a selection ... */
 7868 bruce@momjian.us          851   [ +  -  -  + ]:            278 :     if (seed_1 == 0 || seed_2 == 0)
                                852                 :                :     {
 7958 teodor@sigaev.ru          853                 :UBC           0 :         seed_1 = 1;
                                854                 :              0 :         seed_2 = 2;
                                855                 :                :     }
                                856                 :                : 
                                857                 :                :     /* initialize the result vectors */
 1949 rhodiumtoad@postgres      858                 :CBC         278 :     nbytes = maxoff * sizeof(OffsetNumber);
 5280 tgl@sss.pgh.pa.us         859                 :            278 :     v->spl_left = left = (OffsetNumber *) palloc(nbytes);
                                860                 :            278 :     v->spl_right = right = (OffsetNumber *) palloc(nbytes);
                                861                 :            278 :     v->spl_nleft = 0;
                                862                 :            278 :     v->spl_nright = 0;
                                863                 :                : 
                                864                 :                :     /* form initial .. */
 2176 akorotkov@postgresql      865                 :            278 :     datum_l = gtrgm_alloc(cache[seed_1].allistrue, siglen, cache[seed_1].sign);
                                866                 :            278 :     datum_r = gtrgm_alloc(cache[seed_2].allistrue, siglen, cache[seed_2].sign);
                                867                 :                : 
 7868 bruce@momjian.us          868                 :            278 :     union_l = GETSIGN(datum_l);
                                869                 :            278 :     union_r = GETSIGN(datum_r);
                                870                 :                : 
                                871                 :                :     /* sort before ... */
  100 michael@paquier.xyz       872                 :GNC         278 :     costvector = palloc_array(SPLITCOST, maxoff);
 7868 bruce@momjian.us          873         [ +  + ]:CBC       44388 :     for (j = FirstOffsetNumber; j <= maxoff; j = OffsetNumberNext(j))
                                874                 :                :     {
 7958 teodor@sigaev.ru          875                 :          44110 :         costvector[j - 1].pos = j;
 2176 akorotkov@postgresql      876                 :          44110 :         size_alpha = hemdistcache(&(cache[seed_1]), &(cache[j]), siglen);
                                877                 :          44110 :         size_beta = hemdistcache(&(cache[seed_2]), &(cache[j]), siglen);
 7958 teodor@sigaev.ru          878                 :          44110 :         costvector[j - 1].cost = abs(size_alpha - size_beta);
                                879                 :                :     }
 1132 peter@eisentraut.org      880                 :            278 :     qsort(costvector, maxoff, sizeof(SPLITCOST), comparecost);
                                881                 :                : 
 7868 bruce@momjian.us          882         [ +  + ]:          44388 :     for (k = 0; k < maxoff; k++)
                                883                 :                :     {
 7958 teodor@sigaev.ru          884                 :          44110 :         j = costvector[k].pos;
 7868 bruce@momjian.us          885         [ +  + ]:          44110 :         if (j == seed_1)
                                886                 :                :         {
 7958 teodor@sigaev.ru          887                 :            278 :             *left++ = j;
                                888                 :            278 :             v->spl_nleft++;
                                889                 :            278 :             continue;
                                890                 :                :         }
 7868 bruce@momjian.us          891         [ +  + ]:          43832 :         else if (j == seed_2)
                                892                 :                :         {
 7958 teodor@sigaev.ru          893                 :            278 :             *right++ = j;
                                894                 :            278 :             v->spl_nright++;
                                895                 :            278 :             continue;
                                896                 :                :         }
                                897                 :                : 
 7868 bruce@momjian.us          898   [ +  -  -  + ]:          43554 :         if (ISALLTRUE(datum_l) || cache[j].allistrue)
                                899                 :                :         {
 7868 bruce@momjian.us          900   [ #  #  #  # ]:UBC           0 :             if (ISALLTRUE(datum_l) && cache[j].allistrue)
                                901                 :              0 :                 size_alpha = 0;
                                902                 :                :             else
 2176 akorotkov@postgresql      903                 :              0 :                 size_alpha = SIGLENBIT(siglen) -
 2236 alvherre@alvh.no-ip.      904         [ #  # ]:              0 :                     sizebitvec((cache[j].allistrue) ? GETSIGN(datum_l) :
 2176 akorotkov@postgresql      905                 :              0 :                                GETSIGN(cache[j].sign),
                                906                 :                :                                siglen);
                                907                 :                :         }
                                908                 :                :         else
 2176 akorotkov@postgresql      909                 :CBC       43554 :             size_alpha = hemdistsign(cache[j].sign, GETSIGN(datum_l), siglen);
                                910                 :                : 
 7868 bruce@momjian.us          911   [ +  -  -  + ]:          43554 :         if (ISALLTRUE(datum_r) || cache[j].allistrue)
                                912                 :                :         {
 7868 bruce@momjian.us          913   [ #  #  #  # ]:UBC           0 :             if (ISALLTRUE(datum_r) && cache[j].allistrue)
                                914                 :              0 :                 size_beta = 0;
                                915                 :                :             else
 2176 akorotkov@postgresql      916                 :              0 :                 size_beta = SIGLENBIT(siglen) -
 2236 alvherre@alvh.no-ip.      917         [ #  # ]:              0 :                     sizebitvec((cache[j].allistrue) ? GETSIGN(datum_r) :
 2176 akorotkov@postgresql      918                 :              0 :                                GETSIGN(cache[j].sign),
                                919                 :                :                                siglen);
                                920                 :                :         }
                                921                 :                :         else
 2176 akorotkov@postgresql      922                 :CBC       43554 :             size_beta = hemdistsign(cache[j].sign, GETSIGN(datum_r), siglen);
                                923                 :                : 
 7868 bruce@momjian.us          924         [ +  + ]:          43554 :         if (size_alpha < size_beta + WISH_F(v->spl_nleft, v->spl_nright, 0.1))
                                925                 :                :         {
                                926   [ +  -  -  + ]:          21661 :             if (ISALLTRUE(datum_l) || cache[j].allistrue)
                                927                 :                :             {
 7868 bruce@momjian.us          928         [ #  # ]:UBC           0 :                 if (!ISALLTRUE(datum_l))
 1132 peter@eisentraut.org      929                 :              0 :                     memset(GETSIGN(datum_l), 0xff, siglen);
                                930                 :                :             }
                                931                 :                :             else
                                932                 :                :             {
 7868 bruce@momjian.us          933                 :CBC       21661 :                 ptr = cache[j].sign;
 2176 akorotkov@postgresql      934         [ +  + ]:        2237257 :                 LOOPBYTE(siglen)
 6694 bruce@momjian.us          935                 :        2215596 :                     union_l[i] |= ptr[i];
                                936                 :                :             }
 7958 teodor@sigaev.ru          937                 :          21661 :             *left++ = j;
                                938                 :          21661 :             v->spl_nleft++;
                                939                 :                :         }
                                940                 :                :         else
                                941                 :                :         {
 7868 bruce@momjian.us          942   [ +  -  -  + ]:          21893 :             if (ISALLTRUE(datum_r) || cache[j].allistrue)
                                943                 :                :             {
 7868 bruce@momjian.us          944         [ #  # ]:UBC           0 :                 if (!ISALLTRUE(datum_r))
 1132 peter@eisentraut.org      945                 :              0 :                     memset(GETSIGN(datum_r), 0xff, siglen);
                                946                 :                :             }
                                947                 :                :             else
                                948                 :                :             {
 7868 bruce@momjian.us          949                 :CBC       21893 :                 ptr = cache[j].sign;
 2176 akorotkov@postgresql      950         [ +  + ]:        2240273 :                 LOOPBYTE(siglen)
 6694 bruce@momjian.us          951                 :        2218380 :                     union_r[i] |= ptr[i];
                                952                 :                :             }
 7958 teodor@sigaev.ru          953                 :          21893 :             *right++ = j;
                                954                 :          21893 :             v->spl_nright++;
                                955                 :                :         }
                                956                 :                :     }
                                957                 :                : 
                                958                 :            278 :     v->spl_ldatum = PointerGetDatum(datum_l);
                                959                 :            278 :     v->spl_rdatum = PointerGetDatum(datum_r);
                                960                 :                : 
                                961                 :            278 :     PG_RETURN_POINTER(v);
                                962                 :                : }
                                963                 :                : 
                                964                 :                : Datum
 2176 akorotkov@postgresql      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.4-beta