1
/*-------------------------------------------------------------------------
4
* Synonym dictionary: replace word by its synonym
6
* Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
10
* src/backend/tsearch/dict_synonym.c
12
*-------------------------------------------------------------------------
16
#include "commands/defrem.h"
17
#include "tsearch/ts_locale.h"
18
#include "tsearch/ts_utils.h"
30
int len; /* length of syn array */
36
* Finds the next whitespace-delimited word within the 'in' string.
37
* Returns a pointer to the first character of the word, and a pointer
38
* to the next byte after the last character in the word (in *end).
39
* Character '*' at the end of word will not be threated as word
40
* charater if flags is not null.
43
findwrd(char *in, char **end, uint16 *flags)
48
/* Skip leading spaces */
49
while (*in && t_isspace(in))
52
/* Return NULL on empty lines */
59
lastchar = start = in;
61
/* Find end of word */
62
while (*in && !t_isspace(in))
68
if (in - lastchar == 1 && t_iseq(lastchar, '*') && flags)
84
compareSyn(const void *a, const void *b)
86
return strcmp(((const Syn *) a)->in, ((const Syn *) b)->in);
91
dsynonym_init(PG_FUNCTION_ARGS)
93
List *dictoptions = (List *) PG_GETARG_POINTER(0);
96
char *filename = NULL;
97
bool case_sensitive = false;
98
tsearch_readline_state trst;
106
foreach(l, dictoptions)
108
DefElem *defel = (DefElem *) lfirst(l);
110
if (pg_strcasecmp("Synonyms", defel->defname) == 0)
111
filename = defGetString(defel);
112
else if (pg_strcasecmp("CaseSensitive", defel->defname) == 0)
113
case_sensitive = defGetBoolean(defel);
116
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
117
errmsg("unrecognized synonym parameter: \"%s\"",
123
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
124
errmsg("missing Synonyms parameter")));
126
filename = get_tsearch_config_filename(filename, "syn");
128
if (!tsearch_readline_begin(&trst, filename))
130
(errcode(ERRCODE_CONFIG_FILE_ERROR),
131
errmsg("could not open synonym file \"%s\": %m",
134
d = (DictSyn *) palloc0(sizeof(DictSyn));
136
while ((line = tsearch_readline(&trst)) != NULL)
138
starti = findwrd(line, &end, NULL);
146
/* A line with only one word. Ignore silently. */
151
starto = findwrd(end + 1, &end, &flags);
154
/* A line with only one word (+whitespace). Ignore silently. */
160
* starti now points to the first word, and starto to the second word
161
* on the line, with a \0 terminator at the end of both words.
169
d->syn = (Syn *) palloc(sizeof(Syn) * d->len);
174
d->syn = (Syn *) repalloc(d->syn, sizeof(Syn) * d->len);
180
d->syn[cur].in = pstrdup(starti);
181
d->syn[cur].out = pstrdup(starto);
185
d->syn[cur].in = lowerstr(starti);
186
d->syn[cur].out = lowerstr(starto);
189
d->syn[cur].outlen = strlen(starto);
190
d->syn[cur].flags = flags;
198
tsearch_readline_end(&trst);
201
qsort(d->syn, d->len, sizeof(Syn), compareSyn);
203
d->case_sensitive = case_sensitive;
205
PG_RETURN_POINTER(d);
209
dsynonym_lexize(PG_FUNCTION_ARGS)
211
DictSyn *d = (DictSyn *) PG_GETARG_POINTER(0);
212
char *in = (char *) PG_GETARG_POINTER(1);
213
int32 len = PG_GETARG_INT32(2);
218
/* note: d->len test protects against Solaris bsearch-of-no-items bug */
219
if (len <= 0 || d->len <= 0)
220
PG_RETURN_POINTER(NULL);
222
if (d->case_sensitive)
223
key.in = pnstrdup(in, len);
225
key.in = lowerstr_with_len(in, len);
229
found = (Syn *) bsearch(&key, d->syn, d->len, sizeof(Syn), compareSyn);
233
PG_RETURN_POINTER(NULL);
235
res = palloc0(sizeof(TSLexeme) * 2);
236
res[0].lexeme = pnstrdup(found->out, found->outlen);
237
res[0].flags = found->flags;
239
PG_RETURN_POINTER(res);