2 * interface functions to parser
3 * Teodor Sigaev <teodor@sigaev.ru>
9 #include "catalog/pg_type.h"
10 #include "executor/spi.h"
13 #include "utils/array.h"
14 #include "utils/memutils.h"
21 /*********top interface**********/
23 static Oid current_parser_id = InvalidOid;
26 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 if ( ((WParserInfo *) a)->prs_id == ((WParserInfo *) b)->prs_id )
97 return ( ((WParserInfo *) a)->prs_id < ((WParserInfo *) b)->prs_id ) ? -1 : 1;
104 if (PList.last_prs && PList.last_prs->prs_id == id)
105 return PList.last_prs;
107 /* already used prs */
113 PList.last_prs = bsearch(&key, PList.list, PList.len, sizeof(WParserInfo), compareprs);
114 if (PList.last_prs != NULL)
115 return PList.last_prs;
119 if (PList.len == PList.reallen)
122 int reallen = (PList.reallen) ? 2 * PList.reallen : 16;
124 tmp = (WParserInfo *) realloc(PList.list, sizeof(WParserInfo) * reallen);
126 ts_error(ERROR, "No memory");
127 PList.reallen = reallen;
130 PList.last_prs = &(PList.list[PList.len]);
131 init_prs(id, PList.last_prs);
133 qsort(PList.list, PList.len, sizeof(WParserInfo), compareprs);
134 return findprs(id); /* qsort changed order!! */ ;
138 name2id_prs(text *name)
144 Oid id = findSNMap_t(&(PList.name2id_map), name);
150 pars[0] = PointerGetDatum(name);
156 nsp = get_namespace(TSNSP_FunctionOid);
157 sprintf(buf, "select oid from %s.pg_ts_parser where prs_name = $1", nsp);
159 plan = SPI_prepare(buf, 1, arg);
161 ts_error(ERROR, "SPI_prepare() failed");
163 stat = SPI_execp(plan, pars, " ", 1);
165 ts_error(ERROR, "SPI_execp return %d", stat);
166 if (SPI_processed > 0)
167 id = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull));
169 ts_error(ERROR, "No parser '%s'", text2char(name));
172 addSNMap_t(&(PList.name2id_map), name, id);
177 /******sql-level interface******/
185 setup_firstcall(FuncCallContext *funcctx, Oid prsid)
188 MemoryContext oldcontext;
190 WParserInfo *prs = findprs(prsid);
192 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
194 st = (TypeStorage *) palloc(sizeof(TypeStorage));
196 st->list = (LexDescr *) DatumGetPointer(
197 OidFunctionCall1(prs->lextype, PointerGetDatum(prs->prs))
199 funcctx->user_fctx = (void *) st;
200 tupdesc = RelationNameGetTupleDesc("tokentype");
201 funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
202 MemoryContextSwitchTo(oldcontext);
206 process_call(FuncCallContext *funcctx)
210 st = (TypeStorage *) funcctx->user_fctx;
211 if (st->list && st->list[st->cur].lexid)
219 sprintf(txtid, "%d", st->list[st->cur].lexid);
220 values[1] = st->list[st->cur].alias;
221 values[2] = st->list[st->cur].descr;
223 tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
224 result = HeapTupleGetDatum(tuple);
240 PG_FUNCTION_INFO_V1(token_type);
241 Datum token_type(PG_FUNCTION_ARGS);
244 token_type(PG_FUNCTION_ARGS)
246 FuncCallContext *funcctx;
250 if (SRF_IS_FIRSTCALL())
252 funcctx = SRF_FIRSTCALL_INIT();
253 setup_firstcall(funcctx, PG_GETARG_OID(0));
256 funcctx = SRF_PERCALL_SETUP();
258 if ((result = process_call(funcctx)) != (Datum) 0)
259 SRF_RETURN_NEXT(funcctx, result);
260 SRF_RETURN_DONE(funcctx);
263 PG_FUNCTION_INFO_V1(token_type_byname);
264 Datum token_type_byname(PG_FUNCTION_ARGS);
266 token_type_byname(PG_FUNCTION_ARGS)
268 FuncCallContext *funcctx;
272 if (SRF_IS_FIRSTCALL())
274 text *name = PG_GETARG_TEXT_P(0);
276 funcctx = SRF_FIRSTCALL_INIT();
277 setup_firstcall(funcctx, name2id_prs(name));
278 PG_FREE_IF_COPY(name, 0);
281 funcctx = SRF_PERCALL_SETUP();
283 if ((result = process_call(funcctx)) != (Datum) 0)
284 SRF_RETURN_NEXT(funcctx, result);
285 SRF_RETURN_DONE(funcctx);
288 PG_FUNCTION_INFO_V1(token_type_current);
289 Datum token_type_current(PG_FUNCTION_ARGS);
291 token_type_current(PG_FUNCTION_ARGS)
293 FuncCallContext *funcctx;
297 if (SRF_IS_FIRSTCALL())
299 funcctx = SRF_FIRSTCALL_INIT();
300 if (current_parser_id == InvalidOid)
301 current_parser_id = name2id_prs(char2text("default"));
302 setup_firstcall(funcctx, current_parser_id);
305 funcctx = SRF_PERCALL_SETUP();
307 if ((result = process_call(funcctx)) != (Datum) 0)
308 SRF_RETURN_NEXT(funcctx, result);
309 SRF_RETURN_DONE(funcctx);
313 PG_FUNCTION_INFO_V1(set_curprs);
314 Datum set_curprs(PG_FUNCTION_ARGS);
316 set_curprs(PG_FUNCTION_ARGS)
319 findprs(PG_GETARG_OID(0));
320 current_parser_id = PG_GETARG_OID(0);
324 PG_FUNCTION_INFO_V1(set_curprs_byname);
325 Datum set_curprs_byname(PG_FUNCTION_ARGS);
327 set_curprs_byname(PG_FUNCTION_ARGS)
329 text *name = PG_GETARG_TEXT_P(0);
334 ObjectIdGetDatum(name2id_prs(name))
336 PG_FREE_IF_COPY(name, 0);
355 prs_setup_firstcall(FuncCallContext *funcctx, int prsid, text *txt)
358 MemoryContext oldcontext;
360 WParserInfo *prs = findprs(prsid);
365 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
367 st = (PrsStorage *) palloc(sizeof(PrsStorage));
370 st->list = (LexemEntry *) palloc(sizeof(LexemEntry) * st->len);
372 prs->prs = (void *) DatumGetPointer(
375 PointerGetDatum(VARDATA(txt)),
376 Int32GetDatum(VARSIZE(txt) - VARHDRSZ)
380 while ((type = DatumGetInt32(FunctionCall3(
381 &(prs->getlexeme_info),
382 PointerGetDatum(prs->prs),
383 PointerGetDatum(&lex),
384 PointerGetDatum(&llen)))) != 0)
387 if (st->cur >= st->len)
389 st->len = 2 * st->len;
390 st->list = (LexemEntry *) repalloc(st->list, sizeof(LexemEntry) * st->len);
392 st->list[st->cur].lexem = palloc(llen + 1);
393 memcpy(st->list[st->cur].lexem, lex, llen);
394 st->list[st->cur].lexem[llen] = '\0';
395 st->list[st->cur].type = type;
401 PointerGetDatum(prs->prs)
407 funcctx->user_fctx = (void *) st;
408 tupdesc = RelationNameGetTupleDesc("tokenout");
409 funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
410 MemoryContextSwitchTo(oldcontext);
414 prs_process_call(FuncCallContext *funcctx)
418 st = (PrsStorage *) funcctx->user_fctx;
419 if (st->cur < st->len)
427 sprintf(tid, "%d", st->list[st->cur].type);
428 values[1] = st->list[st->cur].lexem;
429 tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
430 result = HeapTupleGetDatum(tuple);
447 PG_FUNCTION_INFO_V1(parse);
448 Datum parse(PG_FUNCTION_ARGS);
450 parse(PG_FUNCTION_ARGS)
452 FuncCallContext *funcctx;
456 if (SRF_IS_FIRSTCALL())
458 text *txt = PG_GETARG_TEXT_P(1);
460 funcctx = SRF_FIRSTCALL_INIT();
461 prs_setup_firstcall(funcctx, PG_GETARG_OID(0), txt);
462 PG_FREE_IF_COPY(txt, 1);
465 funcctx = SRF_PERCALL_SETUP();
467 if ((result = prs_process_call(funcctx)) != (Datum) 0)
468 SRF_RETURN_NEXT(funcctx, result);
469 SRF_RETURN_DONE(funcctx);
472 PG_FUNCTION_INFO_V1(parse_byname);
473 Datum parse_byname(PG_FUNCTION_ARGS);
475 parse_byname(PG_FUNCTION_ARGS)
477 FuncCallContext *funcctx;
481 if (SRF_IS_FIRSTCALL())
483 text *name = PG_GETARG_TEXT_P(0);
484 text *txt = PG_GETARG_TEXT_P(1);
486 funcctx = SRF_FIRSTCALL_INIT();
487 prs_setup_firstcall(funcctx, name2id_prs(name), txt);
488 PG_FREE_IF_COPY(name, 0);
489 PG_FREE_IF_COPY(txt, 1);
492 funcctx = SRF_PERCALL_SETUP();
494 if ((result = prs_process_call(funcctx)) != (Datum) 0)
495 SRF_RETURN_NEXT(funcctx, result);
496 SRF_RETURN_DONE(funcctx);
500 PG_FUNCTION_INFO_V1(parse_current);
501 Datum parse_current(PG_FUNCTION_ARGS);
503 parse_current(PG_FUNCTION_ARGS)
505 FuncCallContext *funcctx;
509 if (SRF_IS_FIRSTCALL())
511 text *txt = PG_GETARG_TEXT_P(0);
513 funcctx = SRF_FIRSTCALL_INIT();
514 if (current_parser_id == InvalidOid)
515 current_parser_id = name2id_prs(char2text("default"));
516 prs_setup_firstcall(funcctx, current_parser_id, txt);
517 PG_FREE_IF_COPY(txt, 0);
520 funcctx = SRF_PERCALL_SETUP();
522 if ((result = prs_process_call(funcctx)) != (Datum) 0)
523 SRF_RETURN_NEXT(funcctx, result);
524 SRF_RETURN_DONE(funcctx);
527 PG_FUNCTION_INFO_V1(headline);
528 Datum headline(PG_FUNCTION_ARGS);
530 headline(PG_FUNCTION_ARGS)
532 text *in = PG_GETARG_TEXT_P(1);
533 QUERYTYPE *query = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(2)));
534 text *opt = (PG_NARGS() > 3 && PG_GETARG_POINTER(3)) ? PG_GETARG_TEXT_P(3) : NULL;
541 cfg = findcfg(PG_GETARG_OID(0));
542 prsobj = findprs(cfg->prs_id);
544 memset(&prs, 0, sizeof(HLPRSTEXT));
546 prs.words = (HLWORD *) palloc(sizeof(HLWORD) * prs.lenwords);
547 hlparsetext(cfg, &prs, query, VARDATA(in), VARSIZE(in) - VARHDRSZ);
551 &(prsobj->headline_info),
552 PointerGetDatum(&prs),
553 PointerGetDatum(opt),
554 PointerGetDatum(query)
559 PG_FREE_IF_COPY(in, 1);
560 PG_FREE_IF_COPY(query, 2);
562 PG_FREE_IF_COPY(opt, 3);
567 PG_RETURN_POINTER(out);
571 PG_FUNCTION_INFO_V1(headline_byname);
572 Datum headline_byname(PG_FUNCTION_ARGS);
574 headline_byname(PG_FUNCTION_ARGS)
576 text *cfg = PG_GETARG_TEXT_P(0);
581 out = DirectFunctionCall4(
583 ObjectIdGetDatum(name2id_cfg(cfg)),
586 (PG_NARGS() > 3) ? PG_GETARG_DATUM(3) : PointerGetDatum(NULL)
589 PG_FREE_IF_COPY(cfg, 0);
590 PG_RETURN_DATUM(out);
593 PG_FUNCTION_INFO_V1(headline_current);
594 Datum headline_current(PG_FUNCTION_ARGS);
596 headline_current(PG_FUNCTION_ARGS)
599 PG_RETURN_DATUM(DirectFunctionCall4(
601 ObjectIdGetDatum(get_currcfg()),
604 (PG_NARGS() > 2) ? PG_GETARG_DATUM(2) : PointerGetDatum(NULL)