LCOV - code coverage report
Current view: top level - src/backend/utils/adt - tsginidx.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 81.6 % 125 102
Test Date: 2026-03-01 15:14:58 Functions: 58.3 % 12 7
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * tsginidx.c
       4              :  *   GIN support functions for tsvector_ops
       5              :  *
       6              :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       7              :  *
       8              :  *
       9              :  * IDENTIFICATION
      10              :  *    src/backend/utils/adt/tsginidx.c
      11              :  *
      12              :  *-------------------------------------------------------------------------
      13              :  */
      14              : #include "postgres.h"
      15              : 
      16              : #include "access/gin.h"
      17              : #include "tsearch/ts_type.h"
      18              : #include "tsearch/ts_utils.h"
      19              : #include "utils/builtins.h"
      20              : #include "varatt.h"
      21              : 
      22              : 
      23              : Datum
      24       936624 : gin_cmp_tslexeme(PG_FUNCTION_ARGS)
      25              : {
      26       936624 :     text       *a = PG_GETARG_TEXT_PP(0);
      27       936624 :     text       *b = PG_GETARG_TEXT_PP(1);
      28              :     int         cmp;
      29              : 
      30       936624 :     cmp = tsCompareString(VARDATA_ANY(a), VARSIZE_ANY_EXHDR(a),
      31       936624 :                           VARDATA_ANY(b), VARSIZE_ANY_EXHDR(b),
      32              :                           false);
      33              : 
      34       936624 :     PG_FREE_IF_COPY(a, 0);
      35       936624 :     PG_FREE_IF_COPY(b, 1);
      36       936624 :     PG_RETURN_INT32(cmp);
      37              : }
      38              : 
      39              : Datum
      40          222 : gin_cmp_prefix(PG_FUNCTION_ARGS)
      41              : {
      42          222 :     text       *a = PG_GETARG_TEXT_PP(0);
      43          222 :     text       *b = PG_GETARG_TEXT_PP(1);
      44              : 
      45              : #ifdef NOT_USED
      46              :     StrategyNumber strategy = PG_GETARG_UINT16(2);
      47              :     Pointer     extra_data = PG_GETARG_POINTER(3);
      48              : #endif
      49              :     int         cmp;
      50              : 
      51          222 :     cmp = tsCompareString(VARDATA_ANY(a), VARSIZE_ANY_EXHDR(a),
      52          222 :                           VARDATA_ANY(b), VARSIZE_ANY_EXHDR(b),
      53              :                           true);
      54              : 
      55          222 :     if (cmp < 0)
      56            6 :         cmp = 1;                /* prevent continue scan */
      57              : 
      58          222 :     PG_FREE_IF_COPY(a, 0);
      59          222 :     PG_FREE_IF_COPY(b, 1);
      60          222 :     PG_RETURN_INT32(cmp);
      61              : }
      62              : 
      63              : Datum
      64         1548 : gin_extract_tsvector(PG_FUNCTION_ARGS)
      65              : {
      66         1548 :     TSVector    vector = PG_GETARG_TSVECTOR(0);
      67         1548 :     int32      *nentries = (int32 *) PG_GETARG_POINTER(1);
      68         1548 :     Datum      *entries = NULL;
      69              : 
      70         1548 :     *nentries = vector->size;
      71         1548 :     if (vector->size > 0)
      72              :     {
      73              :         int         i;
      74         1521 :         WordEntry  *we = ARRPTR(vector);
      75              : 
      76         1521 :         entries = palloc_array(Datum, vector->size);
      77              : 
      78        87987 :         for (i = 0; i < vector->size; i++)
      79              :         {
      80              :             text       *txt;
      81              : 
      82        86466 :             txt = cstring_to_text_with_len(STRPTR(vector) + we->pos, we->len);
      83        86466 :             entries[i] = PointerGetDatum(txt);
      84              : 
      85        86466 :             we++;
      86              :         }
      87              :     }
      88              : 
      89         1548 :     PG_FREE_IF_COPY(vector, 0);
      90         1548 :     PG_RETURN_POINTER(entries);
      91              : }
      92              : 
      93              : Datum
      94          225 : gin_extract_tsquery(PG_FUNCTION_ARGS)
      95              : {
      96          225 :     TSQuery     query = PG_GETARG_TSQUERY(0);
      97          225 :     int32      *nentries = (int32 *) PG_GETARG_POINTER(1);
      98              : #ifdef NOT_USED
      99              :     StrategyNumber strategy = PG_GETARG_UINT16(2);
     100              : #endif
     101          225 :     bool      **ptr_partialmatch = (bool **) PG_GETARG_POINTER(3);
     102          225 :     Pointer   **extra_data = (Pointer **) PG_GETARG_POINTER(4);
     103              : #ifdef NOT_USED
     104              :     bool      **nullFlags = (bool **) PG_GETARG_POINTER(5);
     105              : #endif
     106          225 :     int32      *searchMode = (int32 *) PG_GETARG_POINTER(6);
     107          225 :     Datum      *entries = NULL;
     108              : 
     109          225 :     *nentries = 0;
     110              : 
     111          225 :     if (query->size > 0)
     112              :     {
     113          225 :         QueryItem  *item = GETQUERY(query);
     114              :         int32       i,
     115              :                     j;
     116              :         bool       *partialmatch;
     117              :         int        *map_item_operand;
     118              : 
     119              :         /*
     120              :          * If the query doesn't have any required positive matches (for
     121              :          * instance, it's something like '! foo'), we have to do a full index
     122              :          * scan.
     123              :          */
     124          225 :         if (tsquery_requires_match(item))
     125          165 :             *searchMode = GIN_SEARCH_MODE_DEFAULT;
     126              :         else
     127           60 :             *searchMode = GIN_SEARCH_MODE_ALL;
     128              : 
     129              :         /* count number of VAL items */
     130          225 :         j = 0;
     131          852 :         for (i = 0; i < query->size; i++)
     132              :         {
     133          627 :             if (item[i].type == QI_VAL)
     134          384 :                 j++;
     135              :         }
     136          225 :         *nentries = j;
     137              : 
     138          225 :         entries = palloc_array(Datum, j);
     139          225 :         partialmatch = *ptr_partialmatch = palloc_array(bool, j);
     140              : 
     141              :         /*
     142              :          * Make map to convert item's number to corresponding operand's (the
     143              :          * same, entry's) number. Entry's number is used in check array in
     144              :          * consistent method. We use the same map for each entry.
     145              :          */
     146          225 :         *extra_data = palloc_array(Pointer, j);
     147          225 :         map_item_operand = palloc0_array(int, query->size);
     148              : 
     149              :         /* Now rescan the VAL items and fill in the arrays */
     150          225 :         j = 0;
     151          852 :         for (i = 0; i < query->size; i++)
     152              :         {
     153          627 :             if (item[i].type == QI_VAL)
     154              :             {
     155          384 :                 QueryOperand *val = &item[i].qoperand;
     156              :                 text       *txt;
     157              : 
     158          384 :                 txt = cstring_to_text_with_len(GETOPERAND(query) + val->distance,
     159          384 :                                                val->length);
     160          384 :                 entries[j] = PointerGetDatum(txt);
     161          384 :                 partialmatch[j] = val->prefix;
     162          384 :                 (*extra_data)[j] = (Pointer) map_item_operand;
     163          384 :                 map_item_operand[i] = j;
     164          384 :                 j++;
     165              :             }
     166              :         }
     167              :     }
     168              : 
     169          225 :     PG_FREE_IF_COPY(query, 0);
     170              : 
     171          225 :     PG_RETURN_POINTER(entries);
     172              : }
     173              : 
     174              : typedef struct
     175              : {
     176              :     QueryItem  *first_item;
     177              :     GinTernaryValue *check;
     178              :     int        *map_item_operand;
     179              : } GinChkVal;
     180              : 
     181              : /*
     182              :  * TS_execute callback for matching a tsquery operand to GIN index data
     183              :  */
     184              : static TSTernaryValue
     185        24183 : checkcondition_gin(void *checkval, QueryOperand *val, ExecPhraseData *data)
     186              : {
     187        24183 :     GinChkVal  *gcv = (GinChkVal *) checkval;
     188              :     int         j;
     189              :     GinTernaryValue result;
     190              : 
     191              :     /* convert item's number to corresponding entry's (operand's) number */
     192        24183 :     j = gcv->map_item_operand[((QueryItem *) val) - gcv->first_item];
     193              : 
     194              :     /* determine presence of current entry in indexed value */
     195        24183 :     result = gcv->check[j];
     196              : 
     197              :     /*
     198              :      * If any val requiring a weight is used or caller needs position
     199              :      * information then we must recheck, so replace TRUE with MAYBE.
     200              :      */
     201        24183 :     if (result == GIN_TRUE)
     202              :     {
     203         7827 :         if (val->weight != 0 || data != NULL)
     204         3249 :             result = GIN_MAYBE;
     205              :     }
     206              : 
     207              :     /*
     208              :      * We rely on GinTernaryValue and TSTernaryValue using equivalent value
     209              :      * assignments.  We could use a switch statement to map the values if that
     210              :      * ever stops being true, but it seems unlikely to happen.
     211              :      */
     212        24183 :     return (TSTernaryValue) result;
     213              : }
     214              : 
     215              : Datum
     216           12 : gin_tsquery_consistent(PG_FUNCTION_ARGS)
     217              : {
     218           12 :     bool       *check = (bool *) PG_GETARG_POINTER(0);
     219              : #ifdef NOT_USED
     220              :     StrategyNumber strategy = PG_GETARG_UINT16(1);
     221              : #endif
     222           12 :     TSQuery     query = PG_GETARG_TSQUERY(2);
     223              : #ifdef NOT_USED
     224              :     int32       nkeys = PG_GETARG_INT32(3);
     225              : #endif
     226           12 :     Pointer    *extra_data = (Pointer *) PG_GETARG_POINTER(4);
     227           12 :     bool       *recheck = (bool *) PG_GETARG_POINTER(5);
     228           12 :     bool        res = false;
     229              : 
     230              :     /* Initially assume query doesn't require recheck */
     231           12 :     *recheck = false;
     232              : 
     233           12 :     if (query->size > 0)
     234              :     {
     235              :         GinChkVal   gcv;
     236              : 
     237              :         /*
     238              :          * check-parameter array has one entry for each value (operand) in the
     239              :          * query.
     240              :          */
     241           12 :         gcv.first_item = GETQUERY(query);
     242           12 :         gcv.check = (GinTernaryValue *) check;
     243           12 :         gcv.map_item_operand = (int *) (extra_data[0]);
     244              : 
     245           12 :         switch (TS_execute_ternary(GETQUERY(query),
     246              :                                    &gcv,
     247              :                                    TS_EXEC_PHRASE_NO_POS,
     248              :                                    checkcondition_gin))
     249              :         {
     250            0 :             case TS_NO:
     251            0 :                 res = false;
     252            0 :                 break;
     253           12 :             case TS_YES:
     254           12 :                 res = true;
     255           12 :                 break;
     256            0 :             case TS_MAYBE:
     257            0 :                 res = true;
     258            0 :                 *recheck = true;
     259            0 :                 break;
     260              :         }
     261              :     }
     262              : 
     263           12 :     PG_RETURN_BOOL(res);
     264              : }
     265              : 
     266              : Datum
     267        18459 : gin_tsquery_triconsistent(PG_FUNCTION_ARGS)
     268              : {
     269        18459 :     GinTernaryValue *check = (GinTernaryValue *) PG_GETARG_POINTER(0);
     270              : #ifdef NOT_USED
     271              :     StrategyNumber strategy = PG_GETARG_UINT16(1);
     272              : #endif
     273        18459 :     TSQuery     query = PG_GETARG_TSQUERY(2);
     274              : #ifdef NOT_USED
     275              :     int32       nkeys = PG_GETARG_INT32(3);
     276              : #endif
     277        18459 :     Pointer    *extra_data = (Pointer *) PG_GETARG_POINTER(4);
     278        18459 :     GinTernaryValue res = GIN_FALSE;
     279              : 
     280        18459 :     if (query->size > 0)
     281              :     {
     282              :         GinChkVal   gcv;
     283              : 
     284              :         /*
     285              :          * check-parameter array has one entry for each value (operand) in the
     286              :          * query.
     287              :          */
     288        18459 :         gcv.first_item = GETQUERY(query);
     289        18459 :         gcv.check = check;
     290        18459 :         gcv.map_item_operand = (int *) (extra_data[0]);
     291              : 
     292        18459 :         res = TS_execute_ternary(GETQUERY(query),
     293              :                                  &gcv,
     294              :                                  TS_EXEC_PHRASE_NO_POS,
     295              :                                  checkcondition_gin);
     296              :     }
     297              : 
     298        18459 :     PG_RETURN_GIN_TERNARY_VALUE(res);
     299              : }
     300              : 
     301              : /*
     302              :  * Formerly, gin_extract_tsvector had only two arguments.  Now it has three,
     303              :  * but we still need a pg_proc entry with two args to support reloading
     304              :  * pre-9.1 contrib/tsearch2 opclass declarations.  This compatibility
     305              :  * function should go away eventually.  (Note: you might say "hey, but the
     306              :  * code above is only *using* two args, so let's just declare it that way".
     307              :  * If you try that you'll find the opr_sanity regression test complains.)
     308              :  */
     309              : Datum
     310            0 : gin_extract_tsvector_2args(PG_FUNCTION_ARGS)
     311              : {
     312            0 :     if (PG_NARGS() < 3)          /* should not happen */
     313            0 :         elog(ERROR, "gin_extract_tsvector requires three arguments");
     314            0 :     return gin_extract_tsvector(fcinfo);
     315              : }
     316              : 
     317              : /*
     318              :  * Likewise, we need a stub version of gin_extract_tsquery declared with
     319              :  * only five arguments.
     320              :  */
     321              : Datum
     322            0 : gin_extract_tsquery_5args(PG_FUNCTION_ARGS)
     323              : {
     324            0 :     if (PG_NARGS() < 7)          /* should not happen */
     325            0 :         elog(ERROR, "gin_extract_tsquery requires seven arguments");
     326            0 :     return gin_extract_tsquery(fcinfo);
     327              : }
     328              : 
     329              : /*
     330              :  * Likewise, we need a stub version of gin_tsquery_consistent declared with
     331              :  * only six arguments.
     332              :  */
     333              : Datum
     334            0 : gin_tsquery_consistent_6args(PG_FUNCTION_ARGS)
     335              : {
     336            0 :     if (PG_NARGS() < 8)          /* should not happen */
     337            0 :         elog(ERROR, "gin_tsquery_consistent requires eight arguments");
     338            0 :     return gin_tsquery_consistent(fcinfo);
     339              : }
     340              : 
     341              : /*
     342              :  * Likewise, a stub version of gin_extract_tsquery declared with argument
     343              :  * types that are no longer considered appropriate.
     344              :  */
     345              : Datum
     346            0 : gin_extract_tsquery_oldsig(PG_FUNCTION_ARGS)
     347              : {
     348            0 :     return gin_extract_tsquery(fcinfo);
     349              : }
     350              : 
     351              : /*
     352              :  * Likewise, a stub version of gin_tsquery_consistent declared with argument
     353              :  * types that are no longer considered appropriate.
     354              :  */
     355              : Datum
     356            0 : gin_tsquery_consistent_oldsig(PG_FUNCTION_ARGS)
     357              : {
     358            0 :     return gin_tsquery_consistent(fcinfo);
     359              : }
        

Generated by: LCOV version 2.0-1