LCOV - code coverage report
Current view: top level - src/backend/utils/adt - like_match.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 95.5 % 134 128
Test Date: 2026-07-22 12:15:41 Functions: 66.7 % 6 4
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 89.9 % 138 124

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * like_match.c
       4                 :             :  *    LIKE pattern matching internal code.
       5                 :             :  *
       6                 :             :  * This file is included by like.c four times, to provide matching code for
       7                 :             :  * (1) single-byte encodings, (2) UTF8, (3) other multi-byte encodings,
       8                 :             :  * and (4) case insensitive matches in single-byte encodings.
       9                 :             :  * (UTF8 is a special case because we can use a much more efficient version
      10                 :             :  * of NextChar than can be used for general multi-byte encodings.)
      11                 :             :  *
      12                 :             :  * Before the inclusion, we need to define the following macros:
      13                 :             :  *
      14                 :             :  * NextChar
      15                 :             :  * MatchText - to name of function wanted
      16                 :             :  * do_like_escape - name of function if wanted - needs CHAREQ and CopyAdvChar
      17                 :             :  * MATCH_LOWER - define for case (4) to specify case folding for 1-byte chars
      18                 :             :  *
      19                 :             :  * Copyright (c) 1996-2026, PostgreSQL Global Development Group
      20                 :             :  *
      21                 :             :  * IDENTIFICATION
      22                 :             :  *  src/backend/utils/adt/like_match.c
      23                 :             :  *
      24                 :             :  *-------------------------------------------------------------------------
      25                 :             :  */
      26                 :             : 
      27                 :             : /*
      28                 :             :  *  Originally written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
      29                 :             :  *  Rich $alz is now <rsalz@bbn.com>.
      30                 :             :  *  Special thanks to Lars Mathiesen <thorinn@diku.dk> for the
      31                 :             :  *  LIKE_ABORT code.
      32                 :             :  *
      33                 :             :  *  This code was shamelessly stolen from the "pql" code by myself and
      34                 :             :  *  slightly modified :)
      35                 :             :  *
      36                 :             :  *  All references to the word "star" were replaced by "percent"
      37                 :             :  *  All references to the word "wild" were replaced by "like"
      38                 :             :  *
      39                 :             :  *  All the nice shell RE matching stuff was replaced by just "_" and "%"
      40                 :             :  *
      41                 :             :  *  As I don't have a copy of the SQL standard handy I wasn't sure whether
      42                 :             :  *  to leave in the '\' escape character handling.
      43                 :             :  *
      44                 :             :  *  Keith Parks. <keith@mtcc.demon.co.uk>
      45                 :             :  *
      46                 :             :  *  SQL lets you specify the escape character by saying
      47                 :             :  *  LIKE <pattern> ESCAPE <escape character>. We are a small operation
      48                 :             :  *  so we force you to use '\'. - ay 7/95
      49                 :             :  *
      50                 :             :  *  Now we have the like_escape() function that converts patterns with
      51                 :             :  *  any specified escape character (or none at all) to the internal
      52                 :             :  *  default escape character, which is still '\'. - tgl 9/2000
      53                 :             :  *
      54                 :             :  * The code is rewritten to avoid requiring null-terminated strings,
      55                 :             :  * which in turn allows us to leave out some memcpy() operations.
      56                 :             :  * This code should be faster and take less memory, but no promises...
      57                 :             :  * - thomas 2000-08-06
      58                 :             :  */
      59                 :             : 
      60                 :             : 
      61                 :             : /*--------------------
      62                 :             :  *  Match text and pattern, return LIKE_TRUE, LIKE_FALSE, or LIKE_ABORT.
      63                 :             :  *
      64                 :             :  *  LIKE_TRUE: they match
      65                 :             :  *  LIKE_FALSE: they don't match
      66                 :             :  *  LIKE_ABORT: not only don't they match, but the text is too short.
      67                 :             :  *
      68                 :             :  * If LIKE_ABORT is returned, then no suffix of the text can match the
      69                 :             :  * pattern either, so an upper-level % scan can stop scanning now.
      70                 :             :  *--------------------
      71                 :             :  */
      72                 :             : 
      73                 :             : /*
      74                 :             :  * MATCH_LOWER is defined for ILIKE in the C locale as an optimization. Other
      75                 :             :  * locales must casefold the inputs before matching.
      76                 :             :  */
      77                 :             : #ifdef MATCH_LOWER
      78                 :             : #define GETCHAR(t) pg_ascii_tolower(t)
      79                 :             : #else
      80                 :             : #define GETCHAR(t) (t)
      81                 :             : #endif
      82                 :             : 
      83                 :             : static int
      84                 :      816025 : MatchText(const char *t, int tlen, const char *p, int plen, pg_locale_t locale)
      85                 :             : {
      86   [ +  +  +  + ]:      816025 :     bool        nondeterministic = (locale && !locale->deterministic);
      87                 :             : 
      88                 :             :     /* Fast path for match-everything pattern */
      89   [ +  +  +  + ]:      816025 :     if (plen == 1 && *p == '%')
      90                 :         146 :         return LIKE_TRUE;
      91                 :             : 
      92                 :             :     /* Since this function recurses, it could be driven to stack overflow */
      93                 :      815879 :     check_stack_depth();
      94                 :             : 
      95                 :             :     /*
      96                 :             :      * In this loop, we advance by char when matching wildcards (and thus on
      97                 :             :      * recursive entry to this function we are properly char-synced). On other
      98                 :             :      * occasions it is safe to advance by byte, as the text and pattern will
      99                 :             :      * be in lockstep. This allows us to perform all comparisons between the
     100                 :             :      * text and pattern on a byte by byte basis, even for multi-byte
     101                 :             :      * encodings.  (But that doesn't work in a nondeterministic locale, so the
     102                 :             :      * nondeterministic case below has to advance the text by chars.)
     103                 :             :      */
     104   [ +  +  +  + ]:     1204028 :     while (tlen > 0 && plen > 0)
     105                 :             :     {
     106                 :             :         /*
     107                 :             :          * At the top of this loop, we are not positioned immediately after an
     108                 :             :          * escape, so we may take wildcards at face value.
     109                 :             :          */
     110         [ +  + ]:     1196762 :         if (*p == '%')
     111                 :             :         {
     112                 :             :             char        firstpat;
     113                 :             : 
     114                 :             :             /*
     115                 :             :              * % processing is essentially a search for a text position at
     116                 :             :              * which the remainder of the text matches the remainder of the
     117                 :             :              * pattern, using a recursive call to check each potential match.
     118                 :             :              *
     119                 :             :              * If there are wildcards immediately following the %, we can skip
     120                 :             :              * over them first, using the idea that any sequence of N _'s and
     121                 :             :              * one or more %'s is equivalent to N _'s and one % (ie, it will
     122                 :             :              * match any sequence of at least N text characters).  In this way
     123                 :             :              * we will always run the recursive search loop using a pattern
     124                 :             :              * fragment that begins with a literal character-to-match, thereby
     125                 :             :              * not recursing more than we have to.
     126                 :             :              */
     127                 :       94395 :             NextByte(p, plen);
     128                 :             : 
     129         [ +  + ]:       94744 :             while (plen > 0)
     130                 :             :             {
     131         [ +  + ]:       73555 :                 if (*p == '%')
     132                 :          15 :                     NextByte(p, plen);
     133         [ +  + ]:       73540 :                 else if (*p == '_')
     134                 :             :                 {
     135                 :             :                     /* If not enough text left to match the pattern, ABORT */
     136         [ +  + ]:         339 :                     if (tlen <= 0)
     137                 :           5 :                         return LIKE_ABORT;
     138   [ +  +  -  + ]:         334 :                     NextChar(t, tlen);
     139                 :         334 :                     NextByte(p, plen);
     140                 :             :                 }
     141                 :             :                 else
     142                 :       73201 :                     break;      /* Reached a non-wildcard pattern char */
     143                 :             :             }
     144                 :             : 
     145                 :             :             /*
     146                 :             :              * If we're at end of pattern, match: we have a trailing % which
     147                 :             :              * matches any remaining text string.
     148                 :             :              */
     149         [ +  + ]:       94390 :             if (plen <= 0)
     150                 :       21189 :                 return LIKE_TRUE;
     151                 :             : 
     152                 :             :             /*
     153                 :             :              * Otherwise, scan for a text position at which we can match the
     154                 :             :              * rest of the pattern.  The first remaining pattern char is known
     155                 :             :              * to be a regular or escaped literal character, so we can compare
     156                 :             :              * the first pattern byte to each text byte to avoid recursing
     157                 :             :              * more than we have to.  This fact also guarantees that we don't
     158                 :             :              * have to consider a match to the zero-length substring at the
     159                 :             :              * end of the text.  But with a nondeterministic locale, we can't
     160                 :             :              * rely on the first byte of a match being equal, so we have to
     161                 :             :              * recurse in any case.
     162                 :             :              */
     163         [ +  + ]:       73201 :             if (*p == '\\')
     164                 :             :             {
     165         [ -  + ]:           2 :                 if (plen < 2)
     166         [ #  # ]:           0 :                     ereport(ERROR,
     167                 :             :                             (errcode(ERRCODE_INVALID_ESCAPE_SEQUENCE),
     168                 :             :                              errmsg("LIKE pattern must not end with escape character")));
     169                 :           2 :                 firstpat = GETCHAR(p[1]);
     170                 :             :             }
     171                 :             :             else
     172                 :       73199 :                 firstpat = GETCHAR(*p);
     173                 :             : 
     174         [ +  + ]:     2152931 :             while (tlen > 0)
     175                 :             :             {
     176   [ +  +  +  + ]:     2095627 :                 if (GETCHAR(*t) == firstpat || nondeterministic)
     177                 :             :                 {
     178                 :       58984 :                     int         matched = MatchText(t, tlen, p, plen, locale);
     179                 :             : 
     180         [ +  + ]:       58984 :                     if (matched != LIKE_FALSE)
     181                 :       15897 :                         return matched; /* TRUE or ABORT */
     182                 :             :                 }
     183                 :             : 
     184   [ +  +  +  + ]:     2079768 :                 NextChar(t, tlen);
     185                 :             :             }
     186                 :             : 
     187                 :             :             /*
     188                 :             :              * End of text with no match, so no point in trying later places
     189                 :             :              * to start matching this pattern.
     190                 :             :              */
     191                 :       57304 :             return LIKE_ABORT;
     192                 :             :         }
     193         [ +  + ]:     1102367 :         else if (*p == '_')
     194                 :             :         {
     195                 :             :             /* _ matches any single character, and we know there is one */
     196   [ +  +  +  + ]:       10154 :             NextChar(t, tlen);
     197                 :       10134 :             NextByte(p, plen);
     198                 :       10134 :             continue;
     199                 :             :         }
     200         [ +  + ]:     1092233 :         else if (nondeterministic)
     201                 :             :         {
     202                 :             :             /*
     203                 :             :              * For nondeterministic locales, we find the next substring of the
     204                 :             :              * pattern that does not contain wildcards and try to find a
     205                 :             :              * matching substring in the text.  Crucially, we cannot do this
     206                 :             :              * character by character, as in the normal case, but must do it
     207                 :             :              * substring by substring, partitioned by the wildcard characters.
     208                 :             :              * (This is per SQL standard.)
     209                 :             :              */
     210                 :             :             const char *p1;
     211                 :             :             size_t      p1len;
     212                 :             :             const char *t1;
     213                 :             :             size_t      t1len;
     214                 :             :             bool        found_escape;
     215                 :             :             const char *subpat;
     216                 :             :             size_t      subpatlen;
     217                 :         277 :             char       *buf = NULL;
     218                 :             : 
     219                 :             :             /*
     220                 :             :              * Determine length of substring of pattern without wildcards.  p
     221                 :             :              * is the start of the subpattern, p1 will advance to one past its
     222                 :             :              * last byte.  Also track if we found an escape character.
     223                 :             :              */
     224                 :         277 :             p1 = p;
     225                 :         277 :             p1len = plen;
     226                 :         277 :             found_escape = false;
     227         [ +  + ]:         923 :             while (p1len > 0)
     228                 :             :             {
     229         [ +  + ]:         776 :                 if (*p1 == '\\')
     230                 :             :                 {
     231                 :          64 :                     found_escape = true;
     232                 :          64 :                     NextByte(p1, p1len);
     233         [ +  + ]:          64 :                     if (p1len == 0)
     234         [ +  - ]:           4 :                         ereport(ERROR,
     235                 :             :                                 (errcode(ERRCODE_INVALID_ESCAPE_SEQUENCE),
     236                 :             :                                  errmsg("LIKE pattern must not end with escape character")));
     237                 :             :                 }
     238   [ +  +  +  + ]:         712 :                 else if (*p1 == '_' || *p1 == '%')
     239                 :             :                     break;
     240                 :             :                 /* Advance over regular or escaped character */
     241                 :         646 :                 NextByte(p1, p1len);
     242                 :             :             }
     243                 :             : 
     244                 :             :             /*
     245                 :             :              * If we found an escape character, then make a de-escaped copy of
     246                 :             :              * the subpattern that we can use to match literally.  Otherwise
     247                 :             :              * we can use the subpattern in-place.  (buf holds the de-escaped
     248                 :             :              * copy; be sure to pfree it before returning.)
     249                 :             :              */
     250         [ +  + ]:         273 :             if (found_escape)
     251                 :             :             {
     252                 :             :                 char       *b;
     253                 :             : 
     254                 :          50 :                 b = buf = palloc(p1 - p);
     255         [ +  + ]:         265 :                 for (const char *c = p; c < p1; c++)
     256                 :             :                 {
     257         [ +  + ]:         215 :                     if (*c == '\\')
     258                 :          60 :                         c++;    /* we already checked this isn't the end */
     259                 :         215 :                     *(b++) = *c;
     260                 :             :                 }
     261                 :             : 
     262                 :          50 :                 subpat = buf;
     263                 :          50 :                 subpatlen = b - buf;
     264                 :             :             }
     265                 :             :             else
     266                 :             :             {
     267                 :         223 :                 subpat = p;
     268                 :         223 :                 subpatlen = p1 - p;
     269                 :             :             }
     270                 :             : 
     271                 :             :             /*
     272                 :             :              * Shortcut: If this is the end of the pattern, then the rest of
     273                 :             :              * the text has to match the rest of the pattern.
     274                 :             :              */
     275         [ +  + ]:         273 :             if (p1len == 0)
     276                 :             :             {
     277                 :             :                 int         cmp;
     278                 :             : 
     279                 :         147 :                 cmp = pg_strncoll(subpat, subpatlen, t, tlen, locale);
     280                 :             : 
     281         [ +  + ]:         147 :                 if (buf)
     282                 :          25 :                     pfree(buf);
     283         [ +  + ]:         147 :                 if (cmp == 0)
     284                 :          97 :                     return LIKE_TRUE;
     285                 :             :                 else
     286                 :          50 :                     return LIKE_FALSE;
     287                 :             :             }
     288                 :             : 
     289                 :             :             /*
     290                 :             :              * Consider each successively-longer substring of the remaining
     291                 :             :              * text and try to match it against the subpattern.  t is the
     292                 :             :              * start of the substring, t1 is one past its last byte.  We start
     293                 :             :              * with a zero-length substring.
     294                 :             :              */
     295                 :         126 :             t1 = t;
     296                 :         126 :             t1len = tlen;
     297                 :             :             for (;;)
     298                 :         336 :             {
     299                 :             :                 int         cmp;
     300                 :             : 
     301                 :             :                 /* This could be slow, so allow interrupts */
     302         [ -  + ]:         462 :                 CHECK_FOR_INTERRUPTS();
     303                 :             : 
     304                 :         462 :                 cmp = pg_strncoll(subpat, subpatlen, t, (t1 - t), locale);
     305                 :             : 
     306                 :             :                 /*
     307                 :             :                  * If we found a match, we have to test if the rest of pattern
     308                 :             :                  * can match against the rest of the text.  If not, we have to
     309                 :             :                  * continue and try the next longer substring.  (This is
     310                 :             :                  * similar to the recursion for the '%' wildcard above.)
     311                 :             :                  *
     312                 :             :                  * Note that we can't just wind forward p and t and continue
     313                 :             :                  * with the main loop.  This would fail for example with
     314                 :             :                  *
     315                 :             :                  * U&'\0061\0308bc' LIKE U&'\00E4_c' COLLATE ignore_accents
     316                 :             :                  *
     317                 :             :                  * You'd find that t=\0061 matches p=\00E4, but then the rest
     318                 :             :                  * won't match; but t=\0061\0308 also matches p=\00E4, and
     319                 :             :                  * then the rest will match.
     320                 :             :                  */
     321         [ +  + ]:         462 :                 if (cmp == 0)
     322                 :             :                 {
     323                 :         100 :                     int         matched = MatchText(t1, t1len, p1, p1len, locale);
     324                 :             : 
     325         [ +  + ]:         100 :                     if (matched == LIKE_TRUE)
     326                 :             :                     {
     327         [ +  + ]:          90 :                         if (buf)
     328                 :          20 :                             pfree(buf);
     329                 :          90 :                         return matched;
     330                 :             :                     }
     331                 :             :                 }
     332                 :             : 
     333                 :             :                 /*
     334                 :             :                  * Didn't match.  If we used up the whole text, then the match
     335                 :             :                  * fails.  Otherwise, try again with a longer substring.
     336                 :             :                  */
     337         [ +  + ]:         372 :                 if (t1len == 0)
     338                 :             :                 {
     339         [ +  + ]:          36 :                     if (buf)
     340                 :           5 :                         pfree(buf);
     341                 :          36 :                     return LIKE_FALSE;
     342                 :             :                 }
     343                 :             :                 else
     344   [ +  +  +  + ]:         366 :                     NextChar(t1, t1len);
     345                 :             :             }                   /* end loop over substrings starting at t */
     346                 :             :         }
     347                 :             :         /* the rest of this loop considers only deterministic cases */
     348         [ +  + ]:     1091956 :         else if (*p == '\\')
     349                 :             :         {
     350                 :             :             /* Next pattern byte must match literally, whatever it is */
     351                 :        9006 :             NextByte(p, plen);
     352                 :             :             /* ... and there had better be one, per SQL standard */
     353         [ -  + ]:        9006 :             if (plen <= 0)
     354         [ #  # ]:           0 :                 ereport(ERROR,
     355                 :             :                         (errcode(ERRCODE_INVALID_ESCAPE_SEQUENCE),
     356                 :             :                          errmsg("LIKE pattern must not end with escape character")));
     357         [ +  + ]:        9006 :             if (GETCHAR(*p) != GETCHAR(*t))
     358                 :        2446 :                 return LIKE_FALSE;
     359                 :             :         }
     360         [ +  + ]:     1082950 :         else if (GETCHAR(*p) != GETCHAR(*t))
     361                 :             :         {
     362                 :             :             /* non-wildcard pattern char fails to match text char */
     363                 :      711495 :             return LIKE_FALSE;
     364                 :             :         }
     365                 :             : 
     366                 :             :         /*
     367                 :             :          * Pattern and text match, so advance.
     368                 :             :          *
     369                 :             :          * It is safe to use NextByte instead of NextChar here, even for
     370                 :             :          * multi-byte character sets, because we are not following immediately
     371                 :             :          * after a wildcard character. If we are in the middle of a multibyte
     372                 :             :          * character, we must already have matched at least one byte of the
     373                 :             :          * character from both text and pattern; so we cannot get out-of-sync
     374                 :             :          * on character boundaries.  And we know that no backend-legal
     375                 :             :          * encoding allows ASCII characters such as '%' to appear as non-first
     376                 :             :          * bytes of characters, so we won't mistakenly detect a new wildcard.
     377                 :             :          */
     378                 :      378015 :         NextByte(t, tlen);
     379                 :      378015 :         NextByte(p, plen);
     380                 :             :     }
     381                 :             : 
     382         [ +  + ]:        7266 :     if (tlen > 0)
     383                 :         259 :         return LIKE_FALSE;      /* end of pattern, but not of text */
     384                 :             : 
     385                 :             :     /*
     386                 :             :      * End of text, but perhaps not of pattern.  Match iff the remaining
     387                 :             :      * pattern can match a zero-length string, ie, it's zero or more %'s.
     388                 :             :      */
     389   [ +  +  +  + ]:        7409 :     while (plen > 0 && *p == '%')
     390                 :         402 :         NextByte(p, plen);
     391         [ +  + ]:        7007 :     if (plen <= 0)
     392                 :        3365 :         return LIKE_TRUE;
     393                 :             : 
     394                 :             :     /*
     395                 :             :      * End of text with no match, so no point in trying later places to start
     396                 :             :      * matching this pattern.
     397                 :             :      */
     398                 :        3642 :     return LIKE_ABORT;
     399                 :             : }                               /* MatchText() */
     400                 :             : 
     401                 :             : /*
     402                 :             :  * like_escape() --- given a pattern and an ESCAPE string,
     403                 :             :  * convert the pattern to use Postgres' standard backslash escape convention.
     404                 :             :  */
     405                 :             : #ifdef do_like_escape
     406                 :             : 
     407                 :             : static text *
     408                 :         196 : do_like_escape(text *pat, text *esc)
     409                 :             : {
     410                 :             :     text       *result;
     411                 :             :     char       *p,
     412                 :             :                *e,
     413                 :             :                *r;
     414                 :             :     int         plen,
     415                 :             :                 elen;
     416                 :             :     bool        afterescape;
     417                 :             : 
     418                 :         196 :     p = VARDATA_ANY(pat);
     419                 :         196 :     plen = VARSIZE_ANY_EXHDR(pat);
     420                 :         196 :     e = VARDATA_ANY(esc);
     421                 :         196 :     elen = VARSIZE_ANY_EXHDR(esc);
     422                 :             : 
     423                 :             :     /*
     424                 :             :      * Worst-case pattern growth is 2x --- unlikely, but it's hardly worth
     425                 :             :      * trying to calculate the size more accurately than that.
     426                 :             :      */
     427                 :         196 :     result = (text *) palloc(plen * 2 + VARHDRSZ);
     428                 :         196 :     r = VARDATA(result);
     429                 :             : 
     430         [ +  + ]:         196 :     if (elen == 0)
     431                 :             :     {
     432                 :             :         /*
     433                 :             :          * No escape character is wanted.  Double any backslashes in the
     434                 :             :          * pattern to make them act like ordinary characters.
     435                 :             :          */
     436         [ +  + ]:          64 :         while (plen > 0)
     437                 :             :         {
     438         [ -  + ]:          48 :             if (*p == '\\')
     439                 :           0 :                 *r++ = '\\';
     440         [ +  + ]:          96 :             CopyAdvChar(r, p, plen);
     441                 :             :         }
     442                 :             :     }
     443                 :             :     else
     444                 :             :     {
     445                 :             :         /*
     446                 :             :          * The specified escape must be only a single character.
     447                 :             :          */
     448                 :         180 :         NextChar(e, elen);
     449         [ -  + ]:         180 :         if (elen != 0)
     450         [ #  # ]:           0 :             ereport(ERROR,
     451                 :             :                     (errcode(ERRCODE_INVALID_ESCAPE_SEQUENCE),
     452                 :             :                      errmsg("invalid escape string"),
     453                 :             :                      errhint("Escape string must be empty or one character.")));
     454                 :             : 
     455                 :         180 :         e = VARDATA_ANY(esc);
     456                 :         180 :         elen = VARSIZE_ANY_EXHDR(esc);
     457                 :             : 
     458                 :             :         /*
     459                 :             :          * If specified escape is '\', just copy the pattern as-is.
     460                 :             :          */
     461         [ -  + ]:         180 :         if (*e == '\\')
     462                 :             :         {
     463                 :           0 :             memcpy(result, pat, VARSIZE_ANY(pat));
     464                 :           0 :             return result;
     465                 :             :         }
     466                 :             : 
     467                 :             :         /*
     468                 :             :          * Otherwise, convert occurrences of the specified escape character to
     469                 :             :          * '\', and double occurrences of '\' --- unless they immediately
     470                 :             :          * follow an escape character!
     471                 :             :          */
     472                 :         180 :         afterescape = false;
     473         [ +  + ]:        1130 :         while (plen > 0)
     474                 :             :         {
     475   [ +  +  +  + ]:         950 :             if (CHAREQ(p, plen, e, elen) && !afterescape)
     476                 :             :             {
     477                 :         175 :                 *r++ = '\\';
     478                 :         175 :                 NextChar(p, plen);
     479                 :         175 :                 afterescape = true;
     480                 :             :             }
     481         [ +  + ]:         775 :             else if (*p == '\\')
     482                 :             :             {
     483                 :          15 :                 *r++ = '\\';
     484         [ +  + ]:          15 :                 if (!afterescape)
     485                 :          10 :                     *r++ = '\\';
     486                 :          15 :                 NextChar(p, plen);
     487                 :          15 :                 afterescape = false;
     488                 :             :             }
     489                 :             :             else
     490                 :             :             {
     491         [ +  + ]:        1500 :                 CopyAdvChar(r, p, plen);
     492                 :         760 :                 afterescape = false;
     493                 :             :             }
     494                 :             :         }
     495                 :             :     }
     496                 :             : 
     497                 :         196 :     SET_VARSIZE(result, r - ((char *) result));
     498                 :             : 
     499                 :         196 :     return result;
     500                 :             : }
     501                 :             : #endif                          /* do_like_escape */
     502                 :             : 
     503                 :             : #ifdef CHAREQ
     504                 :             : #undef CHAREQ
     505                 :             : #endif
     506                 :             : 
     507                 :             : #undef NextChar
     508                 :             : #undef CopyAdvChar
     509                 :             : #undef MatchText
     510                 :             : 
     511                 :             : #ifdef do_like_escape
     512                 :             : #undef do_like_escape
     513                 :             : #endif
     514                 :             : 
     515                 :             : #undef GETCHAR
     516                 :             : 
     517                 :             : #ifdef MATCH_LOWER
     518                 :             : #undef MATCH_LOWER
     519                 :             : 
     520                 :             : #endif
        

Generated by: LCOV version 2.0-1