LCOV - code coverage report
Current view: top level - src/backend/utils/adt - tsrank.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 73.1 % 435 318
Test Date: 2026-07-22 12:15:41 Functions: 66.7 % 24 16
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 52.3 % 304 159

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

Generated by: LCOV version 2.0-1