Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "postgres.h"
00015
00016 #include "commands/defrem.h"
00017 #include "tsearch/ts_locale.h"
00018 #include "tsearch/ts_utils.h"
00019
00020 typedef struct
00021 {
00022 char *in;
00023 char *out;
00024 int outlen;
00025 uint16 flags;
00026 } Syn;
00027
00028 typedef struct
00029 {
00030 int len;
00031 Syn *syn;
00032 bool case_sensitive;
00033 } DictSyn;
00034
00035
00036
00037
00038
00039
00040
00041
00042 static char *
00043 findwrd(char *in, char **end, uint16 *flags)
00044 {
00045 char *start;
00046 char *lastchar;
00047
00048
00049 while (*in && t_isspace(in))
00050 in += pg_mblen(in);
00051
00052
00053 if (*in == '\0')
00054 {
00055 *end = NULL;
00056 return NULL;
00057 }
00058
00059 lastchar = start = in;
00060
00061
00062 while (*in && !t_isspace(in))
00063 {
00064 lastchar = in;
00065 in += pg_mblen(in);
00066 }
00067
00068 if (in - lastchar == 1 && t_iseq(lastchar, '*') && flags)
00069 {
00070 *flags = TSL_PREFIX;
00071 *end = lastchar;
00072 }
00073 else
00074 {
00075 if (flags)
00076 *flags = 0;
00077 *end = in;
00078 }
00079
00080 return start;
00081 }
00082
00083 static int
00084 compareSyn(const void *a, const void *b)
00085 {
00086 return strcmp(((const Syn *) a)->in, ((const Syn *) b)->in);
00087 }
00088
00089
00090 Datum
00091 dsynonym_init(PG_FUNCTION_ARGS)
00092 {
00093 List *dictoptions = (List *) PG_GETARG_POINTER(0);
00094 DictSyn *d;
00095 ListCell *l;
00096 char *filename = NULL;
00097 bool case_sensitive = false;
00098 tsearch_readline_state trst;
00099 char *starti,
00100 *starto,
00101 *end = NULL;
00102 int cur = 0;
00103 char *line = NULL;
00104 uint16 flags = 0;
00105
00106 foreach(l, dictoptions)
00107 {
00108 DefElem *defel = (DefElem *) lfirst(l);
00109
00110 if (pg_strcasecmp("Synonyms", defel->defname) == 0)
00111 filename = defGetString(defel);
00112 else if (pg_strcasecmp("CaseSensitive", defel->defname) == 0)
00113 case_sensitive = defGetBoolean(defel);
00114 else
00115 ereport(ERROR,
00116 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00117 errmsg("unrecognized synonym parameter: \"%s\"",
00118 defel->defname)));
00119 }
00120
00121 if (!filename)
00122 ereport(ERROR,
00123 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00124 errmsg("missing Synonyms parameter")));
00125
00126 filename = get_tsearch_config_filename(filename, "syn");
00127
00128 if (!tsearch_readline_begin(&trst, filename))
00129 ereport(ERROR,
00130 (errcode(ERRCODE_CONFIG_FILE_ERROR),
00131 errmsg("could not open synonym file \"%s\": %m",
00132 filename)));
00133
00134 d = (DictSyn *) palloc0(sizeof(DictSyn));
00135
00136 while ((line = tsearch_readline(&trst)) != NULL)
00137 {
00138 starti = findwrd(line, &end, NULL);
00139 if (!starti)
00140 {
00141
00142 goto skipline;
00143 }
00144 if (*end == '\0')
00145 {
00146
00147 goto skipline;
00148 }
00149 *end = '\0';
00150
00151 starto = findwrd(end + 1, &end, &flags);
00152 if (!starto)
00153 {
00154
00155 goto skipline;
00156 }
00157 *end = '\0';
00158
00159
00160
00161
00162
00163
00164 if (cur >= d->len)
00165 {
00166 if (d->len == 0)
00167 {
00168 d->len = 64;
00169 d->syn = (Syn *) palloc(sizeof(Syn) * d->len);
00170 }
00171 else
00172 {
00173 d->len *= 2;
00174 d->syn = (Syn *) repalloc(d->syn, sizeof(Syn) * d->len);
00175 }
00176 }
00177
00178 if (case_sensitive)
00179 {
00180 d->syn[cur].in = pstrdup(starti);
00181 d->syn[cur].out = pstrdup(starto);
00182 }
00183 else
00184 {
00185 d->syn[cur].in = lowerstr(starti);
00186 d->syn[cur].out = lowerstr(starto);
00187 }
00188
00189 d->syn[cur].outlen = strlen(starto);
00190 d->syn[cur].flags = flags;
00191
00192 cur++;
00193
00194 skipline:
00195 pfree(line);
00196 }
00197
00198 tsearch_readline_end(&trst);
00199
00200 d->len = cur;
00201 qsort(d->syn, d->len, sizeof(Syn), compareSyn);
00202
00203 d->case_sensitive = case_sensitive;
00204
00205 PG_RETURN_POINTER(d);
00206 }
00207
00208 Datum
00209 dsynonym_lexize(PG_FUNCTION_ARGS)
00210 {
00211 DictSyn *d = (DictSyn *) PG_GETARG_POINTER(0);
00212 char *in = (char *) PG_GETARG_POINTER(1);
00213 int32 len = PG_GETARG_INT32(2);
00214 Syn key,
00215 *found;
00216 TSLexeme *res;
00217
00218
00219 if (len <= 0 || d->len <= 0)
00220 PG_RETURN_POINTER(NULL);
00221
00222 if (d->case_sensitive)
00223 key.in = pnstrdup(in, len);
00224 else
00225 key.in = lowerstr_with_len(in, len);
00226
00227 key.out = NULL;
00228
00229 found = (Syn *) bsearch(&key, d->syn, d->len, sizeof(Syn), compareSyn);
00230 pfree(key.in);
00231
00232 if (!found)
00233 PG_RETURN_POINTER(NULL);
00234
00235 res = palloc0(sizeof(TSLexeme) * 2);
00236 res[0].lexeme = pnstrdup(found->out, found->outlen);
00237 res[0].flags = found->flags;
00238
00239 PG_RETURN_POINTER(res);
00240 }