]> git.pld-linux.org Git - packages/postgresql.git/commitdiff
- added indexed search support (changes by Pawel Sikora)
authorwrobell <wrobell@pld-linux.org>
Sat, 20 Dec 2003 11:49:48 +0000 (11:49 +0000)
committercvs2git <feedback@pld-linux.org>
Sun, 24 Jun 2012 12:13:13 +0000 (12:13 +0000)
Changed files:
    postgresql-tsearch2-compound_word_support_20031210.patch -> 1.1
    postgresql.spec -> 1.245

postgresql-tsearch2-compound_word_support_20031210.patch [new file with mode: 0644]
postgresql.spec

diff --git a/postgresql-tsearch2-compound_word_support_20031210.patch b/postgresql-tsearch2-compound_word_support_20031210.patch
new file mode 100644 (file)
index 0000000..9cdee40
--- /dev/null
@@ -0,0 +1,1356 @@
+diff -uNr postgresql-7.4/contrib/tsearch2/dict_ispell.c postgresql-7.4.fixed/contrib/tsearch2/dict_ispell.c
+--- postgresql-7.4/contrib/tsearch2/dict_ispell.c      2003-08-04 02:43:11.000000000 +0200
++++ postgresql-7.4.fixed/contrib/tsearch2/dict_ispell.c        2003-12-18 17:46:03.000000000 +0100
+@@ -27,7 +27,7 @@
+ static void
+ freeDictISpell(DictISpell * d)
+ {
+-      FreeIspell(&(d->obj));
++      NIFree(&(d->obj));
+       freestoplist(&(d->stoplist));
+       free(d);
+ }
+@@ -71,7 +71,7 @@
+                                         (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+                                          errmsg("dictionary already loaded")));
+                       }
+-                      if (ImportDictionary(&(d->obj), pcfg->value))
++                      if (NIImportDictionary(&(d->obj), pcfg->value))
+                       {
+                               freeDictISpell(d);
+                               ereport(ERROR,
+@@ -90,7 +90,7 @@
+                                         (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+                                          errmsg("affixes already loaded")));
+                       }
+-                      if (ImportAffixes(&(d->obj), pcfg->value))
++                      if (NIImportAffixes(&(d->obj), pcfg->value))
+                       {
+                               freeDictISpell(d);
+                               ereport(ERROR,
+@@ -132,8 +132,8 @@
+       if (affloaded && dictloaded)
+       {
+-              SortDictionary(&(d->obj));
+-              SortAffixes(&(d->obj));
++              NISortDictionary(&(d->obj));
++              NISortAffixes(&(d->obj));
+       }
+       else if (!affloaded)
+       {
+@@ -168,7 +168,7 @@
+       res = palloc(sizeof(char *) * 2);
+       txt = pnstrdup(in, PG_GETARG_INT32(2));
+-      res = NormalizeWord(&(d->obj), txt);
++      res = NINormalizeWord(&(d->obj), txt);
+       pfree(txt);
+       if (res == NULL)
+diff -uNr postgresql-7.4/contrib/tsearch2/ispell/spell.c postgresql-7.4.fixed/contrib/tsearch2/ispell/spell.c
+--- postgresql-7.4/contrib/tsearch2/ispell/spell.c     2003-08-04 02:43:11.000000000 +0200
++++ postgresql-7.4.fixed/contrib/tsearch2/ispell/spell.c       2003-12-18 17:46:03.000000000 +0100
+@@ -7,15 +7,26 @@
+ #include "spell.h"
+-#define MAXNORMLEN 56
++#define MAX_NORM 1024
++#define MAXNORMLEN 256
+ #define STRNCASECMP(x,y)              (strncasecmp(x,y,strlen(y)))
++#define GETWCHAR(W,L,N,T) ( ((uint8*)(W))[ ((T)=='p') ? (N) : ( (L) - 1 - (N) ) ] )
++#define GETCHAR(A,N,T)          GETWCHAR( (A)->repl, (A)->replen, N, T )
++
++
++#define MEMOUT(X)  if ( !(X) ) ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory")))
+ static int
+ cmpspell(const void *s1, const void *s2)
+ {
+       return (strcmp(((const SPELL *) s1)->word, ((const SPELL *) s2)->word));
+ }
++static int
++cmpspellaffix(const void *s1, const void *s2)
++{
++      return (strcmp(((const SPELL *) s1)->p.flag, ((const SPELL *) s2)->p.flag));
++}
+ static void
+ strlower(char *str)
+@@ -29,6 +40,13 @@
+       }
+ }
++static char* 
++strnduplicate(char *s, int len) {
++      char *d=(char*)palloc( len + 1 );
++      memcpy(d, s, len );
++      d[len]='\0';
++      return d;
++}
+ /* backward string compaire for suffix tree operations */
+ static int
+ strbcmp(const char *s1, const char *s2)
+@@ -92,7 +110,7 @@
+ }
+ int
+-AddSpell(IspellDict * Conf, const char *word, const char *flag)
++NIAddSpell(IspellDict * Conf, const char *word, const char *flag)
+ {
+       if (Conf->nspell >= Conf->mspell)
+       {
+@@ -106,24 +124,18 @@
+                       Conf->mspell = 1024 * 20;
+                       Conf->Spell = (SPELL *) malloc(Conf->mspell * sizeof(SPELL));
+               }
+-              if (Conf->Spell == NULL)
+-                      ereport(ERROR,
+-                                      (errcode(ERRCODE_OUT_OF_MEMORY),
+-                                       errmsg("out of memory")));
++              MEMOUT(Conf->Spell);
+       }
+       Conf->Spell[Conf->nspell].word = strdup(word);
+-      if (!Conf->Spell[Conf->nspell].word)
+-              ereport(ERROR,
+-                              (errcode(ERRCODE_OUT_OF_MEMORY),
+-                               errmsg("out of memory")));
+-      strncpy(Conf->Spell[Conf->nspell].flag, flag, 10);
++      MEMOUT(Conf->Spell[Conf->nspell].word);
++      strncpy(Conf->Spell[Conf->nspell].p.flag, flag, 16);
+       Conf->nspell++;
+       return (0);
+ }
+ int
+-ImportDictionary(IspellDict * Conf, const char *filename)
++NIImportDictionary(IspellDict * Conf, const char *filename)
+ {
+       unsigned char str[BUFSIZ];
+       FILE       *dict;
+@@ -143,7 +155,7 @@
+                       flag = s;
+                       while (*s)
+                       {
+-                              if (((*s >= 'A') && (*s <= 'Z')) || ((*s >= 'a') && (*s <= 'z')))
++                              if (isprint(*s) && !isspace(*s))
+                                       s++;
+                               else
+                               {
+@@ -166,65 +178,49 @@
+                               *s = 0;
+                       s++;
+               }
+-              AddSpell(Conf, str, flag);
++              NIAddSpell(Conf, str, flag);
+       }
+       fclose(dict);
+       return (0);
+ }
+-static SPELL *
+-FindWord(IspellDict * Conf, const char *word, int affixflag)
++static int
++FindWord(IspellDict * Conf, const char *word, int affixflag, char compoundonly)
+ {
+-      int                     l,
+-                              c,
+-                              r,
+-                              resc,
+-                              resl,
+-                              resr,
+-                              i;
+-
+-      i = (int) (*word) & 255;
+-      l = Conf->SpellTree.Left[i];
+-      r = Conf->SpellTree.Right[i];
+-      if (l == -1)
+-              return (NULL);
+-      while (l <= r)
+-      {
+-              c = (l + r) >> 1;
+-              resc = strcmp(Conf->Spell[c].word, word);
+-              if ((resc == 0) &&
+-                      ((affixflag == 0) || (strchr(Conf->Spell[c].flag, affixflag) != NULL)))
+-                      return (&Conf->Spell[c]);
+-              resl = strcmp(Conf->Spell[l].word, word);
+-              if ((resl == 0) &&
+-                      ((affixflag == 0) || (strchr(Conf->Spell[l].flag, affixflag) != NULL)))
+-                      return (&Conf->Spell[l]);
+-              resr = strcmp(Conf->Spell[r].word, word);
+-              if ((resr == 0) &&
+-                      ((affixflag == 0) || (strchr(Conf->Spell[r].flag, affixflag) != NULL)))
+-                      return (&Conf->Spell[r]);
+-              if (resc < 0)
+-              {
+-                      l = c + 1;
+-                      r--;
+-              }
+-              else if (resc > 0)
+-              {
+-                      r = c - 1;
+-                      l++;
+-              }
+-              else
+-              {
+-                      l++;
+-                      r--;
++      SPNode *node = Conf->Dictionary;
++      SPNodeData *StopLow, *StopHigh, *StopMiddle;
++      int level=0, wrdlen=strlen(word);
++
++      while( node && level<wrdlen) {
++              StopLow = node->data;
++              StopHigh = node->data+node->length;
++              while (StopLow < StopHigh) {
++                      StopMiddle = StopLow + (StopHigh - StopLow) / 2;
++                      if ( StopMiddle->val == ((uint8*)(word))[level] ) {
++                              if ( wrdlen==level+1 && StopMiddle->isword ) {
++                                      if ( compoundonly && !StopMiddle->compoundallow )
++                                              return 0;
++                                      if ( (affixflag == 0) || (strchr(Conf->AffixData[StopMiddle->affix], affixflag) != NULL))
++                                              return 1;
++                              }
++                              node=StopMiddle->node;
++                              level++;
++                              break;
++                      } else if ( StopMiddle->val < ((uint8*)(word))[level] ) {
++                              StopLow = StopMiddle + 1;
++                      } else {
++                              StopHigh = StopMiddle;
++                      }
+               }
++              if ( StopLow >= StopHigh )
++                      break; 
+       }
+-      return (NULL);
++      return 0;
+ }
+ int
+-AddAffix(IspellDict * Conf, int flag, const char *mask, const char *find, const char *repl, int type)
++NIAddAffix(IspellDict * Conf, int flag, char flagflags, const char *mask, const char *find, const char *repl, int type)
+ {
+       if (Conf->naffixes >= Conf->maffixes)
+       {
+@@ -238,16 +234,14 @@
+                       Conf->maffixes = 16;
+                       Conf->Affix = (AFFIX *) malloc(Conf->maffixes * sizeof(AFFIX));
+               }
+-              if (Conf->Affix == NULL)
+-                      ereport(ERROR,
+-                                      (errcode(ERRCODE_OUT_OF_MEMORY),
+-                                       errmsg("out of memory")));
++              MEMOUT(Conf->Affix);
+       }
+       if (type == 's')
+               sprintf(Conf->Affix[Conf->naffixes].mask, "%s$", mask);
+       else
+               sprintf(Conf->Affix[Conf->naffixes].mask, "^%s", mask);
+       Conf->Affix[Conf->naffixes].compile = 1;
++      Conf->Affix[Conf->naffixes].flagflags = flagflags;
+       Conf->Affix[Conf->naffixes].flag = flag;
+       Conf->Affix[Conf->naffixes].type = type;
+@@ -281,7 +275,7 @@
+ int
+-ImportAffixes(IspellDict * Conf, const char *filename)
++NIImportAffixes(IspellDict * Conf, const char *filename)
+ {
+       unsigned char str[BUFSIZ];
+       unsigned char flag = 0;
+@@ -292,13 +286,24 @@
+       int                     i;
+       int                     suffixes = 0;
+       int                     prefixes = 0;
++      unsigned char flagflags = 0;
+       FILE       *affix;
+       if (!(affix = fopen(filename, "r")))
+               return (1);
++      Conf->compoundcontrol='\t';
+       while (fgets(str, sizeof(str), affix))
+       {
++              if (STRNCASECMP(str, "compoundwords")==0) {
++                      s=strchr(str, 'l');
++                      if ( s ) {
++                              while( *s!=' ' ) s++;
++                              while( *s==' ' ) s++;
++                              Conf->compoundcontrol = *s;
++                              continue; 
++                      }
++              }
+               if (!STRNCASECMP(str, "suffixes"))
+               {
+                       suffixes = 1;
+@@ -314,8 +319,18 @@
+               if (!STRNCASECMP(str, "flag "))
+               {
+                       s = str + 5;
+-                      while (strchr("* ", *s))
++                      flagflags=0;
++                      while( *s==' ' ) s++;
++                      if ( *s=='*' ) {
++                              flagflags|=FF_CROSSPRODUCT;
++                              s++;
++                      } else if ( *s=='~' ) {
++                              flagflags|=FF_COMPOUNDONLYAFX;
+                               s++;
++                      }
++
++                      if ( *s=='\\' ) s++;
++              
+                       flag = *s;
+                       continue;
+               }
+@@ -351,7 +366,7 @@
+                               continue;
+               }
+-              AddAffix(Conf, (int) flag, mask, find, repl, suffixes ? 's' : 'p');
++              NIAddAffix(Conf, (int) flag, (char) flagflags, mask, find, repl, suffixes ? 's' : 'p');
+       }
+       fclose(affix);
+@@ -359,87 +374,266 @@
+       return (0);
+ }
++static int 
++MergeAffix(IspellDict *Conf, int a1, int a2) {
++      int naffix=0;
++      char **ptr=Conf->AffixData;
++
++      while(*ptr) {
++              naffix++;
++              ptr++;
++      }
++      
++      Conf->AffixData=(char**)realloc( Conf->AffixData, (naffix+2)*sizeof(char*) );
++      MEMOUT(Conf->AffixData);
++      ptr = Conf->AffixData + naffix;
++      *ptr=malloc( strlen(Conf->AffixData[a1]) + strlen(Conf->AffixData[a2]) + 1 /* space */ + 1 /* \0 */ );
++      MEMOUT(ptr);
++      sprintf(*ptr, "%s %s", Conf->AffixData[a1], Conf->AffixData[a2]);
++      ptr++;
++      *ptr='\0';
++      return naffix; 
++}
++
++
++static SPNode* 
++mkSPNode(IspellDict *Conf, int low, int high, int level) {
++      int i;
++      int nchar=0;
++      char lastchar='\0';
++      SPNode *rs;
++      SPNodeData *data;
++      int lownew=low;
++
++      for(i=low; i<high; i++)
++              if ( Conf->Spell[i].p.d.len>level && lastchar!=Conf->Spell[i].word[level] ) {
++                      nchar++;
++                      lastchar=Conf->Spell[i].word[level];
++              }
++
++      if (!nchar)
++              return NULL;
++
++      rs=(SPNode*)malloc(SPNHRDSZ+nchar*sizeof(SPNodeData));
++      MEMOUT(rs);
++      memset(rs,0,SPNHRDSZ+nchar*sizeof(SPNodeData));
++      rs->length = nchar;
++      data=rs->data;
++
++      lastchar='\0';
++      for(i=low; i<high; i++)
++              if ( Conf->Spell[i].p.d.len>level ) {
++                      if ( lastchar!=Conf->Spell[i].word[level] ) {
++                              if ( lastchar ) {
++                                      data->node = mkSPNode(Conf, lownew, i, level+1);
++                                      lownew=i;
++                                      data++;
++                              }
++                              lastchar=Conf->Spell[i].word[level];
++                      }
++                      data->val=((uint8*)(Conf->Spell[i].word))[level];
++                      if ( Conf->Spell[i].p.d.len == level+1 ) {
++                              if ( data->isword && data->affix!=Conf->Spell[i].p.d.affix) {
++                                      /* 
++                                      fprintf(stderr,"Word already exists: %s (affixes: '%s' and '%s')\n", 
++                                              Conf->Spell[i].word, 
++                                              Conf->AffixData[data->affix],
++                                              Conf->AffixData[Conf->Spell[i].p.d.affix]
++                                      ); 
++                                      */
++                                      /* MergeAffix called a few times */
++                                      data->affix = MergeAffix(Conf, data->affix, Conf->Spell[i].p.d.affix);
++                              } else
++                                      data->affix = Conf->Spell[i].p.d.affix;
++                              data->isword=1;
++                              if ( strchr( Conf->AffixData[ data->affix ], Conf->compoundcontrol ) )
++                                      data->compoundallow=1;
++                      }
++              }
++              
++      data->node = mkSPNode(Conf, lownew, high, level+1);
++
++      return rs;
++}
++
++
++
+ void
+-SortDictionary(IspellDict * Conf)
++NISortDictionary(IspellDict * Conf)
+ {
+-      int                     CurLet = -1,
+-                              Let;
+       size_t          i;
+-
++      int     naffix=3;
++      
++      /* compress affixes */
++      qsort((void *) Conf->Spell, Conf->nspell, sizeof(SPELL), cmpspellaffix);
++      for (i = 1; i < Conf->nspell; i++)
++              if ( strcmp(Conf->Spell[i].p.flag,Conf->Spell[i-1].p.flag) )
++                      naffix++;
++
++      Conf->AffixData=(char**)malloc( naffix*sizeof(char*) );
++      MEMOUT(Conf->AffixData);
++      memset(Conf->AffixData, 0, naffix*sizeof(char*));
++      naffix=1;
++      Conf->AffixData[0]=strdup("");
++      MEMOUT(Conf->AffixData[0]);
++      Conf->AffixData[1]=strdup( Conf->Spell[0].p.flag );
++      MEMOUT(Conf->AffixData[1]);
++      Conf->Spell[0].p.d.affix = 1;
++      Conf->Spell[0].p.d.len = strlen(Conf->Spell[0].word);
++      for (i = 1; i < Conf->nspell; i++) {
++              if ( strcmp(Conf->Spell[i].p.flag, Conf->AffixData[naffix]) ) {
++                      naffix++;
++                      Conf->AffixData[naffix] = strdup( Conf->Spell[i].p.flag );
++                      MEMOUT(Conf->AffixData[naffix]);
++              }
++              Conf->Spell[i].p.d.affix = naffix;
++              Conf->Spell[i].p.d.len = strlen(Conf->Spell[i].word);
++      }
++      
+       qsort((void *) Conf->Spell, Conf->nspell, sizeof(SPELL), cmpspell);
++      Conf->Dictionary = mkSPNode(Conf, 0, Conf->nspell, 0);
++      
++      for (i = 0; i < Conf->nspell; i++) 
++              free( Conf->Spell[i].word );
++      free( Conf->Spell );
++      Conf->Spell=NULL;
++}
++
++static AffixNode*
++mkANode(IspellDict *Conf, int low, int high, int level, int type) {
++      int i;
++      int nchar=0;
++      uint8 lastchar='\0';
++      AffixNode *rs;
++      AffixNodeData *data;
++      int lownew=low;
++
++      for(i=low; i<high; i++)
++              if ( Conf->Affix[i].replen>level && lastchar!=GETCHAR( Conf->Affix + i, level, type ) ) {
++                      nchar++;
++                      lastchar=GETCHAR( Conf->Affix + i, level, type );
++              }
+-      for (i = 0; i < 256; i++)
+-              Conf->SpellTree.Left[i] = -1;
++      if (!nchar)
++              return NULL;
+-      for (i = 0; i < Conf->nspell; i++)
+-      {
+-              Let = (int) (*(Conf->Spell[i].word)) & 255;
+-              if (CurLet != Let)
+-              {
+-                      Conf->SpellTree.Left[Let] = i;
+-                      CurLet = Let;
++      rs=(AffixNode*)malloc(ANHRDSZ+nchar*sizeof(AffixNodeData));
++      MEMOUT(rs);
++      memset(rs,0,ANHRDSZ+nchar*sizeof(AffixNodeData));
++      rs->length = nchar;
++      data=rs->data;
++
++      lastchar='\0';
++      for(i=low; i<high; i++)
++              if ( Conf->Affix[i].replen>level ) {
++                      if ( lastchar!=GETCHAR( Conf->Affix + i, level, type ) ) {
++                              if ( lastchar ) {
++                                      data->node = mkANode(Conf, lownew, i, level+1, type);
++                                      lownew=i;
++                                      data++;
++                              }
++                              lastchar=GETCHAR( Conf->Affix + i, level, type );
++                      }
++                      data->val=GETCHAR( Conf->Affix + i, level, type );
++                      if ( Conf->Affix[i].replen == level+1 ) { /* affix stopped */
++                              if ( !data->naff )
++                                      data->aff=(AFFIX**)malloc(sizeof(AFFIX*)*(high-i+1));
++                                      MEMOUT(data);
++                              data->aff[ data->naff ] = Conf->Affix + i;
++                              data->naff++;
++                      }
+               }
+-              Conf->SpellTree.Right[Let] = i;
+-      }
++              
++      data->node = mkANode(Conf, lownew, high, level+1, type);
++
++      return rs;
+ }
+ void
+-SortAffixes(IspellDict * Conf)
++NISortAffixes(IspellDict * Conf)
+ {
+-      int                     CurLetP = -1,
+-                              CurLetS = -1,
+-                              Let;
+       AFFIX      *Affix;
+       size_t          i;
++      CMPDAffix* ptr;
++      int     firstsuffix=-1;
+       if (Conf->naffixes > 1)
+               qsort((void *) Conf->Affix, Conf->naffixes, sizeof(AFFIX), cmpaffix);
+-      for (i = 0; i < 256; i++)
+-      {
+-              Conf->PrefixTree.Left[i] = Conf->PrefixTree.Right[i] = -1;
+-              Conf->SuffixTree.Left[i] = Conf->SuffixTree.Right[i] = -1;
+-      }
+-      for (i = 0; i < Conf->naffixes; i++)
+-      {
++      Conf->CompoundAffix = ptr = (CMPDAffix*)malloc( sizeof(CMPDAffix) * Conf->naffixes );
++      MEMOUT(Conf->CompoundAffix);
++      ptr->affix=NULL;
++
++      for (i = 0; i < Conf->naffixes; i++) {
+               Affix = &(((AFFIX *) Conf->Affix)[i]);
+-              if (Affix->type == 'p')
+-              {
+-                      Let = (int) (*(Affix->repl)) & 255;
+-                      if (CurLetP != Let)
+-                      {
+-                              Conf->PrefixTree.Left[Let] = i;
+-                              CurLetP = Let;
++              if ( Affix->type == 's' ) {
++                      if ( firstsuffix<0 ) firstsuffix=i;
++                      if ( Affix->flagflags & FF_COMPOUNDONLYAFX ) {
++                              if ( !ptr->affix || strbncmp((ptr-1)->affix, Affix->repl, (ptr-1)->len) ) {
++                                      /* leave only unique and minimals suffixes */
++                                      ptr->affix=Affix->repl;
++                                      ptr->len=Affix->replen;
++                                      ptr++;
++                              }
+                       }
+-                      Conf->PrefixTree.Right[Let] = i;
+               }
+-              else
+-              {
+-                      Let = (Affix->replen) ? (int) (Affix->repl[Affix->replen - 1]) & 255 : 0;
+-                      if (CurLetS != Let)
+-                      {
+-                              Conf->SuffixTree.Left[Let] = i;
+-                              CurLetS = Let;
++      }
++      ptr->affix = NULL;
++      Conf->CompoundAffix = (CMPDAffix*)realloc( Conf->CompoundAffix, sizeof(CMPDAffix) * (ptr-Conf->CompoundAffix+1) );
++
++      Conf->Prefix = mkANode(Conf, 0, firstsuffix, 0, 'p'); 
++      Conf->Suffix = mkANode(Conf, firstsuffix, Conf->naffixes, 0, 's');
++}
++
++static AffixNodeData*
++FinfAffixes(AffixNode *node, const char *word, int wrdlen, int *level, int type) {
++      AffixNodeData *StopLow, *StopHigh, *StopMiddle;
++      uint8 symbol;
++
++      while( node && *level<wrdlen) {
++              StopLow = node->data;
++              StopHigh = node->data+node->length;
++              while (StopLow < StopHigh) {
++                      StopMiddle = StopLow + (StopHigh - StopLow) / 2;
++                      symbol = GETWCHAR(word,wrdlen,*level,type);
++                      if ( StopMiddle->val == symbol ) {
++                              if ( StopMiddle->naff ) 
++                                      return StopMiddle;
++                              node=StopMiddle->node;
++                              (*level)++;
++                              break;
++                      } else if ( StopMiddle->val < symbol ) {
++                              StopLow = StopMiddle + 1;
++                      } else {
++                              StopHigh = StopMiddle;
+                       }
+-                      Conf->SuffixTree.Right[Let] = i;
+               }
++              if ( StopLow >= StopHigh )
++                      break; 
+       }
++      return NULL;
+ }
+ static char *
+-CheckSuffix(const char *word, size_t len, AFFIX * Affix, int *res, IspellDict * Conf)
+-{
++CheckAffix(const char *word, size_t len, AFFIX * Affix, char flagflags, char *newword) {
+       regmatch_t      subs[2];                /* workaround for apache&linux */
+-      char            newword[2 * MAXNORMLEN] = "";
+       int                     err;
+-      *res = strbncmp(word, Affix->repl, Affix->replen);
+-      if (*res < 0)
+-              return NULL;
+-      if (*res > 0)
+-              return NULL;
+-      strcpy(newword, word);
+-      strcpy(newword + len - Affix->replen, Affix->find);
++      if ( flagflags & FF_COMPOUNDONLYAFX ) {
++              if ( (Affix->flagflags & FF_COMPOUNDONLYAFX) == 0 )
++                      return NULL;
++      } else {
++              if ( Affix->flagflags & FF_COMPOUNDONLYAFX )
++                      return NULL;
++      } 
++
++      if ( Affix->type=='s' ) {
++              strcpy(newword, word);
++              strcpy(newword + len - Affix->replen, Affix->find);
++      } else {
++              strcpy(newword, Affix->find);
++              strcat(newword, word + Affix->replen);
++      }
+       if (Affix->compile)
+       {
+@@ -452,205 +646,364 @@
+               }
+               Affix->compile = 0;
+       }
+-      if (!(err = regexec(&(Affix->reg), newword, 1, subs, 0)))
+-      {
+-              if (FindWord(Conf, newword, Affix->flag))
+-                      return pstrdup(newword);
+-      }
++      if (!(err = regexec(&(Affix->reg), newword, 1, subs, 0))) 
++                      return newword;
+       return NULL;
+ }
+-#define NS 1
+-#define MAX_NORM 512
+-static int
+-CheckPrefix(const char *word, size_t len, AFFIX * Affix, IspellDict * Conf, int pi,
+-                      char **forms, char ***cur)
+-{
+-      regmatch_t      subs[NS * 2];
++
++static char     **
++NormalizeSubWord(IspellDict * Conf, char *word, char flag) {
++      AffixNodeData   *suffix=NULL, *prefix=NULL;
++      int     slevel=0, plevel=0;
++      int wrdlen = strlen(word), swrdlen;
++      char      **forms;
++      char      **cur;
+       char            newword[2 * MAXNORMLEN] = "";
+-      int                     err,
+-                              ls,
+-                              res,
+-                              lres;
+-      size_t          newlen;
+-      AFFIX      *CAffix = Conf->Affix;
+-
+-      res = strncmp(word, Affix->repl, Affix->replen);
+-      if (res != 0)
+-              return res;
+-      strcpy(newword, Affix->find);
+-      strcat(newword, word + Affix->replen);
++      char            pnewword[2 * MAXNORMLEN] = "";
++      AffixNode *snode = Conf->Suffix, *pnode;
++      int i,j;
++
++      if (wrdlen > MAXNORMLEN) return NULL;
++      strlower(word); 
++      cur = forms = (char **) palloc(MAX_NORM * sizeof(char *));
++      *cur = NULL;
+-      if (Affix->compile)
+-      {
+-              err = regcomp(&(Affix->reg), Affix->mask, REG_EXTENDED | REG_ICASE | REG_NOSUB);
+-              if (err)
+-              {
+-                      /* regerror(err, &(Affix->reg), regerrstr, ERRSTRSIZE); */
+-                      regfree(&(Affix->reg));
+-                      return (0);
+-              }
+-              Affix->compile = 0;
++
++      /* Check that the word itself is normal form */
++      if (FindWord(Conf, word, 0, flag & FF_COMPOUNDWORD)) {
++              *cur = pstrdup(word);
++              cur++;
++              *cur = NULL;
+       }
+-      if (!(err = regexec(&(Affix->reg), newword, 1, subs, 0)))
+-      {
+-              SPELL      *curspell;
+-              if ((curspell = FindWord(Conf, newword, Affix->flag)))
+-              {
+-                      if ((*cur - forms) < (MAX_NORM - 1))
+-                      {
+-                              **cur = pstrdup(newword);
+-                              (*cur)++;
+-                              **cur = NULL;
++      /* Find all other NORMAL forms of the 'word' (check only prefix)*/
++      pnode=Conf->Prefix;
++      plevel=0;
++      while(pnode) {
++              prefix=FinfAffixes(pnode, word, wrdlen, &plevel,'p');
++              if (!prefix) break;
++              for(j=0;j<prefix->naff;j++) {   
++                      if ( CheckAffix(word,wrdlen,prefix->aff[j], flag, newword) ) {
++                              /* prefix success */
++                              if ( FindWord(Conf, newword, prefix->aff[j]->flag, flag&FF_COMPOUNDWORD) && (cur - forms) < (MAX_NORM-1) ) {
++                                      /* word search success */
++                                      *cur = pstrdup(newword);
++                                      cur++;
++                                      *cur=NULL;
++                              }
+                       }
+               }
+-              newlen = strlen(newword);
+-              ls = Conf->SuffixTree.Left[pi];
+-              if (ls >= 0 && ((*cur - forms) < (MAX_NORM - 1)))
+-              {
+-                      **cur = CheckSuffix(newword, newlen, &CAffix[ls], &lres, Conf);
+-                      if (**cur)
+-                      {
+-                              (*cur)++;
+-                              **cur = NULL;
++              pnode = prefix->node;
++              plevel++;
++      }
++ 
++      /* Find all other NORMAL forms of the 'word' (check suffix and then prefix)*/
++      while( snode ) {
++              /* find possible suffix */
++              suffix = FinfAffixes(snode, word, wrdlen, &slevel, 's');
++              if (!suffix) break;
++              /* foreach suffix check affix */
++              for(i=0;i<suffix->naff;i++) {
++                      if ( CheckAffix(word, wrdlen, suffix->aff[i], flag, newword) ) {
++                              /* suffix success */
++                              if ( FindWord(Conf, newword, suffix->aff[i]->flag, flag&FF_COMPOUNDWORD) && (cur - forms) < (MAX_NORM-1) ) {
++                                      /* word search success */
++                                      *cur = pstrdup(newword);
++                                      cur++;
++                                      *cur=NULL;
++                              }
++                              /* now we will look changed word with prefixes */
++                              pnode=Conf->Prefix;
++                              plevel=0;
++                              swrdlen=strlen(newword);
++                              while(pnode) {
++                                      prefix=FinfAffixes(pnode, newword, swrdlen, &plevel,'p');
++                                      if (!prefix) break;
++                                      for(j=0;j<prefix->naff;j++) {   
++                                              if ( CheckAffix(newword,swrdlen,prefix->aff[j], flag, pnewword) ) {
++                                                      /* prefix success */
++                                                      int ff=( prefix->aff[j]->flagflags & suffix->aff[i]->flagflags & FF_CROSSPRODUCT ) ?
++                                                               0 : prefix->aff[j]->flag; 
++                                                      if ( FindWord(Conf, pnewword, ff, flag&FF_COMPOUNDWORD) && (cur - forms) < (MAX_NORM-1) ) {
++                                                              /* word search success */
++                                                              *cur = pstrdup(pnewword);
++                                                              cur++;
++                                                              *cur=NULL;
++                                                      }
++                                              }
++                                      }
++                                      pnode = prefix->node;
++                                      plevel++;
++                              } 
+                       }
+               }
+-      }
+-      return 0;
+-}
++              snode=suffix->node;
++              slevel++;
++      }
+-char    **
+-NormalizeWord(IspellDict * Conf, char *word)
+-{
+-/*regmatch_t subs[NS];*/
+-      size_t          len;
+-      char      **forms;
+-      char      **cur;
+-      AFFIX      *Affix;
+-      int                     ri,
+-                              pi,
+-                              ipi,
+-                              lp,
+-                              rp,
+-                              cp,
+-                              ls,
+-                              rs;
+-      int                     lres,
+-                              rres,
+-                              cres = 0;
+-      SPELL      *spell;
+-
+-      len = strlen(word);
+-      if (len > MAXNORMLEN)
++      if (cur == forms) {
++              pfree(forms);
+               return (NULL);
++      }
++      return (forms);
++}
+-      strlower(word);
++typedef struct SplitVar {
++      int     nstem;
++      char    **stem; 
++      struct  SplitVar *next;
++} SplitVar;
++
++static int 
++CheckCompoundAffixes(CMPDAffix **ptr, char *word, int len) {
++      while( (*ptr)->affix ) {
++              if ( len > (*ptr)->len && strncmp((*ptr)->affix, word, (*ptr)->len)==0 ) {
++                      len = (*ptr)->len;
++                      (*ptr)++;
++                      return len;
++              }
++              (*ptr)++;
++      }
++      return 0;
++}
+-      forms = (char **) palloc(MAX_NORM * sizeof(char **));
+-      cur = forms;
+-      *cur = NULL;
++static SplitVar*
++CopyVar(SplitVar *s, int makedup) {
++      SplitVar *v = (SplitVar*)palloc(sizeof(SplitVar));
++
++      v->stem=(char**)palloc( sizeof(char*) * (MAX_NORM) );
++      v->next=NULL;
++      if ( s ) {
++              int i;
++              v->nstem = s->nstem;
++              for(i=0;i<s->nstem;i++)
++                      v->stem[i] = (makedup) ? pstrdup( s->stem[i] ) : s->stem[i];
++      } else {
++              v->nstem=0;
++      }
++      return v;
++}
+-      ri = (int) (*word) & 255;
+-      pi = (int) (word[strlen(word) - 1]) & 255;
+-      Affix = (AFFIX *) Conf->Affix;
+-      /* Check that the word itself is normal form */
+-      if ((spell = FindWord(Conf, word, 0)))
+-      {
+-              *cur = pstrdup(word);
+-              cur++;
+-              *cur = NULL;
+-      }
++static SplitVar*
++SplitToVariants( IspellDict * Conf, SPNode *snode, SplitVar * orig, char *word, int wordlen, int startpos, int minpos ) {
++      SplitVar *var=NULL;
++      SPNodeData *StopLow, *StopHigh, *StopMiddle;
++      SPNode *node = (snode) ? snode : Conf->Dictionary;
++      int level=(snode) ? minpos : startpos; /* recursive minpos==level*/
++      int lenaff;
++      CMPDAffix *caff;
++      char    notprobed[wordlen];
++
++      memset(notprobed,1,wordlen);
++      var = CopyVar(orig,1);
++
++      while( node && level<wordlen) {
++              StopLow = node->data;
++              StopHigh = node->data+node->length;
++              while (StopLow < StopHigh) {
++                      StopMiddle = StopLow + (StopHigh - StopLow) / 2;
++                      if ( StopMiddle->val == ((uint8*)(word))[level] ) {
++                              break;
++                      } else if ( StopMiddle->val < ((uint8*)(word))[level] ) {
++                              StopLow = StopMiddle + 1;
++                      } else {
++                              StopHigh = StopMiddle;
++                      }
++              }
++              if ( StopLow >= StopHigh )
++                      break;
+-      /* Find all other NORMAL forms of the 'word' */
++              /* find word with epenthetic */
++              caff = Conf->CompoundAffix;
++              while ( level>startpos && (lenaff=CheckCompoundAffixes( &caff, word + level, wordlen - level ))>0 ) {
++                      /* there is one of compound suffixes, so check word for existings */
++                      char buf[MAXNORMLEN];
++                      char **subres;
++
++                      lenaff=level-startpos+lenaff;
++              
++                      if ( !notprobed[startpos+lenaff-1] )
++                              continue;
++                              
++                      if ( level+lenaff-1 <= minpos )
++                              continue;
+-      for (ipi = 0; ipi <= pi; ipi += pi)
+-      {
++                      memcpy(buf, word+startpos, lenaff);
++                      buf[lenaff]='\0';
+-              /* check prefix */
+-              lp = Conf->PrefixTree.Left[ri];
+-              rp = Conf->PrefixTree.Right[ri];
+-              while (lp >= 0 && lp <= rp)
+-              {
+-                      cp = (lp + rp) >> 1;
+-                      cres = 0;
+-                      if ((cur - forms) < (MAX_NORM - 1))
+-                              cres = CheckPrefix(word, len, &Affix[cp], Conf, ipi, forms, &cur);
+-                      if ((lp < cp) && ((cur - forms) < (MAX_NORM - 1)))
+-                              lres = CheckPrefix(word, len, &Affix[lp], Conf, ipi, forms, &cur);
+-                      if ((rp > cp) && ((cur - forms) < (MAX_NORM - 1)))
+-                              rres = CheckPrefix(word, len, &Affix[rp], Conf, ipi, forms, &cur);
+-                      if (cres < 0)
+-                      {
+-                              rp = cp - 1;
+-                              lp++;
+-                      }
+-                      else if (cres > 0)
+-                      {
+-                              lp = cp + 1;
+-                              rp--;
+-                      }
+-                      else
+-                      {
+-                              lp++;
+-                              rp--;
++                      subres = NormalizeSubWord(Conf, buf, FF_COMPOUNDWORD | FF_COMPOUNDONLYAFX);
++                      if ( subres ) {
++                              /* Yes, it was a word from dictionary */
++                              SplitVar *new=CopyVar(var,0);
++                              SplitVar *ptr=var;
++                              char **sptr=subres;
++                      
++                              notprobed[startpos+lenaff-1]=0;
++      
++                              while(*sptr) {
++                                      new->stem[ new->nstem ] = *sptr;
++                                      new->nstem++;
++                                      sptr++;
++                              }
++                              pfree(subres);
++
++                              while( ptr->next ) 
++                                      ptr = ptr->next;
++                              ptr->next = SplitToVariants(Conf, NULL, new, word, wordlen, startpos+lenaff, startpos+lenaff);
++ 
++                              pfree(new->stem);
++                              pfree(new);
+                       }
+               }
+-              /* check suffix */
+-              ls = Conf->SuffixTree.Left[ipi];
+-              rs = Conf->SuffixTree.Right[ipi];
+-              while (ls >= 0 && ls <= rs)
+-              {
+-                      if (((cur - forms) < (MAX_NORM - 1)))
+-                      {
+-                              *cur = CheckSuffix(word, len, &Affix[ls], &lres, Conf);
+-                              if (*cur)
+-                              {
+-                                      cur++;
+-                                      *cur = NULL;
++              /* find infinitive */
++              if ( StopMiddle->isword && StopMiddle->compoundallow && notprobed[level] ) {
++                      /* ok, we found full compoundallowed word*/
++                      if ( level>minpos ) {
++                              /* and its length more than minimal */
++                              if ( wordlen==level+1 ) {
++                                      /* well, it was last word */
++                                      var->stem[ var->nstem ] = strnduplicate(word + startpos, wordlen - startpos);
++                                      var->nstem++;
++                                      return var;
++                              } else {
++                                      /* then we will search more big word at the same point */
++                                      SplitVar *ptr=var;
++                                      while( ptr->next ) 
++                                              ptr = ptr->next;
++                                      ptr->next=SplitToVariants(Conf, node, var, word, wordlen, startpos, level);
++                                      /* we can find next word */
++                                      level++;
++                                      var->stem[ var->nstem ] = strnduplicate(word + startpos, level - startpos);
++                                      var->nstem++;
++                                      node = Conf->Dictionary;
++                                      startpos=level;
++                                      continue;
+                               }
+                       }
+-                      if ((rs > ls) && ((cur - forms) < (MAX_NORM - 1)))
+-                      {
+-                              *cur = CheckSuffix(word, len, &Affix[rs], &rres, Conf);
+-                              if (*cur)
+-                              {
+-                                      cur++;
+-                                      *cur = NULL;
++              }
++              level++;
++              node=StopMiddle->node;
++      }
++
++      var->stem[ var->nstem ] = strnduplicate(word + startpos, wordlen - startpos);
++      var->nstem++;
++      return var;
++} 
++
++char  **
++NINormalizeWord(IspellDict * Conf, char *word) {
++      char **res= NormalizeSubWord(Conf, word, 0);
++
++      if ( Conf->compoundcontrol != '\t' ) {
++              int wordlen=strlen(word);
++              SplitVar *ptr, *var = SplitToVariants(Conf,NULL,NULL, word, wordlen, 0, -1);
++              char **cur=res;
++              int i;
++      
++              while(var) {
++                      if ( var->nstem > 1 ) {
++                              char **subres = NormalizeSubWord(Conf, var->stem[ var->nstem-1 ], FF_COMPOUNDWORD);
++                              if ( subres ) {
++                                      char **ptr=subres;
++      
++                                      if ( cur ) {
++                                              while(*cur) 
++                                                      cur++;
++                                      } else {
++                                              res=cur=(char **) palloc(MAX_NORM * sizeof(char *));
++                                      }
++      
++                                      for(i=0;i<var->nstem-1;i++) {
++                                              *cur=var->stem[ i ];
++                                              cur++;
++                                      }
++                                      while(*ptr) {
++                                              *cur=*ptr;
++                                              cur++; ptr++;
++                                      }
++                                      *cur=NULL;
++                                      pfree(subres);
++                                      var->stem[ 0 ] = NULL;
+                               }
+                       }
+-                      ls++;
+-                      rs--;
+-              }                                               /* end while */
++      
++                      for(i=0;i<var->nstem && var->stem[ i ];i++)
++                              pfree( var->stem[i] );  
++                      ptr = var->next;
++                      pfree(var->stem);
++                      pfree(var);     
++                      var=ptr;
++              }
++      }
++      return res;
++}
+-      }                                                       /* for ipi */
+-      if (cur == forms)
+-      {
+-              pfree(forms);
+-              return (NULL);
++static void freeSPNode(SPNode *node) {
++      SPNodeData *data;
++
++      if (!node) return;
++      data=node->data;
++      while( node->length ) {
++              freeSPNode(data->node);
++              data++;
++              node->length--;
+       }
+-      return (forms);
++      free(node);
+ }
++      
++static void freeANode(AffixNode *node) {
++      AffixNodeData *data;
++
++      if (!node) return;
++      data=node->data;
++      while( node->length ) {
++              freeANode(data->node);
++              if (data->naff)
++                      free(data->aff);        
++              data++;
++              node->length--;
++      }
++      free(node);
++}
++      
+ void
+-FreeIspell(IspellDict * Conf)
++NIFree(IspellDict * Conf)
+ {
+       int                     i;
+       AFFIX      *Affix = (AFFIX *) Conf->Affix;
++      char**     aff = Conf->AffixData;
++
++      if ( aff ) {
++              while(*aff) {
++                      free(*aff);
++                      aff++;
++              }
++              free(Conf->AffixData);
++      }
++      
+       for (i = 0; i < Conf->naffixes; i++)
+       {
+               if (Affix[i].compile == 0)
+                       regfree(&(Affix[i].reg));
+       }
+-      for (i = 0; i < Conf->naffixes; i++)
+-              free(Conf->Spell[i].word);
+-      free(Conf->Affix);
+-      free(Conf->Spell);
++      if (Conf->Spell) {
++              for (i = 0; i < Conf->nspell; i++)
++                      free(Conf->Spell[i].word);
++              free(Conf->Spell);
++      }
++
++      if (Conf->Affix) free(Conf->Affix);
++      if ( Conf->CompoundAffix ) free(Conf->CompoundAffix);
++      freeSPNode(Conf->Dictionary);
++      freeANode(Conf->Suffix);
++      freeANode(Conf->Prefix);
+       memset((void *) Conf, 0, sizeof(IspellDict));
+       return;
+ }
+diff -uNr postgresql-7.4/contrib/tsearch2/ispell/spell.h postgresql-7.4.fixed/contrib/tsearch2/ispell/spell.h
+--- postgresql-7.4/contrib/tsearch2/ispell/spell.h     2003-08-04 02:43:11.000000000 +0200
++++ postgresql-7.4.fixed/contrib/tsearch2/ispell/spell.h       2003-12-18 17:46:03.000000000 +0100
+@@ -3,16 +3,44 @@
+ #include <sys/types.h>
+ #include <regex.h>
++#include "c.h"
++
++struct SPNode;
++
++
++typedef struct {
++      uint32 
++              val:8,
++              isword:1,
++              compoundallow:1,
++              affix:22;
++      struct SPNode *node; 
++} SPNodeData;
++
++typedef struct SPNode {
++      uint32  length;
++      SPNodeData      data[1];        
++} SPNode;
++
++#define SPNHRDSZ      (sizeof(uint32))
++
+ typedef struct spell_struct
+ {
+       char       *word;
+-      char            flag[10];
++      union {
++              char            flag[16];
++              struct {
++                      int             affix;
++                      int             len;
++              } d;
++      } p;
+ }     SPELL;
+ typedef struct aff_struct
+ {
+       char            flag;
++      char            flagflags;
+       char            type;
+       char            mask[33];
+       char            find[16];
+@@ -22,35 +50,66 @@
+       char            compile;
+ }     AFFIX;
++#define FF_CROSSPRODUCT       0x01
++#define FF_COMPOUNDWORD       0x02
++#define FF_COMPOUNDONLYAFX      0x04
++
++struct AffixNode;
++
++typedef struct {
++      uint32
++              val:8,
++              naff:24;
++      AFFIX   **aff;
++      struct AffixNode *node;
++} AffixNodeData;
++
++typedef struct AffixNode {
++      uint32 length;
++      AffixNodeData   data[1];
++} AffixNode;
++
++#define ANHRDSZ        (sizeof(uint32))
++
+ typedef struct Tree_struct
+ {
+       int                     Left[256],
+                               Right[256];
+ }     Tree_struct;
++typedef struct {
++      char *affix;
++      int len;
++} CMPDAffix;
++
+ typedef struct
+ {
+       int                     maffixes;
+       int                     naffixes;
+       AFFIX      *Affix;
++      char                    compoundcontrol;
+       int                     nspell;
+       int                     mspell;
+       SPELL      *Spell;
+-      Tree_struct SpellTree;
+-      Tree_struct PrefixTree;
+-      Tree_struct SuffixTree;
++
++      AffixNode       *Suffix;
++      AffixNode       *Prefix;
++
++      SPNode  *Dictionary;
++      char    **AffixData;
++      CMPDAffix    *CompoundAffix;
+ }     IspellDict;
+-char    **NormalizeWord(IspellDict * Conf, char *word);
+-int                   ImportAffixes(IspellDict * Conf, const char *filename);
+-int                   ImportDictionary(IspellDict * Conf, const char *filename);
+-
+-int                   AddSpell(IspellDict * Conf, const char *word, const char *flag);
+-int                   AddAffix(IspellDict * Conf, int flag, const char *mask, const char *find, const char *repl, int type);
+-void          SortDictionary(IspellDict * Conf);
+-void          SortAffixes(IspellDict * Conf);
+-void          FreeIspell(IspellDict * Conf);
++char    **NINormalizeWord(IspellDict * Conf, char *word);
++int                   NIImportAffixes(IspellDict * Conf, const char *filename);
++int                   NIImportDictionary(IspellDict * Conf, const char *filename);
++
++int                   NIAddSpell(IspellDict * Conf, const char *word, const char *flag);
++int                   NIAddAffix(IspellDict * Conf, int flag, char flagflags, const char *mask, const char *find, const char *repl, int type);
++void          NISortDictionary(IspellDict * Conf);
++void          NISortAffixes(IspellDict * Conf);
++void          NIFree(IspellDict * Conf);
+ #endif
+diff -uNr postgresql-7.4/contrib/tsearch2/my2ispell/Makefile postgresql-7.4.fixed/contrib/tsearch2/my2ispell/Makefile
+--- postgresql-7.4/contrib/tsearch2/my2ispell/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ postgresql-7.4.fixed/contrib/tsearch2/my2ispell/Makefile   2003-12-18 17:46:03.000000000 +0100
+@@ -0,0 +1,47 @@
++ZIPFILE=nb_NO
++LANGUAGE=norsk
++
++
++UNZIP=unzip -o
++
++
++all: $(LANGUAGE).dict $(LANGUAGE).aff
++
++$(ZIPFILE).aff: $(ZIPFILE).zip
++      $(UNZIP) $? $@
++      touch $@ 
++
++
++# 1 Cleanup dictionary
++# 2 remove " symbol
++# 3 add compoundwords controlled flag to word which hasn't it, but
++#   has compound only suffixes
++
++$(LANGUAGE).dict: $(ZIPFILE).zip
++      $(UNZIP) $? $(ZIPFILE).dic
++      grep -v -E '^[[:digit:]]+$$' < $(ZIPFILE).dic \
++       | grep -v '\.' \
++       | sed -e 's/"//g' \
++       | perl -pi -e 's|/(\S+)| $$q=$$1; ( $$q=~/[\\_`]/ && $$q!~/z/ ) ? "/$${q}z" : "/$${q}"|e' \
++       | sort \
++      > $@
++
++#just convert affix file
++
++$(LANGUAGE).aff: $(ZIPFILE).aff 
++      grep -v -i zyzyzy $(ZIPFILE).aff \
++       | grep -v -i zyzyzy \
++       | perl -pi \
++              -e 's/^COMPOUNDFLAG\s+(\S+)/compoundwords controlled $$1/;' \
++              -e 's/^COMPOUNDMIN\s+(\d+)/compoundmin $$1/;' \
++              -e 's/^PFX\s+(\S+)\s+Y\s+\d+.*$$/ if ( !$$wasprf ) { $$wasprf=1; "prefixes\n\nflag $$1:" } else { "flag $$1:" } /e;' \
++              -e 's/^PFX\s+\S+\s+(\S+)\s+(\S+)\s+(\S+)/ uc("   $$3    > $$2")/e;' \
++              -e 's/^(.*)SFX\s+(\S+)\s+([YN])\s+\d+.*$$/ $$flg=($$3 eq "Y") ? "*" : ""; $$flg="~$$flg" if length $$1; $$q=$$2; $$q="\\$$q" if $$q!~m#[a-zA-Z]#; if ( !$$wassfx ) { $$wassfx=1; "suffixes\n\nflag $$flg$$q:" } else { "flag $$flg$$q:" } /e;' \
++              -e 's/^.*SFX\s+\S+\s+(\S+)\s+(\S+)\s+(\S+)/ uc("   $$3    > ".( ($$1 eq "0") ? "" : "-$$1,").( ($$2 eq "0") ? "" : "$$2") )/e;' \
++              -e 's/^(SET|TRY)/#$$1/' \
++      > $@ 
++
++clean:
++      rm -rf $(ZIPFILE).aff $(ZIPFILE).dic $(LANGUAGE).dict $(LANGUAGE).aff 
++
++
+diff -uNr postgresql-7.4/contrib/tsearch2/my2ispell/README postgresql-7.4.fixed/contrib/tsearch2/my2ispell/README
+--- postgresql-7.4/contrib/tsearch2/my2ispell/README   1970-01-01 01:00:00.000000000 +0100
++++ postgresql-7.4.fixed/contrib/tsearch2/my2ispell/README     2003-12-18 17:46:03.000000000 +0100
+@@ -0,0 +1,12 @@
++Utility for convert MySpell dictionary and affix from
++myspell to ispell format.
++Utility tested on nb_NO.zip and nn_NO.zip from
++OpenOffice (http://lingucomponent.openoffice.org/download_dictionary.html)
++
++usage:
++For example, make norwegian dictionary and affix:
++% cp nb_NO.zip my2ispell
++% cd my2ispell
++% gmake ZIPFILE=nb_NO LANGUAGE=norsk 
++
++Author: Teodor Sigaev <teodor@sigaev.ru>
index cc6f935518ad673ccf7bdcd56d2f14dc2ff4196d..4ca6ceaeefa3c94e4c6a950fb8f6df07bef98fc5 100644 (file)
@@ -46,6 +46,7 @@ Patch6:               %{name}-com_err.patch
 Patch7:                %{name}-ecpg_link.patch
 Patch8:                %{name}-ecpg-includedir.patch
 Patch9:                %{name}-contrib_install.patch
+Patch10:       %{name}-tsearch2-compound_word_support_20031210.patch
 Icon:          postgresql.xpm
 URL:           http://www.postgresql.org/
 BuildRequires: autoconf
@@ -736,6 +737,15 @@ Cryptographic functions for PostgreSQL.
 %description module-pgcrypto -l pl
 Funkcje kryptograficzne dla PostgreSQL.
 
+%package module-tsearch2
+Summary:       Full text extension for PostgreSQL
+Group:         Applications/Databases
+Requires:      %{name} = %{version}
+
+%description module-tsearch2
+Implementation of a new data type tsvector - a searchable data type with
+indexed access: http://www.sai.msu.su/~megera/postgres/gist/tsearch/V2/
+
 %prep
 %setup  -q
 %patch0 -p1
@@ -748,6 +758,7 @@ Funkcje kryptograficzne dla PostgreSQL.
 %patch7 -p1
 %patch8 -p1
 %patch9 -p1
+%patch10 -p1
 
 tar xzf doc/man*.tar.gz
 
@@ -786,6 +797,7 @@ rm -f config/libtool.m4
 %{__make}
 %{__make} -C contrib/pg_autovacuum
 %{__make} -C contrib/pgcrypto
+%{__make} -C contrib/tsearch2
 %ifnarch sparc sparcv9 sparc64 alpha ppc
 %{?with_tests:%{__make} check}
 %endif
@@ -808,6 +820,9 @@ install -d $RPM_BUILD_ROOT{%{_sysconfdir},/etc/{rc.d/init.d,sysconfig}} \
 %{__make} -C contrib/pgcrypto install \
        DESTDIR=$RPM_BUILD_ROOT
 
+%{__make} -C contrib/tsearch2 install \
+       DESTDIR=$RPM_BUILD_ROOT
+
 touch $RPM_BUILD_ROOT/var/log/pgsql
 
 install %{SOURCE1} $RPM_BUILD_ROOT/etc/rc.d/init.d/postgresql
@@ -1081,3 +1096,9 @@ fi
 %doc contrib/pgcrypto/README*
 %attr(755,root,root) %{_pgmoduledir}/pgcrypto.so
 %{_datadir}/%{name}/pgcrypto.sql
+
+%files module-tsearch2
+%defattr(644,root,root,755)
+%attr(755,root,root) %{_pgmoduledir}/tsearch2.so
+%{_datadir}/%{name}/tsearch2.sql
+%{_datadir}/%{name}/untsearch2.sql
This page took 0.094435 seconds and 4 git commands to generate.