2 * interface functions to parser
3 * Teodor Sigaev <teodor@sigaev.ru>
12 #include "utils/array.h"
13 #include "catalog/pg_type.h"
14 #include "executor/spi.h"
22 /*********top interface**********/
24 static Oid current_parser_id = InvalidOid;
27 init_prs(Oid id, WParserInfo * prs)
37 pars[0] = ObjectIdGetDatum(id);
39 memset(prs, 0, sizeof(WParserInfo));
41 nsp=get_namespace(TSNSP_FunctionOid);
42 sprintf(buf, "select prs_start, prs_nexttoken, prs_end, prs_lextype, prs_headline from %s.pg_ts_parser where oid = $1", nsp);
44 plan= SPI_prepare(buf, 1, arg);
46 ts_error(ERROR, "SPI_prepare() failed");
48 stat = SPI_execp(plan, pars, " ", 1);
50 ts_error(ERROR, "SPI_execp return %d", stat);
51 if (SPI_processed > 0)
55 oid = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull));
56 fmgr_info_cxt(oid, &(prs->start_info), TopMemoryContext);
57 oid = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 2, &isnull));
58 fmgr_info_cxt(oid, &(prs->getlexeme_info), TopMemoryContext);
59 oid = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 3, &isnull));
60 fmgr_info_cxt(oid, &(prs->end_info), TopMemoryContext);
61 prs->lextype = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 4, &isnull));
62 oid = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 5, &isnull));
63 fmgr_info_cxt(oid, &(prs->headline_info), TopMemoryContext);
67 ts_error(ERROR, "No parser with id %d", id);
74 WParserInfo *last_prs;
81 static PrsList PList = {NULL, 0, 0, NULL, {0, 0, NULL}};
86 freeSNMap(&(PList.name2id_map));
89 memset(&PList, 0, sizeof(PrsList));
93 compareprs(const void *a, const void *b)
95 return ((WParserInfo *) a)->prs_id - ((WParserInfo *) b)->prs_id;
102 if (PList.last_prs && PList.last_prs->prs_id == id)
103 return PList.last_prs;
105 /* already used prs */
111 PList.last_prs = bsearch(&key, PList.list, PList.len, sizeof(WParserInfo), compareprs);
112 if (PList.last_prs != NULL)
113 return PList.last_prs;
117 if (PList.len == PList.reallen)
120 int reallen = (PList.reallen) ? 2 * PList.reallen : 16;
122 tmp = (WParserInfo *) realloc(PList.list, sizeof(WParserInfo) * reallen);
124 ts_error(ERROR, "No memory");
125 PList.reallen = reallen;
128 PList.last_prs = &(PList.list[PList.len]);
129 init_prs(id, PList.last_prs);
131 qsort(PList.list, PList.len, sizeof(WParserInfo), compareprs);
132 return findprs(id); /* qsort changed order!! */ ;
136 name2id_prs(text *name)
142 Oid id = findSNMap_t(&(PList.name2id_map), name);
143 char buf[1024], *nsp;
147 pars[0] = PointerGetDatum(name);
153 nsp = get_namespace(TSNSP_FunctionOid);
154 sprintf(buf, "select oid from %s.pg_ts_parser where prs_name = $1", nsp);
156 plan= SPI_prepare(buf, 1, arg);
158 ts_error(ERROR, "SPI_prepare() failed");
160 stat = SPI_execp(plan, pars, " ", 1);
162 ts_error(ERROR, "SPI_execp return %d", stat);
163 if (SPI_processed > 0)
164 id = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull));
166 ts_error(ERROR, "No parser '%s'", text2char(name));
169 addSNMap_t(&(PList.name2id_map), name, id);
174 /******sql-level interface******/
182 setup_firstcall(FuncCallContext *funcctx, Oid prsid)
185 MemoryContext oldcontext;
187 WParserInfo *prs = findprs(prsid);
189 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
191 st = (TypeStorage *) palloc(sizeof(TypeStorage));
193 st->list = (LexDescr *) DatumGetPointer(
194 OidFunctionCall1(prs->lextype, PointerGetDatum(prs->prs))
196 funcctx->user_fctx = (void *) st;
197 tupdesc = RelationNameGetTupleDesc("tokentype");
198 funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
199 MemoryContextSwitchTo(oldcontext);
203 process_call(FuncCallContext *funcctx)
207 st = (TypeStorage *) funcctx->user_fctx;
208 if (st->list && st->list[st->cur].lexid)
216 sprintf(txtid, "%d", st->list[st->cur].lexid);
217 values[1] = st->list[st->cur].alias;
218 values[2] = st->list[st->cur].descr;
220 tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
221 result = HeapTupleGetDatum(tuple);
237 PG_FUNCTION_INFO_V1(token_type);
238 Datum token_type(PG_FUNCTION_ARGS);
241 token_type(PG_FUNCTION_ARGS)
243 FuncCallContext *funcctx;
246 if (SRF_IS_FIRSTCALL())
248 funcctx = SRF_FIRSTCALL_INIT();
249 setup_firstcall(funcctx, PG_GETARG_OID(0));
252 funcctx = SRF_PERCALL_SETUP();
254 if ((result = process_call(funcctx)) != (Datum) 0)
255 SRF_RETURN_NEXT(funcctx, result);
256 SRF_RETURN_DONE(funcctx);
259 PG_FUNCTION_INFO_V1(token_type_byname);
260 Datum token_type_byname(PG_FUNCTION_ARGS);
262 token_type_byname(PG_FUNCTION_ARGS)
264 FuncCallContext *funcctx;
267 if (SRF_IS_FIRSTCALL())
269 text *name = PG_GETARG_TEXT_P(0);
271 funcctx = SRF_FIRSTCALL_INIT();
272 setup_firstcall(funcctx, name2id_prs(name));
273 PG_FREE_IF_COPY(name, 0);
276 funcctx = SRF_PERCALL_SETUP();
278 if ((result = process_call(funcctx)) != (Datum) 0)
279 SRF_RETURN_NEXT(funcctx, result);
280 SRF_RETURN_DONE(funcctx);
283 PG_FUNCTION_INFO_V1(token_type_current);
284 Datum token_type_current(PG_FUNCTION_ARGS);
286 token_type_current(PG_FUNCTION_ARGS)
288 FuncCallContext *funcctx;
291 if (SRF_IS_FIRSTCALL())
293 funcctx = SRF_FIRSTCALL_INIT();
294 if (current_parser_id == InvalidOid)
295 current_parser_id = name2id_prs(char2text("default"));
296 setup_firstcall(funcctx, current_parser_id);
299 funcctx = SRF_PERCALL_SETUP();
301 if ((result = process_call(funcctx)) != (Datum) 0)
302 SRF_RETURN_NEXT(funcctx, result);
303 SRF_RETURN_DONE(funcctx);
307 PG_FUNCTION_INFO_V1(set_curprs);
308 Datum set_curprs(PG_FUNCTION_ARGS);
310 set_curprs(PG_FUNCTION_ARGS)
313 findprs(PG_GETARG_OID(0));
314 current_parser_id = PG_GETARG_OID(0);
318 PG_FUNCTION_INFO_V1(set_curprs_byname);
319 Datum set_curprs_byname(PG_FUNCTION_ARGS);
321 set_curprs_byname(PG_FUNCTION_ARGS)
323 text *name = PG_GETARG_TEXT_P(0);
327 ObjectIdGetDatum(name2id_prs(name))
329 PG_FREE_IF_COPY(name, 0);
348 prs_setup_firstcall(FuncCallContext *funcctx, int prsid, text *txt)
351 MemoryContext oldcontext;
353 WParserInfo *prs = findprs(prsid);
358 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
360 st = (PrsStorage *) palloc(sizeof(PrsStorage));
363 st->list = (LexemEntry *) palloc(sizeof(LexemEntry) * st->len);
365 prs->prs = (void *) DatumGetPointer(
368 PointerGetDatum(VARDATA(txt)),
369 Int32GetDatum(VARSIZE(txt) - VARHDRSZ)
373 while ((type = DatumGetInt32(FunctionCall3(
374 &(prs->getlexeme_info),
375 PointerGetDatum(prs->prs),
376 PointerGetDatum(&lex),
377 PointerGetDatum(&llen)))) != 0)
380 if (st->cur >= st->len)
382 st->len = 2 * st->len;
383 st->list = (LexemEntry *) repalloc(st->list, sizeof(LexemEntry) * st->len);
385 st->list[st->cur].lexem = palloc(llen + 1);
386 memcpy(st->list[st->cur].lexem, lex, llen);
387 st->list[st->cur].lexem[llen] = '\0';
388 st->list[st->cur].type = type;
394 PointerGetDatum(prs->prs)
400 funcctx->user_fctx = (void *) st;
401 tupdesc = RelationNameGetTupleDesc("tokenout");
402 funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
403 MemoryContextSwitchTo(oldcontext);
407 prs_process_call(FuncCallContext *funcctx)
411 st = (PrsStorage *) funcctx->user_fctx;
412 if (st->cur < st->len)
420 sprintf(tid, "%d", st->list[st->cur].type);
421 values[1] = st->list[st->cur].lexem;
422 tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
423 result = HeapTupleGetDatum(tuple);
440 PG_FUNCTION_INFO_V1(parse);
441 Datum parse(PG_FUNCTION_ARGS);
443 parse(PG_FUNCTION_ARGS)
445 FuncCallContext *funcctx;
448 if (SRF_IS_FIRSTCALL())
450 text *txt = PG_GETARG_TEXT_P(1);
452 funcctx = SRF_FIRSTCALL_INIT();
453 prs_setup_firstcall(funcctx, PG_GETARG_OID(0), txt);
454 PG_FREE_IF_COPY(txt, 1);
457 funcctx = SRF_PERCALL_SETUP();
459 if ((result = prs_process_call(funcctx)) != (Datum) 0)
460 SRF_RETURN_NEXT(funcctx, result);
461 SRF_RETURN_DONE(funcctx);
464 PG_FUNCTION_INFO_V1(parse_byname);
465 Datum parse_byname(PG_FUNCTION_ARGS);
467 parse_byname(PG_FUNCTION_ARGS)
469 FuncCallContext *funcctx;
472 if (SRF_IS_FIRSTCALL())
474 text *name = PG_GETARG_TEXT_P(0);
475 text *txt = PG_GETARG_TEXT_P(1);
477 funcctx = SRF_FIRSTCALL_INIT();
478 prs_setup_firstcall(funcctx, name2id_prs(name), txt);
479 PG_FREE_IF_COPY(name, 0);
480 PG_FREE_IF_COPY(txt, 1);
483 funcctx = SRF_PERCALL_SETUP();
485 if ((result = prs_process_call(funcctx)) != (Datum) 0)
486 SRF_RETURN_NEXT(funcctx, result);
487 SRF_RETURN_DONE(funcctx);
491 PG_FUNCTION_INFO_V1(parse_current);
492 Datum parse_current(PG_FUNCTION_ARGS);
494 parse_current(PG_FUNCTION_ARGS)
496 FuncCallContext *funcctx;
499 if (SRF_IS_FIRSTCALL())
501 text *txt = PG_GETARG_TEXT_P(0);
503 funcctx = SRF_FIRSTCALL_INIT();
504 if (current_parser_id == InvalidOid)
505 current_parser_id = name2id_prs(char2text("default"));
506 prs_setup_firstcall(funcctx, current_parser_id, txt);
507 PG_FREE_IF_COPY(txt, 0);
510 funcctx = SRF_PERCALL_SETUP();
512 if ((result = prs_process_call(funcctx)) != (Datum) 0)
513 SRF_RETURN_NEXT(funcctx, result);
514 SRF_RETURN_DONE(funcctx);
517 PG_FUNCTION_INFO_V1(headline);
518 Datum headline(PG_FUNCTION_ARGS);
520 headline(PG_FUNCTION_ARGS)
522 text *in = PG_GETARG_TEXT_P(1);
523 QUERYTYPE *query = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(2)));
524 text *opt = (PG_NARGS() > 3 && PG_GETARG_POINTER(3)) ? PG_GETARG_TEXT_P(3) : NULL;
531 cfg = findcfg(PG_GETARG_OID(0));
532 prsobj = findprs(cfg->prs_id);
534 memset(&prs, 0, sizeof(HLPRSTEXT));
536 prs.words = (HLWORD *) palloc(sizeof(HLWORD) * prs.lenwords);
537 hlparsetext(cfg, &prs, query, VARDATA(in), VARSIZE(in) - VARHDRSZ);
541 &(prsobj->headline_info),
542 PointerGetDatum(&prs),
543 PointerGetDatum(opt),
544 PointerGetDatum(query)
549 PG_FREE_IF_COPY(in, 1);
550 PG_FREE_IF_COPY(query, 2);
552 PG_FREE_IF_COPY(opt, 3);
557 PG_RETURN_POINTER(out);
561 PG_FUNCTION_INFO_V1(headline_byname);
562 Datum headline_byname(PG_FUNCTION_ARGS);
564 headline_byname(PG_FUNCTION_ARGS)
566 text *cfg = PG_GETARG_TEXT_P(0);
570 out = DirectFunctionCall4(
572 ObjectIdGetDatum(name2id_cfg(cfg)),
575 (PG_NARGS() > 3) ? PG_GETARG_DATUM(3) : PointerGetDatum(NULL)
578 PG_FREE_IF_COPY(cfg, 0);
579 PG_RETURN_DATUM(out);
582 PG_FUNCTION_INFO_V1(headline_current);
583 Datum headline_current(PG_FUNCTION_ARGS);
585 headline_current(PG_FUNCTION_ARGS)
588 PG_RETURN_DATUM(DirectFunctionCall4(
590 ObjectIdGetDatum(get_currcfg()),
593 (PG_NARGS() > 2) ? PG_GETARG_DATUM(2) : PointerGetDatum(NULL)