LCOV - code coverage report
Current view: top level - src/backend/utils/adt - tsrank.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 73.4 % 537 394
Test Date: 2026-01-26 10:56:24 Functions: 66.7 % 24 16
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 50.3 % 314 158

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * tsrank.c
       4                 :             :  *              rank tsvector by tsquery
       5                 :             :  *
       6                 :             :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       7                 :             :  *
       8                 :             :  *
       9                 :             :  * IDENTIFICATION
      10                 :             :  *        src/backend/utils/adt/tsrank.c
      11                 :             :  *
      12                 :             :  *-------------------------------------------------------------------------
      13                 :             :  */
      14                 :             : #include "postgres.h"
      15                 :             : 
      16                 :             : #include <limits.h>
      17                 :             : #include <math.h>
      18                 :             : 
      19                 :             : #include "miscadmin.h"
      20                 :             : #include "tsearch/ts_utils.h"
      21                 :             : #include "utils/array.h"
      22                 :             : #include "utils/fmgrprotos.h"
      23                 :             : 
      24                 :             : #define NUM_WEIGHTS 4
      25                 :             : static const float default_weights[NUM_WEIGHTS] = {0.1f, 0.2f, 0.4f, 1.0f};
      26                 :             : 
      27                 :             : #define wpos(wep)       ( w[ WEP_GETWEIGHT(wep) ] )
      28                 :             : 
      29                 :             : #define RANK_NO_NORM                    0x00
      30                 :             : #define RANK_NORM_LOGLENGTH             0x01
      31                 :             : #define RANK_NORM_LENGTH                0x02
      32                 :             : #define RANK_NORM_EXTDIST               0x04
      33                 :             : #define RANK_NORM_UNIQ                  0x08
      34                 :             : #define RANK_NORM_LOGUNIQ               0x10
      35                 :             : #define RANK_NORM_RDIVRPLUS1    0x20
      36                 :             : #define DEF_NORM_METHOD                 RANK_NO_NORM
      37                 :             : 
      38                 :             : static float calc_rank_or(const float *w, TSVector t, TSQuery q);
      39                 :             : static float calc_rank_and(const float *w, TSVector t, TSQuery q);
      40                 :             : 
      41                 :             : /*
      42                 :             :  * Returns a weight of a word collocation
      43                 :             :  */
      44                 :             : static float4
      45                 :           3 : word_distance(int32 w)
      46                 :             : {
      47         [ -  + ]:           3 :         if (w > 100)
      48                 :           0 :                 return 1e-30f;
      49                 :             : 
      50                 :           3 :         return 1.0 / (1.005 + 0.05 * exp(((float4) w) / 1.5 - 2));
      51                 :           3 : }
      52                 :             : 
      53                 :             : static int
      54                 :           0 : cnt_length(TSVector t)
      55                 :             : {
      56                 :           0 :         WordEntry  *ptr = ARRPTR(t),
      57                 :           0 :                            *end = (WordEntry *) STRPTR(t);
      58                 :           0 :         int                     len = 0;
      59                 :             : 
      60         [ #  # ]:           0 :         while (ptr < end)
      61                 :             :         {
      62         [ #  # ]:           0 :                 int                     clen = POSDATALEN(t, ptr);
      63                 :             : 
      64         [ #  # ]:           0 :                 if (clen == 0)
      65                 :           0 :                         len += 1;
      66                 :             :                 else
      67                 :           0 :                         len += clen;
      68                 :             : 
      69                 :           0 :                 ptr++;
      70                 :           0 :         }
      71                 :             : 
      72                 :           0 :         return len;
      73                 :           0 : }
      74                 :             : 
      75                 :             : 
      76                 :             : #define WordECompareQueryItem(e,q,p,i,m) \
      77                 :             :         tsCompareString((q) + (i)->distance, (i)->length, \
      78                 :             :                                         (e) + (p)->pos, (p)->len, (m))
      79                 :             : 
      80                 :             : 
      81                 :             : /*
      82                 :             :  * Returns a pointer to a WordEntry's array corresponding to 'item' from
      83                 :             :  * tsvector 't'. 'q' is the TSQuery containing 'item'.
      84                 :             :  * Returns NULL if not found.
      85                 :             :  */
      86                 :             : static WordEntry *
      87                 :          71 : find_wordentry(TSVector t, TSQuery q, QueryOperand *item, int32 *nitem)
      88                 :             : {
      89                 :          71 :         WordEntry  *StopLow = ARRPTR(t);
      90                 :          71 :         WordEntry  *StopHigh = (WordEntry *) STRPTR(t);
      91                 :          71 :         WordEntry  *StopMiddle = StopHigh;
      92                 :          71 :         int                     difference;
      93                 :             : 
      94                 :          71 :         *nitem = 0;
      95                 :             : 
      96                 :             :         /* Loop invariant: StopLow <= item < StopHigh */
      97         [ +  + ]:         191 :         while (StopLow < StopHigh)
      98                 :             :         {
      99                 :         183 :                 StopMiddle = StopLow + (StopHigh - StopLow) / 2;
     100                 :         183 :                 difference = WordECompareQueryItem(STRPTR(t), GETOPERAND(q), StopMiddle, item, false);
     101         [ +  + ]:         183 :                 if (difference == 0)
     102                 :             :                 {
     103                 :          63 :                         StopHigh = StopMiddle;
     104                 :          63 :                         *nitem = 1;
     105                 :          63 :                         break;
     106                 :             :                 }
     107         [ +  + ]:         120 :                 else if (difference > 0)
     108                 :          42 :                         StopLow = StopMiddle + 1;
     109                 :             :                 else
     110                 :          78 :                         StopHigh = StopMiddle;
     111                 :             :         }
     112                 :             : 
     113         [ +  + ]:          71 :         if (item->prefix)
     114                 :             :         {
     115         [ -  + ]:           9 :                 if (StopLow >= StopHigh)
     116                 :           9 :                         StopMiddle = StopHigh;
     117                 :             : 
     118                 :           9 :                 *nitem = 0;
     119                 :             : 
     120   [ +  +  +  + ]:          32 :                 while (StopMiddle < (WordEntry *) STRPTR(t) &&
     121                 :          14 :                            WordECompareQueryItem(STRPTR(t), GETOPERAND(q), StopMiddle, item, true) == 0)
     122                 :             :                 {
     123                 :          14 :                         (*nitem)++;
     124                 :          14 :                         StopMiddle++;
     125                 :             :                 }
     126                 :           9 :         }
     127                 :             : 
     128         [ +  + ]:          71 :         return (*nitem > 0) ? StopHigh : NULL;
     129                 :          71 : }
     130                 :             : 
     131                 :             : 
     132                 :             : /*
     133                 :             :  * sort QueryOperands by (length, word)
     134                 :             :  */
     135                 :             : static int
     136                 :          18 : compareQueryOperand(const void *a, const void *b, void *arg)
     137                 :             : {
     138                 :          18 :         char       *operand = (char *) arg;
     139                 :          18 :         QueryOperand *qa = (*(QueryOperand *const *) a);
     140                 :          18 :         QueryOperand *qb = (*(QueryOperand *const *) b);
     141                 :             : 
     142                 :          54 :         return tsCompareString(operand + qa->distance, qa->length,
     143                 :          18 :                                                    operand + qb->distance, qb->length,
     144                 :             :                                                    false);
     145                 :          18 : }
     146                 :             : 
     147                 :             : /*
     148                 :             :  * Returns a sorted, de-duplicated array of QueryOperands in a query.
     149                 :             :  * The returned QueryOperands are pointers to the original QueryOperands
     150                 :             :  * in the query.
     151                 :             :  *
     152                 :             :  * Length of the returned array is stored in *size
     153                 :             :  */
     154                 :             : static QueryOperand **
     155                 :           9 : SortAndUniqItems(TSQuery q, int *size)
     156                 :             : {
     157                 :           9 :         char       *operand = GETOPERAND(q);
     158                 :           9 :         QueryItem  *item = GETQUERY(q);
     159                 :           9 :         QueryOperand **res,
     160                 :             :                           **ptr,
     161                 :             :                           **prevptr;
     162                 :             : 
     163                 :           9 :         ptr = res = palloc_array(QueryOperand *, *size);
     164                 :             : 
     165                 :             :         /* Collect all operands from the tree to res */
     166         [ +  + ]:          36 :         while ((*size)--)
     167                 :             :         {
     168         [ +  + ]:          27 :                 if (item->type == QI_VAL)
     169                 :             :                 {
     170                 :          18 :                         *ptr = (QueryOperand *) item;
     171                 :          18 :                         ptr++;
     172                 :          18 :                 }
     173                 :          27 :                 item++;
     174                 :             :         }
     175                 :             : 
     176                 :           9 :         *size = ptr - res;
     177         [ -  + ]:           9 :         if (*size < 2)
     178                 :           0 :                 return res;
     179                 :             : 
     180                 :           9 :         qsort_arg(res, *size, sizeof(QueryOperand *), compareQueryOperand, operand);
     181                 :             : 
     182                 :           9 :         ptr = res + 1;
     183                 :           9 :         prevptr = res;
     184                 :             : 
     185                 :             :         /* remove duplicates */
     186         [ +  + ]:          18 :         while (ptr - res < *size)
     187                 :             :         {
     188         [ -  + ]:           9 :                 if (compareQueryOperand(ptr, prevptr, operand) != 0)
     189                 :             :                 {
     190                 :           9 :                         prevptr++;
     191                 :           9 :                         *prevptr = *ptr;
     192                 :           9 :                 }
     193                 :           9 :                 ptr++;
     194                 :             :         }
     195                 :             : 
     196                 :           9 :         *size = prevptr + 1 - res;
     197                 :           9 :         return res;
     198                 :           9 : }
     199                 :             : 
     200                 :             : static float
     201                 :           3 : calc_rank_and(const float *w, TSVector t, TSQuery q)
     202                 :             : {
     203                 :           3 :         WordEntryPosVector **pos;
     204                 :           3 :         WordEntryPosVector1 posnull;
     205                 :           3 :         WordEntryPosVector *POSNULL;
     206                 :           3 :         int                     i,
     207                 :             :                                 k,
     208                 :             :                                 l,
     209                 :             :                                 p;
     210                 :           3 :         WordEntry  *entry,
     211                 :             :                            *firstentry;
     212                 :           3 :         WordEntryPos *post,
     213                 :             :                            *ct;
     214                 :           3 :         int32           dimt,
     215                 :             :                                 lenct,
     216                 :             :                                 dist,
     217                 :             :                                 nitem;
     218                 :           3 :         float           res = -1.0;
     219                 :           3 :         QueryOperand **item;
     220                 :           3 :         int                     size = q->size;
     221                 :             : 
     222                 :           3 :         item = SortAndUniqItems(q, &size);
     223         [ -  + ]:           3 :         if (size < 2)
     224                 :             :         {
     225                 :           0 :                 pfree(item);
     226                 :           0 :                 return calc_rank_or(w, t, q);
     227                 :             :         }
     228                 :           3 :         pos = palloc0_array(WordEntryPosVector *, q->size);
     229                 :             : 
     230                 :             :         /* A dummy WordEntryPos array to use when haspos is false */
     231                 :           3 :         posnull.npos = 1;
     232                 :           3 :         posnull.pos[0] = 0;
     233                 :           3 :         WEP_SETPOS(posnull.pos[0], MAXENTRYPOS - 1);
     234                 :           3 :         POSNULL = (WordEntryPosVector *) &posnull;
     235                 :             : 
     236         [ +  + ]:           9 :         for (i = 0; i < size; i++)
     237                 :             :         {
     238                 :           6 :                 firstentry = entry = find_wordentry(t, q, item[i], &nitem);
     239         [ +  - ]:           6 :                 if (!entry)
     240                 :           0 :                         continue;
     241                 :             : 
     242         [ +  + ]:          12 :                 while (entry - firstentry < nitem)
     243                 :             :                 {
     244         [ +  - ]:           6 :                         if (entry->haspos)
     245                 :           6 :                                 pos[i] = _POSVECPTR(t, entry);
     246                 :             :                         else
     247                 :           0 :                                 pos[i] = POSNULL;
     248                 :             : 
     249                 :           6 :                         dimt = pos[i]->npos;
     250                 :           6 :                         post = pos[i]->pos;
     251         [ +  + ]:           9 :                         for (k = 0; k < i; k++)
     252                 :             :                         {
     253         [ +  - ]:           3 :                                 if (!pos[k])
     254                 :           0 :                                         continue;
     255                 :           3 :                                 lenct = pos[k]->npos;
     256                 :           3 :                                 ct = pos[k]->pos;
     257         [ +  + ]:           6 :                                 for (l = 0; l < dimt; l++)
     258                 :             :                                 {
     259         [ +  + ]:           6 :                                         for (p = 0; p < lenct; p++)
     260                 :             :                                         {
     261                 :           3 :                                                 dist = abs((int) WEP_GETPOS(post[l]) - (int) WEP_GETPOS(ct[p]));
     262   [ -  +  #  #  :           3 :                                                 if (dist || (dist == 0 && (pos[i] == POSNULL || pos[k] == POSNULL)))
             #  #  #  # ]
     263                 :             :                                                 {
     264                 :           3 :                                                         float           curw;
     265                 :             : 
     266         [ +  - ]:           3 :                                                         if (!dist)
     267                 :           0 :                                                                 dist = MAXENTRYPOS;
     268                 :           3 :                                                         curw = sqrt(wpos(post[l]) * wpos(ct[p]) * word_distance(dist));
     269         [ +  - ]:           3 :                                                         res = (res < 0) ? curw : 1.0 - (1.0 - res) * (1.0 - curw);
     270                 :           3 :                                                 }
     271                 :           3 :                                         }
     272                 :           3 :                                 }
     273                 :           3 :                         }
     274                 :             : 
     275                 :           6 :                         entry++;
     276                 :             :                 }
     277                 :           6 :         }
     278                 :           3 :         pfree(pos);
     279                 :           3 :         pfree(item);
     280                 :           3 :         return res;
     281                 :           3 : }
     282                 :             : 
     283                 :             : static float
     284                 :           6 : calc_rank_or(const float *w, TSVector t, TSQuery q)
     285                 :             : {
     286                 :           6 :         WordEntry  *entry,
     287                 :             :                            *firstentry;
     288                 :           6 :         WordEntryPosVector1 posnull;
     289                 :           6 :         WordEntryPos *post;
     290                 :           6 :         int32           dimt,
     291                 :             :                                 j,
     292                 :             :                                 i,
     293                 :             :                                 nitem;
     294                 :           6 :         float           res = 0.0;
     295                 :           6 :         QueryOperand **item;
     296                 :           6 :         int                     size = q->size;
     297                 :             : 
     298                 :             :         /* A dummy WordEntryPos array to use when haspos is false */
     299                 :           6 :         posnull.npos = 1;
     300                 :           6 :         posnull.pos[0] = 0;
     301                 :             : 
     302                 :           6 :         item = SortAndUniqItems(q, &size);
     303                 :             : 
     304         [ +  + ]:          18 :         for (i = 0; i < size; i++)
     305                 :             :         {
     306                 :          12 :                 float           resj,
     307                 :             :                                         wjm;
     308                 :          12 :                 int32           jm;
     309                 :             : 
     310                 :          12 :                 firstentry = entry = find_wordentry(t, q, item[i], &nitem);
     311         [ +  + ]:          12 :                 if (!entry)
     312                 :           1 :                         continue;
     313                 :             : 
     314         [ +  + ]:          22 :                 while (entry - firstentry < nitem)
     315                 :             :                 {
     316         [ +  - ]:          11 :                         if (entry->haspos)
     317                 :             :                         {
     318         [ +  - ]:          11 :                                 dimt = POSDATALEN(t, entry);
     319                 :          11 :                                 post = POSDATAPTR(t, entry);
     320                 :          11 :                         }
     321                 :             :                         else
     322                 :             :                         {
     323                 :           0 :                                 dimt = posnull.npos;
     324                 :           0 :                                 post = posnull.pos;
     325                 :             :                         }
     326                 :             : 
     327                 :          11 :                         resj = 0.0;
     328                 :          11 :                         wjm = -1.0;
     329                 :          11 :                         jm = 0;
     330         [ +  + ]:          22 :                         for (j = 0; j < dimt; j++)
     331                 :             :                         {
     332                 :          11 :                                 resj = resj + wpos(post[j]) / ((j + 1) * (j + 1));
     333         [ -  + ]:          11 :                                 if (wpos(post[j]) > wjm)
     334                 :             :                                 {
     335                 :          11 :                                         wjm = wpos(post[j]);
     336                 :          11 :                                         jm = j;
     337                 :          11 :                                 }
     338                 :          11 :                         }
     339                 :             : /*
     340                 :             :                         limit (sum(1/i^2),i=1,inf) = pi^2/6
     341                 :             :                         resj = sum(wi/i^2),i=1,noccurrence,
     342                 :             :                         wi - should be sorted desc,
     343                 :             :                         don't sort for now, just choose maximum weight. This should be corrected
     344                 :             :                         Oleg Bartunov
     345                 :             : */
     346                 :          11 :                         res = res + (wjm + resj - wjm / ((jm + 1) * (jm + 1))) / 1.64493406685;
     347                 :             : 
     348                 :          11 :                         entry++;
     349                 :             :                 }
     350      [ -  +  + ]:          12 :         }
     351         [ -  + ]:           6 :         if (size > 0)
     352                 :           6 :                 res = res / size;
     353                 :           6 :         pfree(item);
     354                 :          12 :         return res;
     355                 :           6 : }
     356                 :             : 
     357                 :             : static float
     358                 :           9 : calc_rank(const float *w, TSVector t, TSQuery q, int32 method)
     359                 :             : {
     360                 :           9 :         QueryItem  *item = GETQUERY(q);
     361                 :           9 :         float           res = 0.0;
     362                 :           9 :         int                     len;
     363                 :             : 
     364   [ +  -  -  + ]:           9 :         if (!t->size || !q->size)
     365                 :           0 :                 return 0.0;
     366                 :             : 
     367                 :             :         /* XXX: What about NOT? */
     368   [ +  -  +  +  :           9 :         res = (item->type == QI_OPR && (item->qoperator.oper == OP_AND ||
                   -  + ]
     369                 :           6 :                                                                         item->qoperator.oper == OP_PHRASE)) ?
     370                 :           3 :                 calc_rank_and(w, t, q) :
     371                 :           6 :                 calc_rank_or(w, t, q);
     372                 :             : 
     373         [ +  - ]:           9 :         if (res < 0)
     374                 :           0 :                 res = 1e-20f;
     375                 :             : 
     376   [ -  +  #  # ]:           9 :         if ((method & RANK_NORM_LOGLENGTH) && t->size > 0)
     377                 :           0 :                 res /= log((double) (cnt_length(t) + 1)) / log(2.0);
     378                 :             : 
     379         [ +  - ]:           9 :         if (method & RANK_NORM_LENGTH)
     380                 :             :         {
     381                 :           0 :                 len = cnt_length(t);
     382         [ #  # ]:           0 :                 if (len > 0)
     383                 :           0 :                         res /= (float) len;
     384                 :           0 :         }
     385                 :             : 
     386                 :             :         /* RANK_NORM_EXTDIST not applicable */
     387                 :             : 
     388   [ -  +  #  # ]:           9 :         if ((method & RANK_NORM_UNIQ) && t->size > 0)
     389                 :           0 :                 res /= (float) (t->size);
     390                 :             : 
     391   [ -  +  #  # ]:           9 :         if ((method & RANK_NORM_LOGUNIQ) && t->size > 0)
     392                 :           0 :                 res /= log((double) (t->size + 1)) / log(2.0);
     393                 :             : 
     394         [ +  - ]:           9 :         if (method & RANK_NORM_RDIVRPLUS1)
     395                 :           0 :                 res /= (res + 1);
     396                 :             : 
     397                 :           9 :         return res;
     398                 :           9 : }
     399                 :             : 
     400                 :             : /*
     401                 :             :  * Extract weights from an array. The weights are stored in *ws, which must
     402                 :             :  * have space for NUM_WEIGHTS elements.
     403                 :             :  */
     404                 :             : static void
     405                 :           0 : getWeights(ArrayType *win, float *ws)
     406                 :             : {
     407                 :           0 :         int                     i;
     408                 :           0 :         float4     *arrdata;
     409                 :             : 
     410         [ #  # ]:           0 :         Assert(win != NULL);
     411                 :             : 
     412         [ #  # ]:           0 :         if (ARR_NDIM(win) != 1)
     413   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     414                 :             :                                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
     415                 :             :                                  errmsg("array of weight must be one-dimensional")));
     416                 :             : 
     417         [ #  # ]:           0 :         if (ArrayGetNItems(ARR_NDIM(win), ARR_DIMS(win)) < NUM_WEIGHTS)
     418   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     419                 :             :                                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
     420                 :             :                                  errmsg("array of weight is too short")));
     421                 :             : 
     422         [ #  # ]:           0 :         if (array_contains_nulls(win))
     423   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     424                 :             :                                 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
     425                 :             :                                  errmsg("array of weight must not contain nulls")));
     426                 :             : 
     427         [ #  # ]:           0 :         arrdata = (float4 *) ARR_DATA_PTR(win);
     428         [ #  # ]:           0 :         for (i = 0; i < NUM_WEIGHTS; i++)
     429                 :             :         {
     430         [ #  # ]:           0 :                 ws[i] = (arrdata[i] >= 0) ? arrdata[i] : default_weights[i];
     431         [ #  # ]:           0 :                 if (ws[i] > 1.0)
     432   [ #  #  #  # ]:           0 :                         ereport(ERROR,
     433                 :             :                                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     434                 :             :                                          errmsg("weight out of range")));
     435                 :           0 :         }
     436                 :           0 : }
     437                 :             : 
     438                 :             : Datum
     439                 :           0 : ts_rank_wttf(PG_FUNCTION_ARGS)
     440                 :             : {
     441                 :           0 :         ArrayType  *win = (ArrayType *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
     442                 :           0 :         TSVector        txt = PG_GETARG_TSVECTOR(1);
     443                 :           0 :         TSQuery         query = PG_GETARG_TSQUERY(2);
     444                 :           0 :         int                     method = PG_GETARG_INT32(3);
     445                 :           0 :         float           weights[NUM_WEIGHTS];
     446                 :           0 :         float           res;
     447                 :             : 
     448                 :           0 :         getWeights(win, weights);
     449                 :           0 :         res = calc_rank(weights, txt, query, method);
     450                 :             : 
     451         [ #  # ]:           0 :         PG_FREE_IF_COPY(win, 0);
     452         [ #  # ]:           0 :         PG_FREE_IF_COPY(txt, 1);
     453         [ #  # ]:           0 :         PG_FREE_IF_COPY(query, 2);
     454                 :           0 :         PG_RETURN_FLOAT4(res);
     455                 :           0 : }
     456                 :             : 
     457                 :             : Datum
     458                 :           0 : ts_rank_wtt(PG_FUNCTION_ARGS)
     459                 :             : {
     460                 :           0 :         ArrayType  *win = (ArrayType *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
     461                 :           0 :         TSVector        txt = PG_GETARG_TSVECTOR(1);
     462                 :           0 :         TSQuery         query = PG_GETARG_TSQUERY(2);
     463                 :           0 :         float           weights[NUM_WEIGHTS];
     464                 :           0 :         float           res;
     465                 :             : 
     466                 :           0 :         getWeights(win, weights);
     467                 :           0 :         res = calc_rank(weights, txt, query, DEF_NORM_METHOD);
     468                 :             : 
     469         [ #  # ]:           0 :         PG_FREE_IF_COPY(win, 0);
     470         [ #  # ]:           0 :         PG_FREE_IF_COPY(txt, 1);
     471         [ #  # ]:           0 :         PG_FREE_IF_COPY(query, 2);
     472                 :           0 :         PG_RETURN_FLOAT4(res);
     473                 :           0 : }
     474                 :             : 
     475                 :             : Datum
     476                 :           0 : ts_rank_ttf(PG_FUNCTION_ARGS)
     477                 :             : {
     478                 :           0 :         TSVector        txt = PG_GETARG_TSVECTOR(0);
     479                 :           0 :         TSQuery         query = PG_GETARG_TSQUERY(1);
     480                 :           0 :         int                     method = PG_GETARG_INT32(2);
     481                 :           0 :         float           res;
     482                 :             : 
     483                 :           0 :         res = calc_rank(default_weights, txt, query, method);
     484                 :             : 
     485         [ #  # ]:           0 :         PG_FREE_IF_COPY(txt, 0);
     486         [ #  # ]:           0 :         PG_FREE_IF_COPY(query, 1);
     487                 :           0 :         PG_RETURN_FLOAT4(res);
     488                 :           0 : }
     489                 :             : 
     490                 :             : Datum
     491                 :           9 : ts_rank_tt(PG_FUNCTION_ARGS)
     492                 :             : {
     493                 :           9 :         TSVector        txt = PG_GETARG_TSVECTOR(0);
     494                 :           9 :         TSQuery         query = PG_GETARG_TSQUERY(1);
     495                 :           9 :         float           res;
     496                 :             : 
     497                 :           9 :         res = calc_rank(default_weights, txt, query, DEF_NORM_METHOD);
     498                 :             : 
     499         [ +  - ]:           9 :         PG_FREE_IF_COPY(txt, 0);
     500         [ +  - ]:           9 :         PG_FREE_IF_COPY(query, 1);
     501                 :          18 :         PG_RETURN_FLOAT4(res);
     502                 :           9 : }
     503                 :             : 
     504                 :             : typedef struct
     505                 :             : {
     506                 :             :         union
     507                 :             :         {
     508                 :             :                 struct
     509                 :             :                 {                                               /* compiled doc representation */
     510                 :             :                         QueryItem **items;
     511                 :             :                         int16           nitem;
     512                 :             :                 }                       query;
     513                 :             :                 struct
     514                 :             :                 {                                               /* struct is used for preparing doc
     515                 :             :                                                                  * representation */
     516                 :             :                         QueryItem  *item;
     517                 :             :                         WordEntry  *entry;
     518                 :             :                 }                       map;
     519                 :             :         }                       data;
     520                 :             :         WordEntryPos pos;
     521                 :             : } DocRepresentation;
     522                 :             : 
     523                 :             : static int
     524                 :          58 : compareDocR(const void *va, const void *vb)
     525                 :             : {
     526                 :          58 :         const DocRepresentation *a = (const DocRepresentation *) va;
     527                 :          58 :         const DocRepresentation *b = (const DocRepresentation *) vb;
     528                 :             : 
     529         [ +  + ]:          58 :         if (WEP_GETPOS(a->pos) == WEP_GETPOS(b->pos))
     530                 :             :         {
     531         [ +  + ]:           6 :                 if (WEP_GETWEIGHT(a->pos) == WEP_GETWEIGHT(b->pos))
     532                 :             :                 {
     533         [ -  + ]:           1 :                         if (a->data.map.entry == b->data.map.entry)
     534                 :           1 :                                 return 0;
     535                 :             : 
     536                 :           0 :                         return (a->data.map.entry > b->data.map.entry) ? 1 : -1;
     537                 :             :                 }
     538                 :             : 
     539                 :           5 :                 return (WEP_GETWEIGHT(a->pos) > WEP_GETWEIGHT(b->pos)) ? 1 : -1;
     540                 :             :         }
     541                 :             : 
     542                 :          52 :         return (WEP_GETPOS(a->pos) > WEP_GETPOS(b->pos)) ? 1 : -1;
     543                 :          58 : }
     544                 :             : 
     545                 :             : #define MAXQROPOS       MAXENTRYPOS
     546                 :             : typedef struct
     547                 :             : {
     548                 :             :         bool            operandexists;
     549                 :             :         bool            reverseinsert;  /* indicates insert order, true means
     550                 :             :                                                                  * descending order */
     551                 :             :         uint32          npos;
     552                 :             :         WordEntryPos pos[MAXQROPOS];
     553                 :             : } QueryRepresentationOperand;
     554                 :             : 
     555                 :             : typedef struct
     556                 :             : {
     557                 :             :         TSQuery         query;
     558                 :             :         QueryRepresentationOperand *operandData;
     559                 :             : } QueryRepresentation;
     560                 :             : 
     561                 :             : #define QR_GET_OPERAND_DATA(q, v) \
     562                 :             :         ( (q)->operandData + (((QueryItem*)(v)) - GETQUERY((q)->query)) )
     563                 :             : 
     564                 :             : /*
     565                 :             :  * TS_execute callback for matching a tsquery operand to QueryRepresentation
     566                 :             :  */
     567                 :             : static TSTernaryValue
     568                 :         193 : checkcondition_QueryOperand(void *checkval, QueryOperand *val,
     569                 :             :                                                         ExecPhraseData *data)
     570                 :             : {
     571                 :         193 :         QueryRepresentation *qr = (QueryRepresentation *) checkval;
     572                 :         193 :         QueryRepresentationOperand *opData = QR_GET_OPERAND_DATA(qr, val);
     573                 :             : 
     574         [ +  + ]:         193 :         if (!opData->operandexists)
     575                 :          74 :                 return TS_NO;
     576                 :             : 
     577         [ +  + ]:         119 :         if (data)
     578                 :             :         {
     579                 :          58 :                 data->npos = opData->npos;
     580                 :          58 :                 data->pos = opData->pos;
     581         [ +  + ]:          58 :                 if (opData->reverseinsert)
     582                 :          18 :                         data->pos += MAXQROPOS - opData->npos;
     583                 :          58 :         }
     584                 :             : 
     585                 :         119 :         return TS_YES;
     586                 :         193 : }
     587                 :             : 
     588                 :             : typedef struct
     589                 :             : {
     590                 :             :         int                     pos;
     591                 :             :         int                     p;
     592                 :             :         int                     q;
     593                 :             :         DocRepresentation *begin;
     594                 :             :         DocRepresentation *end;
     595                 :             : } CoverExt;
     596                 :             : 
     597                 :             : static void
     598                 :          83 : resetQueryRepresentation(QueryRepresentation *qr, bool reverseinsert)
     599                 :             : {
     600                 :          83 :         int                     i;
     601                 :             : 
     602         [ +  + ]:         336 :         for (i = 0; i < qr->query->size; i++)
     603                 :             :         {
     604                 :         253 :                 qr->operandData[i].operandexists = false;
     605                 :         253 :                 qr->operandData[i].reverseinsert = reverseinsert;
     606                 :         253 :                 qr->operandData[i].npos = 0;
     607                 :         253 :         }
     608                 :          83 : }
     609                 :             : 
     610                 :             : static void
     611                 :         120 : fillQueryRepresentationData(QueryRepresentation *qr, DocRepresentation *entry)
     612                 :             : {
     613                 :         120 :         int                     i;
     614                 :         120 :         int                     lastPos;
     615                 :         120 :         QueryRepresentationOperand *opData;
     616                 :             : 
     617         [ +  + ]:         241 :         for (i = 0; i < entry->data.query.nitem; i++)
     618                 :             :         {
     619         [ -  + ]:         121 :                 if (entry->data.query.items[i]->type != QI_VAL)
     620                 :           0 :                         continue;
     621                 :             : 
     622                 :         121 :                 opData = QR_GET_OPERAND_DATA(qr, entry->data.query.items[i]);
     623                 :             : 
     624                 :         121 :                 opData->operandexists = true;
     625                 :             : 
     626         [ +  + ]:         121 :                 if (opData->npos == 0)
     627                 :             :                 {
     628                 :         110 :                         lastPos = (opData->reverseinsert) ? (MAXQROPOS - 1) : 0;
     629                 :         110 :                         opData->pos[lastPos] = entry->pos;
     630                 :         110 :                         opData->npos++;
     631                 :         110 :                         continue;
     632                 :             :                 }
     633                 :             : 
     634         [ -  + ]:          11 :                 lastPos = opData->reverseinsert ?
     635                 :           0 :                         (MAXQROPOS - opData->npos) :
     636                 :          11 :                         (opData->npos - 1);
     637                 :             : 
     638         [ +  + ]:          11 :                 if (WEP_GETPOS(opData->pos[lastPos]) != WEP_GETPOS(entry->pos))
     639                 :             :                 {
     640         [ -  + ]:           7 :                         lastPos = opData->reverseinsert ?
     641                 :           0 :                                 (MAXQROPOS - 1 - opData->npos) :
     642                 :           7 :                                 (opData->npos);
     643                 :             : 
     644                 :           7 :                         opData->pos[lastPos] = entry->pos;
     645                 :           7 :                         opData->npos++;
     646                 :           7 :                 }
     647                 :          11 :         }
     648                 :         120 : }
     649                 :             : 
     650                 :             : static bool
     651                 :          54 : Cover(DocRepresentation *doc, int len, QueryRepresentation *qr, CoverExt *ext)
     652                 :             : {
     653                 :          54 :         DocRepresentation *ptr;
     654                 :          54 :         int                     lastpos = ext->pos;
     655                 :          54 :         bool            found = false;
     656                 :             : 
     657                 :             :         /*
     658                 :             :          * since this function recurses, it could be driven to stack overflow.
     659                 :             :          * (though any decent compiler will optimize away the tail-recursion.
     660                 :             :          */
     661                 :          54 :         check_stack_depth();
     662                 :             : 
     663                 :          54 :         resetQueryRepresentation(qr, false);
     664                 :             : 
     665                 :          54 :         ext->p = INT_MAX;
     666                 :          54 :         ext->q = 0;
     667                 :          54 :         ptr = doc + ext->pos;
     668                 :             : 
     669                 :             :         /* find upper bound of cover from current position, move up */
     670         [ +  + ]:         101 :         while (ptr - doc < len)
     671                 :             :         {
     672                 :          76 :                 fillQueryRepresentationData(qr, ptr);
     673                 :             : 
     674         [ +  + ]:          76 :                 if (TS_execute(GETQUERY(qr->query), qr,
     675                 :             :                                            TS_EXEC_EMPTY, checkcondition_QueryOperand))
     676                 :             :                 {
     677         [ -  + ]:          29 :                         if (WEP_GETPOS(ptr->pos) > ext->q)
     678                 :             :                         {
     679                 :          29 :                                 ext->q = WEP_GETPOS(ptr->pos);
     680                 :          29 :                                 ext->end = ptr;
     681                 :          29 :                                 lastpos = ptr - doc;
     682                 :          29 :                                 found = true;
     683                 :          29 :                         }
     684                 :          29 :                         break;
     685                 :             :                 }
     686                 :          47 :                 ptr++;
     687                 :             :         }
     688                 :             : 
     689         [ +  + ]:          54 :         if (!found)
     690                 :          25 :                 return false;
     691                 :             : 
     692                 :          29 :         resetQueryRepresentation(qr, true);
     693                 :             : 
     694                 :          29 :         ptr = doc + lastpos;
     695                 :             : 
     696                 :             :         /* find lower bound of cover from found upper bound, move down */
     697         [ -  + ]:          44 :         while (ptr >= doc + ext->pos)
     698                 :             :         {
     699                 :             :                 /*
     700                 :             :                  * we scan doc from right to left, so pos info in reverse order!
     701                 :             :                  */
     702                 :          44 :                 fillQueryRepresentationData(qr, ptr);
     703                 :             : 
     704         [ +  + ]:          44 :                 if (TS_execute(GETQUERY(qr->query), qr,
     705                 :             :                                            TS_EXEC_EMPTY, checkcondition_QueryOperand))
     706                 :             :                 {
     707         [ -  + ]:          29 :                         if (WEP_GETPOS(ptr->pos) < ext->p)
     708                 :             :                         {
     709                 :          29 :                                 ext->begin = ptr;
     710                 :          29 :                                 ext->p = WEP_GETPOS(ptr->pos);
     711                 :          29 :                         }
     712                 :          29 :                         break;
     713                 :             :                 }
     714                 :          15 :                 ptr--;
     715                 :             :         }
     716                 :             : 
     717         [ +  - ]:          29 :         if (ext->p <= ext->q)
     718                 :             :         {
     719                 :             :                 /*
     720                 :             :                  * set position for next try to next lexeme after beginning of found
     721                 :             :                  * cover
     722                 :             :                  */
     723                 :          29 :                 ext->pos = (ptr - doc) + 1;
     724                 :          29 :                 return true;
     725                 :             :         }
     726                 :             : 
     727                 :           0 :         ext->pos++;
     728                 :           0 :         return Cover(doc, len, qr, ext);
     729                 :          54 : }
     730                 :             : 
     731                 :             : static DocRepresentation *
     732                 :          26 : get_docrep(TSVector txt, QueryRepresentation *qr, int *doclen)
     733                 :             : {
     734                 :          26 :         QueryItem  *item = GETQUERY(qr->query);
     735                 :          26 :         WordEntry  *entry,
     736                 :             :                            *firstentry;
     737                 :          26 :         WordEntryPos *post;
     738                 :          26 :         int32           dimt,                   /* number of 'post' items */
     739                 :             :                                 j,
     740                 :             :                                 i,
     741                 :             :                                 nitem;
     742                 :          26 :         int                     len = qr->query->size * 4,
     743                 :          26 :                                 cur = 0;
     744                 :          26 :         DocRepresentation *doc;
     745                 :             : 
     746                 :          26 :         doc = palloc_array(DocRepresentation, len);
     747                 :             : 
     748                 :             :         /*
     749                 :             :          * Iterate through query to make DocRepresentation for words and it's
     750                 :             :          * entries satisfied by query
     751                 :             :          */
     752         [ +  + ]:         106 :         for (i = 0; i < qr->query->size; i++)
     753                 :             :         {
     754                 :          80 :                 QueryOperand *curoperand;
     755                 :             : 
     756         [ +  + ]:          80 :                 if (item[i].type != QI_VAL)
     757                 :          27 :                         continue;
     758                 :             : 
     759                 :          53 :                 curoperand = &item[i].qoperand;
     760                 :             : 
     761                 :          53 :                 firstentry = entry = find_wordentry(txt, qr->query, curoperand, &nitem);
     762         [ +  + ]:          53 :                 if (!entry)
     763                 :           1 :                         continue;
     764                 :             : 
     765                 :             :                 /* iterations over entries in tsvector */
     766         [ +  + ]:         109 :                 while (entry - firstentry < nitem)
     767                 :             :                 {
     768         [ +  + ]:          57 :                         if (entry->haspos)
     769                 :             :                         {
     770         [ +  - ]:          55 :                                 dimt = POSDATALEN(txt, entry);
     771                 :          55 :                                 post = POSDATAPTR(txt, entry);
     772                 :          55 :                         }
     773                 :             :                         else
     774                 :             :                         {
     775                 :             :                                 /* ignore words without positions */
     776                 :           2 :                                 entry++;
     777                 :           2 :                                 continue;
     778                 :             :                         }
     779                 :             : 
     780         [ -  + ]:          55 :                         while (cur + dimt >= len)
     781                 :             :                         {
     782                 :           0 :                                 len *= 2;
     783                 :           0 :                                 doc = (DocRepresentation *) repalloc(doc, sizeof(DocRepresentation) * len);
     784                 :             :                         }
     785                 :             : 
     786                 :             :                         /* iterations over entry's positions */
     787         [ +  + ]:         119 :                         for (j = 0; j < dimt; j++)
     788                 :             :                         {
     789   [ +  +  +  + ]:          64 :                                 if (curoperand->weight == 0 ||
     790                 :           5 :                                         curoperand->weight & (1 << WEP_GETWEIGHT(post[j])))
     791                 :             :                                 {
     792                 :          62 :                                         doc[cur].pos = post[j];
     793                 :          62 :                                         doc[cur].data.map.entry = entry;
     794                 :          62 :                                         doc[cur].data.map.item = (QueryItem *) curoperand;
     795                 :          62 :                                         cur++;
     796                 :          62 :                                 }
     797                 :          64 :                         }
     798                 :             : 
     799                 :          55 :                         entry++;
     800                 :             :                 }
     801      [ -  +  + ]:          80 :         }
     802                 :             : 
     803         [ +  + ]:          26 :         if (cur > 0)
     804                 :             :         {
     805                 :          50 :                 DocRepresentation *rptr = doc + 1,
     806                 :          25 :                                    *wptr = doc,
     807                 :             :                                         storage;
     808                 :             : 
     809                 :             :                 /*
     810                 :             :                  * Sort representation in ascending order by pos and entry
     811                 :             :                  */
     812                 :          25 :                 qsort(doc, cur, sizeof(DocRepresentation), compareDocR);
     813                 :             : 
     814                 :             :                 /*
     815                 :             :                  * Join QueryItem per WordEntry and its position
     816                 :             :                  */
     817                 :          25 :                 storage.pos = doc->pos;
     818                 :          25 :                 storage.data.query.items = palloc_array(QueryItem *, qr->query->size);
     819                 :          25 :                 storage.data.query.items[0] = doc->data.map.item;
     820                 :          25 :                 storage.data.query.nitem = 1;
     821                 :             : 
     822         [ +  + ]:          62 :                 while (rptr - doc < cur)
     823                 :             :                 {
     824   [ +  +  -  + ]:          37 :                         if (rptr->pos == (rptr - 1)->pos &&
     825                 :           1 :                                 rptr->data.map.entry == (rptr - 1)->data.map.entry)
     826                 :             :                         {
     827                 :           1 :                                 storage.data.query.items[storage.data.query.nitem] = rptr->data.map.item;
     828                 :           1 :                                 storage.data.query.nitem++;
     829                 :           1 :                         }
     830                 :             :                         else
     831                 :             :                         {
     832                 :          36 :                                 *wptr = storage;
     833                 :          36 :                                 wptr++;
     834                 :          36 :                                 storage.pos = rptr->pos;
     835                 :          36 :                                 storage.data.query.items = palloc_array(QueryItem *, qr->query->size);
     836                 :          36 :                                 storage.data.query.items[0] = rptr->data.map.item;
     837                 :          36 :                                 storage.data.query.nitem = 1;
     838                 :             :                         }
     839                 :             : 
     840                 :          37 :                         rptr++;
     841                 :             :                 }
     842                 :             : 
     843                 :          25 :                 *wptr = storage;
     844                 :          25 :                 wptr++;
     845                 :             : 
     846                 :          25 :                 *doclen = wptr - doc;
     847                 :          25 :                 return doc;
     848                 :          25 :         }
     849                 :             : 
     850                 :           1 :         pfree(doc);
     851                 :           1 :         return NULL;
     852                 :          26 : }
     853                 :             : 
     854                 :             : static float4
     855                 :          26 : calc_rank_cd(const float4 *arrdata, TSVector txt, TSQuery query, int method)
     856                 :             : {
     857                 :          26 :         DocRepresentation *doc;
     858                 :          26 :         int                     len,
     859                 :             :                                 i,
     860                 :          26 :                                 doclen = 0;
     861                 :          26 :         CoverExt        ext;
     862                 :          26 :         double          Wdoc = 0.0;
     863                 :          26 :         double          invws[NUM_WEIGHTS];
     864                 :          26 :         double          SumDist = 0.0,
     865                 :          26 :                                 PrevExtPos = 0.0;
     866                 :          26 :         int                     NExtent = 0;
     867                 :          26 :         QueryRepresentation qr;
     868                 :             : 
     869                 :             : 
     870         [ +  + ]:         130 :         for (i = 0; i < NUM_WEIGHTS; i++)
     871                 :             :         {
     872         [ +  - ]:         104 :                 invws[i] = ((double) ((arrdata[i] >= 0) ? arrdata[i] : default_weights[i]));
     873         [ +  - ]:         104 :                 if (invws[i] > 1.0)
     874   [ #  #  #  # ]:           0 :                         ereport(ERROR,
     875                 :             :                                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     876                 :             :                                          errmsg("weight out of range")));
     877                 :         104 :                 invws[i] = 1.0 / invws[i];
     878                 :         104 :         }
     879                 :             : 
     880                 :          26 :         qr.query = query;
     881                 :          26 :         qr.operandData = palloc0_array(QueryRepresentationOperand, query->size);
     882                 :             : 
     883                 :          26 :         doc = get_docrep(txt, &qr, &doclen);
     884         [ +  + ]:          26 :         if (!doc)
     885                 :             :         {
     886                 :           1 :                 pfree(qr.operandData);
     887                 :           1 :                 return 0.0;
     888                 :             :         }
     889                 :             : 
     890   [ +  -  +  -  :         125 :         MemSet(&ext, 0, sizeof(CoverExt));
          +  -  -  +  +  
                      + ]
     891         [ +  + ]:          54 :         while (Cover(doc, doclen, &qr, &ext))
     892                 :             :         {
     893                 :          29 :                 double          Cpos = 0.0;
     894                 :          29 :                 double          InvSum = 0.0;
     895                 :          29 :                 double          CurExtPos;
     896                 :          29 :                 int                     nNoise;
     897                 :          29 :                 DocRepresentation *ptr = ext.begin;
     898                 :             : 
     899         [ +  + ]:          73 :                 while (ptr <= ext.end)
     900                 :             :                 {
     901                 :          44 :                         InvSum += invws[WEP_GETWEIGHT(ptr->pos)];
     902                 :          44 :                         ptr++;
     903                 :             :                 }
     904                 :             : 
     905                 :          29 :                 Cpos = ((double) (ext.end - ext.begin + 1)) / InvSum;
     906                 :             : 
     907                 :             :                 /*
     908                 :             :                  * if doc are big enough then ext.q may be equal to ext.p due to limit
     909                 :             :                  * of positional information. In this case we approximate number of
     910                 :             :                  * noise word as half cover's length
     911                 :             :                  */
     912                 :          29 :                 nNoise = (ext.q - ext.p) - (ext.end - ext.begin);
     913         [ +  - ]:          29 :                 if (nNoise < 0)
     914                 :           0 :                         nNoise = (ext.end - ext.begin) / 2;
     915                 :          29 :                 Wdoc += Cpos / ((double) (1 + nNoise));
     916                 :             : 
     917                 :          29 :                 CurExtPos = ((double) (ext.q + ext.p)) / 2.0;
     918   [ +  +  +  - ]:          29 :                 if (NExtent > 0 && CurExtPos > PrevExtPos /* prevent division by
     919                 :             :                                                                                                          * zero in a case of
     920                 :             :                           * multiple lexize */ )
     921                 :           7 :                         SumDist += 1.0 / (CurExtPos - PrevExtPos);
     922                 :             : 
     923                 :          29 :                 PrevExtPos = CurExtPos;
     924                 :          29 :                 NExtent++;
     925                 :          29 :         }
     926                 :             : 
     927   [ -  +  #  # ]:          25 :         if ((method & RANK_NORM_LOGLENGTH) && txt->size > 0)
     928                 :           0 :                 Wdoc /= log((double) (cnt_length(txt) + 1));
     929                 :             : 
     930         [ +  - ]:          25 :         if (method & RANK_NORM_LENGTH)
     931                 :             :         {
     932                 :           0 :                 len = cnt_length(txt);
     933         [ #  # ]:           0 :                 if (len > 0)
     934                 :           0 :                         Wdoc /= (double) len;
     935                 :           0 :         }
     936                 :             : 
     937   [ -  +  #  #  :          25 :         if ((method & RANK_NORM_EXTDIST) && NExtent > 0 && SumDist > 0)
                   #  # ]
     938                 :           0 :                 Wdoc /= ((double) NExtent) / SumDist;
     939                 :             : 
     940   [ -  +  #  # ]:          25 :         if ((method & RANK_NORM_UNIQ) && txt->size > 0)
     941                 :           0 :                 Wdoc /= (double) (txt->size);
     942                 :             : 
     943   [ -  +  #  # ]:          25 :         if ((method & RANK_NORM_LOGUNIQ) && txt->size > 0)
     944                 :           0 :                 Wdoc /= log((double) (txt->size + 1)) / log(2.0);
     945                 :             : 
     946         [ +  - ]:          25 :         if (method & RANK_NORM_RDIVRPLUS1)
     947                 :           0 :                 Wdoc /= (Wdoc + 1);
     948                 :             : 
     949                 :          25 :         pfree(doc);
     950                 :             : 
     951                 :          25 :         pfree(qr.operandData);
     952                 :             : 
     953                 :          25 :         return (float4) Wdoc;
     954                 :          26 : }
     955                 :             : 
     956                 :             : Datum
     957                 :           0 : ts_rankcd_wttf(PG_FUNCTION_ARGS)
     958                 :             : {
     959                 :           0 :         ArrayType  *win = (ArrayType *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
     960                 :           0 :         TSVector        txt = PG_GETARG_TSVECTOR(1);
     961                 :           0 :         TSQuery         query = PG_GETARG_TSQUERY(2);
     962                 :           0 :         int                     method = PG_GETARG_INT32(3);
     963                 :           0 :         float           weights[NUM_WEIGHTS];
     964                 :           0 :         float           res;
     965                 :             : 
     966                 :           0 :         getWeights(win, weights);
     967                 :           0 :         res = calc_rank_cd(weights, txt, query, method);
     968                 :             : 
     969         [ #  # ]:           0 :         PG_FREE_IF_COPY(win, 0);
     970         [ #  # ]:           0 :         PG_FREE_IF_COPY(txt, 1);
     971         [ #  # ]:           0 :         PG_FREE_IF_COPY(query, 2);
     972                 :           0 :         PG_RETURN_FLOAT4(res);
     973                 :           0 : }
     974                 :             : 
     975                 :             : Datum
     976                 :           0 : ts_rankcd_wtt(PG_FUNCTION_ARGS)
     977                 :             : {
     978                 :           0 :         ArrayType  *win = (ArrayType *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
     979                 :           0 :         TSVector        txt = PG_GETARG_TSVECTOR(1);
     980                 :           0 :         TSQuery         query = PG_GETARG_TSQUERY(2);
     981                 :           0 :         float           weights[NUM_WEIGHTS];
     982                 :           0 :         float           res;
     983                 :             : 
     984                 :           0 :         getWeights(win, weights);
     985                 :           0 :         res = calc_rank_cd(weights, txt, query, DEF_NORM_METHOD);
     986                 :             : 
     987         [ #  # ]:           0 :         PG_FREE_IF_COPY(win, 0);
     988         [ #  # ]:           0 :         PG_FREE_IF_COPY(txt, 1);
     989         [ #  # ]:           0 :         PG_FREE_IF_COPY(query, 2);
     990                 :           0 :         PG_RETURN_FLOAT4(res);
     991                 :           0 : }
     992                 :             : 
     993                 :             : Datum
     994                 :           0 : ts_rankcd_ttf(PG_FUNCTION_ARGS)
     995                 :             : {
     996                 :           0 :         TSVector        txt = PG_GETARG_TSVECTOR(0);
     997                 :           0 :         TSQuery         query = PG_GETARG_TSQUERY(1);
     998                 :           0 :         int                     method = PG_GETARG_INT32(2);
     999                 :           0 :         float           res;
    1000                 :             : 
    1001                 :           0 :         res = calc_rank_cd(default_weights, txt, query, method);
    1002                 :             : 
    1003         [ #  # ]:           0 :         PG_FREE_IF_COPY(txt, 0);
    1004         [ #  # ]:           0 :         PG_FREE_IF_COPY(query, 1);
    1005                 :           0 :         PG_RETURN_FLOAT4(res);
    1006                 :           0 : }
    1007                 :             : 
    1008                 :             : Datum
    1009                 :          26 : ts_rankcd_tt(PG_FUNCTION_ARGS)
    1010                 :             : {
    1011                 :          26 :         TSVector        txt = PG_GETARG_TSVECTOR(0);
    1012                 :          26 :         TSQuery         query = PG_GETARG_TSQUERY(1);
    1013                 :          26 :         float           res;
    1014                 :             : 
    1015                 :          26 :         res = calc_rank_cd(default_weights, txt, query, DEF_NORM_METHOD);
    1016                 :             : 
    1017         [ +  - ]:          26 :         PG_FREE_IF_COPY(txt, 0);
    1018         [ +  - ]:          26 :         PG_FREE_IF_COPY(query, 1);
    1019                 :          52 :         PG_RETURN_FLOAT4(res);
    1020                 :          26 : }
        

Generated by: LCOV version 2.3.2-1