diff -c -r -N src.orig/backend/tsearch/dict_synonym.c src/backend/tsearch/dict_synonym.c
*** src.orig/backend/tsearch/dict_synonym.c	2009-08-06 18:34:25.000000000 +0400
--- src/backend/tsearch/dict_synonym.c	2009-08-06 19:50:22.000000000 +0400
***************
*** 23,28 ****
--- 23,30 ----
  {
  	char	   *in;
  	char	   *out;
+ 	int			outlen;
+ 	uint16		flags;
  } Syn;
  
  typedef struct
***************
*** 36,46 ****
   * Finds the next whitespace-delimited word within the 'in' string.
   * Returns a pointer to the first character of the word, and a pointer
   * to the next byte after the last character in the word (in *end).
   */
  static char *
! findwrd(char *in, char **end)
  {
  	char	   *start;
  
  	/* Skip leading spaces */
  	while (*in && t_isspace(in))
--- 38,51 ----
   * Finds the next whitespace-delimited word within the 'in' string.
   * Returns a pointer to the first character of the word, and a pointer
   * to the next byte after the last character in the word (in *end).
+  * Character '*' at the end of word will not be threated as word
+  * charater if flags is not null.
   */
  static char *
! findwrd(char *in, char **end, uint16 *flags)
  {
  	char	   *start;
+ 	char	   *lastchar;
  
  	/* Skip leading spaces */
  	while (*in && t_isspace(in))
***************
*** 53,65 ****
  		return NULL;
  	}
  
! 	start = in;
  
  	/* Find end of word */
  	while (*in && !t_isspace(in))
  		in += pg_mblen(in);
  
- 	*end = in;
  	return start;
  }
  
--- 58,84 ----
  		return NULL;
  	}
  
! 	lastchar = start = in;
  
  	/* Find end of word */
  	while (*in && !t_isspace(in))
+ 	{
+ 		lastchar = in;
  		in += pg_mblen(in);
+ 	}
+ 
+ 	if ( in - lastchar == 1 && t_iseq(lastchar, '*') && flags )
+ 	{
+ 		*flags = TSL_PREFIX;
+ 		*end = lastchar;
+ 	}
+ 	else
+ 	{
+ 		if (flags)
+ 				*flags = 0;
+ 		*end = in;
+ 	}
  
  	return start;
  }
  
***************
*** 84,89 ****
--- 103,109 ----
  			   *end = NULL;
  	int			cur = 0;
  	char	   *line = NULL;
