mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-21 08:29:39 +08:00
Fix incorrect search for "x?" style matches in creviterdissect().
When the number of allowed iterations is limited (either a "?" quantifier
or a bound expression), the last sub-match has to reach to the end of the
target string. The previous coding here first tried the shortest possible
match (one character, usually) and then gave up and back-tracked if that
didn't work, typically leading to failure to match overall, as shown in
bug #11478 from Christoph Berg. The minimum change to fix that would be to
not decrement k before "goto backtrack"; but that would be a pretty stupid
solution, because we'd laboriously try each possible sub-match length
before finally discovering that only ending at the end can work. Instead,
force the sub-match endpoint limit up to the end for even the first
shortest() call if we cannot have any more sub-matches after this one.
Bug introduced in my rewrite that added the iterdissect logic, commit
173e29aa5d
. The shortest-first search code
was too closely modeled on the longest-first code, which hasn't got this
issue since it tries a match reaching to the end to start with anyway.
Back-patch to all affected branches.
This commit is contained in:
parent
a564307373
commit
3694b4d7e1
@ -1190,6 +1190,10 @@ creviterdissect(struct vars * v,
|
|||||||
(k >= min_matches || min_matches - k < end - limit))
|
(k >= min_matches || min_matches - k < end - limit))
|
||||||
limit++;
|
limit++;
|
||||||
|
|
||||||
|
/* if this is the last allowed sub-match, it must reach to the end */
|
||||||
|
if (k >= max_matches)
|
||||||
|
limit = end;
|
||||||
|
|
||||||
/* try to find an endpoint for the k'th sub-match */
|
/* try to find an endpoint for the k'th sub-match */
|
||||||
endpts[k] = shortest(v, d, endpts[k - 1], limit, end,
|
endpts[k] = shortest(v, d, endpts[k - 1], limit, end,
|
||||||
(chr **) NULL, (int *) NULL);
|
(chr **) NULL, (int *) NULL);
|
||||||
|
@ -188,3 +188,11 @@ select regexp_matches('Programmer', '(\w)(.*?\1)', 'g');
|
|||||||
{m,m}
|
{m,m}
|
||||||
(2 rows)
|
(2 rows)
|
||||||
|
|
||||||
|
-- Test for proper matching of non-greedy iteration (bug #11478)
|
||||||
|
select regexp_matches('foo/bar/baz',
|
||||||
|
'^([^/]+?)(?:/([^/]+?))(?:/([^/]+?))?$', '');
|
||||||
|
regexp_matches
|
||||||
|
----------------
|
||||||
|
{foo,bar,baz}
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
@ -46,3 +46,7 @@ select 'a' ~ '((((((a+|)+|)+|)+|)+|)+|)';
|
|||||||
-- https://core.tcl.tk/tcl/tktview/6585b21ca8fa6f3678d442b97241fdd43dba2ec0
|
-- https://core.tcl.tk/tcl/tktview/6585b21ca8fa6f3678d442b97241fdd43dba2ec0
|
||||||
select 'Programmer' ~ '(\w).*?\1' as t;
|
select 'Programmer' ~ '(\w).*?\1' as t;
|
||||||
select regexp_matches('Programmer', '(\w)(.*?\1)', 'g');
|
select regexp_matches('Programmer', '(\w)(.*?\1)', 'g');
|
||||||
|
|
||||||
|
-- Test for proper matching of non-greedy iteration (bug #11478)
|
||||||
|
select regexp_matches('foo/bar/baz',
|
||||||
|
'^([^/]+?)(?:/([^/]+?))(?:/([^/]+?))?$', '');
|
||||||
|
Loading…
Reference in New Issue
Block a user