LCOV - code coverage report
Current view: top level - contrib/pg_trgm - trgm_op.c (source / functions) Hit Total Coverage
Test: test.info Lines: 202 225 89.8 %
Date: 2013-01-22 Functions: 22 24 91.7 %
Branches: 143 200 71.5 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * contrib/pg_trgm/trgm_op.c
       3                 :            :  */
       4                 :            : #include "postgres.h"
       5                 :            : 
       6                 :            : #include <ctype.h>
       7                 :            : 
       8                 :            : #include "trgm.h"
       9                 :            : 
      10                 :            : #include "catalog/pg_type.h"
      11                 :            : #include "tsearch/ts_locale.h"
      12                 :            : 
      13                 :            : 
      14                 :          2 : PG_MODULE_MAGIC;
      15                 :            : 
      16                 :            : float4          trgm_limit = 0.3f;
      17                 :            : 
      18                 :          1 : PG_FUNCTION_INFO_V1(set_limit);
      19                 :            : Datum           set_limit(PG_FUNCTION_ARGS);
      20                 :            : 
      21                 :          1 : PG_FUNCTION_INFO_V1(show_limit);
      22                 :            : Datum           show_limit(PG_FUNCTION_ARGS);
      23                 :            : 
      24                 :          2 : PG_FUNCTION_INFO_V1(show_trgm);
      25                 :            : Datum           show_trgm(PG_FUNCTION_ARGS);
      26                 :            : 
      27                 :          2 : PG_FUNCTION_INFO_V1(similarity);
      28                 :            : Datum           similarity(PG_FUNCTION_ARGS);
      29                 :            : 
      30                 :          2 : PG_FUNCTION_INFO_V1(similarity_dist);
      31                 :            : Datum           similarity_dist(PG_FUNCTION_ARGS);
      32                 :            : 
      33                 :          2 : PG_FUNCTION_INFO_V1(similarity_op);
      34                 :            : Datum           similarity_op(PG_FUNCTION_ARGS);
      35                 :            : 
      36                 :            : 
      37                 :            : Datum
      38                 :          0 : set_limit(PG_FUNCTION_ARGS)
      39                 :            : {
      40                 :          0 :         float4          nlimit = PG_GETARG_FLOAT4(0);
      41                 :            : 
      42 [ #  # ][ #  # ]:          0 :         if (nlimit < 0 || nlimit > 1.0)
      43                 :          0 :                 elog(ERROR, "wrong limit, should be between 0 and 1");
      44                 :          0 :         trgm_limit = nlimit;
      45                 :          0 :         PG_RETURN_FLOAT4(trgm_limit);
      46                 :            : }
      47                 :            : 
      48                 :            : Datum
      49                 :          0 : show_limit(PG_FUNCTION_ARGS)
      50                 :            : {
      51                 :          0 :         PG_RETURN_FLOAT4(trgm_limit);
      52                 :            : }
      53                 :            : 
      54                 :            : static int
      55                 :    1046792 : comp_trgm(const void *a, const void *b)
      56                 :            : {
      57 [ +  + ][ +  - ]:    1046792 :         return CMPTRGM(a, b);
         [ +  + ][ +  + ]
         [ +  - ][ +  + ]
         [ +  + ][ +  + ]
      58                 :            : }
      59                 :            : 
      60                 :            : static int
      61                 :      22710 : unique_array(trgm *a, int len)
      62                 :            : {
      63                 :            :         trgm       *curend,
      64                 :            :                            *tmp;
      65                 :            : 
      66                 :      22710 :         curend = tmp = a;
      67         [ +  + ]:     298985 :         while (tmp - a < len)
      68 [ +  + ][ +  + ]:     276275 :                 if (CMPTRGM(tmp, curend))
                 [ +  + ]
      69                 :            :                 {
      70                 :     252562 :                         curend++;
      71                 :     252562 :                         CPTRGM(curend, tmp);
      72                 :     252562 :                         tmp++;
      73                 :            :                 }
      74                 :            :                 else
      75                 :     276275 :                         tmp++;
      76                 :            : 
      77                 :      22710 :         return curend + 1 - a;
      78                 :            : }
      79                 :            : 
      80                 :            : /*
      81                 :            :  * Finds first word in string, returns pointer to the word,
      82                 :            :  * endword points to the character after word
      83                 :            :  */
      84                 :            : static char *
      85                 :      45397 : find_word(char *str, int lenstr, char **endword, int *charlen)
      86                 :            : {
      87                 :      45397 :         char       *beginword = str;
      88                 :            : 
      89 [ +  + ][ +  + ]:      45425 :         while (beginword - str < lenstr && !ISWORDCHR(beginword))
                 [ +  - ]
      90                 :         28 :                 beginword += pg_mblen(beginword);
      91                 :            : 
      92         [ +  + ]:      45397 :         if (beginword - str >= lenstr)
      93                 :            :                 return NULL;
      94                 :            : 
      95                 :      22703 :         *endword = beginword;
      96                 :      22703 :         *charlen = 0;
      97 [ +  + ][ +  + ]:     276252 :         while (*endword - str < lenstr && ISWORDCHR(*endword))
                 [ +  + ]
      98                 :            :         {
      99                 :     253549 :                 *endword += pg_mblen(*endword);
     100                 :     253549 :                 (*charlen)++;
     101                 :            :         }
     102                 :            : 
     103                 :      45397 :         return beginword;
     104                 :            : }
     105                 :            : 
     106                 :            : void
     107                 :     276589 : cnt_trigram(trgm *tptr, char *str, int bytelen)
     108                 :            : {
     109         [ +  - ]:     276589 :         if (bytelen == 3)
     110                 :            :         {
     111                 :     276589 :                 CPTRGM(tptr, str);
     112                 :            :         }
     113                 :            :         else
     114                 :            :         {
     115                 :            :                 pg_crc32        crc;
     116                 :            : 
     117                 :          0 :                 INIT_CRC32(crc);
     118         [ #  # ]:          0 :                 COMP_CRC32(crc, str, bytelen);
     119                 :          0 :                 FIN_CRC32(crc);
     120                 :            : 
     121                 :            :                 /*
     122                 :            :                  * use only 3 upper bytes from crc, hope, it's good enough hashing
     123                 :            :                  */
     124                 :          0 :                 CPTRGM(tptr, &crc);
     125                 :            :         }
     126                 :     276589 : }
     127                 :            : 
     128                 :            : /*
     129                 :            :  * Adds trigrams from words (already padded).
     130                 :            :  */
     131                 :            : static trgm *
     132                 :      22720 : make_trigrams(trgm *tptr, char *str, int bytelen, int charlen)
     133                 :            : {
     134                 :      22720 :         char       *ptr = str;
     135                 :            : 
     136         [ +  - ]:      22720 :         if (charlen < 3)
     137                 :            :                 return tptr;
     138                 :            : 
     139                 :            : #ifdef USE_WIDE_UPPER_LOWER
     140         [ +  - ]:      22720 :         if (pg_database_encoding_max_length() > 1)
     141                 :            :         {
     142                 :      22720 :                 int                     lenfirst = pg_mblen(str),
     143                 :      22720 :                                         lenmiddle = pg_mblen(str + lenfirst),
     144                 :      22720 :                                         lenlast = pg_mblen(str + lenfirst + lenmiddle);
     145                 :            : 
     146         [ +  + ]:     298995 :                 while ((ptr - str) + lenfirst + lenmiddle + lenlast <= bytelen)
     147                 :            :                 {
     148                 :     276275 :                         cnt_trigram(tptr, ptr, lenfirst + lenmiddle + lenlast);
     149                 :            : 
     150                 :     276275 :                         ptr += lenfirst;
     151                 :     276275 :                         tptr++;
     152                 :            : 
     153                 :     276275 :                         lenfirst = lenmiddle;
     154                 :     276275 :                         lenmiddle = lenlast;
     155                 :     276275 :                         lenlast = pg_mblen(ptr + lenfirst + lenmiddle);
     156                 :            :                 }
     157                 :            :         }
     158                 :            :         else
     159                 :            : #endif
     160                 :            :         {
     161 [ #  # ][ #  # ]:          0 :                 Assert(bytelen == charlen);
     162                 :            : 
     163         [ #  # ]:          0 :                 while (ptr - str < bytelen - 2 /* number of trigrams = strlen - 2 */ )
     164                 :            :                 {
     165                 :          0 :                         CPTRGM(tptr, ptr);
     166                 :          0 :                         ptr++;
     167                 :          0 :                         tptr++;
     168                 :            :                 }
     169                 :            :         }
     170                 :            : 
     171                 :      22720 :         return tptr;
     172                 :            : }
     173                 :            : 
     174                 :            : TRGM *
     175                 :      22695 : generate_trgm(char *str, int slen)
     176                 :            : {
     177                 :            :         TRGM       *trg;
     178                 :            :         char       *buf;
     179                 :            :         trgm       *tptr;
     180                 :            :         int                     len,
     181                 :            :                                 charlen,
     182                 :            :                                 bytelen;
     183                 :            :         char       *bword,
     184                 :            :                            *eword;
     185                 :            : 
     186                 :      22695 :         trg = (TRGM *) palloc(TRGMHDRSIZE + sizeof(trgm) * (slen / 2 + 1) *3);
     187                 :      22695 :         trg->flag = ARRKEY;
     188                 :      22695 :         SET_VARSIZE(trg, TRGMHDRSIZE);
     189                 :            : 
     190 [ +  - ][ +  + ]:      22695 :         if (slen + LPADDING + RPADDING < 3 || slen == 0)
     191                 :            :                 return trg;
     192                 :            : 
     193                 :      22694 :         tptr = GETARR(trg);
     194                 :            : 
     195                 :      22694 :         buf = palloc(sizeof(char) * (slen + 4));
     196                 :            : 
     197                 :            :         if (LPADDING > 0)
     198                 :            :         {
     199                 :      22694 :                 *buf = ' ';
     200                 :            :                 if (LPADDING > 1)
     201                 :      22694 :                         *(buf + 1) = ' ';
     202                 :            :         }
     203                 :            : 
     204                 :      22694 :         eword = str;
     205         [ +  + ]:      45397 :         while ((bword = find_word(eword, slen - (eword - str), &eword, &charlen)) != NULL)
     206                 :            :         {
     207                 :            : #ifdef IGNORECASE
     208                 :      22703 :                 bword = lowerstr_with_len(bword, eword - bword);
     209                 :      22703 :                 bytelen = strlen(bword);
     210                 :            : #else
     211                 :            :                 bytelen = eword - bword;
     212                 :            : #endif
     213                 :            : 
     214                 :      22703 :                 memcpy(buf + LPADDING, bword, bytelen);
     215                 :            : 
     216                 :            : #ifdef IGNORECASE
     217                 :      22703 :                 pfree(bword);
     218                 :            : #endif
     219                 :      22703 :                 buf[LPADDING + bytelen] = ' ';
     220                 :      22703 :                 buf[LPADDING + bytelen + 1] = ' ';
     221                 :            : 
     222                 :            :                 /*
     223                 :            :                  * count trigrams
     224                 :            :                  */
     225                 :      22703 :                 tptr = make_trigrams(tptr, buf, bytelen + LPADDING + RPADDING,
     226                 :            :                                                          charlen + LPADDING + RPADDING);
     227                 :            :         }
     228                 :            : 
     229                 :      22694 :         pfree(buf);
     230                 :            : 
     231         [ +  + ]:      22694 :         if ((len = tptr - GETARR(trg)) == 0)
     232                 :            :                 return trg;
     233                 :            : 
     234         [ +  - ]:      22693 :         if (len > 0)
     235                 :            :         {
     236                 :      22693 :                 qsort((void *) GETARR(trg), len, sizeof(trgm), comp_trgm);
     237                 :      22693 :                 len = unique_array(GETARR(trg), len);
     238                 :            :         }
     239                 :            : 
     240                 :      22695 :         SET_VARSIZE(trg, CALCGTSIZE(ARRKEY, len));
     241                 :            : 
     242                 :            :         return trg;
     243                 :            : }
     244                 :            : 
     245                 :            : /*
     246                 :            :  * Extract the next non-wildcard part of a search string, ie, a word bounded
     247                 :            :  * by '_' or '%' meta-characters, non-word characters or string end.
     248                 :            :  *
     249                 :            :  * str: source string, of length lenstr bytes (need not be null-terminated)
     250                 :            :  * buf: where to return the substring (must be long enough)
     251                 :            :  * *bytelen: receives byte length of the found substring
     252                 :            :  * *charlen: receives character length of the found substring
     253                 :            :  *
     254                 :            :  * Returns pointer to end+1 of the found substring in the source string.
     255                 :            :  * Returns NULL if no word found (in which case buf, bytelen, charlen not set)
     256                 :            :  *
     257                 :            :  * If the found word is bounded by non-word characters or string boundaries
     258                 :            :  * then this function will include corresponding padding spaces into buf.
     259                 :            :  */
     260                 :            : static const char *
     261                 :         34 : get_wildcard_part(const char *str, int lenstr,
     262                 :            :                                   char *buf, int *bytelen, int *charlen)
     263                 :            : {
     264                 :         34 :         const char *beginword = str;
     265                 :            :         const char *endword;
     266                 :         34 :         char       *s = buf;
     267                 :         34 :         bool            in_leading_wildcard_meta = false;
     268                 :         34 :         bool            in_trailing_wildcard_meta = false;
     269                 :         34 :         bool            in_escape = false;
     270                 :            :         int                     clen;
     271                 :            : 
     272                 :            :         /*
     273                 :            :          * Find the first word character, remembering whether preceding character
     274                 :            :          * was wildcard meta-character.  Note that the in_escape state persists
     275                 :            :          * from this loop to the next one, since we may exit at a word character
     276                 :            :          * that is in_escape.
     277                 :            :          */
     278         [ +  + ]:         68 :         while (beginword - str < lenstr)
     279                 :            :         {
     280         [ +  + ]:         51 :                 if (in_escape)
     281                 :            :                 {
     282 [ -  + ][ #  # ]:          3 :                         if (ISWORDCHR(beginword))
     283                 :            :                                 break;
     284                 :            :                         in_escape = false;
     285                 :            :                         in_leading_wildcard_meta = false;
     286                 :            :                 }
     287                 :            :                 else
     288                 :            :                 {
     289         [ +  + ]:         48 :                         if (ISESCAPECHAR(beginword))
     290                 :            :                                 in_escape = true;
     291         [ +  + ]:         45 :                         else if (ISWILDCARDCHAR(beginword))
     292                 :            :                                 in_leading_wildcard_meta = true;
     293 [ -  + ][ #  # ]:         14 :                         else if (ISWORDCHR(beginword))
     294                 :            :                                 break;
     295                 :            :                         else
     296                 :            :                                 in_leading_wildcard_meta = false;
     297                 :            :                 }
     298                 :         34 :                 beginword += pg_mblen(beginword);
     299                 :            :         }
     300                 :            : 
     301                 :            :         /*
     302                 :            :          * Handle string end.
     303                 :            :          */
     304         [ +  + ]:         34 :         if (beginword - str >= lenstr)
     305                 :            :                 return NULL;
     306                 :            : 
     307                 :            :         /*
     308                 :            :          * Add left padding spaces if preceding character wasn't wildcard
     309                 :            :          * meta-character.
     310                 :            :          */
     311                 :         17 :         *charlen = 0;
     312         [ +  + ]:         17 :         if (!in_leading_wildcard_meta)
     313                 :            :         {
     314                 :            :                 if (LPADDING > 0)
     315                 :            :                 {
     316                 :          3 :                         *s++ = ' ';
     317                 :          3 :                         (*charlen)++;
     318                 :            :                         if (LPADDING > 1)
     319                 :            :                         {
     320                 :          3 :                                 *s++ = ' ';
     321                 :          3 :                                 (*charlen)++;
     322                 :            :                         }
     323                 :            :                 }
     324                 :            :         }
     325                 :            : 
     326                 :            :         /*
     327                 :            :          * Copy data into buf until wildcard meta-character, non-word character or
     328                 :            :          * string boundary.  Strip escapes during copy.
     329                 :            :          */
     330                 :         17 :         endword = beginword;
     331         [ +  - ]:         68 :         while (endword - str < lenstr)
     332                 :            :         {
     333                 :         68 :                 clen = pg_mblen(endword);
     334         [ +  + ]:         68 :                 if (in_escape)
     335                 :            :                 {
     336 [ -  + ][ #  # ]:          3 :                         if (ISWORDCHR(endword))
     337                 :            :                         {
     338                 :          3 :                                 memcpy(s, endword, clen);
     339                 :          3 :                                 (*charlen)++;
     340                 :          3 :                                 s += clen;
     341                 :            :                         }
     342                 :            :                         else
     343                 :            :                         {
     344                 :            :                                 /*
     345                 :            :                                  * Back up endword to the escape character when stopping at
     346                 :            :                                  * an escaped char, so that subsequent get_wildcard_part will
     347                 :            :                                  * restart from the escape character.  We assume here that
     348                 :            :                                  * escape chars are single-byte.
     349                 :            :                                  */
     350                 :          0 :                                 endword--;
     351                 :          0 :                                 break;
     352                 :            :                         }
     353                 :          3 :                         in_escape = false;
     354                 :            :                 }
     355                 :            :                 else
     356                 :            :                 {
     357         [ +  - ]:         65 :                         if (ISESCAPECHAR(endword))
     358                 :            :                                 in_escape = true;
     359         [ +  + ]:         65 :                         else if (ISWILDCARDCHAR(endword))
     360                 :            :                         {
     361                 :            :                                 in_trailing_wildcard_meta = true;
     362                 :            :                                 break;
     363                 :            :                         }
     364 [ -  + ][ #  # ]:         48 :                         else if (ISWORDCHR(endword))
     365                 :            :                         {
     366                 :         48 :                                 memcpy(s, endword, clen);
     367                 :         48 :                                 (*charlen)++;
     368                 :         48 :                                 s += clen;
     369                 :            :                         }
     370                 :            :                         else
     371                 :            :                                 break;
     372                 :            :                 }
     373                 :         51 :                 endword += clen;
     374                 :            :         }
     375                 :            : 
     376                 :            :         /*
     377                 :            :          * Add right padding spaces if next character isn't wildcard
     378                 :            :          * meta-character.
     379                 :            :          */
     380         [ -  + ]:         17 :         if (!in_trailing_wildcard_meta)
     381                 :            :         {
     382                 :            :                 if (RPADDING > 0)
     383                 :            :                 {
     384                 :          0 :                         *s++ = ' ';
     385                 :          0 :                         (*charlen)++;
     386                 :            :                         if (RPADDING > 1)
     387                 :            :                         {
     388                 :            :                                 *s++ = ' ';
     389                 :            :                                 (*charlen)++;
     390                 :            :                         }
     391                 :            :                 }
     392                 :            :         }
     393                 :            : 
     394                 :         17 :         *bytelen = s - buf;
     395                 :         34 :         return endword;
     396                 :            : }
     397                 :            : 
     398                 :            : /*
     399                 :            :  * Generates trigrams for wildcard search string.
     400                 :            :  *
     401                 :            :  * Returns array of trigrams that must occur in any string that matches the
     402                 :            :  * wildcard string.  For example, given pattern "a%bcd%" the trigrams
     403                 :            :  * " a", "bcd" would be extracted.
     404                 :            :  */
     405                 :            : TRGM *
     406                 :         17 : generate_wildcard_trgm(const char *str, int slen)
     407                 :            : {
     408                 :            :         TRGM       *trg;
     409                 :            :         char       *buf,
     410                 :            :                            *buf2;
     411                 :            :         trgm       *tptr;
     412                 :            :         int                     len,
     413                 :            :                                 charlen,
     414                 :            :                                 bytelen;
     415                 :            :         const char *eword;
     416                 :            : 
     417                 :         17 :         trg = (TRGM *) palloc(TRGMHDRSIZE + sizeof(trgm) * (slen / 2 + 1) *3);
     418                 :         17 :         trg->flag = ARRKEY;
     419                 :         17 :         SET_VARSIZE(trg, TRGMHDRSIZE);
     420                 :            : 
     421 [ +  - ][ +  - ]:         17 :         if (slen + LPADDING + RPADDING < 3 || slen == 0)
     422                 :            :                 return trg;
     423                 :            : 
     424                 :         17 :         tptr = GETARR(trg);
     425                 :            : 
     426                 :         17 :         buf = palloc(sizeof(char) * (slen + 4));
     427                 :            : 
     428                 :            :         /*
     429                 :            :          * Extract trigrams from each substring extracted by get_wildcard_part.
     430                 :            :          */
     431                 :         17 :         eword = str;
     432         [ +  + ]:         34 :         while ((eword = get_wildcard_part(eword, slen - (eword - str),
     433                 :            :                                                                           buf, &bytelen, &charlen)) != NULL)
     434                 :            :         {
     435                 :            : #ifdef IGNORECASE
     436                 :         17 :                 buf2 = lowerstr_with_len(buf, bytelen);
     437                 :         17 :                 bytelen = strlen(buf2);
     438                 :            : #else
     439                 :            :                 buf2 = buf;
     440                 :            : #endif
     441                 :            : 
     442                 :            :                 /*
     443                 :            :                  * count trigrams
     444                 :            :                  */
     445                 :         17 :                 tptr = make_trigrams(tptr, buf2, bytelen, charlen);
     446                 :            : #ifdef IGNORECASE
     447                 :         17 :                 pfree(buf2);
     448                 :            : #endif
     449                 :            :         }
     450                 :            : 
     451                 :         17 :         pfree(buf);
     452                 :            : 
     453         [ +  - ]:         17 :         if ((len = tptr - GETARR(trg)) == 0)
     454                 :            :                 return trg;
     455                 :            : 
     456                 :            :         /*
     457                 :            :          * Make trigrams unique.
     458                 :            :          */
     459         [ +  - ]:         17 :         if (len > 0)
     460                 :            :         {
     461                 :         17 :                 qsort((void *) GETARR(trg), len, sizeof(trgm), comp_trgm);
     462                 :         17 :                 len = unique_array(GETARR(trg), len);
     463                 :            :         }
     464                 :            : 
     465                 :         17 :         SET_VARSIZE(trg, CALCGTSIZE(ARRKEY, len));
     466                 :            : 
     467                 :            :         return trg;
     468                 :            : }
     469                 :            : 
     470                 :            : uint32
     471                 :      12415 : trgm2int(trgm *ptr)
     472                 :            : {
     473                 :      12415 :         uint32          val = 0;
     474                 :            : 
     475                 :      12415 :         val |= *(((unsigned char *) ptr));
     476                 :      12415 :         val <<= 8;
     477                 :      12415 :         val |= *(((unsigned char *) ptr) + 1);
     478                 :      12415 :         val <<= 8;
     479                 :      12415 :         val |= *(((unsigned char *) ptr) + 2);
     480                 :            : 
     481                 :      12415 :         return val;
     482                 :            : }
     483                 :            : 
     484                 :            : Datum
     485                 :          7 : show_trgm(PG_FUNCTION_ARGS)
     486                 :            : {
     487                 :          7 :         text       *in = PG_GETARG_TEXT_P(0);
     488                 :            :         TRGM       *trg;
     489                 :            :         Datum      *d;
     490                 :            :         ArrayType  *a;
     491                 :            :         trgm       *ptr;
     492                 :            :         int                     i;
     493                 :            : 
     494                 :          7 :         trg = generate_trgm(VARDATA(in), VARSIZE(in) - VARHDRSZ);
     495                 :          7 :         d = (Datum *) palloc(sizeof(Datum) * (1 + ARRNELEM(trg)));
     496                 :            : 
     497         [ +  + ]:         44 :         for (i = 0, ptr = GETARR(trg); i < ARRNELEM(trg); i++, ptr++)
     498                 :            :         {
     499         [ +  - ]:         37 :                 text       *item = (text *) palloc(VARHDRSZ + Max(12, pg_database_encoding_max_length() * 3));
     500                 :            : 
     501 [ +  - ][ +  - ]:         37 :                 if (pg_database_encoding_max_length() > 1 && !ISPRINTABLETRGM(ptr))
         [ +  + ][ +  - ]
         [ +  - ][ +  + ]
         [ +  - ][ +  - ]
         [ +  + ][ -  + ]
     502                 :            :                 {
     503                 :          0 :                         snprintf(VARDATA(item), 12, "0x%06x", trgm2int(ptr));
     504                 :          0 :                         SET_VARSIZE(item, VARHDRSZ + strlen(VARDATA(item)));
     505                 :            :                 }
     506                 :            :                 else
     507                 :            :                 {
     508                 :         37 :                         SET_VARSIZE(item, VARHDRSZ + 3);
     509                 :         37 :                         CPTRGM(VARDATA(item), ptr);
     510                 :            :                 }
     511                 :         37 :                 d[i] = PointerGetDatum(item);
     512                 :            :         }
     513                 :            : 
     514                 :          7 :         a = construct_array(
     515                 :            :                                                 d,
     516                 :            :                                                 ARRNELEM(trg),
     517                 :            :                                                 TEXTOID,
     518                 :            :                                                 -1,
     519                 :            :                                                 false,
     520                 :            :                                                 'i'
     521                 :            :                 );
     522                 :            : 
     523         [ +  + ]:         44 :         for (i = 0; i < ARRNELEM(trg); i++)
     524                 :         37 :                 pfree(DatumGetPointer(d[i]));
     525                 :            : 
     526                 :          7 :         pfree(d);
     527                 :          7 :         pfree(trg);
     528         [ -  + ]:          7 :         PG_FREE_IF_COPY(in, 0);
     529                 :            : 
     530                 :          7 :         PG_RETURN_POINTER(a);
     531                 :            : }
     532                 :            : 
     533                 :            : float4
     534                 :      14337 : cnt_sml(TRGM *trg1, TRGM *trg2)
     535                 :            : {
     536                 :            :         trgm       *ptr1,
     537                 :            :                            *ptr2;
     538                 :      14337 :         int                     count = 0;
     539                 :            :         int                     len1,
     540                 :            :                                 len2;
     541                 :            : 
     542                 :      14337 :         ptr1 = GETARR(trg1);
     543                 :      14337 :         ptr2 = GETARR(trg2);
     544                 :            : 
     545                 :      14337 :         len1 = ARRNELEM(trg1);
     546                 :      14337 :         len2 = ARRNELEM(trg2);
     547                 :            : 
     548 [ +  + ][ +  + ]:     270957 :         while (ptr1 - GETARR(trg1) < len1 && ptr2 - GETARR(trg2) < len2)
     549                 :            :         {
     550 [ +  + ][ +  - ]:     256620 :                 int                     res = CMPTRGM(ptr1, ptr2);
         [ +  + ][ +  + ]
         [ +  - ][ +  + ]
         [ +  + ][ +  + ]
     551                 :            : 
     552         [ +  + ]:     256620 :                 if (res < 0)
     553                 :      81585 :                         ptr1++;
     554         [ +  + ]:     175035 :                 else if (res > 0)
     555                 :      84603 :                         ptr2++;
     556                 :            :                 else
     557                 :            :                 {
     558                 :      90432 :                         ptr1++;
     559                 :      90432 :                         ptr2++;
     560                 :     256620 :                         count++;
     561                 :            :                 }
     562                 :            :         }
     563                 :            : 
     564                 :            : #ifdef DIVUNION
     565                 :      14337 :         return ((((float4) count) / ((float4) (len1 + len2 - count))));
     566                 :            : #else
     567                 :            :         return (((float) count) / ((float) ((len1 > len2) ? len1 : len2)));
     568                 :            : #endif
     569                 :            : 
     570                 :            : }
     571                 :            : 
     572                 :            : /*
     573                 :            :  * Returns whether trg2 contains all trigrams in trg1.
     574                 :            :  * This relies on the trigram arrays being sorted.
     575                 :            :  */
     576                 :            : bool
     577                 :         10 : trgm_contained_by(TRGM *trg1, TRGM *trg2)
     578                 :            : {
     579                 :            :         trgm       *ptr1,
     580                 :            :                            *ptr2;
     581                 :            :         int                     len1,
     582                 :            :                                 len2;
     583                 :            : 
     584                 :         10 :         ptr1 = GETARR(trg1);
     585                 :         10 :         ptr2 = GETARR(trg2);
     586                 :            : 
     587                 :         10 :         len1 = ARRNELEM(trg1);
     588                 :         10 :         len2 = ARRNELEM(trg2);
     589                 :            : 
     590 [ +  + ][ +  - ]:         43 :         while (ptr1 - GETARR(trg1) < len1 && ptr2 - GETARR(trg2) < len2)
     591                 :            :         {
     592 [ +  + ][ +  - ]:         38 :                 int                     res = CMPTRGM(ptr1, ptr2);
         [ +  + ][ +  + ]
         [ +  - ][ -  + ]
         [ +  + ][ +  - ]
     593                 :            : 
     594         [ +  + ]:         38 :                 if (res < 0)
     595                 :            :                         return false;
     596         [ +  + ]:         33 :                 else if (res > 0)
     597                 :         26 :                         ptr2++;
     598                 :            :                 else
     599                 :            :                 {
     600                 :          7 :                         ptr1++;
     601                 :         33 :                         ptr2++;
     602                 :            :                 }
     603                 :            :         }
     604         [ +  - ]:          5 :         if (ptr1 - GETARR(trg1) < len1)
     605                 :            :                 return false;
     606                 :            :         else
     607                 :         10 :                 return true;
     608                 :            : }
     609                 :            : 
     610                 :            : Datum
     611                 :      10337 : similarity(PG_FUNCTION_ARGS)
     612                 :            : {
     613                 :      10337 :         text       *in1 = PG_GETARG_TEXT_P(0);
     614                 :      10337 :         text       *in2 = PG_GETARG_TEXT_P(1);
     615                 :            :         TRGM       *trg1,
     616                 :            :                            *trg2;
     617                 :            :         float4          res;
     618                 :            : 
     619                 :      10337 :         trg1 = generate_trgm(VARDATA(in1), VARSIZE(in1) - VARHDRSZ);
     620                 :      10337 :         trg2 = generate_trgm(VARDATA(in2), VARSIZE(in2) - VARHDRSZ);
     621                 :            : 
     622                 :      10337 :         res = cnt_sml(trg1, trg2);
     623                 :            : 
     624                 :      10337 :         pfree(trg1);
     625                 :      10337 :         pfree(trg2);
     626         [ +  + ]:      10337 :         PG_FREE_IF_COPY(in1, 0);
     627         [ -  + ]:      10337 :         PG_FREE_IF_COPY(in2, 1);
     628                 :            : 
     629                 :      10337 :         PG_RETURN_FLOAT4(res);
     630                 :            : }
     631                 :            : 
     632                 :            : Datum
     633                 :       1002 : similarity_dist(PG_FUNCTION_ARGS)
     634                 :            : {
     635                 :       1002 :         float4          res = DatumGetFloat4(DirectFunctionCall2(similarity,
     636                 :            :                                                                                                                  PG_GETARG_DATUM(0),
     637                 :            :                                                                                                                  PG_GETARG_DATUM(1)));
     638                 :            : 
     639                 :       1002 :         PG_RETURN_FLOAT4(1.0 - res);
     640                 :            : }
     641                 :            : 
     642                 :            : Datum
     643                 :       6000 : similarity_op(PG_FUNCTION_ARGS)
     644                 :            : {
     645                 :       6000 :         float4          res = DatumGetFloat4(DirectFunctionCall2(similarity,
     646                 :            :                                                                                                                  PG_GETARG_DATUM(0),
     647                 :            :                                                                                                                  PG_GETARG_DATUM(1)));
     648                 :            : 
     649         [ +  + ]:       6000 :         PG_RETURN_BOOL(res >= trgm_limit);
     650                 :            : }

Generated by: LCOV version 1.9