aboutsummaryrefslogtreecommitdiff
path: root/src/backend/regex
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/regex')
-rw-r--r--src/backend/regex/regc_color.c18
-rw-r--r--src/backend/regex/regc_nfa.c40
-rw-r--r--src/backend/regex/regcomp.c3
3 files changed, 60 insertions, 1 deletions
diff --git a/src/backend/regex/regc_color.c b/src/backend/regex/regc_color.c
index 30bda0e5ad0..8ae788f5195 100644
--- a/src/backend/regex/regc_color.c
+++ b/src/backend/regex/regc_color.c
@@ -1075,9 +1075,19 @@ colorcomplement(struct nfa *nfa,
assert(of != from);
- /* A RAINBOW arc matches all colors, making the complement empty */
+ /*
+ * A RAINBOW arc matches all colors, making the complement empty. But we
+ * can't just return without making any arcs, because that would leave the
+ * NFA disconnected which would break any future delsub(). Instead, make
+ * a CANTMATCH arc. Also set the HASCANTMATCH flag so we know we need to
+ * clean that up at the start of NFA optimization.
+ */
if (findarc(of, PLAIN, RAINBOW) != NULL)
+ {
+ newarc(nfa, CANTMATCH, 0, from, to);
+ nfa->flags |= HASCANTMATCH;
return;
+ }
/* Otherwise, transiently mark the colors that appear in of's out-arcs */
for (a = of->outs; a != NULL; a = a->outchain)
@@ -1089,6 +1099,12 @@ colorcomplement(struct nfa *nfa,
assert(!UNUSEDCOLOR(cd));
cd->flags |= COLMARK;
}
+
+ /*
+ * There's no syntax for re-complementing a color set, so we cannot
+ * see CANTMATCH arcs here.
+ */
+ assert(a->type != CANTMATCH);
}
/* Scan colors, clear transient marks, add arcs for unmarked colors */
diff --git a/src/backend/regex/regc_nfa.c b/src/backend/regex/regc_nfa.c
index f1819a24f6d..acd2286defd 100644
--- a/src/backend/regex/regc_nfa.c
+++ b/src/backend/regex/regc_nfa.c
@@ -1462,6 +1462,7 @@ removetraverse(struct nfa *nfa,
{
case PLAIN:
case EMPTY:
+ case CANTMATCH:
/* nothing to do */
break;
case AHEAD:
@@ -1599,6 +1600,12 @@ optimize(struct nfa *nfa,
if (verbose)
fprintf(f, "\ninitial cleanup:\n");
#endif
+ /* If we have any CANTMATCH arcs, drop them; but this is uncommon */
+ if (nfa->flags & HASCANTMATCH)
+ {
+ removecantmatch(nfa);
+ nfa->flags &= ~HASCANTMATCH;
+ }
cleanup(nfa); /* may simplify situation */
#ifdef REG_DEBUG
if (verbose)
@@ -2923,6 +2930,34 @@ clonesuccessorstates(struct nfa *nfa,
}
/*
+ * removecantmatch - remove CANTMATCH arcs, which are no longer useful
+ * once we are done with the parsing phase. (We need them only to
+ * preserve connectedness of NFA subgraphs during parsing.)
+ */
+static void
+removecantmatch(struct nfa *nfa)
+{
+ struct state *s;
+
+ for (s = nfa->states; s != NULL; s = s->next)
+ {
+ struct arc *a;
+ struct arc *nexta;
+
+ for (a = s->outs; a != NULL; a = nexta)
+ {
+ nexta = a->outchain;
+ if (a->type == CANTMATCH)
+ {
+ freearc(nfa, a);
+ if (NISERR())
+ return;
+ }
+ }
+ }
+}
+
+/*
* cleanup - clean up NFA after optimizations
*/
static void
@@ -3627,6 +3662,8 @@ dumpnfa(struct nfa *nfa,
fprintf(f, ", eol [%ld]", (long) nfa->eos[1]);
if (nfa->flags & HASLACONS)
fprintf(f, ", haslacons");
+ if (nfa->flags & HASCANTMATCH)
+ fprintf(f, ", hascantmatch");
if (nfa->flags & MATCHALL)
{
fprintf(f, ", minmatchall %d", nfa->minmatchall);
@@ -3749,6 +3786,9 @@ dumparc(struct arc *a,
break;
case EMPTY:
break;
+ case CANTMATCH:
+ fprintf(f, "X");
+ break;
default:
fprintf(f, "0x%x/0%lo", a->type, (long) a->co);
break;
diff --git a/src/backend/regex/regcomp.c b/src/backend/regex/regcomp.c
index 8a6cfb2973d..15b264e50f1 100644
--- a/src/backend/regex/regcomp.c
+++ b/src/backend/regex/regcomp.c
@@ -215,6 +215,7 @@ static void clonesuccessorstates(struct nfa *nfa, struct state *ssource,
struct state *spredecessor,
struct arc *refarc, char *curdonemap,
char *outerdonemap, int nstates);
+static void removecantmatch(struct nfa *nfa);
static void cleanup(struct nfa *nfa);
static void markreachable(struct nfa *nfa, struct state *s,
struct state *okay, struct state *mark);
@@ -342,6 +343,7 @@ struct vars
#define BEHIND 'r' /* color-lookbehind arc */
#define WBDRY 'w' /* word boundary constraint */
#define NWBDRY 'W' /* non-word-boundary constraint */
+#define CANTMATCH 'x' /* arc that cannot match anything */
#define SBEGIN 'A' /* beginning of string (even if not BOL) */
#define SEND 'Z' /* end of string (even if not EOL) */
@@ -2368,6 +2370,7 @@ nfanode(struct vars *v,
nfa = newnfa(v, v->cm, v->nfa);
NOERRZ();
dupnfa(nfa, t->begin, t->end, nfa->init, nfa->final);
+ nfa->flags = v->nfa->flags;
if (!ISERR())
specialcolors(nfa);
if (!ISERR())