diff --git a/src/backend/regex/regc_nfa.c b/src/backend/regex/regc_nfa.c
index 06351bb..5461dd3 100644
*** a/src/backend/regex/regc_nfa.c
--- b/src/backend/regex/regc_nfa.c
*************** pullback(struct nfa * nfa,
*** 1513,1518 ****
--- 1513,1519 ----
  	struct state *nexts;
  	struct arc *a;
  	struct arc *nexta;
+ 	struct state *intermediates;
  	int			progress;
  
  	/* find and pull until there are no more */
*************** pullback(struct nfa * nfa,
*** 1522,1535 ****
  		for (s = nfa->states; s != NULL && !NISERR(); s = nexts)
  		{
  			nexts = s->next;
  			for (a = s->outs; a != NULL && !NISERR(); a = nexta)
  			{
  				nexta = a->outchain;
  				if (a->type == '^' || a->type == BEHIND)
! 					if (pull(nfa, a))
  						progress = 1;
- 				assert(nexta == NULL || s->no != FREESTATE);
  			}
  		}
  		if (progress && f != NULL)
  			dumpnfa(nfa, f);
--- 1523,1547 ----
  		for (s = nfa->states; s != NULL && !NISERR(); s = nexts)
  		{
  			nexts = s->next;
+ 			intermediates = NULL;
  			for (a = s->outs; a != NULL && !NISERR(); a = nexta)
  			{
  				nexta = a->outchain;
  				if (a->type == '^' || a->type == BEHIND)
! 					if (pull(nfa, a, &intermediates))
  						progress = 1;
  			}
+ 			/* clear tmp fields of intermediate states created here */
+ 			while (intermediates != NULL)
+ 			{
+ 				struct state *ns = intermediates->tmp;
+ 
+ 				intermediates->tmp = NULL;
+ 				intermediates = ns;
+ 			}
+ 			/* if s is now useless, get rid of it */
+ 			if ((s->nins == 0 || s->nouts == 0) && !s->flag)
+ 				dropstate(nfa, s);
  		}
  		if (progress && f != NULL)
  			dumpnfa(nfa, f);
*************** pullback(struct nfa * nfa,
*** 1557,1569 ****
  
  /*
   * pull - pull a back constraint backward past its source state
!  * A significant property of this function is that it deletes at most
!  * one state -- the constraint's from state -- and only if the constraint
!  * was that state's last outarc.
   */
! static int						/* 0 couldn't, 1 could */
  pull(struct nfa * nfa,
! 	 struct arc * con)
  {
  	struct state *from = con->from;
  	struct state *to = con->to;
--- 1569,1594 ----
  
  /*
   * pull - pull a back constraint backward past its source state
!  *
!  * Returns 1 if successful (which it always is unless the source is the
!  * start state or we have an internal error), 0 if nothing happened.
!  *
!  * A significant property of this function is that it deletes no pre-existing
!  * states, and no outarcs of the constraint's from state other than the given
!  * constraint arc.  This makes the loops in pullback() safe, at the cost that
!  * we may leave useless states behind.  Therefore, we leave it to pullback()
!  * to delete such states.
!  *
!  * If the from state has multiple back-constraint outarcs, and/or multiple
!  * compatible constraint inarcs, we only need to create one new intermediate
!  * state per combination of predecessor and successor states.  *intermediates
!  * points to a list of such intermediate states for this from state (chained
!  * through their tmp fields).
   */
! static int
  pull(struct nfa * nfa,
! 	 struct arc * con,
! 	 struct state ** intermediates)
  {
  	struct state *from = con->from;
  	struct state *to = con->to;
*************** pull(struct nfa * nfa,
*** 1580,1586 ****
  		return 1;
  	}
  
! 	/* first, clone from state if necessary to avoid other outarcs */
  	if (from->nouts > 1)
  	{
  		s = newstate(nfa);
--- 1605,1615 ----
  		return 1;
  	}
  
! 	/*
! 	 * First, clone from state if necessary to avoid other outarcs.  This may
! 	 * seem wasteful, but it simplifies the logic, and we'll get rid of the
! 	 * clone state again at the bottom.
! 	 */
  	if (from->nouts > 1)
  	{
  		s = newstate(nfa);
*************** pull(struct nfa * nfa,
*** 1589,1601 ****
  		copyins(nfa, from, s, 1);		/* duplicate inarcs */
  		cparc(nfa, con, s, to); /* move constraint arc */
  		freearc(nfa, con);
  		from = s;
  		con = from->outs;
  	}
  	assert(from->nouts == 1);
  
  	/* propagate the constraint into the from state's inarcs */
! 	for (a = from->ins; a != NULL; a = nexta)
  	{
  		nexta = a->inchain;
  		switch (combine(con, a))
--- 1618,1632 ----
  		copyins(nfa, from, s, 1);		/* duplicate inarcs */
  		cparc(nfa, con, s, to); /* move constraint arc */
  		freearc(nfa, con);
+ 		if (NISERR())
+ 			return 0;
  		from = s;
  		con = from->outs;
  	}
  	assert(from->nouts == 1);
  
  	/* propagate the constraint into the from state's inarcs */
! 	for (a = from->ins; a != NULL && !NISERR(); a = nexta)
  	{
  		nexta = a->inchain;
  		switch (combine(con, a))
*************** pull(struct nfa * nfa,
*** 1606,1618 ****
  			case SATISFIED:		/* no action needed */
  				break;
  			case COMPATIBLE:	/* swap the two arcs, more or less */
! 				s = newstate(nfa);
! 				if (NISERR())
! 					return 0;
! 				cparc(nfa, a, s, to);	/* anticipate move */
  				cparc(nfa, con, a->from, s);
! 				if (NISERR())
! 					return 0;
  				freearc(nfa, a);
  				break;
  			default:
--- 1637,1659 ----
  			case SATISFIED:		/* no action needed */
  				break;
  			case COMPATIBLE:	/* swap the two arcs, more or less */
! 				/* need an intermediate state, but might have one already */
! 				for (s = *intermediates; s != NULL; s = s->tmp)
! 				{
! 					assert(s->nins > 0 && s->nouts > 0);
! 					if (s->ins->from == a->from && s->outs->to == to)
! 						break;
! 				}
! 				if (s == NULL)
! 				{
! 					s = newstate(nfa);
! 					if (NISERR())
! 						return 0;
! 					s->tmp = *intermediates;
! 					*intermediates = s;
! 				}
  				cparc(nfa, con, a->from, s);
! 				cparc(nfa, a, s, to);
  				freearc(nfa, a);
  				break;
  			default:
*************** pull(struct nfa * nfa,
*** 1623,1629 ****
  
  	/* remaining inarcs, if any, incorporate the constraint */
  	moveins(nfa, from, to);
! 	dropstate(nfa, from);		/* will free the constraint */
  	return 1;
  }
  
--- 1664,1671 ----
  
  	/* remaining inarcs, if any, incorporate the constraint */
  	moveins(nfa, from, to);
! 	freearc(nfa, con);
! 	/* from state is now useless, but we leave it to pullback() to clean up */
  	return 1;
  }
  
*************** pushfwd(struct nfa * nfa,
*** 1638,1643 ****
--- 1680,1686 ----
  	struct state *nexts;
  	struct arc *a;
  	struct arc *nexta;
+ 	struct state *intermediates;
  	int			progress;
  
  	/* find and push until there are no more */
*************** pushfwd(struct nfa * nfa,
*** 1647,1660 ****
  		for (s = nfa->states; s != NULL && !NISERR(); s = nexts)
  		{
  			nexts = s->next;
  			for (a = s->ins; a != NULL && !NISERR(); a = nexta)
  			{
  				nexta = a->inchain;
  				if (a->type == '$' || a->type == AHEAD)
! 					if (push(nfa, a))
  						progress = 1;
- 				assert(nexta == NULL || s->no != FREESTATE);
  			}
  		}
  		if (progress && f != NULL)
  			dumpnfa(nfa, f);
--- 1690,1714 ----
  		for (s = nfa->states; s != NULL && !NISERR(); s = nexts)
  		{
  			nexts = s->next;
+ 			intermediates = NULL;
  			for (a = s->ins; a != NULL && !NISERR(); a = nexta)
  			{
  				nexta = a->inchain;
  				if (a->type == '$' || a->type == AHEAD)
! 					if (push(nfa, a, &intermediates))
  						progress = 1;
  			}
+ 			/* clear tmp fields of intermediate states created here */
+ 			while (intermediates != NULL)
+ 			{
+ 				struct state *ns = intermediates->tmp;
+ 
+ 				intermediates->tmp = NULL;
+ 				intermediates = ns;
+ 			}
+ 			/* if s is now useless, get rid of it */
+ 			if ((s->nins == 0 || s->nouts == 0) && !s->flag)
+ 				dropstate(nfa, s);
  		}
  		if (progress && f != NULL)
  			dumpnfa(nfa, f);
*************** pushfwd(struct nfa * nfa,
*** 1682,1694 ****
  
  /*
   * push - push a forward constraint forward past its destination state
!  * A significant property of this function is that it deletes at most
!  * one state -- the constraint's to state -- and only if the constraint
!  * was that state's last inarc.
   */
! static int						/* 0 couldn't, 1 could */
  push(struct nfa * nfa,
! 	 struct arc * con)
  {
  	struct state *from = con->from;
  	struct state *to = con->to;
--- 1736,1761 ----
  
  /*
   * push - push a forward constraint forward past its destination state
!  *
!  * Returns 1 if successful (which it always is unless the destination is the
!  * post state or we have an internal error), 0 if nothing happened.
!  *
!  * A significant property of this function is that it deletes no pre-existing
!  * states, and no inarcs of the constraint's to state other than the given
!  * constraint arc.  This makes the loops in pushfwd() safe, at the cost that
!  * we may leave useless states behind.  Therefore, we leave it to pushfwd()
!  * to delete such states.
!  *
!  * If the to state has multiple forward-constraint inarcs, and/or multiple
!  * compatible constraint outarcs, we only need to create one new intermediate
!  * state per combination of predecessor and successor states.  *intermediates
!  * points to a list of such intermediate states for this to state (chained
!  * through their tmp fields).
   */
! static int
  push(struct nfa * nfa,
! 	 struct arc * con,
! 	 struct state ** intermediates)
  {
  	struct state *from = con->from;
  	struct state *to = con->to;
*************** push(struct nfa * nfa,
*** 1705,1726 ****
  		return 1;
  	}
  
! 	/* first, clone to state if necessary to avoid other inarcs */
  	if (to->nins > 1)
  	{
  		s = newstate(nfa);
  		if (NISERR())
  			return 0;
  		copyouts(nfa, to, s, 1);	/* duplicate outarcs */
! 		cparc(nfa, con, from, s);		/* move constraint */
  		freearc(nfa, con);
  		to = s;
  		con = to->ins;
  	}
  	assert(to->nins == 1);
  
  	/* propagate the constraint into the to state's outarcs */
! 	for (a = to->outs; a != NULL; a = nexta)
  	{
  		nexta = a->outchain;
  		switch (combine(con, a))
--- 1772,1799 ----
  		return 1;
  	}
  
! 	/*
! 	 * First, clone to state if necessary to avoid other inarcs.  This may
! 	 * seem wasteful, but it simplifies the logic, and we'll get rid of the
! 	 * clone state again at the bottom.
! 	 */
  	if (to->nins > 1)
  	{
  		s = newstate(nfa);
  		if (NISERR())
  			return 0;
  		copyouts(nfa, to, s, 1);	/* duplicate outarcs */
! 		cparc(nfa, con, from, s);		/* move constraint arc */
  		freearc(nfa, con);
+ 		if (NISERR())
+ 			return 0;
  		to = s;
  		con = to->ins;
  	}
  	assert(to->nins == 1);
  
  	/* propagate the constraint into the to state's outarcs */
! 	for (a = to->outs; a != NULL && !NISERR(); a = nexta)
  	{
  		nexta = a->outchain;
  		switch (combine(con, a))
*************** push(struct nfa * nfa,
*** 1731,1743 ****
  			case SATISFIED:		/* no action needed */
  				break;
  			case COMPATIBLE:	/* swap the two arcs, more or less */
! 				s = newstate(nfa);
! 				if (NISERR())
! 					return 0;
! 				cparc(nfa, con, s, a->to);		/* anticipate move */
  				cparc(nfa, a, from, s);
- 				if (NISERR())
- 					return 0;
  				freearc(nfa, a);
  				break;
  			default:
--- 1804,1826 ----
  			case SATISFIED:		/* no action needed */
  				break;
  			case COMPATIBLE:	/* swap the two arcs, more or less */
! 				/* need an intermediate state, but might have one already */
! 				for (s = *intermediates; s != NULL; s = s->tmp)
! 				{
! 					assert(s->nins > 0 && s->nouts > 0);
! 					if (s->ins->from == from && s->outs->to == a->to)
! 						break;
! 				}
! 				if (s == NULL)
! 				{
! 					s = newstate(nfa);
! 					if (NISERR())
! 						return 0;
! 					s->tmp = *intermediates;
! 					*intermediates = s;
! 				}
! 				cparc(nfa, con, s, a->to);
  				cparc(nfa, a, from, s);
  				freearc(nfa, a);
  				break;
  			default:
*************** push(struct nfa * nfa,
*** 1748,1754 ****
  
  	/* remaining outarcs, if any, incorporate the constraint */
  	moveouts(nfa, to, from);
! 	dropstate(nfa, to);			/* will free the constraint */
  	return 1;
  }
  
--- 1831,1838 ----
  
  	/* remaining outarcs, if any, incorporate the constraint */
  	moveouts(nfa, to, from);
! 	freearc(nfa, con);
! 	/* to state is now useless, but we leave it to pushfwd() to clean up */
  	return 1;
  }
  
diff --git a/src/backend/regex/regcomp.c b/src/backend/regex/regcomp.c
index 91eb771..6b03107 100644
*** a/src/backend/regex/regcomp.c
--- b/src/backend/regex/regcomp.c
*************** static void cleartraverse(struct nfa *, 
*** 149,157 ****
  static void specialcolors(struct nfa *);
  static long optimize(struct nfa *, FILE *);
  static void pullback(struct nfa *, FILE *);
! static int	pull(struct nfa *, struct arc *);
  static void pushfwd(struct nfa *, FILE *);
! static int	push(struct nfa *, struct arc *);
  
  #define INCOMPATIBLE	1		/* destroys arc */
  #define SATISFIED	2			/* constraint satisfied */
--- 149,157 ----
  static void specialcolors(struct nfa *);
  static long optimize(struct nfa *, FILE *);
  static void pullback(struct nfa *, FILE *);
! static int	pull(struct nfa *, struct arc *, struct state **);
  static void pushfwd(struct nfa *, FILE *);
! static int	push(struct nfa *, struct arc *, struct state **);
  
  #define INCOMPATIBLE	1		/* destroys arc */
  #define SATISFIED	2			/* constraint satisfied */
