LCOV - differential code coverage report
Current view: top level - contrib/ltree - lquery_op.c (source / functions) Coverage Total Hit UBC GIC GNC CBC ECB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 94.4 % 107 101 6 3 4 94 3 4
Current Date: 2023-04-08 17:13:01 Functions: 84.6 % 13 11 2 5 6 5
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (180,240] days: 100.0 % 4 4 4
Legend: Lines: hit not hit (240..) days: 94.2 % 103 97 6 3 94 3
Function coverage date bins:
(240..) days: 61.1 % 18 11 2 5 6 5

 Age         Owner                  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                 : 
 7558 bruce                      16 GIC           3 : PG_FUNCTION_INFO_V1(ltq_regex);
 7558 bruce                      17 CBC           2 : PG_FUNCTION_INFO_V1(ltq_rregex);
 7558 bruce                      18 ECB             : 
 7354 bruce                      19 GIC           3 : PG_FUNCTION_INFO_V1(lt_q_regex);
 7354 bruce                      20 CBC           2 : PG_FUNCTION_INFO_V1(lt_q_rregex);
 7354 bruce                      21 ECB             : 
                                 22                 : #define NEXTVAL(x) ( (lquery*)( (char*)(x) + INTALIGN( VARSIZE(x) ) ) )
                                 23                 : 
                                 24                 : static char *
 6248 neilc                      25 GIC          36 : getlexeme(char *start, char *end, int *len)
 7522 bruce                      26 ECB             : {
                                 27                 :     char       *ptr;
                                 28                 : 
  185 tgl                        29 GNC          44 :     while (start < end && t_iseq(start, '_'))
                                 30               8 :         start += pg_mblen(start);
                                 31                 : 
 7558 bruce                      32 CBC          36 :     ptr = start;
 5396 teodor                     33              36 :     if (ptr >= end)
 7558 bruce                      34               8 :         return NULL;
                                 35                 : 
  185 tgl                        36 GNC         114 :     while (ptr < end && !t_iseq(ptr, '_'))
                                 37              86 :         ptr += pg_mblen(ptr);
                                 38                 : 
 7558 bruce                      39 CBC          28 :     *len = ptr - start;
                                 40              28 :     return start;
                                 41                 : }
                                 42                 : 
                                 43                 : bool
 1418 tgl                        44               8 : compare_subnode(ltree_level *t, char *qn, int len, int (*cmpptr) (const char *, const char *, size_t), bool anyend)
                                 45                 : {
 7522 bruce                      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                 : 
 6248 neilc                      53              16 :     while ((qn = getlexeme(qn, endq, &lenq)) != NULL)
                                 54                 :     {
 7522 bruce                      55              12 :         tn = t->name;
 7558                            56              12 :         isok = false;
 6248 neilc                      57              20 :         while ((tn = getlexeme(tn, endt, &lent)) != NULL)
                                 58                 :         {
 1165 alvherre                   59              32 :             if ((lent == lenq || (lent > lenq && anyend)) &&
 7522 bruce                      60              16 :                 (*cmpptr) (qn, tn, lenq) == 0)
                                 61                 :             {
                                 62                 : 
                                 63               8 :                 isok = true;
 7558                            64               8 :                 break;
                                 65                 :             }
                                 66               8 :             tn += lent;
                                 67                 :         }
                                 68                 : 
 7522                            69              12 :         if (!isok)
 7558                            70               4 :             return false;
                                 71               8 :         qn += lenq;
                                 72                 :     }
                                 73                 : 
                                 74               4 :     return true;
                                 75                 : }
                                 76                 : 
                                 77                 : int
 5396 teodor                     78              26 : ltree_strncasecmp(const char *a, const char *b, size_t s)
                                 79                 : {
 4443 peter_e                    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                 : 
 5050 bruce                      84              26 :     res = strncmp(al, bl, s);
                                 85                 : 
 5396 teodor                     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
 5050 bruce                      99          216918 : checkLevel(lquery_level *curq, ltree_level *curt)
                                100                 : {
 7558                           101          216918 :     lquery_variant *curvar = LQL_FIRST(curq);
                                102                 :     bool        success;
                                103                 : 
 1104 tgl                       104          216918 :     success = (curq->flag & LQL_NOT) ? false : true;
                                105                 : 
                                106                 :     /* numvar == 0 means '*' which matches anything */
                                107          216918 :     if (curq->numvar == 0)
                                108           83195 :         return success;
                                109                 : 
                                110          260897 :     for (int i = 0; i < curq->numvar; i++)
                                111                 :     {
                                112                 :         int         (*cmpptr) (const char *, const char *, size_t);
                                113                 : 
 5396 teodor                    114          133728 :         cmpptr = (curvar->flag & LVAR_INCASE) ? ltree_strncasecmp : strncmp;
                                115                 : 
 6248 neilc                     116          133728 :         if (curvar->flag & LVAR_SUBLEXEME)
                                117                 :         {
 1104 tgl                       118               4 :             if (compare_subnode(curt, curvar->name, curvar->len, cmpptr,
                                119               4 :                                 (curvar->flag & LVAR_ANYEND)))
                                120               3 :                 return success;
                                121                 :         }
 1165 alvherre                  122          133724 :         else if ((curvar->len == curt->len ||
                                123          133727 :                   (curt->len > curvar->len && (curvar->flag & LVAR_ANYEND))) &&
 7522 bruce                     124           55166 :                  (*cmpptr) (curvar->name, curt->name, curvar->len) == 0)
 1104 tgl                       125            6551 :             return success;
                                126                 : 
 7522 bruce                     127          127174 :         curvar = LVAR_NEXT(curvar);
                                128                 :     }
 1104 tgl                       129          127169 :     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          143589 : 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          143589 :     check_stack_depth();
                                141                 : 
                                142                 :     /* Pathological patterns could take awhile, too */
                                143          143589 :     CHECK_FOR_INTERRUPTS();
                                144                 : 
                                145                 :     /* Loop while we have query items to consider */
                                146          162868 :     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          159155 :         if ((curq->flag & LQL_COUNT) || curq->numvar == 0)
                                158           13307 :             low = curq->low, high = curq->high;
                                159                 :         else
                                160          145848 :             low = high = 1;
                                161                 : 
                                162                 :         /*
                                163                 :          * We may limit "high" to the remaining text length; this avoids
                                164                 :          * separate tests below.
                                165                 :          */
                                166          159155 :         if (high > tlen)
                                167           24988 :             high = tlen;
                                168                 : 
                                169                 :         /* Fail if a match of required number of items is impossible */
                                170          159155 :         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          146982 :         nextq = LQL_NEXT(curq);
 7558 bruce                     178          146982 :         qlen--;
                                179                 : 
 1104 tgl                       180          236791 :         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          217512 :             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          216918 :             if (!checkLevel(curq, curt))
 1107                           193          127109 :                 return false;
                                194                 : 
 1104                           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
 7522 bruce                     215           60271 : ltq_regex(PG_FUNCTION_ARGS)
                                216                 : {
 2029 tgl                       217           60271 :     ltree      *tree = PG_GETARG_LTREE_P(0);
                                218           60271 :     lquery     *query = PG_GETARG_LQUERY_P(1);
                                219                 :     bool        res;
                                220                 : 
 1104                           221           60271 :     res = checkCond(LQUERY_FIRST(query), query->numlevel,
                                222           60271 :                     LTREE_FIRST(tree), tree->numlevel);
                                223                 : 
 7522 bruce                     224           60271 :     PG_FREE_IF_COPY(tree, 0);
                                225           60271 :     PG_FREE_IF_COPY(query, 1);
                                226           60271 :     PG_RETURN_BOOL(res);
                                227                 : }
                                228                 : 
                                229                 : Datum
 7522 bruce                     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
 7354 bruce                     239 CBC        1600 : lt_q_regex(PG_FUNCTION_ARGS)
                                240                 : {
 2029 tgl                       241            1600 :     ltree      *tree = PG_GETARG_LTREE_P(0);
 7188 bruce                     242            1600 :     ArrayType  *_query = PG_GETARG_ARRAYTYPE_P(1);
                                243            1600 :     lquery     *query = (lquery *) ARR_DATA_PTR(_query);
                                244            1600 :     bool        res = false;
                                245            1600 :     int         num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query));
                                246                 : 
 4792 tgl                       247            1600 :     if (ARR_NDIM(_query) > 1)
 7188 bruce                     248 UBC           0 :         ereport(ERROR,
                                249                 :                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
                                250                 :                  errmsg("array must be one-dimensional")));
 4473 tgl                       251 CBC        1600 :     if (array_contains_nulls(_query))
 6350 tgl                       252 UBC           0 :         ereport(ERROR,
                                253                 :                 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
                                254                 :                  errmsg("array must not contain nulls")));
                                255                 : 
 7188 bruce                     256 CBC        4775 :     while (num > 0)
                                257                 :     {
 7354                           258            3189 :         if (DatumGetBool(DirectFunctionCall2(ltq_regex,
                                259                 :                                              PointerGetDatum(tree), PointerGetDatum(query))))
                                260                 :         {
                                261                 : 
                                262              14 :             res = true;
                                263              14 :             break;
                                264                 :         }
                                265            3175 :         num--;
                                266            3175 :         query = NEXTVAL(query);
                                267                 :     }
                                268                 : 
                                269            1600 :     PG_FREE_IF_COPY(tree, 0);
                                270            1600 :     PG_FREE_IF_COPY(_query, 1);
                                271            1600 :     PG_RETURN_BOOL(res);
                                272                 : }
                                273                 : 
                                274                 : Datum
 7354 bruce                     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 v1.16-55-g56c0a2a