LCOV - code coverage report
Current view: top level - src/backend/utils/adt - tsquery_op.c (source / functions) Hit Total Coverage
Test: PostgreSQL 12beta2 Lines: 154 170 90.6 %
Date: 2019-06-19 14:06:47 Functions: 20 21 95.2 %
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-2019, 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 "tsearch/ts_utils.h"
      18             : #include "utils/builtins.h"
      19             : 
      20             : Datum
      21          12 : tsquery_numnode(PG_FUNCTION_ARGS)
      22             : {
      23          12 :     TSQuery     query = PG_GETARG_TSQUERY(0);
      24          12 :     int         nnode = query->size;
      25             : 
      26          12 :     PG_FREE_IF_COPY(query, 0);
      27          12 :     PG_RETURN_INT32(nnode);
      28             : }
      29             : 
      30             : static QTNode *
      31          64 : join_tsqueries(TSQuery a, TSQuery b, int8 operator, uint16 distance)
      32             : {
      33          64 :     QTNode     *res = (QTNode *) palloc0(sizeof(QTNode));
      34             : 
      35          64 :     res->flags |= QTN_NEEDFREE;
      36             : 
      37          64 :     res->valnode = (QueryItem *) palloc0(sizeof(QueryItem));
      38          64 :     res->valnode->type = QI_OPR;
      39          64 :     res->valnode->qoperator.oper = operator;
      40          64 :     if (operator == OP_PHRASE)
      41          32 :         res->valnode->qoperator.distance = distance;
      42             : 
      43          64 :     res->child = (QTNode **) palloc0(sizeof(QTNode *) * 2);
      44          64 :     res->child[0] = QT2QTN(GETQUERY(b), GETOPERAND(b));
      45          64 :     res->child[1] = QT2QTN(GETQUERY(a), GETOPERAND(a));
      46          64 :     res->nchild = 2;
      47             : 
      48          64 :     return res;
      49             : }
      50             : 
      51             : Datum
      52          16 : tsquery_and(PG_FUNCTION_ARGS)
      53             : {
      54          16 :     TSQuery     a = PG_GETARG_TSQUERY_COPY(0);
      55          16 :     TSQuery     b = PG_GETARG_TSQUERY_COPY(1);
      56             :     QTNode     *res;
      57             :     TSQuery     query;
      58             : 
      59          16 :     if (a->size == 0)
      60             :     {
      61           0 :         PG_FREE_IF_COPY(a, 1);
      62           0 :         PG_RETURN_POINTER(b);
      63             :     }
      64          16 :     else if (b->size == 0)
      65             :     {
      66           0 :         PG_FREE_IF_COPY(b, 1);
      67           0 :         PG_RETURN_POINTER(a);
      68             :     }
      69             : 
      70          16 :     res = join_tsqueries(a, b, OP_AND, 0);
      71             : 
      72          16 :     query = QTN2QT(res);
      73             : 
      74          16 :     QTNFree(res);
      75          16 :     PG_FREE_IF_COPY(a, 0);
      76          16 :     PG_FREE_IF_COPY(b, 1);
      77             : 
      78          16 :     PG_RETURN_TSQUERY(query);
      79             : }
      80             : 
      81             : Datum
      82          16 : tsquery_or(PG_FUNCTION_ARGS)
      83             : {
      84          16 :     TSQuery     a = PG_GETARG_TSQUERY_COPY(0);
      85          16 :     TSQuery     b = PG_GETARG_TSQUERY_COPY(1);
      86             :     QTNode     *res;
      87             :     TSQuery     query;
      88             : 
      89          16 :     if (a->size == 0)
      90             :     {
      91           0 :         PG_FREE_IF_COPY(a, 1);
      92           0 :         PG_RETURN_POINTER(b);
      93             :     }
      94          16 :     else if (b->size == 0)
      95             :     {
      96           0 :         PG_FREE_IF_COPY(b, 1);
      97           0 :         PG_RETURN_POINTER(a);
      98             :     }
      99             : 
     100          16 :     res = join_tsqueries(a, b, OP_OR, 0);
     101             : 
     102          16 :     query = QTN2QT(res);
     103             : 
     104          16 :     QTNFree(res);
     105          16 :     PG_FREE_IF_COPY(a, 0);
     106          16 :     PG_FREE_IF_COPY(b, 1);
     107             : 
     108          16 :     PG_RETURN_TSQUERY(query);
     109             : }
     110             : 
     111             : Datum
     112          32 : tsquery_phrase_distance(PG_FUNCTION_ARGS)
     113             : {
     114          32 :     TSQuery     a = PG_GETARG_TSQUERY_COPY(0);
     115          32 :     TSQuery     b = PG_GETARG_TSQUERY_COPY(1);
     116             :     QTNode     *res;
     117             :     TSQuery     query;
     118          32 :     int32       distance = PG_GETARG_INT32(2);
     119             : 
     120          32 :     if (distance < 0 || distance > MAXENTRYPOS)
     121           0 :         ereport(ERROR,
     122             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     123             :                  errmsg("distance in phrase operator should be non-negative and less than %d",
     124             :                         MAXENTRYPOS)));
     125          32 :     if (a->size == 0)
     126             :     {
     127           0 :         PG_FREE_IF_COPY(a, 1);
     128           0 :         PG_RETURN_POINTER(b);
     129             :     }
     130          32 :     else if (b->size == 0)
     131             :     {
     132           0 :         PG_FREE_IF_COPY(b, 1);
     133           0 :         PG_RETURN_POINTER(a);
     134             :     }
     135             : 
     136          32 :     res = join_tsqueries(a, b, OP_PHRASE, (uint16) distance);
     137             : 
     138          32 :     query = QTN2QT(res);
     139             : 
     140          32 :     QTNFree(res);
     141          32 :     PG_FREE_IF_COPY(a, 0);
     142          32 :     PG_FREE_IF_COPY(b, 1);
     143             : 
     144          32 :     PG_RETURN_TSQUERY(query);
     145             : }
     146             : 
     147             : Datum
     148          28 : tsquery_phrase(PG_FUNCTION_ARGS)
     149             : {
     150          28 :     PG_RETURN_POINTER(DirectFunctionCall3(
     151             :                                           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         448 : CompareTSQ(TSQuery a, TSQuery b)
     189             : {
     190         448 :     if (a->size != b->size)
     191             :     {
     192         234 :         return (a->size < b->size) ? -1 : 1;
     193             :     }
     194         214 :     else if (VARSIZE(a) != VARSIZE(b))
     195             :     {
     196         154 :         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          64 : CMPFUNC(tsquery_lt, res < 0);
     242          44 : 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          96 : makeTSQuerySign(TSQuery a)
     250             : {
     251             :     int         i;
     252          96 :     QueryItem  *ptr = GETQUERY(a);
     253          96 :     TSQuerySign sign = 0;
     254             : 
     255         248 :     for (i = 0; i < a->size; i++)
     256             :     {
     257         152 :         if (ptr->type == QI_VAL)
     258         124 :             sign |= ((TSQuerySign) 1) << (((unsigned int) ptr->qoperand.valcrc) % TSQS_SIGLEN);
     259         152 :         ptr++;
     260             :     }
     261             : 
     262          96 :     return sign;
     263             : }
     264             : 
     265             : static char **
     266         256 : collectTSQueryValues(TSQuery a, int *nvalues_p)
     267             : {
     268         256 :     QueryItem  *ptr = GETQUERY(a);
     269         256 :     char       *operand = GETOPERAND(a);
     270             :     char      **values;
     271         256 :     int         nvalues = 0;
     272             :     int         i;
     273             : 
     274         256 :     values = (char **) palloc(sizeof(char *) * a->size);
     275             : 
     276         796 :     for (i = 0; i < a->size; i++)
     277             :     {
     278         540 :         if (ptr->type == QI_VAL)
     279             :         {
     280         398 :             int         len = ptr->qoperand.length;
     281             :             char       *val;
     282             : 
     283         398 :             val = palloc(len + 1);
     284         398 :             memcpy(val, operand + ptr->qoperand.distance, len);
     285         398 :             val[len] = '\0';
     286             : 
     287         398 :             values[nvalues++] = val;
     288             :         }
     289         540 :         ptr++;
     290             :     }
     291             : 
     292         256 :     *nvalues_p = nvalues;
     293         256 :     return values;
     294             : }
     295             : 
     296             : static int
     297         182 : cmp_string(const void *a, const void *b)
     298             : {
     299         182 :     const char *sa = *((char *const *) a);
     300         182 :     const char *sb = *((char *const *) b);
     301             : 
     302         182 :     return strcmp(sa, sb);
     303             : }
     304             : 
     305             : static int
     306         256 : remove_duplicates(char **strings, int n)
     307             : {
     308         256 :     if (n <= 1)
     309         154 :         return n;
     310             :     else
     311             :     {
     312             :         int         i;
     313         102 :         char       *prev = strings[0];
     314         102 :         int         new_n = 1;
     315             : 
     316         244 :         for (i = 1; i < n; i++)
     317             :         {
     318         142 :             if (strcmp(strings[i], prev) != 0)
     319             :             {
     320         142 :                 strings[new_n++] = strings[i];
     321         142 :                 prev = strings[i];
     322             :             }
     323             :         }
     324         102 :         return new_n;
     325             :     }
     326             : }
     327             : 
     328             : Datum
     329         128 : tsq_mcontains(PG_FUNCTION_ARGS)
     330             : {
     331         128 :     TSQuery     query = PG_GETARG_TSQUERY(0);
     332         128 :     TSQuery     ex = PG_GETARG_TSQUERY(1);
     333             :     char      **query_values;
     334             :     int         query_nvalues;
     335             :     char      **ex_values;
     336             :     int         ex_nvalues;
     337         128 :     bool        result = true;
     338             : 
     339             :     /* Extract the query terms into arrays */
     340         128 :     query_values = collectTSQueryValues(query, &query_nvalues);
     341         128 :     ex_values = collectTSQueryValues(ex, &ex_nvalues);
     342             : 
     343             :     /* Sort and remove duplicates from both arrays */
     344         128 :     qsort(query_values, query_nvalues, sizeof(char *), cmp_string);
     345         128 :     query_nvalues = remove_duplicates(query_values, query_nvalues);
     346         128 :     qsort(ex_values, ex_nvalues, sizeof(char *), cmp_string);
     347         128 :     ex_nvalues = remove_duplicates(ex_values, ex_nvalues);
     348             : 
     349         128 :     if (ex_nvalues > query_nvalues)
     350          40 :         result = false;
     351             :     else
     352             :     {
     353             :         int         i;
     354          88 :         int         j = 0;
     355             : 
     356         112 :         for (i = 0; i < ex_nvalues; i++)
     357             :         {
     358         230 :             for (; j < query_nvalues; j++)
     359             :             {
     360         166 :                 if (strcmp(ex_values[i], query_values[j]) == 0)
     361          24 :                     break;
     362             :             }
     363          88 :             if (j == query_nvalues)
     364             :             {
     365          64 :                 result = false;
     366          64 :                 break;
     367             :             }
     368             :         }
     369             :     }
     370             : 
     371         128 :     PG_RETURN_BOOL(result);
     372             : }
     373             : 
     374             : Datum
     375          52 : tsq_mcontained(PG_FUNCTION_ARGS)
     376             : {
     377          52 :     PG_RETURN_DATUM(
     378             :                     DirectFunctionCall2(
     379             :                                         tsq_mcontains,
     380             :                                         PG_GETARG_DATUM(1),
     381             :                                         PG_GETARG_DATUM(0)
     382             :                                         )
     383             :         );
     384             : }

Generated by: LCOV version 1.13