diff --git a/src/backend/regex/regc_nfa.c b/src/backend/regex/regc_nfa.c
index 5461dd3..bdd00fa 100644
*** a/src/backend/regex/regc_nfa.c
--- b/src/backend/regex/regc_nfa.c
*************** newnfa(struct vars * v,
*** 63,69 ****
  	nfa->nstates = 0;
  	nfa->cm = cm;
  	nfa->v = v;
- 	nfa->size = 0;
  	nfa->bos[0] = nfa->bos[1] = COLORLESS;
  	nfa->eos[0] = nfa->eos[1] = COLORLESS;
  	nfa->parent = parent;		/* Precedes newfstate so parent is valid. */
--- 63,68 ----
*************** newnfa(struct vars * v,
*** 93,149 ****
  }
  
  /*
-  * TooManyStates - checks if the max states exceeds the compile-time value
-  */
- static int
- TooManyStates(struct nfa * nfa)
- {
- 	struct nfa *parent = nfa->parent;
- 	size_t		sz = nfa->size;
- 
- 	while (parent != NULL)
- 	{
- 		sz = parent->size;
- 		parent = parent->parent;
- 	}
- 	if (sz > REG_MAX_STATES)
- 		return 1;
- 	return 0;
- }
- 
- /*
-  * IncrementSize - increases the tracked size of the NFA and its parents.
-  */
- static void
- IncrementSize(struct nfa * nfa)
- {
- 	struct nfa *parent = nfa->parent;
- 
- 	nfa->size++;
- 	while (parent != NULL)
- 	{
- 		parent->size++;
- 		parent = parent->parent;
- 	}
- }
- 
- /*
-  * DecrementSize - decreases the tracked size of the NFA and its parents.
-  */
- static void
- DecrementSize(struct nfa * nfa)
- {
- 	struct nfa *parent = nfa->parent;
- 
- 	nfa->size--;
- 	while (parent != NULL)
- 	{
- 		parent->size--;
- 		parent = parent->parent;
- 	}
- }
- 
- /*
   * freenfa - free an entire NFA
   */
  static void
--- 92,97 ----
*************** newstate(struct nfa * nfa)
*** 188,199 ****
  		return NULL;
  	}
  
- 	if (TooManyStates(nfa))
- 	{
- 		NERR(REG_ETOOBIG);
- 		return NULL;
- 	}
- 
  	if (nfa->free != NULL)
  	{
  		s = nfa->free;
--- 136,141 ----
*************** newstate(struct nfa * nfa)
*** 201,212 ****
--- 143,160 ----
  	}
  	else
  	{
+ 		if (nfa->v->spaceused >= REG_MAX_COMPILE_SPACE)
+ 		{
+ 			NERR(REG_ETOOBIG);
+ 			return NULL;
+ 		}
  		s = (struct state *) MALLOC(sizeof(struct state));
  		if (s == NULL)
  		{
  			NERR(REG_ESPACE);
  			return NULL;
  		}
+ 		nfa->v->spaceused += sizeof(struct state);
  		s->oas.next = NULL;
  		s->free = NULL;
  		s->noas = 0;
*************** newstate(struct nfa * nfa)
*** 230,237 ****
  	}
  	s->prev = nfa->slast;
  	nfa->slast = s;
- 	/* track the current size and the parent size */
- 	IncrementSize(nfa);
  	return s;
  }
  
--- 178,183 ----
*************** freestate(struct nfa * nfa,
*** 294,300 ****
  	s->prev = NULL;
  	s->next = nfa->free;		/* don't delete it, put it on the free list */
  	nfa->free = s;
- 	DecrementSize(nfa);
  }
  
  /*
--- 240,245 ----
*************** destroystate(struct nfa * nfa,
*** 312,322 ****
--- 257,269 ----
  	{
  		abnext = ab->next;
  		FREE(ab);
+ 		nfa->v->spaceused -= sizeof(struct arcbatch);
  	}
  	s->ins = NULL;
  	s->outs = NULL;
  	s->next = NULL;
  	FREE(s);
+ 	nfa->v->spaceused -= sizeof(struct state);
  }
  
  /*
*************** allocarc(struct nfa * nfa,
*** 437,448 ****
--- 384,401 ----
  		struct arcbatch *newAb;
  		int			i;
  
+ 		if (nfa->v->spaceused >= REG_MAX_COMPILE_SPACE)
+ 		{
+ 			NERR(REG_ETOOBIG);
+ 			return NULL;
+ 		}
  		newAb = (struct arcbatch *) MALLOC(sizeof(struct arcbatch));
  		if (newAb == NULL)
  		{
  			NERR(REG_ESPACE);
  			return NULL;
  		}
+ 		nfa->v->spaceused += sizeof(struct arcbatch);
  		newAb->next = s->oas.next;
  		s->oas.next = newAb;
  
diff --git a/src/backend/regex/regcomp.c b/src/backend/regex/regcomp.c
index 6b03107..324fea5 100644
*** a/src/backend/regex/regcomp.c
--- b/src/backend/regex/regcomp.c
*************** struct vars
*** 248,253 ****
--- 248,254 ----
  	struct cvec *cv2;			/* utility cvec */
  	struct subre *lacons;		/* lookahead-constraint vector */
  	int			nlacons;		/* size of lacons */