+ 	uint16		flags = 0;
  
  	foreach(l, dictoptions)
  	{
***************
*** 117,123 ****
  
  	while ((line = tsearch_readline(&trst)) != NULL)
  	{
! 		starti = findwrd(line, &end);
  		if (!starti)
  		{
  			/* Empty line */
--- 137,143 ----
  
  	while ((line = tsearch_readline(&trst)) != NULL)
  	{
! 		starti = findwrd(line, &end, NULL);
  		if (!starti)
  		{
  			/* Empty line */
***************
*** 130,136 ****
  		}
  		*end = '\0';
  
! 		starto = findwrd(end + 1, &end);
  		if (!starto)
  		{
  			/* A line with only one word (+whitespace). Ignore silently. */
--- 150,156 ----
  		}
  		*end = '\0';
  
! 		starto = findwrd(end + 1, &end, &flags);
  		if (!starto)
  		{
  			/* A line with only one word (+whitespace). Ignore silently. */
***************
*** 168,173 ****
--- 188,196 ----
  			d->syn[cur].out = lowerstr(starto);
  		}
  
+ 		d->syn[cur].outlen = strlen(starto);
+ 		d->syn[cur].flags = flags; 
+ 
  		cur++;
  
  skipline:
***************
*** 212,218 ****
  		PG_RETURN_POINTER(NULL);
  
  	res = palloc0(sizeof(TSLexeme) * 2);
! 	res[0].lexeme = pstrdup(found->out);
  
  	PG_RETURN_POINTER(res);
  }
--- 235,242 ----
  		PG_RETURN_POINTER(NULL);
  
  	res = palloc0(sizeof(TSLexeme) * 2);
! 	res[0].lexeme = pnstrdup(found->out, found->outlen);
! 	res[0].flags = found->flags;
  
  	PG_RETURN_POINTER(res);
  }
diff -c -r -N src.orig/backend/tsearch/synonym_sample.syn src/backend/tsearch/synonym_sample.syn
*** src.orig/backend/tsearch/synonym_sample.syn	2009-08-06 18:34:25.000000000 +0400
--- src/backend/tsearch/synonym_sample.syn	2009-08-06 18:50:02.000000000 +0400
***************
*** 2,4 ****
--- 2,5 ----
  postgresql	pgsql
  postgre	pgsql
  gogle	googl
+ indices	index*
diff -c -r -N src.orig/test/regress/expected/tsdicts.out src/test/regress/expected/tsdicts.out
*** src.orig/test/regress/expected/tsdicts.out	2009-08-06 18:34:29.000000000 +0400
--- src/test/regress/expected/tsdicts.out	2009-08-06 18:50:02.000000000 +0400
***************
*** 208,213 ****
--- 208,219 ----
   {googl}
  (1 row)
  
+ SELECT ts_lexize('synonym', 'indices');
+  ts_lexize 
+ -----------
+  {index}
+ (1 row)
+ 
  -- Create and simple test thesaurus dictionary
  -- More tests in configuration checks because ts_lexize()
  -- cannot pass more than one word to thesaurus.
***************
*** 290,295 ****
--- 296,313 ----
   'common':2 'googl':7,10 'instead':8 'mistak':3 'write':6
  (1 row)
  
+ SELECT to_tsvector('synonym_tst', 'Indexes or indices - Which is right plural form of index?');
+                  to_tsvector                  
+ ----------------------------------------------
+  'form':8 'index':1,3,10 'plural':7 'right':6
+ (1 row)
+ 
+ SELECT to_tsquery('synonym_tst', 'Index & indices');
+      to_tsquery      
+ ---------------------
+  'index' & 'index':*
+ (1 row)
+ 
  -- test thesaurus in configuration
  -- see thesaurus_sample.ths to understand 'odd' resulting tsvector
  CREATE TEXT SEARCH CONFIGURATION thesaurus_tst (
diff -c -r -N src.orig/test/regress/sql/tsdicts.sql src/test/regress/sql/tsdicts.sql
*** src.orig/test/regress/sql/tsdicts.sql	2009-08-06 18:34:30.000000000 +0400
--- src/test/regress/sql/tsdicts.sql	2009-08-06 18:50:02.000000000 +0400
***************
*** 56,61 ****
--- 56,62 ----
  
  SELECT ts_lexize('synonym', 'PoStGrEs');
  SELECT ts_lexize('synonym', 'Gogle');
+ SELECT ts_lexize('synonym', 'indices');
  
  -- Create and simple test thesaurus dictionary
  -- More tests in configuration checks because ts_lexize()
***************
*** 104,109 ****
--- 105,112 ----
  
  SELECT to_tsvector('synonym_tst', 'Postgresql is often called as postgres or pgsql and pronounced as postgre');
  SELECT to_tsvector('synonym_tst', 'Most common mistake is to write Gogle instead of Google');
+ SELECT to_tsvector('synonym_tst', 'Indexes or indices - Which is right plural form of index?');
+ SELECT to_tsquery('synonym_tst', 'Index & indices');
  
  -- test thesaurus in configuration
  -- see thesaurus_sample.ths to understand 'odd' resulting tsvector
diff -c -r -N doc.orig/src/sgml/textsearch.sgml doc/src/sgml/textsearch.sgml
*** doc.orig/src/sgml/textsearch.sgml	2009-08-06 18:34:30.000000000 +0400
--- doc/src/sgml/textsearch.sgml	2009-08-06 18:50:35.000000000 +0400
***************
*** 2288,2293 ****
--- 2288,2350 ----
   asciiword | Word, all ASCII | Paris | {my_synonym,english_stem} | my_synonym | {paris}
  </programlisting>
     </para>
+    
+    <para>
+     An asterisk (<literal>*</literal>) at the end of definition word indicates 
+     that definition word is a prefix, and <function>to_tsquery()</function> 
+     function will transform that definition to the prefix search format (see 
+     <xref linkend="textsearch-parsing-queries">). 
+     Notice that it is ignored in <function>to_tsvector()</function>.
+    </para>
+ 
+    <para>
+     Contents of <filename>$SHAREDIR/tsearch_data/synonym_sample.syn</>:
+    </para>
+ <programlisting>
+ postgres        pgsql
+ postgresql      pgsql
+ postgre pgsql
+ gogle   googl
+ indices index*
+ </programlisting>
+ 
+    <para>
+     Results:
+    </para>
+ <programlisting>
+ =# create text search dictionary syn( template=synonym,synonyms='synonym_sample');
+ =# select ts_lexize('syn','indices');
+  ts_lexize
+ -----------
+  {index}
+ (1 row)
+ 
+ =# create text search configuration tst ( copy=simple);
+ =# alter text search configuration tst alter mapping for asciiword with syn;
+ =# select to_tsquery('tst','indices');
+  to_tsquery
+ ------------
+  'index':*
+ (1 row)
+ 
+ =# select 'indexes are very useful'::tsvector;
+             tsvector             
+ ---------------------------------
+  'are' 'indexes' 'useful' 'very'
+ (1 row)
+ 
+ =# select 'indexes are very useful'::tsvector @@ to_tsquery('tst','indices');
+  ?column?
+ ----------
+  t
+ (1 row)
+ 
+ =# select to_tsvector('tst','indices');
+  to_tsvector
+ -------------
+  'index':1
+ (1 row)
+ </programlisting>
  
     <para>
      The only parameter required by the <literal>synonym</> template is
