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

Generated by: LCOV version 1.13