+ 	size_t		spaceused;		/* approx. space used for compilation */
  };
  
  /* parsing macros; most know that `v' is the struct vars pointer */
*************** pg_regcomp(regex_t *re,
*** 363,368 ****
--- 364,370 ----
  	v->cv2 = NULL;
  	v->lacons = NULL;
  	v->nlacons = 0;
+ 	v->spaceused = 0;
  	re->re_magic = REMAGIC;
  	re->re_info = 0;			/* bits get set during parse */
  	re->re_csize = sizeof(chr);
diff --git a/src/include/regex/regerrs.h b/src/include/regex/regerrs.h
index 809b511..41e25f7 100644
*** a/src/include/regex/regerrs.h
--- b/src/include/regex/regerrs.h
***************
*** 75,81 ****
  },
  
  {
! 	REG_ETOOBIG, "REG_ETOOBIG", "nfa has too many states"
  },
  
  {
--- 75,81 ----
  },
  
  {
! 	REG_ETOOBIG, "REG_ETOOBIG", "regular expression is too complex"
  },
  
  {
diff --git a/src/include/regex/regex.h b/src/include/regex/regex.h
index 3020b0f..5e1b692 100644
*** a/src/include/regex/regex.h
--- b/src/include/regex/regex.h
*************** typedef struct
*** 152,158 ****
  #define REG_INVARG	16			/* invalid argument to regex function */
  #define REG_MIXED	17			/* character widths of regex and string differ */
  #define REG_BADOPT	18			/* invalid embedded option */
! #define REG_ETOOBIG 19			/* nfa has too many states */
  #define REG_ECOLORS 20			/* too many colors */
  #define REG_CANCEL	21			/* operation cancelled */
  /* two specials for debugging and testing */
--- 152,158 ----
  #define REG_INVARG	16			/* invalid argument to regex function */
  #define REG_MIXED	17			/* character widths of regex and string differ */
  #define REG_BADOPT	18			/* invalid embedded option */
! #define REG_ETOOBIG 19			/* regular expression is too complex */
  #define REG_ECOLORS 20			/* too many colors */
  #define REG_CANCEL	21			/* operation cancelled */
  /* two specials for debugging and testing */
diff --git a/src/include/regex/regguts.h b/src/include/regex/regguts.h
index 357891a..19fe991 100644
*** a/src/include/regex/regguts.h
--- b/src/include/regex/regguts.h
*************** struct nfa
*** 334,342 ****
  	struct colormap *cm;		/* the color map */
  	color		bos[2];			/* colors, if any, assigned to BOS and BOL */
  	color		eos[2];			/* colors, if any, assigned to EOS and EOL */
- 	size_t		size;			/* Current NFA size; differs from nstates as
- 								 * it also counts the number of states in
- 								 * children of this NFA. */
  	struct vars *v;				/* simplifies compile error reporting */
  	struct nfa *parent;			/* parent NFA, if any */
  };
--- 334,339 ----
*************** struct cnfa
*** 384,393 ****
  #define NULLCNFA(cnfa)	((cnfa).nstates == 0)
  
  /*
!  * Used to limit the maximum NFA size to something sane. [Tcl Bug 1810264]
   */
! #ifndef REG_MAX_STATES
! #define REG_MAX_STATES	100000
  #endif
  
  /*
--- 381,396 ----
  #define NULLCNFA(cnfa)	((cnfa).nstates == 0)
  
  /*
!  * This symbol limits the transient heap space used by the regex compiler,
!  * and thereby also the maximum complexity of NFAs that we'll deal with.
!  * Currently we only count NFA states and arcs against this; the other
!  * transient data is generally not large enough to notice compared to those.
!  * Note that we do not charge anything for the final output data structures
!  * (the compacted NFA and the colormap).
   */
! #ifndef REG_MAX_COMPILE_SPACE
! #define REG_MAX_COMPILE_SPACE  \
! 	(100000 * sizeof(struct state) + 100000 * sizeof(struct arcbatch))
  #endif
  
  /*
