LCOV - code coverage report
Current view: top level - src/backend/utils/adt - tsquery_op.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 144 160 90.0 %
Date: 2024-04-25 16:11:28 Functions: 19 20 95.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * tsquery_op.c
       4             :  *    Various operations with tsquery
       5             :  *
       6             :  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
       7             :  *
       8             :  *
       9             :  * IDENTIFICATION
      10             :  *    src/backend/utils/adt/tsquery_op.c
      11             :  *
      12             :  *-------------------------------------------------------------------------
      13             :  */
      14             : 
      15             : #include "postgres.h"
      16             : 
      17             : #include "lib/qunique.h"
      18             : #include "tsearch/ts_utils.h"
      19             : #include "utils/fmgrprotos.h"
      20             : #include "varatt.h"
      21             : 
      22             : Datum
      23          18 : tsquery_numnode(PG_FUNCTION_ARGS)
      24             : {
      25          18 :     TSQuery     query = PG_GETARG_TSQUERY(0);
      26          18 :     int         nnode = query->size;
      27             : 
      28          18 :     PG_FREE_IF_COPY(query, 0);
      29          18 :     PG_RETURN_INT32(nnode);
      30             : }
      31             : 
      32             : static QTNode *
      33         108 : join_tsqueries(TSQuery a, TSQuery b, int8 operator, uint16 distance)
      34             : {
      35         108 :     QTNode     *res = (QTNode *) palloc0(sizeof(QTNode));
      36             : 
      37         108 :     res->flags |= QTN_NEEDFREE;
      38             : 
      39         108 :     res->valnode = (QueryItem *) palloc0(sizeof(QueryItem));
      40         108 :     res->valnode->type = QI_OPR;
      41         108 :     res->valnode->qoperator.oper = operator;
      42         108 :     if (operator == OP_PHRASE)
      43          48 :         res->valnode->qoperator.distance = distance;
      44             : 
      45         108 :     res->child = (QTNode **) palloc0(sizeof(QTNode *) * 2);
      46         108 :     res->child[0] = QT2QTN(GETQUERY(b), GETOPERAND(b));
      47         108 :     res->child[1] = QT2QTN(GETQUERY(a), GETOPERAND(a));
      48         108 :     res->nchild = 2;
      49             : 
      50         108 :     return res;
      51             : }
      52             : 
      53             : Datum
      54          36 : tsquery_and(PG_FUNCTION_ARGS)
      55             : {
      56          36 :     TSQuery     a = PG_GETARG_TSQUERY_COPY(0);
      57          36 :     TSQuery     b = PG_GETARG_TSQUERY_COPY(1);
      58             :     QTNode     *res;
      59             :     TSQuery     query;
      60             : 
      61          36 :     if (a->size == 0)
      62             :     {
      63           0 :         PG_FREE_IF_COPY(a, 1);
      64           0 :         PG_RETURN_POINTER(b);
      65             :     }
      66          36 :     else if (b->size == 0)
      67             :     {
      68           0 :         PG_FREE_IF_COPY(b, 1);
      69           0 :         PG_RETURN_POINTER(a);
      70             :     }
      71             : 
      72          36 :     res = join_tsqueries(a, b, OP_AND, 0);
      73             : 
      74          36 :     query = QTN2QT(res);
      75             : 
      76          36 :     QTNFree(res);
      77          36 :     PG_FREE_IF_COPY(a, 0);
      78          36 :     PG_FREE_IF_COPY(b, 1);
      79             : 
      80          36 :     PG_RETURN_TSQUERY(query);
      81             : }
      82             : 
      83             : Datum
      84          24 : tsquery_or(PG_FUNCTION_ARGS)
      85             : {
      86          24 :     TSQuery     a = PG_GETARG_TSQUERY_COPY(0);
      87          24 :     TSQuery     b = PG_GETARG_TSQUERY_COPY(1);
      88             :     QTNode     *res;
      89             :     TSQuery     query;
      90             : 
      91          24 :     if (a->size == 0)
      92             :     {
      93           0 :         PG_FREE_IF_COPY(a, 1);
      94           0 :         PG_RETURN_POINTER(b);
      95             :     }
      96          24 :     else if (b->size == 0)
      97             :     {
      98           0 :         PG_FREE_IF_COPY(b, 1);
      99           0 :         PG_RETURN_POINTER(a);
     100             :     }
     101             : 
     102          24 :     res = join_tsqueries(a, b, OP_OR, 0);
     103             : 
     104          24 :     query = QTN2QT(res);
     105             : 
     106          24 :     QTNFree(res);
     107          24 :     PG_FREE_IF_COPY(a, 0);
     108          24 :     PG_FREE_IF_COPY(b, 1);
     109             : 
     110          24 :     PG_RETURN_TSQUERY(query);
     111             : }
     112             : 
     113             : Datum
     114          48 : tsquery_phrase_distance(PG_FUNCTION_ARGS)
     115             : {
     116          48 :     TSQuery     a = PG_GETARG_TSQUERY_COPY(0);
     117          48 :     TSQuery     b = PG_GETARG_TSQUERY_COPY(1);
     118             :     QTNode     *res;
     119             :     TSQuery     query;
     120          48 :     int32       distance = PG_GETARG_INT32(2);
     121             : 
     122          48 :     if (distance < 0 || distance > MAXENTRYPOS)
     123           0 :         ereport(ERROR,
     124             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     125             :                  errmsg("distance in phrase operator must be an integer value between zero and %d inclusive",
     126             :                         MAXENTRYPOS)));
     127          48 :     if (a->size == 0)
     128             :     {
     129           0 :         PG_FREE_IF_COPY(a, 1);
     130           0 :         PG_RETURN_POINTER(b);
     131             :     }
     132          48 :     else if (b->size == 0)
     133             :     {
     134           0 :         PG_FREE_IF_COPY(b, 1);
     135           0 :         PG_RETURN_POINTER(a);
     136             :     }
     137             : 
     138          48 :     res = join_tsqueries(a, b, OP_PHRASE, (uint16) distance);
     139             : 
     140          48 :     query = QTN2QT(res);
     141             : 
     142          48 :     QTNFree(res);
     143          48 :     PG_FREE_IF_COPY(a, 0);
     144          48 :     PG_FREE_IF_COPY(b, 1);
     145             : 
     146          48 :     PG_RETURN_TSQUERY(query);
     147             : }
     148             : 
     149             : Datum
     150          42 : tsquery_phrase(PG_FUNCTION_ARGS)
     151             : {
     152          42 :     PG_RETURN_DATUM(DirectFunctionCall3(tsquery_phrase_distance,
     153             :                                         PG_GETARG_DATUM(0),
     154             :                                         PG_GETARG_DATUM(1),
     155             :                                         Int32GetDatum(1)));
     156             : }
     157             : 
     158             : Datum
     159          12 : tsquery_not(PG_FUNCTION_ARGS)
     160             : {
     161          12 :     TSQuery     a = PG_GETARG_TSQUERY_COPY(0);
     162             :     QTNode     *res;
     163             :     TSQuery     query;
     164             : 
     165          12 :     if (a->size == 0)
     166           0 :         PG_RETURN_POINTER(a);
     167             : 
     168          12 :     res = (QTNode *) palloc0(sizeof(QTNode));
     169             : 
     170          12 :     res->flags |= QTN_NEEDFREE;
     171             : 
     172          12 :     res->valnode = (QueryItem *) palloc0(sizeof(QueryItem));
     173          12 :     res->valnode->type = QI_OPR;
     174          12 :     res->valnode->qoperator.oper = OP_NOT;
     175             : 
     176          12 :     res->child = (QTNode **) palloc0(sizeof(QTNode *));
     177          12 :     res->child[0] = QT2QTN(GETQUERY(a), GETOPERAND(a));
     178          12 :     res->nchild = 1;
     179             : 
     180          12 :     query = QTN2QT(res);
     181             : 
     182          12 :     QTNFree(res);
     183          12 :     PG_FREE_IF_COPY(a, 0);
     184             : 
     185          12 :     PG_RETURN_POINTER(query);
     186             : }
     187             : 
     188             : static int
     189         392 : CompareTSQ(TSQuery a, TSQuery b)
     190             : {
     191         392 :     if (a->size != b->size)
     192             :     {
     193         156 :         return (a->size < b->size) ? -1 : 1;
     194             :     }
     195         236 :     else if (VARSIZE(a) != VARSIZE(b))
     196             :     {
     197         156 :         return (VARSIZE(a) < VARSIZE(b)) ? -1 : 1;
     198             :     }
     199          80 :     else if (a->size != 0)
     200             :     {
     201          80 :         QTNode     *an = QT2QTN(GETQUERY(a), GETOPERAND(a));
     202          80 :         QTNode     *bn = QT2QTN(GETQUERY(b), GETOPERAND(b));
     203          80 :         int         res = QTNodeCompare(an, bn);
     204             : 
     205          80 :         QTNFree(an);
     206          80 :         QTNFree(bn);
     207             : 
     208          80 :         return res;
     209             :     }
     210             : 
     211           0 :     return 0;
     212             : }
     213             : 
     214             : Datum
     215         114 : tsquery_cmp(PG_FUNCTION_ARGS)
     216             : {
     217         114 :     TSQuery     a = PG_GETARG_TSQUERY_COPY(0);
     218         114 :     TSQuery     b = PG_GETARG_TSQUERY_COPY(1);
     219         114 :     int         res = CompareTSQ(a, b);
     220             : 
     221         114 :     PG_FREE_IF_COPY(a, 0);
     222         114 :     PG_FREE_IF_COPY(b, 1);
     223             : 
     224         114 :     PG_RETURN_INT32(res);
     225             : }
     226             : 
     227             : #define CMPFUNC( NAME, CONDITION )              \
     228             : Datum                                           \
     229             : NAME(PG_FUNCTION_ARGS) {                        \
     230             :     TSQuery  a = PG_GETARG_TSQUERY_COPY(0);     \
     231             :     TSQuery  b = PG_GETARG_TSQUERY_COPY(1);     \
     232             :     int res = CompareTSQ(a,b);                  \
     233             :                                                 \
     234             :     PG_FREE_IF_COPY(a,0);                       \
     235             :     PG_FREE_IF_COPY(b,1);                       \
     236             :                                                 \
     237             :     PG_RETURN_BOOL( CONDITION );                \
     238             : }   \
     239             : /* keep compiler quiet - no extra ; */          \
     240             : extern int no_such_variable
     241             : 
     242          78 : CMPFUNC(tsquery_lt, res < 0);
     243          60 : CMPFUNC(tsquery_le, res <= 0);
     244          50 : CMPFUNC(tsquery_eq, res == 0);
     245          42 : CMPFUNC(tsquery_ge, res >= 0);
     246          48 : CMPFUNC(tsquery_gt, res > 0);
     247           0 : CMPFUNC(tsquery_ne, res != 0);
     248             : 
     249             : TSQuerySign
     250         180 : makeTSQuerySign(TSQuery a)
     251             : {
     252             :     int         i;
     253         180 :     QueryItem  *ptr = GETQUERY(a);
     254         180 :     TSQuerySign sign = 0;
     255             : 
     256         444 :     for (i = 0; i < a->size; i++)
     257             :     {
     258         264 :         if (ptr->type == QI_VAL)
     259         222 :             sign |= ((TSQuerySign) 1) << (((unsigned int) ptr->qoperand.valcrc) % TSQS_SIGLEN);
     260         264 :         ptr++;
     261             :     }
     262             : 
     263         180 :     return sign;
     264             : }
     265             : 
     266             : static char **
     267         324 : collectTSQueryValues(TSQuery a, int *nvalues_p)
     268             : {
     269         324 :     QueryItem  *ptr = GETQUERY(a);
     270         324 :     char       *operand = GETOPERAND(a);
     271             :     char      **values;
     272         324 :     int         nvalues = 0;
     273             :     int         i;
     274             : 
     275         324 :     values = (char **) palloc(sizeof(char *) * a->size);
     276             : 
     277         996 :     for (i = 0; i < a->size; i++)
     278             :     {
     279         672 :         if (ptr->type == QI_VAL)
     280             :         {
     281         498 :             int         len = ptr->qoperand.length;
     282             :             char       *val;
     283             : 
     284         498 :             val = palloc(len + 1);
     285         498 :             memcpy(val, operand + ptr->qoperand.distance, len);
     286         498 :             val[len] = '\0';
     287             : 
     288         498 :             values[nvalues++] = val;
     289             :         }
     290         672 :         ptr++;
     291             :     }
     292             : 
     293         324 :     *nvalues_p = nvalues;
     294         324 :     return values;
     295             : }
     296             : 
     297             : static int
     298         396 : cmp_string(const void *a, const void *b)
     299             : {
     300         396 :     const char *sa = *((char *const *) a);
     301         396 :     const char *sb = *((char *const *) b);
     302             : 
     303         396 :     return strcmp(sa, sb);
     304             : }
     305             : 
     306             : Datum
     307         162 : tsq_mcontains(PG_FUNCTION_ARGS)
     308             : {
     309         162 :     TSQuery     query = PG_GETARG_TSQUERY(0);
     310         162 :     TSQuery     ex = PG_GETARG_TSQUERY(1);
     311             :     char      **query_values;
     312             :     int         query_nvalues;
     313             :     char      **ex_values;
     314             :     int         ex_nvalues;
     315         162 :     bool        result = true;
     316             : 
     317             :     /* Extract the query terms into arrays */
     318         162 :     query_values = collectTSQueryValues(query, &query_nvalues);
     319         162 :     ex_values = collectTSQueryValues(ex, &ex_nvalues);
     320             : 
     321             :     /* Sort and remove duplicates from both arrays */
     322         162 :     qsort(query_values, query_nvalues, sizeof(char *), cmp_string);
     323         162 :     query_nvalues = qunique(query_values, query_nvalues, sizeof(char *),
     324             :                             cmp_string);
     325         162 :     qsort(ex_values, ex_nvalues, sizeof(char *), cmp_string);
     326         162 :     ex_nvalues = qunique(ex_values, ex_nvalues, sizeof(char *), cmp_string);
     327             : 
     328         162 :     if (ex_nvalues > query_nvalues)
     329          60 :         result = false;
     330             :     else
     331             :     {
     332             :         int         i;
     333         102 :         int         j = 0;
     334             : 
     335         138 :         for (i = 0; i < ex_nvalues; i++)
     336             :         {
     337         246 :             for (; j < query_nvalues; j++)
     338             :             {
     339         180 :                 if (strcmp(ex_values[i], query_values[j]) == 0)
     340          36 :                     break;
     341             :             }
     342         102 :             if (j == query_nvalues)
     343             :             {
     344          66 :                 result = false;
     345          66 :                 break;
     346             :             }
     347             :         }
     348             :     }
     349             : 
     350         162 :     PG_RETURN_BOOL(result);
     351             : }
     352             : 
     353             : Datum
     354          78 : tsq_mcontained(PG_FUNCTION_ARGS)
     355             : {
     356          78 :     PG_RETURN_DATUM(DirectFunctionCall2(tsq_mcontains,
     357             :                                         PG_GETARG_DATUM(1),
     358             :                                         PG_GETARG_DATUM(0)));
     359             : }

Generated by: LCOV version 1.14