2 * interface functions to tscfg
3 * Teodor Sigaev <teodor@sigaev.ru>
10 #include "catalog/pg_type.h"
11 #include "executor/spi.h"
13 #include "utils/array.h"
14 #include "utils/memutils.h"
25 #define IGNORE_LONGLEXEME 1
27 /*********top interface**********/
29 static Oid current_cfg_id = 0;
32 init_cfg(Oid id, TSCfgInfo * cfg)
42 char *nsp = get_namespace(TSNSP_FunctionOid);
44 MemoryContext oldcontext;
49 pars[0] = ObjectIdGetDatum(id);
50 pars[1] = ObjectIdGetDatum(id);
52 memset(cfg, 0, sizeof(TSCfgInfo));
55 sprintf(buf, "select prs_name from %s.pg_ts_cfg where oid = $1", nsp);
56 plan = SPI_prepare(buf, 1, arg);
58 ts_error(ERROR, "SPI_prepare() failed");
60 stat = SPI_execp(plan, pars, " ", 1);
62 ts_error(ERROR, "SPI_execp return %d", stat);
63 if (SPI_processed > 0)
65 prsname = (text *) DatumGetPointer(
66 SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull)
68 oldcontext = MemoryContextSwitchTo(TopMemoryContext);
69 prsname = ptextdup(prsname);
70 MemoryContextSwitchTo(oldcontext);
75 ts_error(ERROR, "No tsearch cfg with id %d", id);
80 sprintf(buf, "select lt.tokid, map.dict_name from %s.pg_ts_cfgmap as map, %s.pg_ts_cfg as cfg, %s.token_type( $1 ) as lt where lt.alias = map.tok_alias and map.ts_name = cfg.ts_name and cfg.oid= $2 order by lt.tokid desc;", nsp, nsp, nsp);
81 plan = SPI_prepare(buf, 2, arg);
83 ts_error(ERROR, "SPI_prepare() failed");
85 pars[0] = PointerGetDatum(prsname);
86 stat = SPI_execp(plan, pars, " ", 0);
88 ts_error(ERROR, "SPI_execp return %d", stat);
89 if (SPI_processed <= 0)
90 ts_error(ERROR, "No parser with id %d", id);
92 for (i = 0; i < SPI_processed; i++)
94 int lexid = DatumGetInt32(SPI_getbinval(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 1, &isnull));
95 ArrayType *toasted_a = (ArrayType *) PointerGetDatum(SPI_getbinval(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 2, &isnull));
100 cfg->len = lexid + 1;
101 cfg->map = (ListDictionary *) malloc(sizeof(ListDictionary) * cfg->len);
104 (errcode(ERRCODE_OUT_OF_MEMORY),
105 errmsg("out of memory")));
106 memset(cfg->map, 0, sizeof(ListDictionary) * cfg->len);
112 a = (ArrayType *) PointerGetDatum(PG_DETOAST_DATUM(DatumGetPointer(toasted_a)));
114 if (ARR_NDIM(a) != 1)
115 ts_error(ERROR, "Wrong dimension");
116 if (ARRNELEMS(a) < 1)
119 ts_error(ERROR, "Array must not contain nulls");
121 cfg->map[lexid].len = ARRNELEMS(a);
122 cfg->map[lexid].dict_id = (Datum *) malloc(sizeof(Datum) * cfg->map[lexid].len);
123 if (!cfg->map[lexid].dict_id)
124 ts_error(ERROR, "No memory");
126 memset(cfg->map[lexid].dict_id, 0, sizeof(Datum) * cfg->map[lexid].len);
127 ptr = (text *) ARR_DATA_PTR(a);
128 oldcontext = MemoryContextSwitchTo(TopMemoryContext);
129 for (j = 0; j < cfg->map[lexid].len; j++)
131 cfg->map[lexid].dict_id[j] = PointerGetDatum(ptextdup(ptr));
134 MemoryContextSwitchTo(oldcontext);
142 cfg->prs_id = name2id_prs(prsname);
145 for (i = 0; i < cfg->len; i++)
147 for (j = 0; j < cfg->map[i].len; j++)
149 ptr = (text *) DatumGetPointer(cfg->map[i].dict_id[j]);
150 cfg->map[i].dict_id[j] = ObjectIdGetDatum(name2id_dict(ptr));
165 static CFGList CList = {NULL, 0, 0, NULL, {0, 0, NULL}};
170 freeSNMap(&(CList.name2id_map));
176 for (i = 0; i < CList.len; i++)
177 if (CList.list[i].map)
179 for (j = 0; j < CList.list[i].len; j++)
180 if (CList.list[i].map[j].dict_id)
181 free(CList.list[i].map[j].dict_id);
182 free(CList.list[i].map);
186 memset(&CList, 0, sizeof(CFGList));
190 comparecfg(const void *a, const void *b)
192 if (((TSCfgInfo *) a)->id == ((TSCfgInfo *) b)->id)
194 return (((TSCfgInfo *) a)->id < ((TSCfgInfo *) b)->id) ? -1 : 1;
201 if (CList.last_cfg && CList.last_cfg->id == id)
202 return CList.last_cfg;
204 /* already used cfg */
210 CList.last_cfg = bsearch(&key, CList.list, CList.len, sizeof(TSCfgInfo), comparecfg);
211 if (CList.last_cfg != NULL)
212 return CList.last_cfg;
216 if (CList.len == CList.reallen)
219 int reallen = (CList.reallen) ? 2 * CList.reallen : 16;
221 tmp = (TSCfgInfo *) realloc(CList.list, sizeof(TSCfgInfo) * reallen);
223 ts_error(ERROR, "No memory");
224 CList.reallen = reallen;
227 CList.last_cfg = &(CList.list[CList.len]);
228 init_cfg(id, CList.last_cfg);
230 qsort(CList.list, CList.len, sizeof(TSCfgInfo), comparecfg);
231 return findcfg(id); /* qsort changed order!! */ ;
236 name2id_cfg(text *name)
242 Oid id = findSNMap_t(&(CList.name2id_map), name);
248 pars[0] = PointerGetDatum(name);
253 nsp = get_namespace(TSNSP_FunctionOid);
255 sprintf(buf, "select oid from %s.pg_ts_cfg where ts_name = $1", nsp);
256 plan = SPI_prepare(buf, 1, arg);
259 elog(ERROR, "SPI_prepare() failed");
261 stat = SPI_execp(plan, pars, " ", 1);
264 elog(ERROR, "SPI_execp return %d", stat);
265 if (SPI_processed > 0)
267 id = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull));
270 (errcode(ERRCODE_CONFIG_FILE_ERROR),
271 errmsg("null id for tsearch config")));
275 (errcode(ERRCODE_CONFIG_FILE_ERROR),
276 errmsg("no tsearch config")));
280 addSNMap_t(&(CList.name2id_map), name, id);
285 parsetext_v2(TSCfgInfo * cfg, PRSTEXT * prs, char *buf, int4 buflen)
290 WParserInfo *prsobj = findprs(cfg->prs_id);
294 prsobj->prs = (void *) DatumGetPointer(
296 &(prsobj->start_info),
297 PointerGetDatum(buf),
298 Int32GetDatum(buflen)
302 LexizeInit(&ldata, cfg);
306 type = DatumGetInt32(FunctionCall3(
307 &(prsobj->getlexeme_info),
308 PointerGetDatum(prsobj->prs),
309 PointerGetDatum(&lemm),
310 PointerGetDatum(&lenlemm)));
312 if (type > 0 && lenlemm >= MAXSTRLEN)
314 #ifdef IGNORE_LONGLEXEME
316 (errcode(ERRCODE_SYNTAX_ERROR),
317 errmsg("A word you are indexing is too long. It will be ignored.")));
321 (errcode(ERRCODE_SYNTAX_ERROR),
322 errmsg("A word you are indexing is too long")));
326 LexizeAddLemm(&ldata, type, lemm, lenlemm);
328 while ((norms = LexizeExec(&ldata, NULL)) != NULL)
330 TSLexeme *ptr = norms;
332 prs->pos++; /* set pos */
336 if (prs->curwords == prs->lenwords)
339 prs->words = (TSWORD *) repalloc((void *) prs->words, prs->lenwords * sizeof(TSWORD));
342 if (ptr->flags & TSL_ADDPOS)
344 prs->words[prs->curwords].len = strlen(ptr->lexeme);
345 prs->words[prs->curwords].word = ptr->lexeme;
346 prs->words[prs->curwords].nvariant = ptr->nvariant;
347 prs->words[prs->curwords].alen = 0;
348 prs->words[prs->curwords].pos.pos = LIMITPOS(prs->pos);
358 PointerGetDatum(prsobj->prs)
363 hladdword(HLPRSTEXT * prs, char *buf, int4 buflen, int type)
365 while (prs->curwords >= prs->lenwords)
368 prs->words = (HLWORD *) repalloc((void *) prs->words, prs->lenwords * sizeof(HLWORD));
370 memset(&(prs->words[prs->curwords]), 0, sizeof(HLWORD));
371 prs->words[prs->curwords].type = (uint8) type;
372 prs->words[prs->curwords].len = buflen;
373 prs->words[prs->curwords].word = palloc(buflen);
374 memcpy(prs->words[prs->curwords].word, buf, buflen);
379 hlfinditem(HLPRSTEXT * prs, QUERYTYPE * query, char *buf, int buflen)
382 ITEM *item = GETQUERY(query);
385 while (prs->curwords + query->size >= prs->lenwords)
388 prs->words = (HLWORD *) repalloc((void *) prs->words, prs->lenwords * sizeof(HLWORD));
391 word = &(prs->words[prs->curwords - 1]);
392 for (i = 0; i < query->size; i++)
394 if (item->type == VAL && item->length == buflen && strncmp(GETOPERAND(query) + item->distance, buf, buflen) == 0)
398 memcpy(&(prs->words[prs->curwords]), word, sizeof(HLWORD));
399 prs->words[prs->curwords].item = item;
400 prs->words[prs->curwords].repeated = 1;
411 addHLParsedLex(HLPRSTEXT * prs, QUERYTYPE * query, ParsedLex * lexs, TSLexeme * norms)
420 hladdword(prs, lexs->lemm, lexs->lenlemm, lexs->type);
423 while (ptr && ptr->lexeme)
425 hlfinditem(prs, query, ptr->lexeme, strlen(ptr->lexeme));
429 tmplexs = lexs->next;
447 hlparsetext(TSCfgInfo * cfg, HLPRSTEXT * prs, QUERYTYPE * query, char *buf, int4 buflen)
452 WParserInfo *prsobj = findprs(cfg->prs_id);
457 prsobj->prs = (void *) DatumGetPointer(
459 &(prsobj->start_info),
460 PointerGetDatum(buf),
461 Int32GetDatum(buflen)
465 LexizeInit(&ldata, cfg);
469 type = DatumGetInt32(FunctionCall3(
470 &(prsobj->getlexeme_info),
471 PointerGetDatum(prsobj->prs),
472 PointerGetDatum(&lemm),
473 PointerGetDatum(&lenlemm)));
475 if (type > 0 && lenlemm >= MAXSTRLEN)
477 #ifdef IGNORE_LONGLEXEME
479 (errcode(ERRCODE_SYNTAX_ERROR),
480 errmsg("A word you are indexing is too long. It will be ignored.")));
484 (errcode(ERRCODE_SYNTAX_ERROR),
485 errmsg("A word you are indexing is too long")));
489 LexizeAddLemm(&ldata, type, lemm, lenlemm);
493 if ((norms = LexizeExec(&ldata, &lexs)) != NULL)
494 addHLParsedLex(prs, query, lexs, norms);
496 addHLParsedLex(prs, query, lexs, NULL);
503 PointerGetDatum(prsobj->prs)
508 genhl(HLPRSTEXT * prs)
513 HLWORD *wrd = prs->words;
515 out = (text *) palloc(len);
516 ptr = ((char *) out) + VARHDRSZ;
518 while (wrd - prs->words < prs->curwords)
520 while (wrd->len + prs->stopsellen + prs->startsellen + (ptr - ((char *) out)) >= len)
522 int dist = ptr - ((char *) out);
525 out = (text *) repalloc(out, len);
526 ptr = ((char *) out) + dist;
529 if (wrd->in && !wrd->repeated)
540 memcpy(ptr, prs->startsel, prs->startsellen);
541 ptr += prs->startsellen;
543 memcpy(ptr, wrd->word, wrd->len);
547 memcpy(ptr, prs->stopsel, prs->stopsellen);
548 ptr += prs->stopsellen;
552 else if (!wrd->repeated)
558 VARATT_SIZEP(out) = ptr - ((char *) out);
565 Oid arg[1] = {TEXTOID};
566 const char *curlocale;
574 if (current_cfg_id > 0)
575 return current_cfg_id;
577 nsp = get_namespace(TSNSP_FunctionOid);
579 sprintf(buf, "select oid from %s.pg_ts_cfg where locale = $1 ", nsp);
581 plan = SPI_prepare(buf, 1, arg);
584 elog(ERROR, "SPI_prepare() failed");
586 curlocale = setlocale(LC_CTYPE, NULL);
587 pars[0] = PointerGetDatum(char2text((char *) curlocale));
588 stat = SPI_execp(plan, pars, " ", 1);
592 elog(ERROR, "SPI_execp return %d", stat);
593 if (SPI_processed > 0)
594 current_cfg_id = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull));
597 (errcode(ERRCODE_CONFIG_FILE_ERROR),
598 errmsg("could not find tsearch config by locale")));
600 pfree(DatumGetPointer(pars[0]));
603 return current_cfg_id;
606 PG_FUNCTION_INFO_V1(set_curcfg);
607 Datum set_curcfg(PG_FUNCTION_ARGS);
609 set_curcfg(PG_FUNCTION_ARGS)
612 findcfg(PG_GETARG_OID(0));
613 current_cfg_id = PG_GETARG_OID(0);
617 PG_FUNCTION_INFO_V1(set_curcfg_byname);
618 Datum set_curcfg_byname(PG_FUNCTION_ARGS);
620 set_curcfg_byname(PG_FUNCTION_ARGS)
622 text *name = PG_GETARG_TEXT_P(0);
627 ObjectIdGetDatum(name2id_cfg(name))
629 PG_FREE_IF_COPY(name, 0);
633 PG_FUNCTION_INFO_V1(show_curcfg);
634 Datum show_curcfg(PG_FUNCTION_ARGS);
636 show_curcfg(PG_FUNCTION_ARGS)
639 PG_RETURN_OID(get_currcfg());
642 PG_FUNCTION_INFO_V1(reset_tsearch);
643 Datum reset_tsearch(PG_FUNCTION_ARGS);
645 reset_tsearch(PG_FUNCTION_ARGS)
648 ts_error(NOTICE, "TSearch cache cleaned");