Handle interaction of regexp's makesearch and MATCHALL more honestly.
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 27 Aug 2021 16:18:58 +0000 (12:18 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 27 Aug 2021 16:18:58 +0000 (12:18 -0400)
Second thoughts about commit 824bf7190: we apply makesearch() to
an NFA after having determined whether it is a MATCHALL pattern.
Prepending ".*" doesn't make it non-MATCHALL, but it does change the
maximum possible match length, and makesearch() failed to update that.
This has no ill effects given the stylized usage of search NFAs, but
it seems like it's better to keep the data structure consistent.  In
particular, fixing this allows more honest handling of the MATCHALL
check in matchuntil(): we can now assert that maxmatchall is infinity,
instead of lamely assuming that it should act that way.

In passing, improve the code in dump[c]nfa so that infinite maxmatchall
is printed as "inf" not a magic number.

src/backend/regex/regc_nfa.c
src/backend/regex/regcomp.c
src/backend/regex/rege_dfa.c

index 6d77c59e121396bbe5198c13a79e2ff83ab90ec9..0e93c74287ec76a2560645cd9e7f5cd01426d6e4 100644 (file)
@@ -3602,8 +3602,13 @@ dumpnfa(struct nfa *nfa,
    if (nfa->flags & HASLACONS)
        fprintf(f, ", haslacons");
    if (nfa->flags & MATCHALL)
-       fprintf(f, ", minmatchall %d, maxmatchall %d",
-               nfa->minmatchall, nfa->maxmatchall);
+   {
+       fprintf(f, ", minmatchall %d", nfa->minmatchall);
+       if (nfa->maxmatchall == DUPINF)
+           fprintf(f, ", maxmatchall inf");
+       else
+           fprintf(f, ", maxmatchall %d", nfa->maxmatchall);
+   }
    fprintf(f, "\n");
    for (s = nfa->states; s != NULL; s = s->next)
    {
@@ -3766,8 +3771,13 @@ dumpcnfa(struct cnfa *cnfa,
    if (cnfa->flags & HASLACONS)
        fprintf(f, ", haslacons");
    if (cnfa->flags & MATCHALL)
-       fprintf(f, ", minmatchall %d, maxmatchall %d",
-               cnfa->minmatchall, cnfa->maxmatchall);
+   {
+       fprintf(f, ", minmatchall %d", cnfa->minmatchall);
+       if (cnfa->maxmatchall == DUPINF)
+           fprintf(f, ", maxmatchall inf");
+       else
+           fprintf(f, ", maxmatchall %d", cnfa->maxmatchall);
+   }
    fprintf(f, "\n");
    for (st = 0; st < cnfa->nstates; st++)
        dumpcstate(st, cnfa, f);
index bfe12eb08b361f7a3316ad1f9d54c2a07df2b211..b735fa6eaff75c9d56f29c6c55ec506e0a12478f 100644 (file)
@@ -598,6 +598,13 @@ makesearch(struct vars *v,
        /* and ^* and \A* too -- not always necessary, but harmless */
        newarc(nfa, PLAIN, nfa->bos[0], pre, pre);
        newarc(nfa, PLAIN, nfa->bos[1], pre, pre);
+
+       /*
+        * The pattern is still MATCHALL if it was before, but the max match
+        * length is now infinity.
+        */
+       if (nfa->flags & MATCHALL)
+           nfa->maxmatchall = DUPINF;
    }
 
    /*
index 1d79d734468f94db502ad3db599cfbc5553134cf..ba1289c64a9553d622068046c0f2037ca6ecc486 100644 (file)
@@ -385,14 +385,10 @@ matchuntil(struct vars *v,
    {
        size_t      nchr = probe - v->start;
 
-       /*
-        * It might seem that we should check maxmatchall too, but the .* at
-        * the front of the pattern absorbs any extra characters (and it was
-        * tacked on *after* computing minmatchall/maxmatchall).  Thus, we
-        * should match if there are at least minmatchall characters.
-        */
        if (nchr < d->cnfa->minmatchall)
            return 0;
+       /* maxmatchall will always be infinity, cf. makesearch() */
+       assert(d->cnfa->maxmatchall == DUPINF);
        return 1;
    }