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