From e01bac641f318b378c4353aa6ccebc76b3071166 Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Thu, 10 Dec 2009 19:54:22 +0100
Subject: [PATCH] Fix TSearch inefficiency because of repeated copying of strings

---
 src/backend/tsearch/wparser_def.c |   69 ++++++++++++++++++++++++++++++++++--
 1 files changed, 65 insertions(+), 4 deletions(-)

diff --git a/src/backend/tsearch/wparser_def.c b/src/backend/tsearch/wparser_def.c
index 72b435c..46e86ee 100644
*** a/src/backend/tsearch/wparser_def.c
--- b/src/backend/tsearch/wparser_def.c
*************** TParserInit(char *str, int len)
*** 328,333 ****
--- 328,371 ----
  	return prs;
  }
  
+ /*
+  * As an alternative to a full TParserInit one can create a
+  * TParserCopy which basically is a normally TParser without a private
+  * copy of the string - instead it uses the one from another TParser.
+  * This is useful because at some places TParsers are created
+  * recursively and the repeated copying around of the strings can
+  * cause major inefficiency.
+  * Obviously one may not close the original TParser before the copy.
+  */
+ static TParser *
+ TParserCopyInit(const TParser const* orig)
+ {
+ 	TParser    *prs = (TParser *) palloc0(sizeof(TParser));
+ 
+ 	prs->charmaxlen = orig->charmaxlen;
+ 	prs->str = orig->str + orig->state->posbyte;
+ 	prs->lenstr = orig->lenstr - orig->state->posbyte;
+ 
+ #ifdef USE_WIDE_UPPER_LOWER
+ 	prs->usewide = orig->usewide;
+ 
+ 	if(orig->pgwstr)
+ 		prs->pgwstr = orig->pgwstr + orig->state->poschar;
+ 	if(orig->wstr)
+ 		prs->wstr = orig->wstr + orig->state->poschar;
+ #endif
+ 
+ 	prs->state = newTParserPosition(NULL);
+ 	prs->state->state = TPS_Base;
+ 
+ #ifdef WPARSER_TRACE
+ 	fprintf(stderr, "parsing copy of \"%.*s\"\n", len, str);
+ #endif
+ 
+ 	return prs;
+ }
+ 
+ 
  static void
  TParserClose(TParser *prs)
  {
*************** TParserClose(TParser *prs)
*** 346,354 ****
--- 384,415 ----
  		pfree(prs->pgwstr);
  #endif
  
+ #ifdef WPARSER_TRACE
+ 	fprintf(stderr, "closing parser");
+ #endif
+ 	pfree(prs);
+ }
+ 
+ /*
+  * See TParserCopyInit
+  */
+ static void
+ TParserCopyClose(TParser *prs)
+ {
+ 	while (prs->state)
+ 	{
+ 		TParserPosition *ptr = prs->state->prev;
+ 
+ 		pfree(prs->state);
+ 		prs->state = ptr;
+ 	}
+ #ifdef WPARSER_TRACE
+ 	fprintf(stderr, "closing parser copy");
+ #endif
  	pfree(prs);
  }
  
+ 
  /*
   * Character-type support functions, equivalent to is* macros, but
   * working with any possible encodings and locales. Notes:
*************** p_isignore(TParser *prs)
*** 617,623 ****
  static int
  p_ishost(TParser *prs)
  {
! 	TParser    *tmpprs = TParserInit(prs->str + prs->state->posbyte, prs->lenstr - prs->state->posbyte);
  	int			res = 0;
  
  	tmpprs->wanthost = true;
--- 678,684 ----
  static int
  p_ishost(TParser *prs)
  {
! 	TParser *tmpprs = TParserCopyInit(prs);
  	int			res = 0;
  
  	tmpprs->wanthost = true;
*************** p_ishost(TParser *prs)
*** 631,637 ****
  		prs->state->charlen = tmpprs->state->charlen;
  		res = 1;
  	}
! 	TParserClose(tmpprs);
  
  	return res;
  }
--- 692,698 ----
  		prs->state->charlen = tmpprs->state->charlen;
  		res = 1;
  	}
! 	TParserCopyClose(tmpprs);
  
  	return res;
  }
*************** p_ishost(TParser *prs)
*** 639,645 ****
  static int
  p_isURLPath(TParser *prs)
  {
! 	TParser    *tmpprs = TParserInit(prs->str + prs->state->posbyte, prs->lenstr - prs->state->posbyte);
  	int			res = 0;
  
  	tmpprs->state = newTParserPosition(tmpprs->state);
--- 700,706 ----
  static int
  p_isURLPath(TParser *prs)
  {
! 	TParser *tmpprs = TParserCopyInit(prs);
  	int			res = 0;
  
  	tmpprs->state = newTParserPosition(tmpprs->state);
*************** p_isURLPath(TParser *prs)
*** 654,660 ****
  		prs->state->charlen = tmpprs->state->charlen;
  		res = 1;
  	}
! 	TParserClose(tmpprs);
  
  	return res;
  }
--- 715,721 ----
  		prs->state->charlen = tmpprs->state->charlen;
  		res = 1;
  	}
! 	TParserCopyClose(tmpprs);
  
  	return res;
  }
-- 
1.6.5.12.gd65df24

