1 /*-------------------------------------------------------------------------
4 * Synonym dictionary: replace word by its synonym
6 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
12 *-------------------------------------------------------------------------
16 #include "commands/defrem.h"
17 #include "tsearch/ts_locale.h"
18 #include "tsearch/ts_public.h"
19 #include "tsearch/ts_utils.h"
20 #include "utils/builtins.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).
41 findwrd(char *in
, char **end
)
45 /* Skip leading spaces */
46 while (*in
&& t_isspace(in
))
49 /* Return NULL on empty lines */
58 /* Find end of word */
59 while (*in
&& !t_isspace(in
))
67 compareSyn(const void *a
, const void *b
)
69 return strcmp(((Syn
*) a
)->in
, ((Syn
*) b
)->in
);
74 dsynonym_init(PG_FUNCTION_ARGS
)
76 List
*dictoptions
= (List
*) PG_GETARG_POINTER(0);
79 char *filename
= NULL
;
80 bool case_sensitive
= false;
81 tsearch_readline_state trst
;
88 foreach(l
, dictoptions
)
90 DefElem
*defel
= (DefElem
*) lfirst(l
);
92 if (pg_strcasecmp("Synonyms", defel
->defname
) == 0)
93 filename
= defGetString(defel
);
94 else if (pg_strcasecmp("CaseSensitive", defel
->defname
) == 0)
95 case_sensitive
= defGetBoolean(defel
);
98 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
99 errmsg("unrecognized synonym parameter: \"%s\"",
105 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
106 errmsg("missing Synonyms parameter")));
108 filename
= get_tsearch_config_filename(filename
, "syn");
110 if (!tsearch_readline_begin(&trst
, filename
))
112 (errcode(ERRCODE_CONFIG_FILE_ERROR
),
113 errmsg("could not open synonym file \"%s\": %m",
116 d
= (DictSyn
*) palloc0(sizeof(DictSyn
));
118 while ((line
= tsearch_readline(&trst
)) != NULL
)
120 starti
= findwrd(line
, &end
);
128 /* A line with only one word. Ignore silently. */
133 starto
= findwrd(end
+ 1, &end
);
136 /* A line with only one word (+whitespace). Ignore silently. */
142 * starti now points to the first word, and starto to the second word
143 * on the line, with a \0 terminator at the end of both words.
151 d
->syn
= (Syn
*) palloc(sizeof(Syn
) * d
->len
);
156 d
->syn
= (Syn
*) repalloc(d
->syn
, sizeof(Syn
) * d
->len
);
162 d
->syn
[cur
].in
= pstrdup(starti
);
163 d
->syn
[cur
].out
= pstrdup(starto
);
167 d
->syn
[cur
].in
= lowerstr(starti
);
168 d
->syn
[cur
].out
= lowerstr(starto
);
177 tsearch_readline_end(&trst
);
180 qsort(d
->syn
, d
->len
, sizeof(Syn
), compareSyn
);
182 d
->case_sensitive
= case_sensitive
;
184 PG_RETURN_POINTER(d
);
188 dsynonym_lexize(PG_FUNCTION_ARGS
)
190 DictSyn
*d
= (DictSyn
*) PG_GETARG_POINTER(0);
191 char *in
= (char *) PG_GETARG_POINTER(1);
192 int32 len
= PG_GETARG_INT32(2);
197 /* note: d->len test protects against Solaris bsearch-of-no-items bug */
198 if (len
<= 0 || d
->len
<= 0)
199 PG_RETURN_POINTER(NULL
);
201 if (d
->case_sensitive
)
202 key
.in
= pnstrdup(in
, len
);
204 key
.in
= lowerstr_with_len(in
, len
);
208 found
= (Syn
*) bsearch(&key
, d
->syn
, d
->len
, sizeof(Syn
), compareSyn
);
212 PG_RETURN_POINTER(NULL
);
214 res
= palloc0(sizeof(TSLexeme
) * 2);
215 res
[0].lexeme
= pstrdup(found
->out
);
217 PG_RETURN_POINTER(res
);