1 /*-------------------------------------------------------------------------
4 * Extended synonym dictionary
6 * Copyright (c) 2007-2011, PostgreSQL Global Development Group
9 * contrib/dict_xsyn/dict_xsyn.c
11 *-------------------------------------------------------------------------
17 #include "commands/defrem.h"
18 #include "tsearch/ts_locale.h"
19 #include "tsearch/ts_utils.h"
26 char *value; /* Unparsed list of synonyms, including the
42 PG_FUNCTION_INFO_V1(dxsyn_init);
43 Datum dxsyn_init(PG_FUNCTION_ARGS);
45 PG_FUNCTION_INFO_V1(dxsyn_lexize);
46 Datum dxsyn_lexize(PG_FUNCTION_ARGS);
49 find_word(char *in, char **end)
54 while (*in && t_isspace(in))
57 if (!*in || *in == '#')
61 while (*in && !t_isspace(in))
70 compare_syn(const void *a, const void *b)
72 return strcmp(((const Syn *) a)->key, ((const Syn *) b)->key);
76 read_dictionary(DictSyn *d, char *filename)
78 char *real_filename = get_tsearch_config_filename(filename, "rules");
79 tsearch_readline_state trst;
83 if (!tsearch_readline_begin(&trst, real_filename))
85 (errcode(ERRCODE_CONFIG_FILE_ERROR),
86 errmsg("could not open synonym file \"%s\": %m",
89 while ((line = tsearch_readline(&trst)) != NULL)
99 value = lowerstr(line);
103 while ((key = find_word(pos, &end)) != NULL)
105 /* Enlarge syn structure if full */
108 d->len = (d->len > 0) ? 2 * d->len : 16;
110 d->syn = (Syn *) repalloc(d->syn, sizeof(Syn) * d->len);
112 d->syn = (Syn *) palloc(sizeof(Syn) * d->len);
115 /* Save first word only if we will match it */
116 if (pos != value || d->matchorig)
118 d->syn[cur].key = pnstrdup(key, end - key);
119 d->syn[cur].value = pstrdup(value);
126 /* Don't bother scanning synonyms if we will not match them */
127 if (!d->matchsynonyms)
134 tsearch_readline_end(&trst);
138 qsort(d->syn, d->len, sizeof(Syn), compare_syn);
140 pfree(real_filename);
144 dxsyn_init(PG_FUNCTION_ARGS)
146 List *dictoptions = (List *) PG_GETARG_POINTER(0);
149 char *filename = NULL;
151 d = (DictSyn *) palloc0(sizeof(DictSyn));
156 d->matchsynonyms = false;
157 d->keepsynonyms = true;
159 foreach(l, dictoptions)
161 DefElem *defel = (DefElem *) lfirst(l);
163 if (pg_strcasecmp(defel->defname, "MATCHORIG") == 0)
165 d->matchorig = defGetBoolean(defel);
167 else if (pg_strcasecmp(defel->defname, "KEEPORIG") == 0)
169 d->keeporig = defGetBoolean(defel);
171 else if (pg_strcasecmp(defel->defname, "MATCHSYNONYMS") == 0)
173 d->matchsynonyms = defGetBoolean(defel);
175 else if (pg_strcasecmp(defel->defname, "KEEPSYNONYMS") == 0)
177 d->keepsynonyms = defGetBoolean(defel);
179 else if (pg_strcasecmp(defel->defname, "RULES") == 0)
181 /* we can't read the rules before parsing all options! */
182 filename = defGetString(defel);
187 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
188 errmsg("unrecognized xsyn parameter: \"%s\"",
194 read_dictionary(d, filename);
196 PG_RETURN_POINTER(d);
200 dxsyn_lexize(PG_FUNCTION_ARGS)
202 DictSyn *d = (DictSyn *) PG_GETARG_POINTER(0);
203 char *in = (char *) PG_GETARG_POINTER(1);
204 int length = PG_GETARG_INT32(2);
207 TSLexeme *res = NULL;
209 if (!length || d->len == 0)
210 PG_RETURN_POINTER(NULL);
212 /* Create search pattern */
214 char *temp = pnstrdup(in, length);
216 word.key = lowerstr(temp);
221 /* Look for matching syn */
222 found = (Syn *) bsearch(&word, d->syn, d->len, sizeof(Syn), compare_syn);
226 PG_RETURN_POINTER(NULL);
228 /* Parse string of synonyms and return array of words */
230 char *value = found->value;
236 res = palloc(sizeof(TSLexeme));
239 while ((syn = find_word(pos, &end)) != NULL)
241 res = repalloc(res, sizeof(TSLexeme) * (nsyns + 2));
243 /* The first word is output only if keeporig=true */
244 if (pos != value || d->keeporig)
246 res[nsyns].lexeme = pnstrdup(syn, end - syn);
247 res[nsyns].nvariant = 0;
248 res[nsyns].flags = 0;
254 /* Stop if we are not to output the synonyms */
255 if (!d->keepsynonyms)
258 res[nsyns].lexeme = NULL;
261 PG_RETURN_POINTER(res);