diff options
Diffstat (limited to 'src/backend/regex/regexec.c')
-rw-r--r-- | src/backend/regex/regexec.c | 73 |
1 files changed, 46 insertions, 27 deletions
diff --git a/src/backend/regex/regexec.c b/src/backend/regex/regexec.c index f8e31f8f4ad..224da5064b6 100644 --- a/src/backend/regex/regexec.c +++ b/src/backend/regex/regexec.c @@ -720,7 +720,7 @@ cdissect(struct vars * v, case '|': /* alternation */ assert(t->left != NULL); return caltdissect(v, t, begin, end); - case 'b': /* back ref -- shouldn't be calling us! */ + case 'b': /* back reference */ assert(t->left == NULL && t->right == NULL); return cbrdissect(v, t, begin, end); case '.': /* concatenation */ @@ -962,12 +962,12 @@ cbrdissect(struct vars * v, chr *begin, /* beginning of relevant substring */ chr *end) /* end of same */ { - int i; int n = t->subno; - size_t len; - chr *paren; + size_t numreps; + size_t tlen; + size_t brlen; + chr *brstring; chr *p; - chr *stop; int min = t->min; int max = t->max; @@ -978,46 +978,65 @@ cbrdissect(struct vars * v, MDEBUG(("cbackref n%d %d{%d-%d}\n", t->retry, n, min, max)); + /* get the backreferenced string */ if (v->pmatch[n].rm_so == -1) return REG_NOMATCH; - paren = v->start + v->pmatch[n].rm_so; - len = v->pmatch[n].rm_eo - v->pmatch[n].rm_so; + brstring = v->start + v->pmatch[n].rm_so; + brlen = v->pmatch[n].rm_eo - v->pmatch[n].rm_so; /* no room to maneuver -- retries are pointless */ if (v->mem[t->retry]) return REG_NOMATCH; v->mem[t->retry] = 1; - /* special-case zero-length string */ - if (len == 0) + /* special cases for zero-length strings */ + if (brlen == 0) + { + /* + * matches only if target is zero length, but any number of + * repetitions can be considered to be present + */ + if (begin == end && min <= max) + { + MDEBUG(("cbackref matched trivially\n")); + return REG_OKAY; + } + return REG_NOMATCH; + } + if (begin == end) { - if (begin == end) + /* matches only if zero repetitions are okay */ + if (min == 0) + { + MDEBUG(("cbackref matched trivially\n")); return REG_OKAY; + } return REG_NOMATCH; } - /* and too-short string */ - assert(end >= begin); - if ((size_t) (end - begin) < len) + /* + * check target length to see if it could possibly be an allowed number of + * repetitions of brstring + */ + assert(end > begin); + tlen = end - begin; + if (tlen % brlen != 0) + return REG_NOMATCH; + numreps = tlen / brlen; + if (numreps < min || (numreps > max && max != INFINITY)) return REG_NOMATCH; - stop = end - len; - /* count occurrences */ - i = 0; - for (p = begin; p <= stop && (i < max || max == INFINITY); p += len) + /* okay, compare the actual string contents */ + p = begin; + while (numreps-- > 0) { - if ((*v->g->compare) (paren, p, len) != 0) - break; - i++; + if ((*v->g->compare) (brstring, p, brlen) != 0) + return REG_NOMATCH; + p += brlen; } - MDEBUG(("cbackref found %d\n", i)); - /* and sort it out */ - if (p != end) /* didn't consume all of it */ - return REG_NOMATCH; - if (min <= i && (i <= max || max == INFINITY)) - return REG_OKAY; - return REG_NOMATCH; /* out of range */ + MDEBUG(("cbackref matched\n")); + return REG_OKAY; } /* |