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

Generated by: LCOV version 1.14