LCOV - differential code coverage report
Current view: top level - contrib/ltree - lquery_op.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 94.4 % 107 101 6 101
Current Date: 2024-04-14 14:21:10 Functions: 84.6 % 13 11 2 11
Baseline: 16@8cea358b128 Branches: 84.5 % 84 71 13 71
Baseline Date: 2024-04-14 14:21:09 Line coverage date bins:
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed (240..) days: 94.4 % 107 101 6 101
Function coverage date bins:
(240..) days: 84.6 % 13 11 2 11
Branch coverage date bins:
(240..) days: 84.5 % 84 71 13 71

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*
                                  2                 :                :  * op function for ltree and lquery
                                  3                 :                :  * Teodor Sigaev <teodor@stack.net>
                                  4                 :                :  * contrib/ltree/lquery_op.c
                                  5                 :                :  */
                                  6                 :                : #include "postgres.h"
                                  7                 :                : 
                                  8                 :                : #include <ctype.h>
                                  9                 :                : 
                                 10                 :                : #include "catalog/pg_collation.h"
                                 11                 :                : #include "ltree.h"
                                 12                 :                : #include "miscadmin.h"
                                 13                 :                : #include "utils/array.h"
                                 14                 :                : #include "utils/formatting.h"
                                 15                 :                : 
 7929 bruce@momjian.us           16                 :CBC           3 : PG_FUNCTION_INFO_V1(ltq_regex);
                                 17                 :              2 : PG_FUNCTION_INFO_V1(ltq_rregex);
                                 18                 :                : 
 7725                            19                 :              3 : PG_FUNCTION_INFO_V1(lt_q_regex);
                                 20                 :              2 : PG_FUNCTION_INFO_V1(lt_q_rregex);
                                 21                 :                : 
                                 22                 :                : #define NEXTVAL(x) ( (lquery*)( (char*)(x) + INTALIGN( VARSIZE(x) ) ) )
                                 23                 :                : 
                                 24                 :                : static char *
 6619 neilc@samurai.com          25                 :             36 : getlexeme(char *start, char *end, int *len)
                                 26                 :                : {
                                 27                 :                :     char       *ptr;
                                 28                 :                : 
  556 tgl@sss.pgh.pa.us          29   [ +  +  +  + ]:             44 :     while (start < end && t_iseq(start, '_'))
                                 30                 :              8 :         start += pg_mblen(start);
                                 31                 :                : 
 7929 bruce@momjian.us           32                 :             36 :     ptr = start;
 5767 teodor@sigaev.ru           33         [ +  + ]:             36 :     if (ptr >= end)
 7929 bruce@momjian.us           34                 :              8 :         return NULL;
                                 35                 :                : 
  556 tgl@sss.pgh.pa.us          36   [ +  +  +  + ]:            114 :     while (ptr < end && !t_iseq(ptr, '_'))
                                 37                 :             86 :         ptr += pg_mblen(ptr);
                                 38                 :                : 
 7929 bruce@momjian.us           39                 :             28 :     *len = ptr - start;
                                 40                 :             28 :     return start;
                                 41                 :                : }
                                 42                 :                : 
                                 43                 :                : bool
 1789 tgl@sss.pgh.pa.us          44                 :              8 : compare_subnode(ltree_level *t, char *qn, int len, int (*cmpptr) (const char *, const char *, size_t), bool anyend)
                                 45                 :                : {
 7893 bruce@momjian.us           46                 :              8 :     char       *endt = t->name + t->len;
                                 47                 :              8 :     char       *endq = qn + len;
                                 48                 :                :     char       *tn;
                                 49                 :                :     int         lent,
                                 50                 :                :                 lenq;
                                 51                 :                :     bool        isok;
                                 52                 :                : 
 6619 neilc@samurai.com          53         [ +  + ]:             16 :     while ((qn = getlexeme(qn, endq, &lenq)) != NULL)
                                 54                 :                :     {
 7893 bruce@momjian.us           55                 :             12 :         tn = t->name;
 7929                            56                 :             12 :         isok = false;
 6619 neilc@samurai.com          57         [ +  + ]:             20 :         while ((tn = getlexeme(tn, endt, &lent)) != NULL)
                                 58                 :                :         {
 1536 alvherre@alvh.no-ip.       59   [ +  -  +  -  :             32 :             if ((lent == lenq || (lent > lenq && anyend)) &&
                                        +  -  +  + ]
 7893 bruce@momjian.us           60                 :             16 :                 (*cmpptr) (qn, tn, lenq) == 0)
                                 61                 :                :             {
                                 62                 :                : 
                                 63                 :              8 :                 isok = true;
 7929                            64                 :              8 :                 break;
                                 65                 :                :             }
                                 66                 :              8 :             tn += lent;
                                 67                 :                :         }
                                 68                 :                : 
 7893                            69         [ +  + ]:             12 :         if (!isok)
 7929                            70                 :              4 :             return false;
                                 71                 :              8 :         qn += lenq;
                                 72                 :                :     }
                                 73                 :                : 
                                 74                 :              4 :     return true;
                                 75                 :                : }
                                 76                 :                : 
                                 77                 :                : int
 5767 teodor@sigaev.ru           78                 :             26 : ltree_strncasecmp(const char *a, const char *b, size_t s)
                                 79                 :                : {
 4814 peter_e@gmx.net            80                 :             26 :     char       *al = str_tolower(a, s, DEFAULT_COLLATION_OID);
                                 81                 :             26 :     char       *bl = str_tolower(b, s, DEFAULT_COLLATION_OID);
                                 82                 :                :     int         res;
                                 83                 :                : 
 5421 bruce@momjian.us           84                 :             26 :     res = strncmp(al, bl, s);
                                 85                 :                : 
 5767 teodor@sigaev.ru           86                 :             26 :     pfree(al);
                                 87                 :             26 :     pfree(bl);
                                 88                 :                : 
                                 89                 :             26 :     return res;
                                 90                 :                : }
                                 91                 :                : 
                                 92                 :                : /*
                                 93                 :                :  * See if an lquery_level matches an ltree_level
                                 94                 :                :  *
                                 95                 :                :  * This accounts for all flags including LQL_NOT, but does not
                                 96                 :                :  * consider repetition counts.
                                 97                 :                :  */
                                 98                 :                : static bool
 5421 bruce@momjian.us           99                 :         216743 : checkLevel(lquery_level *curq, ltree_level *curt)
                                100                 :                : {
 7929                           101                 :         216743 :     lquery_variant *curvar = LQL_FIRST(curq);
                                102                 :                :     bool        success;
                                103                 :                : 
 1475 tgl@sss.pgh.pa.us         104                 :         216743 :     success = (curq->flag & LQL_NOT) ? false : true;
                                105                 :                : 
                                106                 :                :     /* numvar == 0 means '*' which matches anything */
                                107         [ +  + ]:         216743 :     if (curq->numvar == 0)
                                108                 :          83195 :         return success;
                                109                 :                : 
                                110         [ +  + ]:         260547 :     for (int i = 0; i < curq->numvar; i++)
                                111                 :                :     {
                                112                 :                :         int         (*cmpptr) (const char *, const char *, size_t);
                                113                 :                : 
 5767 teodor@sigaev.ru          114         [ +  + ]:         133553 :         cmpptr = (curvar->flag & LVAR_INCASE) ? ltree_strncasecmp : strncmp;
                                115                 :                : 
 6619 neilc@samurai.com         116         [ +  + ]:         133553 :         if (curvar->flag & LVAR_SUBLEXEME)
                                117                 :                :         {
 1475 tgl@sss.pgh.pa.us         118         [ +  + ]:              4 :             if (compare_subnode(curt, curvar->name, curvar->len, cmpptr,
                                119                 :              4 :                                 (curvar->flag & LVAR_ANYEND)))
                                120                 :              3 :                 return success;
                                121                 :                :         }
 1536 alvherre@alvh.no-ip.      122         [ +  + ]:         133549 :         else if ((curvar->len == curt->len ||
                                123   [ +  +  +  +  :         133552 :                   (curt->len > curvar->len && (curvar->flag & LVAR_ANYEND))) &&
                                              +  + ]
 7893 bruce@momjian.us          124                 :          54991 :                  (*cmpptr) (curvar->name, curt->name, curvar->len) == 0)
 1475 tgl@sss.pgh.pa.us         125                 :           6551 :             return success;
                                126                 :                : 
 7893 bruce@momjian.us          127                 :         126999 :         curvar = LVAR_NEXT(curvar);
                                128                 :                :     }
 1475 tgl@sss.pgh.pa.us         129                 :         126994 :     return !success;
                                130                 :                : }
                                131                 :                : 
                                132                 :                : /*
                                133                 :                :  * Try to match an lquery (of qlen items) to an ltree (of tlen items)
                                134                 :                :  */
                                135                 :                : static bool
                                136                 :         143414 : checkCond(lquery_level *curq, int qlen,
                                137                 :                :           ltree_level *curt, int tlen)
                                138                 :                : {
                                139                 :                :     /* Since this function recurses, it could be driven to stack overflow */
                                140                 :         143414 :     check_stack_depth();
                                141                 :                : 
                                142                 :                :     /* Pathological patterns could take awhile, too */
                                143         [ -  + ]:         143414 :     CHECK_FOR_INTERRUPTS();
                                144                 :                : 
                                145                 :                :     /* Loop while we have query items to consider */
                                146         [ +  + ]:         162693 :     while (qlen > 0)
                                147                 :                :     {
                                148                 :                :         int         low,
                                149                 :                :                     high;
                                150                 :                :         lquery_level *nextq;
                                151                 :                : 
                                152                 :                :         /*
                                153                 :                :          * Get min and max repetition counts for this query item, dealing with
                                154                 :                :          * the backwards-compatibility hack that the low/high fields aren't
                                155                 :                :          * meaningful for non-'*' items unless LQL_COUNT is set.
                                156                 :                :          */
                                157   [ +  +  +  + ]:         158980 :         if ((curq->flag & LQL_COUNT) || curq->numvar == 0)
                                158                 :          13307 :             low = curq->low, high = curq->high;
                                159                 :                :         else
                                160                 :         145673 :             low = high = 1;
                                161                 :                : 
                                162                 :                :         /*
                                163                 :                :          * We may limit "high" to the remaining text length; this avoids
                                164                 :                :          * separate tests below.
                                165                 :                :          */
                                166         [ +  + ]:         158980 :         if (high > tlen)
                                167                 :          24988 :             high = tlen;
                                168                 :                : 
                                169                 :                :         /* Fail if a match of required number of items is impossible */
                                170         [ +  + ]:         158980 :         if (high < low)
                                171                 :          12173 :             return false;
                                172                 :                : 
                                173                 :                :         /*
                                174                 :                :          * Recursively check the rest of the pattern against each possible
                                175                 :                :          * start point following some of this item's match(es).
                                176                 :                :          */
                                177                 :         146807 :         nextq = LQL_NEXT(curq);
 7929 bruce@momjian.us          178                 :         146807 :         qlen--;
                                179                 :                : 
 1475 tgl@sss.pgh.pa.us         180         [ +  + ]:         236616 :         for (int matchcnt = 0; matchcnt < high; matchcnt++)
                                181                 :                :         {
                                182                 :                :             /*
                                183                 :                :              * If we've consumed an acceptable number of matches of this item,
                                184                 :                :              * and the rest of the pattern matches beginning here, we're good.
                                185                 :                :              */
                                186   [ +  +  +  + ]:         217337 :             if (matchcnt >= low && checkCond(nextq, qlen, curt, tlen))
                                187                 :            594 :                 return true;
                                188                 :                : 
                                189                 :                :             /*
                                190                 :                :              * Otherwise, try to match one more text item to this query item.
                                191                 :                :              */
                                192         [ +  + ]:         216743 :             if (!checkLevel(curq, curt))
 1478                           193                 :         126934 :                 return false;
                                194                 :                : 
 1475                           195                 :          89809 :             curt = LEVEL_NEXT(curt);
                                196                 :          89809 :             tlen--;
                                197                 :                :         }
                                198                 :                : 
                                199                 :                :         /*
                                200                 :                :          * Once we've consumed "high" matches, we can succeed only if the rest
                                201                 :                :          * of the pattern matches beginning here.  Loop around (if you prefer,
                                202                 :                :          * think of this as tail recursion).
                                203                 :                :          */
                                204                 :          19279 :         curq = nextq;
                                205                 :                :     }
                                206                 :                : 
                                207                 :                :     /*
                                208                 :                :      * Once we're out of query items, we match only if there's no remaining
                                209                 :                :      * text either.
                                210                 :                :      */
                                211                 :           3713 :     return (tlen == 0);
                                212                 :                : }
                                213                 :                : 
                                214                 :                : Datum
 7893 bruce@momjian.us          215                 :          60096 : ltq_regex(PG_FUNCTION_ARGS)
                                216                 :                : {
 2400 tgl@sss.pgh.pa.us         217                 :          60096 :     ltree      *tree = PG_GETARG_LTREE_P(0);
                                218                 :          60096 :     lquery     *query = PG_GETARG_LQUERY_P(1);
                                219                 :                :     bool        res;
                                220                 :                : 
 1475                           221                 :          60096 :     res = checkCond(LQUERY_FIRST(query), query->numlevel,
                                222                 :          60096 :                     LTREE_FIRST(tree), tree->numlevel);
                                223                 :                : 
 7893 bruce@momjian.us          224         [ +  + ]:          60096 :     PG_FREE_IF_COPY(tree, 0);
                                225         [ -  + ]:          60096 :     PG_FREE_IF_COPY(query, 1);
                                226                 :          60096 :     PG_RETURN_BOOL(res);
                                227                 :                : }
                                228                 :                : 
                                229                 :                : Datum
 7893 bruce@momjian.us          230                 :UBC           0 : ltq_rregex(PG_FUNCTION_ARGS)
                                231                 :                : {
                                232                 :              0 :     PG_RETURN_DATUM(DirectFunctionCall2(ltq_regex,
                                233                 :                :                                         PG_GETARG_DATUM(1),
                                234                 :                :                                         PG_GETARG_DATUM(0)
                                235                 :                :                                         ));
                                236                 :                : }
                                237                 :                : 
                                238                 :                : Datum
 7725 bruce@momjian.us          239                 :CBC        1565 : lt_q_regex(PG_FUNCTION_ARGS)
                                240                 :                : {
 2400 tgl@sss.pgh.pa.us         241                 :           1565 :     ltree      *tree = PG_GETARG_LTREE_P(0);
 7559 bruce@momjian.us          242                 :           1565 :     ArrayType  *_query = PG_GETARG_ARRAYTYPE_P(1);
                                243         [ -  + ]:           1565 :     lquery     *query = (lquery *) ARR_DATA_PTR(_query);
                                244                 :           1565 :     bool        res = false;
                                245                 :           1565 :     int         num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query));
                                246                 :                : 
 5163 tgl@sss.pgh.pa.us         247         [ -  + ]:           1565 :     if (ARR_NDIM(_query) > 1)
 7559 bruce@momjian.us          248         [ #  # ]:UBC           0 :         ereport(ERROR,
                                249                 :                :                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
                                250                 :                :                  errmsg("array must be one-dimensional")));
 4844 tgl@sss.pgh.pa.us         251         [ -  + ]:CBC        1565 :     if (array_contains_nulls(_query))
 6721 tgl@sss.pgh.pa.us         252         [ #  # ]:UBC           0 :         ereport(ERROR,
                                253                 :                :                 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
                                254                 :                :                  errmsg("array must not contain nulls")));
                                255                 :                : 
 7559 bruce@momjian.us          256         [ +  + ]:CBC        4670 :     while (num > 0)
                                257                 :                :     {
 7725                           258         [ +  + ]:           3119 :         if (DatumGetBool(DirectFunctionCall2(ltq_regex,
                                259                 :                :                                              PointerGetDatum(tree), PointerGetDatum(query))))
                                260                 :                :         {
                                261                 :                : 
                                262                 :             14 :             res = true;
                                263                 :             14 :             break;
                                264                 :                :         }
                                265                 :           3105 :         num--;
                                266                 :           3105 :         query = NEXTVAL(query);
                                267                 :                :     }
                                268                 :                : 
                                269         [ +  + ]:           1565 :     PG_FREE_IF_COPY(tree, 0);
                                270         [ -  + ]:           1565 :     PG_FREE_IF_COPY(_query, 1);
                                271                 :           1565 :     PG_RETURN_BOOL(res);
                                272                 :                : }
                                273                 :                : 
                                274                 :                : Datum
 7725 bruce@momjian.us          275                 :UBC           0 : lt_q_rregex(PG_FUNCTION_ARGS)
                                276                 :                : {
                                277                 :              0 :     PG_RETURN_DATUM(DirectFunctionCall2(lt_q_regex,
                                278                 :                :                                         PG_GETARG_DATUM(1),
                                279                 :                :                                         PG_GETARG_DATUM(0)
                                280                 :                :                                         ));
                                281                 :                : }
        

Generated by: LCOV version 2.1-beta2-3-g6141622