]> granicus.if.org Git - postgresql/commitdiff
Fix incorrect handling of lookahead constraints in pg_regprefix().
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 19 Oct 2015 20:54:53 +0000 (13:54 -0700)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 19 Oct 2015 20:54:53 +0000 (13:54 -0700)
pg_regprefix was doing nothing with lookahead constraints, which would
be fine if it were the right kind of nothing, but it isn't: we have to
terminate our search for a fixed prefix, not just pretend the LACON arc
isn't there.  Otherwise, if the current state has both a LACON outarc and a
single plain-color outarc, we'd falsely conclude that the color represents
an addition to the fixed prefix, and generate an extracted index condition
that restricts the indexscan too much.  (See added regression test case.)

Terminating the search is conservative: we could traverse the LACON arc
(thus assuming that the constraint can be satisfied at runtime) and then
examine the outarcs of the linked-to state.  But that would be a lot more
work than it seems worth, because writing a LACON followed by a single
plain character is a pretty silly thing to do.

This makes a difference only in rather contrived cases, but it's a bug,
so back-patch to all supported branches.

src/backend/regex/regprefix.c
src/test/regress/expected/regex.out
src/test/regress/sql/regex.sql

index e78faf399606fb004f11163e462bb9a1f2349f89..ce41620a0b4b1b740955da99aacdd5f502de9b36 100644 (file)
@@ -162,14 +162,12 @@ findprefix(struct cnfa * cnfa,
                thiscolor = COLORLESS;
                for (ca = cnfa->states[st]; ca->co != COLORLESS; ca++)
                {
-                       /* We ignore lookahead constraints */
-                       if (ca->co >= cnfa->ncolors)
-                               continue;
-                       /* We can also ignore BOS/BOL arcs */
+                       /* We can ignore BOS/BOL arcs */
                        if (ca->co == cnfa->bos[0] || ca->co == cnfa->bos[1])
                                continue;
-                       /* ... but EOS/EOL arcs terminate the search */
-                       if (ca->co == cnfa->eos[0] || ca->co == cnfa->eos[1])
+                       /* ... but EOS/EOL arcs terminate the search, as do LACONs */
+                       if (ca->co == cnfa->eos[0] || ca->co == cnfa->eos[1] ||
+                               ca->co >= cnfa->ncolors)
                        {
                                thiscolor = COLORLESS;
                                break;
index 320f5e88c378147d1829a2e9737675b6e087b359..be151858a3884a9c9f32d64608d80e959e8f912c 100644 (file)
@@ -153,6 +153,14 @@ explain (costs off) select * from pg_proc where proname ~ '^(abc)?d';
    Filter: (proname ~ '^(abc)?d'::text)
 (2 rows)
 
+explain (costs off) select * from pg_proc where proname ~ '^abcd(x|(?=\w\w)q)';
+                               QUERY PLAN                               
+------------------------------------------------------------------------
+ Index Scan using pg_proc_proname_args_nsp_index on pg_proc
+   Index Cond: ((proname >= 'abcd'::name) AND (proname < 'abce'::name))
+   Filter: (proname ~ '^abcd(x|(?=\w\w)q)'::text)
+(3 rows)
+
 -- Test for infinite loop in pullback() (CVE-2007-4772)
 select 'a' ~ '($|^)*';
  ?column? 
index 5412f6e1c58408d3e772882fa814d2fc0c3f3dad..c59fa35f24d81f5e2c4aceae0ada1ca3832f0ac4 100644 (file)
@@ -34,6 +34,7 @@ explain (costs off) select * from pg_proc where proname ~ '^abc+d';
 explain (costs off) select * from pg_proc where proname ~ '^(abc)(def)';
 explain (costs off) select * from pg_proc where proname ~ '^(abc)$';
 explain (costs off) select * from pg_proc where proname ~ '^(abc)?d';
+explain (costs off) select * from pg_proc where proname ~ '^abcd(x|(?=\w\w)q)';
 
 -- Test for infinite loop in pullback() (CVE-2007-4772)
 select 'a' ~ '($|^)*';