LCOV - differential code coverage report
Current view: top level - src/backend/utils/adt - tsquery_util.c (source / functions) Coverage Total Hit LBC UIC GIC GNC CBC EUB ECB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 98.9 % 178 176 1 1 110 1 65 2 109 1
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 13 13 13 13
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  * tsquery_util.c
       4                 :  *    Utilities for tsquery datatype
       5                 :  *
       6                 :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
       7                 :  *
       8                 :  *
       9                 :  * IDENTIFICATION
      10                 :  *    src/backend/utils/adt/tsquery_util.c
      11                 :  *
      12                 :  *-------------------------------------------------------------------------
      13                 :  */
      14                 : 
      15                 : #include "postgres.h"
      16                 : 
      17                 : #include "miscadmin.h"
      18                 : #include "tsearch/ts_utils.h"
      19                 : #include "varatt.h"
      20                 : 
      21                 : /*
      22                 :  * Build QTNode tree for a tsquery given in QueryItem array format.
      23                 :  */
      24                 : QTNode *
      25 GIC        4455 : QT2QTN(QueryItem *in, char *operand)
      26 ECB             : {
      27 GIC        4455 :     QTNode     *node = (QTNode *) palloc0(sizeof(QTNode));
      28 ECB             : 
      29                 :     /* since this function recurses, it could be driven to stack overflow. */
      30 GIC        4455 :     check_stack_depth();
      31 ECB             : 
      32 GIC        4455 :     node->valnode = in;
      33 ECB             : 
      34 GIC        4455 :     if (in->type == QI_OPR)
      35 ECB             :     {
      36 GIC        1679 :         node->child = (QTNode **) palloc0(sizeof(QTNode *) * 2);
      37 CBC        1679 :         node->child[0] = QT2QTN(in + 1, operand);
      38            1679 :         node->sign = node->child[0]->sign;
      39            1679 :         if (in->qoperator.oper == OP_NOT)
      40              21 :             node->nchild = 1;
      41 ECB             :         else
      42                 :         {
      43 GIC        1658 :             node->nchild = 2;
      44 CBC        1658 :             node->child[1] = QT2QTN(in + in->qoperator.left, operand);
      45            1658 :             node->sign |= node->child[1]->sign;
      46 ECB             :         }
      47                 :     }
      48 GIC        2776 :     else if (operand)
      49 ECB             :     {
      50 GIC        2776 :         node->word = operand + in->qoperand.distance;
      51 CBC        2776 :         node->sign = ((uint32) 1) << (((unsigned int) in->qoperand.valcrc) % 32);
      52 ECB             :     }
      53                 : 
      54 GIC        4455 :     return node;
      55 ECB             : }
      56                 : 
      57                 : /*
      58                 :  * Free a QTNode tree.
      59                 :  *
      60                 :  * Referenced "word" and "valnode" items are freed if marked as transient
      61                 :  * by flags.
      62                 :  */
      63                 : void
      64 GIC        4920 : QTNFree(QTNode *in)
      65 ECB             : {
      66 GIC        4920 :     if (!in)
      67 CBC           6 :         return;
      68 ECB             : 
      69                 :     /* since this function recurses, it could be driven to stack overflow. */
      70 GIC        4914 :     check_stack_depth();
      71 ECB             : 
      72 GIC        4914 :     if (in->valnode->type == QI_VAL && in->word && (in->flags & QTN_WORDFREE) != 0)
      73 CBC         306 :         pfree(in->word);
      74 ECB             : 
      75 GIC        4914 :     if (in->valnode->type == QI_OPR)
      76 ECB             :     {
      77                 :         int         i;
      78                 : 
      79 GIC        5529 :         for (i = 0; i < in->nchild; i++)
      80 CBC        3697 :             QTNFree(in->child[i]);
      81 ECB             :     }
      82 GIC        4914 :     if (in->child)
      83 CBC        1832 :         pfree(in->child);
      84 ECB             : 
      85 GIC        4914 :     if (in->flags & QTN_NEEDFREE)
      86 CBC         576 :         pfree(in->valnode);
      87 ECB             : 
      88 GIC        4914 :     pfree(in);
      89 ECB             : }
      90                 : 
      91                 : /*
      92                 :  * Sort comparator for QTNodes.
      93                 :  *
      94                 :  * The sort order is somewhat arbitrary.
      95                 :  */
      96                 : int
      97 GIC        2007 : QTNodeCompare(QTNode *an, QTNode *bn)
      98 ECB             : {
      99                 :     /* since this function recurses, it could be driven to stack overflow. */
     100 GIC        2007 :     check_stack_depth();
     101 ECB             : 
     102 GIC        2007 :     if (an->valnode->type != bn->valnode->type)
     103 CBC         591 :         return (an->valnode->type > bn->valnode->type) ? -1 : 1;
     104 ECB             : 
     105 GIC        1416 :     if (an->valnode->type == QI_OPR)
     106 ECB             :     {
     107 GIC         277 :         QueryOperator *ao = &an->valnode->qoperator;
     108 CBC         277 :         QueryOperator *bo = &bn->valnode->qoperator;
     109 ECB             : 
     110 GIC         277 :         if (ao->oper != bo->oper)
     111 CBC          24 :             return (ao->oper > bo->oper) ? -1 : 1;
     112 ECB             : 
     113 GIC         253 :         if (an->nchild != bn->nchild)
     114 CBC          54 :             return (an->nchild > bn->nchild) ? -1 : 1;
     115 ECB             : 
     116                 :         {
     117                 :             int         i,
     118                 :                         res;
     119                 : 
     120 GIC         339 :             for (i = 0; i < an->nchild; i++)
     121 CBC         269 :                 if ((res = QTNodeCompare(an->child[i], bn->child[i])) != 0)
     122             129 :                     return res;
     123 ECB             :         }
     124                 : 
     125 GIC          70 :         if (ao->oper == OP_PHRASE && ao->distance != bo->distance)
     126 CBC           3 :             return (ao->distance > bo->distance) ? -1 : 1;
     127 ECB             : 
     128 GIC          67 :         return 0;
     129 ECB             :     }
     130 GIC        1139 :     else if (an->valnode->type == QI_VAL)
     131 ECB             :     {
     132 GIC        1139 :         QueryOperand *ao = &an->valnode->qoperand;
     133 CBC        1139 :         QueryOperand *bo = &bn->valnode->qoperand;
     134 ECB             : 
     135 GIC        1139 :         if (ao->valcrc != bo->valcrc)
     136 ECB             :         {
     137 GIC         876 :             return (ao->valcrc > bo->valcrc) ? -1 : 1;
     138 ECB             :         }
     139                 : 
     140 GIC         263 :         return tsCompareString(an->word, ao->length, bn->word, bo->length, false);
     141 ECB             :     }
     142                 :     else
     143                 :     {
     144 UIC           0 :         elog(ERROR, "unrecognized QueryItem type: %d", an->valnode->type);
     145 EUB             :         return 0;               /* keep compiler quiet */
     146                 :     }
     147                 : }
     148                 : 
     149                 : /*
     150                 :  * qsort comparator for QTNode pointers.
     151                 :  */
     152                 : static int
     153 GIC        1518 : cmpQTN(const void *a, const void *b)
     154 ECB             : {
     155 GIC        1518 :     return QTNodeCompare(*(QTNode *const *) a, *(QTNode *const *) b);
     156 ECB             : }
     157                 : 
     158                 : /*
     159                 :  * Canonicalize a QTNode tree by sorting the children of AND/OR nodes
     160                 :  * into an arbitrary but well-defined order.
     161                 :  */
     162                 : void
     163 GIC        4542 : QTNSort(QTNode *in)
     164 ECB             : {
     165                 :     int         i;
     166                 : 
     167                 :     /* since this function recurses, it could be driven to stack overflow. */
     168 GIC        4542 :     check_stack_depth();
     169 ECB             : 
     170 GIC        4542 :     if (in->valnode->type != QI_OPR)
     171 CBC        2958 :         return;
     172 ECB             : 
     173 GIC        5199 :     for (i = 0; i < in->nchild; i++)
     174 CBC        3615 :         QTNSort(in->child[i]);
     175            1584 :     if (in->nchild > 1 && in->valnode->qoperator.oper != OP_PHRASE)
     176 GNC         924 :         qsort(in->child, in->nchild, sizeof(QTNode *), cmpQTN);
     177 ECB             : }
     178                 : 
     179                 : /*
     180                 :  * Are two QTNode trees equal according to QTNodeCompare?
     181                 :  */
     182                 : bool
     183 GIC          99 : QTNEq(QTNode *a, QTNode *b)
     184 ECB             : {
     185 GIC          99 :     uint32      sign = a->sign & b->sign;
     186 ECB             : 
     187 GIC          99 :     if (!(sign == a->sign && sign == b->sign))
     188 CBC           3 :         return false;
     189 ECB             : 
     190 GIC          96 :     return (QTNodeCompare(a, b) == 0);
     191 ECB             : }
     192                 : 
     193                 : /*
     194                 :  * Remove unnecessary intermediate nodes. For example:
     195                 :  *
     196                 :  *  OR          OR
     197                 :  * a  OR    -> a b c
     198                 :  *   b  c
     199                 :  */
     200                 : void
     201 GIC        4374 : QTNTernary(QTNode *in)
     202 ECB             : {
     203                 :     int         i;
     204                 : 
     205                 :     /* since this function recurses, it could be driven to stack overflow. */
     206 GIC        4374 :     check_stack_depth();
     207 ECB             : 
     208 GIC        4374 :     if (in->valnode->type != QI_OPR)
     209 CBC        2769 :         return;
     210 ECB             : 
     211 GIC        5073 :     for (i = 0; i < in->nchild; i++)
     212 CBC        3468 :         QTNTernary(in->child[i]);
     213 ECB             : 
     214                 :     /* Only AND and OR are associative, so don't flatten other node types */
     215 GIC        1605 :     if (in->valnode->qoperator.oper != OP_AND &&
     216 CBC        1008 :         in->valnode->qoperator.oper != OP_OR)
     217             624 :         return;
     218 ECB             : 
     219 GIC        3213 :     for (i = 0; i < in->nchild; i++)
     220 ECB             :     {
     221 GIC        2232 :         QTNode     *cc = in->child[i];
     222 ECB             : 
     223 GIC        2232 :         if (cc->valnode->type == QI_OPR &&
     224 CBC         777 :             in->valnode->qoperator.oper == cc->valnode->qoperator.oper)
     225 ECB             :         {
     226 GIC         165 :             int         oldnchild = in->nchild;
     227 ECB             : 
     228 GIC         165 :             in->nchild += cc->nchild - 1;
     229 CBC         165 :             in->child = (QTNode **) repalloc(in->child, in->nchild * sizeof(QTNode *));
     230 ECB             : 
     231 GIC         165 :             if (i + 1 != oldnchild)
     232 CBC          18 :                 memmove(in->child + i + cc->nchild, in->child + i + 1,
     233              18 :                         (oldnchild - i - 1) * sizeof(QTNode *));
     234 ECB             : 
     235 GIC         165 :             memcpy(in->child + i, cc->child, cc->nchild * sizeof(QTNode *));
     236 CBC         165 :             i += cc->nchild - 1;
     237 ECB             : 
     238 GIC         165 :             if (cc->flags & QTN_NEEDFREE)
     239 CBC          54 :                 pfree(cc->valnode);
     240             165 :             pfree(cc);
     241 ECB             :         }
     242                 :     }
     243                 : }
     244                 : 
     245                 : /*
     246                 :  * Convert a tree to binary tree by inserting intermediate nodes.
     247                 :  * (Opposite of QTNTernary)
     248                 :  */
     249                 : void
     250 GIC         591 : QTNBinary(QTNode *in)
     251 ECB             : {
     252                 :     int         i;
     253                 : 
     254                 :     /* since this function recurses, it could be driven to stack overflow. */
     255 GIC         591 :     check_stack_depth();
     256 ECB             : 
     257 GIC         591 :     if (in->valnode->type != QI_OPR)
     258 CBC         363 :         return;
     259 ECB             : 
     260 GIC         732 :     for (i = 0; i < in->nchild; i++)
     261 CBC         504 :         QTNBinary(in->child[i]);
     262 ECB             : 
     263 GIC         288 :     while (in->nchild > 2)
     264 ECB             :     {
     265 GIC          60 :         QTNode     *nn = (QTNode *) palloc0(sizeof(QTNode));
     266 ECB             : 
     267 GIC          60 :         nn->valnode = (QueryItem *) palloc0(sizeof(QueryItem));
     268 CBC          60 :         nn->child = (QTNode **) palloc0(sizeof(QTNode *) * 2);
     269 ECB             : 
     270 GIC          60 :         nn->nchild = 2;
     271 CBC          60 :         nn->flags = QTN_NEEDFREE;
     272 ECB             : 
     273 GIC          60 :         nn->child[0] = in->child[0];
     274 CBC          60 :         nn->child[1] = in->child[1];
     275              60 :         nn->sign = nn->child[0]->sign | nn->child[1]->sign;
     276 ECB             : 
     277 GIC          60 :         nn->valnode->type = in->valnode->type;
     278 CBC          60 :         nn->valnode->qoperator.oper = in->valnode->qoperator.oper;
     279 ECB             : 
     280 GIC          60 :         in->child[0] = nn;
     281 CBC          60 :         in->child[1] = in->child[in->nchild - 1];
     282              60 :         in->nchild--;
     283 ECB             :     }
     284                 : }
     285                 : 
     286                 : /*
     287                 :  * Count the total length of operand strings in tree (including '\0'-
     288                 :  * terminators) and the total number of nodes.
     289                 :  * Caller must initialize *sumlen and *nnode to zeroes.
     290                 :  */
     291                 : static void
     292 GIC         993 : cntsize(QTNode *in, int *sumlen, int *nnode)
     293 ECB             : {
     294                 :     /* since this function recurses, it could be driven to stack overflow. */
     295 GIC         993 :     check_stack_depth();
     296 ECB             : 
     297 GIC         993 :     *nnode += 1;
     298 CBC         993 :     if (in->valnode->type == QI_OPR)
     299 ECB             :     {
     300                 :         int         i;
     301                 : 
     302 GIC        1281 :         for (i = 0; i < in->nchild; i++)
     303 CBC         846 :             cntsize(in->child[i], sumlen, nnode);
     304 ECB             :     }
     305                 :     else
     306                 :     {
     307 GIC         558 :         *sumlen += in->valnode->qoperand.length + 1;
     308 ECB             :     }
     309 GIC         993 : }
     310 ECB             : 
     311                 : typedef struct
     312                 : {
     313                 :     QueryItem  *curitem;
     314                 :     char       *operand;
     315                 :     char       *curoperand;
     316                 : } QTN2QTState;
     317                 : 
     318                 : /*
     319                 :  * Recursively convert a QTNode tree into flat tsquery format.
     320                 :  * Caller must have allocated arrays of the correct size.
     321                 :  */
     322                 : static void
     323 GIC         993 : fillQT(QTN2QTState *state, QTNode *in)
     324 ECB             : {
     325                 :     /* since this function recurses, it could be driven to stack overflow. */
     326 GIC         993 :     check_stack_depth();
     327 ECB             : 
     328 GIC         993 :     if (in->valnode->type == QI_VAL)
     329 ECB             :     {
     330 GIC         558 :         memcpy(state->curitem, in->valnode, sizeof(QueryOperand));
     331 ECB             : 
     332 GIC         558 :         memcpy(state->curoperand, in->word, in->valnode->qoperand.length);
     333 CBC         558 :         state->curitem->qoperand.distance = state->curoperand - state->operand;
     334             558 :         state->curoperand[in->valnode->qoperand.length] = '\0';
     335             558 :         state->curoperand += in->valnode->qoperand.length + 1;
     336             558 :         state->curitem++;
     337 ECB             :     }
     338                 :     else
     339                 :     {
     340 GIC         435 :         QueryItem  *curitem = state->curitem;
     341 ECB             : 
     342 GIC         435 :         Assert(in->valnode->type == QI_OPR);
     343 ECB             : 
     344 GIC         435 :         memcpy(state->curitem, in->valnode, sizeof(QueryOperator));
     345 ECB             : 
     346 GIC         435 :         Assert(in->nchild <= 2);
     347 CBC         435 :         state->curitem++;
     348 ECB             : 
     349 GIC         435 :         fillQT(state, in->child[0]);
     350 ECB             : 
     351 GIC         435 :         if (in->nchild == 2)
     352 ECB             :         {
     353 GIC         411 :             curitem->qoperator.left = state->curitem - curitem;
     354 CBC         411 :             fillQT(state, in->child[1]);
     355 ECB             :         }
     356                 :     }
     357 GIC         993 : }
     358 ECB             : 
     359                 : /*
     360                 :  * Build flat tsquery from a QTNode tree.
     361                 :  */
     362                 : TSQuery
     363 GIC         147 : QTN2QT(QTNode *in)
     364 ECB             : {
     365                 :     TSQuery     out;
     366                 :     int         len;
     367 GIC         147 :     int         sumlen = 0,
     368 CBC         147 :                 nnode = 0;
     369 ECB             :     QTN2QTState state;
     370                 : 
     371 GIC         147 :     cntsize(in, &sumlen, &nnode);
     372 ECB             : 
     373 GIC         147 :     if (TSQUERY_TOO_BIG(nnode, sumlen))
     374 LBC           0 :         ereport(ERROR,
     375 EUB             :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     376                 :                  errmsg("tsquery is too large")));
     377 GIC         147 :     len = COMPUTESIZE(nnode, sumlen);
     378 ECB             : 
     379 GIC         147 :     out = (TSQuery) palloc0(len);
     380 CBC         147 :     SET_VARSIZE(out, len);
     381             147 :     out->size = nnode;
     382 ECB             : 
     383 GIC         147 :     state.curitem = GETQUERY(out);
     384 CBC         147 :     state.operand = state.curoperand = GETOPERAND(out);
     385 ECB             : 
     386 GIC         147 :     fillQT(&state, in);
     387 CBC         147 :     return out;
     388 ECB             : }
     389                 : 
     390                 : /*
     391                 :  * Copy a QTNode tree.
     392                 :  *
     393                 :  * Modifiable copies of the words and valnodes are made, too.
     394                 :  */
     395                 : QTNode *
     396 GIC         510 : QTNCopy(QTNode *in)
     397 ECB             : {
     398                 :     QTNode     *out;
     399                 : 
     400                 :     /* since this function recurses, it could be driven to stack overflow. */
     401 GIC         510 :     check_stack_depth();
     402 ECB             : 
     403 GIC         510 :     out = (QTNode *) palloc(sizeof(QTNode));
     404 ECB             : 
     405 GIC         510 :     *out = *in;
     406 CBC         510 :     out->valnode = (QueryItem *) palloc(sizeof(QueryItem));
     407             510 :     *(out->valnode) = *(in->valnode);
     408             510 :     out->flags |= QTN_NEEDFREE;
     409 ECB             : 
     410 GIC         510 :     if (in->valnode->type == QI_VAL)
     411 ECB             :     {
     412 GIC         306 :         out->word = palloc(in->valnode->qoperand.length + 1);
     413 CBC         306 :         memcpy(out->word, in->word, in->valnode->qoperand.length);
     414             306 :         out->word[in->valnode->qoperand.length] = '\0';
     415             306 :         out->flags |= QTN_WORDFREE;
     416 ECB             :     }
     417                 :     else
     418                 :     {
     419                 :         int         i;
     420                 : 
     421 GIC         204 :         out->child = (QTNode **) palloc(sizeof(QTNode *) * in->nchild);
     422 ECB             : 
     423 GIC         609 :         for (i = 0; i < in->nchild; i++)
     424 CBC         405 :             out->child[i] = QTNCopy(in->child[i]);
     425 ECB             :     }
     426                 : 
     427 GIC         510 :     return out;
     428 ECB             : }
     429                 : 
     430                 : /*
     431                 :  * Clear the specified flag bit(s) in all nodes of a QTNode tree.
     432                 :  */
     433                 : void
     434 GIC        2622 : QTNClearFlags(QTNode *in, uint32 flags)
     435 ECB             : {
     436                 :     /* since this function recurses, it could be driven to stack overflow. */
     437 GIC        2622 :     check_stack_depth();
     438 ECB             : 
     439 GIC        2622 :     in->flags &= ~flags;
     440 ECB             : 
     441 GIC        2622 :     if (in->valnode->type != QI_VAL)
     442 ECB             :     {
     443                 :         int         i;
     444                 : 
     445 GIC        3204 :         for (i = 0; i < in->nchild; i++)
     446 CBC        2226 :             QTNClearFlags(in->child[i], flags);
     447 ECB             :     }
     448 GIC        2622 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a