--- /dev/null
+/*
+ * interface functions to dictionary
+ */
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "postgres.h"
+#include "fmgr.h"
+#include "utils/array.h"
+#include "catalog/pg_type.h"
+#include "executor/spi.h"
+
+#include "dict.h"
+#include "common.h"
+#include "snmap.h"
+
+/*********top interface**********/
+
+static void *plan_getdict = NULL;
+
+void
+init_dict(Oid id, DictInfo * dict)
+{
+ Oid arg[1] = {OIDOID};
+ bool isnull;
+ Datum pars[1] = {ObjectIdGetDatum(id)};
+ int stat;
+
+ memset(dict, 0, sizeof(DictInfo));
+ SPI_connect();
+ if (!plan_getdict)
+ {
+ plan_getdict = SPI_saveplan(SPI_prepare("select dict_init, dict_initoption, dict_lexize from pg_ts_dict where oid = $1", 1, arg));
+ if (!plan_getdict)
+ ts_error(ERROR, "SPI_prepare() failed");
+ }
+
+ stat = SPI_execp(plan_getdict, pars, " ", 1);
+ if (stat < 0)
+ ts_error(ERROR, "SPI_execp return %d", stat);
+ if (SPI_processed > 0)
+ {
+ Datum opt;
+ Oid oid = InvalidOid;
+
+ oid = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull));
+ if (!(isnull || oid == InvalidOid))
+ {
+ opt = SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 2, &isnull);
+ dict->dictionary = (void *) DatumGetPointer(OidFunctionCall1(oid, opt));
+ }
+ oid = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 3, &isnull));
+ if (isnull || oid == InvalidOid)
+ ts_error(ERROR, "Null dict_lexize for dictonary %d", id);
+ fmgr_info_cxt(oid, &(dict->lexize_info), TopMemoryContext);
+ dict->dict_id = id;
+ }
+ else
+ ts_error(ERROR, "No dictionary with id %d", id);
+ SPI_finish();
+}
+
+typedef struct
+{
+ DictInfo *last_dict;
+ int len;
+ int reallen;
+ DictInfo *list;
+ SNMap name2id_map;
+} DictList;
+
+static DictList DList = {NULL, 0, 0, NULL, {0, 0, NULL}};
+
+void
+reset_dict(void)
+{
+ freeSNMap(&(DList.name2id_map));
+ /* XXX need to free DList.list[*].dictionary */
+ if (DList.list)
+ free(DList.list);
+ memset(&DList, 0, sizeof(DictList));
+}
+
+
+static int
+comparedict(const void *a, const void *b)
+{
+ if ( ((DictInfo *) a)->dict_id == ((DictInfo *) b)->dict_id )
+ return 0;
+ return ( ((DictInfo *) a)->dict_id < ((DictInfo *) b)->dict_id ) ? -1 : 1;
+}
+
+DictInfo *
+finddict(Oid id)
+{
+ /* last used dict */
+ if (DList.last_dict && DList.last_dict->dict_id == id)
+ return DList.last_dict;
+
+
+ /* already used dict */
+ if (DList.len != 0)
+ {
+ DictInfo key;
+
+ key.dict_id = id;
+ DList.last_dict = bsearch(&key, DList.list, DList.len, sizeof(DictInfo), comparedict);
+ if (DList.last_dict != NULL)
+ return DList.last_dict;
+ }
+
+ /* last chance */
+ if (DList.len == DList.reallen)
+ {
+ DictInfo *tmp;
+ int reallen = (DList.reallen) ? 2 * DList.reallen : 16;
+
+ tmp = (DictInfo *) realloc(DList.list, sizeof(DictInfo) * reallen);
+ if (!tmp)
+ ts_error(ERROR, "No memory");
+ DList.reallen = reallen;
+ DList.list = tmp;
+ }
+ DList.last_dict = &(DList.list[DList.len]);
+ init_dict(id, DList.last_dict);
+
+ DList.len++;
+ qsort(DList.list, DList.len, sizeof(DictInfo), comparedict);
+ return finddict(id); /* qsort changed order!! */ ;
+}
+
+static void *plan_name2id = NULL;
+
+Oid
+name2id_dict(text *name)
+{
+ Oid arg[1] = {TEXTOID};
+ bool isnull;
+ Datum pars[1] = {PointerGetDatum(name)};
+ int stat;
+ Oid id = findSNMap_t(&(DList.name2id_map), name);
+
+ if (id)
+ return id;
+
+ SPI_connect();
+ if (!plan_name2id)
+ {
+ plan_name2id = SPI_saveplan(SPI_prepare("select oid from pg_ts_dict where dict_name = $1", 1, arg));
+ if (!plan_name2id)
+ ts_error(ERROR, "SPI_prepare() failed");
+ }
+
+ stat = SPI_execp(plan_name2id, pars, " ", 1);
+ if (stat < 0)
+ ts_error(ERROR, "SPI_execp return %d", stat);
+ if (SPI_processed > 0)
+ id = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull));
+ else
+ ts_error(ERROR, "No dictionary with name '%s'", text2char(name));
+ SPI_finish();
+ addSNMap_t(&(DList.name2id_map), name, id);
+ return id;
+}
+
+
+/******sql-level interface******/
+PG_FUNCTION_INFO_V1(lexize);
+Datum lexize(PG_FUNCTION_ARGS);
+
+Datum
+lexize(PG_FUNCTION_ARGS)
+{
+ text *in = PG_GETARG_TEXT_P(1);
+ DictInfo *dict = finddict(PG_GETARG_OID(0));
+ char **res,
+ **ptr;
+ Datum *da;
+ ArrayType *a;
+
+
+ ptr = res = (char **) DatumGetPointer(
+ FunctionCall3(&(dict->lexize_info),
+ PointerGetDatum(dict->dictionary),
+ PointerGetDatum(VARDATA(in)),
+ Int32GetDatum(VARSIZE(in) - VARHDRSZ)
+ )
+ );
+ PG_FREE_IF_COPY(in, 1);
+ if (!res)
+ {
+ if (PG_NARGS() > 2)
+ PG_RETURN_POINTER(NULL);
+ else
+ PG_RETURN_NULL();
+ }
+
+ while (*ptr)
+ ptr++;
+ da = (Datum *) palloc(sizeof(Datum) * (ptr - res + 1));
+ ptr = res;
+ while (*ptr)
+ {
+ da[ptr - res] = PointerGetDatum(char2text(*ptr));
+ ptr++;
+ }
+
+ a = construct_array(
+ da,
+ ptr - res,
+ TEXTOID,
+ -1,
+ false,
+ 'i'
+ );
+
+ ptr = res;
+ while (*ptr)
+ {
+ pfree(DatumGetPointer(da[ptr - res]));
+ pfree(*ptr);
+ ptr++;
+ }
+ pfree(res);
+ pfree(da);
+
+ PG_RETURN_POINTER(a);
+}
+
+PG_FUNCTION_INFO_V1(lexize_byname);
+Datum lexize_byname(PG_FUNCTION_ARGS);
+Datum
+lexize_byname(PG_FUNCTION_ARGS)
+{
+ text *dictname = PG_GETARG_TEXT_P(0);
+ Datum res;
+
+ strdup("simple");
+ res = DirectFunctionCall3(
+ lexize,
+ ObjectIdGetDatum(name2id_dict(dictname)),
+ PG_GETARG_DATUM(1),
+ (Datum) 0
+ );
+ PG_FREE_IF_COPY(dictname, 0);
+ if (res)
+ PG_RETURN_DATUM(res);
+ else
+ PG_RETURN_NULL();
+}
+
+static Oid currect_dictionary_id = 0;
+
+PG_FUNCTION_INFO_V1(set_curdict);
+Datum set_curdict(PG_FUNCTION_ARGS);
+Datum
+set_curdict(PG_FUNCTION_ARGS)
+{
+ finddict(PG_GETARG_OID(0));
+ currect_dictionary_id = PG_GETARG_OID(0);
+ PG_RETURN_VOID();
+}
+
+PG_FUNCTION_INFO_V1(set_curdict_byname);
+Datum set_curdict_byname(PG_FUNCTION_ARGS);
+Datum
+set_curdict_byname(PG_FUNCTION_ARGS)
+{
+ text *dictname = PG_GETARG_TEXT_P(0);
+
+ DirectFunctionCall1(
+ set_curdict,
+ ObjectIdGetDatum(name2id_dict(dictname))
+ );
+ PG_FREE_IF_COPY(dictname, 0);
+ PG_RETURN_VOID();
+}
+
+PG_FUNCTION_INFO_V1(lexize_bycurrent);
+Datum lexize_bycurrent(PG_FUNCTION_ARGS);
+Datum
+lexize_bycurrent(PG_FUNCTION_ARGS)
+{
+ Datum res;
+
+ if (currect_dictionary_id == 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("no currect dictionary"),
+ errhint("Execute select set_curdict().")));
+
+ res = DirectFunctionCall3(
+ lexize,
+ ObjectIdGetDatum(currect_dictionary_id),
+ PG_GETARG_DATUM(0),
+ (Datum) 0
+ );
+ if (res)
+ PG_RETURN_DATUM(res);
+ else
+ PG_RETURN_NULL();
+}
--- /dev/null
+/*
+ * interface functions to parser
+ */
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "postgres.h"
+#include "fmgr.h"
+#include "utils/array.h"
+#include "catalog/pg_type.h"
+#include "executor/spi.h"
+#include "funcapi.h"
+
+#include "wparser.h"
+#include "ts_cfg.h"
+#include "snmap.h"
+#include "common.h"
+
+/*********top interface**********/
+
+static void *plan_getparser = NULL;
+static Oid current_parser_id = InvalidOid;
+
+void
+init_prs(Oid id, WParserInfo * prs)
+{
+ Oid arg[1] = {OIDOID};
+ bool isnull;
+ Datum pars[1] = {ObjectIdGetDatum(id)};
+ int stat;
+
+ memset(prs, 0, sizeof(WParserInfo));
+ SPI_connect();
+ if (!plan_getparser)
+ {
+ plan_getparser = SPI_saveplan(SPI_prepare("select prs_start, prs_nexttoken, prs_end, prs_lextype, prs_headline from pg_ts_parser where oid = $1", 1, arg));
+ if (!plan_getparser)
+ ts_error(ERROR, "SPI_prepare() failed");
+ }
+
+ stat = SPI_execp(plan_getparser, pars, " ", 1);
+ if (stat < 0)
+ ts_error(ERROR, "SPI_execp return %d", stat);
+ if (SPI_processed > 0)
+ {
+ Oid oid = InvalidOid;
+
+ oid = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull));
+ fmgr_info_cxt(oid, &(prs->start_info), TopMemoryContext);
+ oid = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 2, &isnull));
+ fmgr_info_cxt(oid, &(prs->getlexeme_info), TopMemoryContext);
+ oid = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 3, &isnull));
+ fmgr_info_cxt(oid, &(prs->end_info), TopMemoryContext);
+ prs->lextype = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 4, &isnull));
+ oid = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 5, &isnull));
+ fmgr_info_cxt(oid, &(prs->headline_info), TopMemoryContext);
+ prs->prs_id = id;
+ }
+ else
+ ts_error(ERROR, "No parser with id %d", id);
+ SPI_finish();
+}
+
+typedef struct
+{
+ WParserInfo *last_prs;
+ int len;
+ int reallen;
+ WParserInfo *list;
+ SNMap name2id_map;
+} PrsList;
+
+static PrsList PList = {NULL, 0, 0, NULL, {0, 0, NULL}};
+
+void
+reset_prs(void)
+{
+ freeSNMap(&(PList.name2id_map));
+ if (PList.list)
+ free(PList.list);
+ memset(&PList, 0, sizeof(PrsList));
+}
+
+static int
+compareprs(const void *a, const void *b)
+{
+ if ( ((WParserInfo *) a)->prs_id == ((WParserInfo *) b)->prs_id )
+ return 0;
+ return ( ((WParserInfo *) a)->prs_id < ((WParserInfo *) b)->prs_id ) ? -1 : 1;
+}
+
+WParserInfo *
+findprs(Oid id)
+{
+ /* last used prs */
+ if (PList.last_prs && PList.last_prs->prs_id == id)
+ return PList.last_prs;
+
+ /* already used prs */
+ if (PList.len != 0)
+ {
+ WParserInfo key;
+
+ key.prs_id = id;
+ PList.last_prs = bsearch(&key, PList.list, PList.len, sizeof(WParserInfo), compareprs);
+ if (PList.last_prs != NULL)
+ return PList.last_prs;
+ }
+
+ /* last chance */
+ if (PList.len == PList.reallen)
+ {
+ WParserInfo *tmp;
+ int reallen = (PList.reallen) ? 2 * PList.reallen : 16;
+
+ tmp = (WParserInfo *) realloc(PList.list, sizeof(WParserInfo) * reallen);
+ if (!tmp)
+ ts_error(ERROR, "No memory");
+ PList.reallen = reallen;
+ PList.list = tmp;
+ }
+ PList.last_prs = &(PList.list[PList.len]);
+ init_prs(id, PList.last_prs);
+ PList.len++;
+ qsort(PList.list, PList.len, sizeof(WParserInfo), compareprs);
+ return findprs(id); /* qsort changed order!! */ ;
+}
+
+static void *plan_name2id = NULL;
+
+Oid
+name2id_prs(text *name)
+{
+ Oid arg[1] = {TEXTOID};
+ bool isnull;
+ Datum pars[1] = {PointerGetDatum(name)};
+ int stat;
+ Oid id = findSNMap_t(&(PList.name2id_map), name);
+
+ if (id)
+ return id;
+
+
+ SPI_connect();
+ if (!plan_name2id)
+ {
+ plan_name2id = SPI_saveplan(SPI_prepare("select oid from pg_ts_parser where prs_name = $1", 1, arg));
+ if (!plan_name2id)
+ ts_error(ERROR, "SPI_prepare() failed");
+ }
+
+ stat = SPI_execp(plan_name2id, pars, " ", 1);
+ if (stat < 0)
+ ts_error(ERROR, "SPI_execp return %d", stat);
+ if (SPI_processed > 0)
+ id = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull));
+ else
+ ts_error(ERROR, "No parser '%s'", text2char(name));
+ SPI_finish();
+ addSNMap_t(&(PList.name2id_map), name, id);
+ return id;
+}
+
+
+/******sql-level interface******/
+typedef struct
+{
+ int cur;
+ LexDescr *list;
+} TypeStorage;
+
+static void
+setup_firstcall(FuncCallContext *funcctx, Oid prsid)
+{
+ TupleDesc tupdesc;
+ MemoryContext oldcontext;
+ TypeStorage *st;
+ WParserInfo *prs = findprs(prsid);
+
+ oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
+
+ st = (TypeStorage *) palloc(sizeof(TypeStorage));
+ st->cur = 0;
+ st->list = (LexDescr *) DatumGetPointer(
+ OidFunctionCall1(prs->lextype, PointerGetDatum(prs->prs))
+ );
+ funcctx->user_fctx = (void *) st;
+ tupdesc = RelationNameGetTupleDesc("tokentype");
+ funcctx->slot = TupleDescGetSlot(tupdesc);
+ funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
+ MemoryContextSwitchTo(oldcontext);
+}
+
+static Datum
+process_call(FuncCallContext *funcctx)
+{
+ TypeStorage *st;
+
+ st = (TypeStorage *) funcctx->user_fctx;
+ if (st->list && st->list[st->cur].lexid)
+ {
+ Datum result;
+ char *values[3];
+ char txtid[16];
+ HeapTuple tuple;
+
+ values[0] = txtid;
+ sprintf(txtid, "%d", st->list[st->cur].lexid);
+ values[1] = st->list[st->cur].alias;
+ values[2] = st->list[st->cur].descr;
+
+ tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
+ result = TupleGetDatum(funcctx->slot, tuple);
+
+ pfree(values[1]);
+ pfree(values[2]);
+ st->cur++;
+ return result;
+ }
+ else
+ {
+ if (st->list)
+ pfree(st->list);
+ pfree(st);
+ }
+ return (Datum) 0;
+}
+
+PG_FUNCTION_INFO_V1(token_type);
+Datum token_type(PG_FUNCTION_ARGS);
+
+Datum
+token_type(PG_FUNCTION_ARGS)
+{
+ FuncCallContext *funcctx;
+ Datum result;
+
+ if (SRF_IS_FIRSTCALL())
+ {
+ funcctx = SRF_FIRSTCALL_INIT();
+ setup_firstcall(funcctx, PG_GETARG_OID(0));
+ }
+
+ funcctx = SRF_PERCALL_SETUP();
+
+ if ((result = process_call(funcctx)) != (Datum) 0)
+ SRF_RETURN_NEXT(funcctx, result);
+ SRF_RETURN_DONE(funcctx);
+}
+
+PG_FUNCTION_INFO_V1(token_type_byname);
+Datum token_type_byname(PG_FUNCTION_ARGS);
+Datum
+token_type_byname(PG_FUNCTION_ARGS)
+{
+ FuncCallContext *funcctx;
+ Datum result;
+
+ if (SRF_IS_FIRSTCALL())
+ {
+ text *name = PG_GETARG_TEXT_P(0);
+
+ funcctx = SRF_FIRSTCALL_INIT();
+ setup_firstcall(funcctx, name2id_prs(name));
+ PG_FREE_IF_COPY(name, 0);
+ }
+
+ funcctx = SRF_PERCALL_SETUP();
+
+ if ((result = process_call(funcctx)) != (Datum) 0)
+ SRF_RETURN_NEXT(funcctx, result);
+ SRF_RETURN_DONE(funcctx);
+}
+
+PG_FUNCTION_INFO_V1(token_type_current);
+Datum token_type_current(PG_FUNCTION_ARGS);
+Datum
+token_type_current(PG_FUNCTION_ARGS)
+{
+ FuncCallContext *funcctx;
+ Datum result;
+
+ if (SRF_IS_FIRSTCALL())
+ {
+ funcctx = SRF_FIRSTCALL_INIT();
+ if (current_parser_id == InvalidOid)
+ current_parser_id = name2id_prs(char2text("default"));
+ setup_firstcall(funcctx, current_parser_id);
+ }
+
+ funcctx = SRF_PERCALL_SETUP();
+
+ if ((result = process_call(funcctx)) != (Datum) 0)
+ SRF_RETURN_NEXT(funcctx, result);
+ SRF_RETURN_DONE(funcctx);
+}
+
+
+PG_FUNCTION_INFO_V1(set_curprs);
+Datum set_curprs(PG_FUNCTION_ARGS);
+Datum
+set_curprs(PG_FUNCTION_ARGS)
+{
+ findprs(PG_GETARG_OID(0));
+ current_parser_id = PG_GETARG_OID(0);
+ PG_RETURN_VOID();
+}
+
+PG_FUNCTION_INFO_V1(set_curprs_byname);
+Datum set_curprs_byname(PG_FUNCTION_ARGS);
+Datum
+set_curprs_byname(PG_FUNCTION_ARGS)
+{
+ text *name = PG_GETARG_TEXT_P(0);
+
+ DirectFunctionCall1(
+ set_curprs,
+ ObjectIdGetDatum(name2id_prs(name))
+ );
+ PG_FREE_IF_COPY(name, 0);
+ PG_RETURN_VOID();
+}
+
+typedef struct
+{
+ int type;
+ char *lexem;
+} LexemEntry;
+
+typedef struct
+{
+ int cur;
+ int len;
+ LexemEntry *list;
+} PrsStorage;
+
+
+static void
+prs_setup_firstcall(FuncCallContext *funcctx, int prsid, text *txt)
+{
+ TupleDesc tupdesc;
+ MemoryContext oldcontext;
+ PrsStorage *st;
+ WParserInfo *prs = findprs(prsid);
+ char *lex = NULL;
+ int llen = 0,
+ type = 0;
+
+ oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
+
+ st = (PrsStorage *) palloc(sizeof(PrsStorage));
+ st->cur = 0;
+ st->len = 16;
+ st->list = (LexemEntry *) palloc(sizeof(LexemEntry) * st->len);
+
+ prs->prs = (void *) DatumGetPointer(
+ FunctionCall2(
+ &(prs->start_info),
+ PointerGetDatum(VARDATA(txt)),
+ Int32GetDatum(VARSIZE(txt) - VARHDRSZ)
+ )
+ );
+
+ while ((type = DatumGetInt32(FunctionCall3(
+ &(prs->getlexeme_info),
+ PointerGetDatum(prs->prs),
+ PointerGetDatum(&lex),
+ PointerGetDatum(&llen)))) != 0)
+ {
+
+ if (st->cur >= st->len)
+ {
+ st->len = 2 * st->len;
+ st->list = (LexemEntry *) repalloc(st->list, sizeof(LexemEntry) * st->len);
+ }
+ st->list[st->cur].lexem = palloc(llen + 1);
+ memcpy(st->list[st->cur].lexem, lex, llen);
+ st->list[st->cur].lexem[llen] = '\0';
+ st->list[st->cur].type = type;
+ st->cur++;
+ }
+
+ FunctionCall1(
+ &(prs->end_info),
+ PointerGetDatum(prs->prs)
+ );
+
+ st->len = st->cur;
+ st->cur = 0;
+
+ funcctx->user_fctx = (void *) st;
+ tupdesc = RelationNameGetTupleDesc("tokenout");
+ funcctx->slot = TupleDescGetSlot(tupdesc);
+ funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
+ MemoryContextSwitchTo(oldcontext);
+}
+
+static Datum
+prs_process_call(FuncCallContext *funcctx)
+{
+ PrsStorage *st;
+
+ st = (PrsStorage *) funcctx->user_fctx;
+ if (st->cur < st->len)
+ {
+ Datum result;
+ char *values[2];
+ char tid[16];
+ HeapTuple tuple;
+
+ values[0] = tid;
+ sprintf(tid, "%d", st->list[st->cur].type);
+ values[1] = st->list[st->cur].lexem;
+ tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
+ result = TupleGetDatum(funcctx->slot, tuple);
+
+ pfree(values[1]);
+ st->cur++;
+ return result;
+ }
+ else
+ {
+ if (st->list)
+ pfree(st->list);
+ pfree(st);
+ }
+ return (Datum) 0;
+}
+
+
+
+PG_FUNCTION_INFO_V1(parse);
+Datum parse(PG_FUNCTION_ARGS);
+Datum
+parse(PG_FUNCTION_ARGS)
+{
+ FuncCallContext *funcctx;
+ Datum result;
+
+ if (SRF_IS_FIRSTCALL())
+ {
+ text *txt = PG_GETARG_TEXT_P(1);
+
+ funcctx = SRF_FIRSTCALL_INIT();
+ prs_setup_firstcall(funcctx, PG_GETARG_OID(0), txt);
+ PG_FREE_IF_COPY(txt, 1);
+ }
+
+ funcctx = SRF_PERCALL_SETUP();
+
+ if ((result = prs_process_call(funcctx)) != (Datum) 0)
+ SRF_RETURN_NEXT(funcctx, result);
+ SRF_RETURN_DONE(funcctx);
+}
+
+PG_FUNCTION_INFO_V1(parse_byname);
+Datum parse_byname(PG_FUNCTION_ARGS);
+Datum
+parse_byname(PG_FUNCTION_ARGS)
+{
+ FuncCallContext *funcctx;
+ Datum result;
+
+ if (SRF_IS_FIRSTCALL())
+ {
+ text *name = PG_GETARG_TEXT_P(0);
+ text *txt = PG_GETARG_TEXT_P(1);
+
+ funcctx = SRF_FIRSTCALL_INIT();
+ prs_setup_firstcall(funcctx, name2id_prs(name), txt);
+ PG_FREE_IF_COPY(name, 0);
+ PG_FREE_IF_COPY(txt, 1);
+ }
+
+ funcctx = SRF_PERCALL_SETUP();
+
+ if ((result = prs_process_call(funcctx)) != (Datum) 0)
+ SRF_RETURN_NEXT(funcctx, result);
+ SRF_RETURN_DONE(funcctx);
+}
+
+
+PG_FUNCTION_INFO_V1(parse_current);
+Datum parse_current(PG_FUNCTION_ARGS);
+Datum
+parse_current(PG_FUNCTION_ARGS)
+{
+ FuncCallContext *funcctx;
+ Datum result;
+
+ if (SRF_IS_FIRSTCALL())
+ {
+ text *txt = PG_GETARG_TEXT_P(0);
+
+ funcctx = SRF_FIRSTCALL_INIT();
+ if (current_parser_id == InvalidOid)
+ current_parser_id = name2id_prs(char2text("default"));
+ prs_setup_firstcall(funcctx, current_parser_id, txt);
+ PG_FREE_IF_COPY(txt, 0);
+ }
+
+ funcctx = SRF_PERCALL_SETUP();
+
+ if ((result = prs_process_call(funcctx)) != (Datum) 0)
+ SRF_RETURN_NEXT(funcctx, result);
+ SRF_RETURN_DONE(funcctx);
+}
+
+PG_FUNCTION_INFO_V1(headline);
+Datum headline(PG_FUNCTION_ARGS);
+Datum
+headline(PG_FUNCTION_ARGS)
+{
+ TSCfgInfo *cfg = findcfg(PG_GETARG_OID(0));
+ text *in = PG_GETARG_TEXT_P(1);
+ QUERYTYPE *query = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(2)));
+ text *opt = (PG_NARGS() > 3 && PG_GETARG_POINTER(3)) ? PG_GETARG_TEXT_P(3) : NULL;
+ HLPRSTEXT prs;
+ text *out;
+ WParserInfo *prsobj = findprs(cfg->prs_id);
+
+ memset(&prs, 0, sizeof(HLPRSTEXT));
+ prs.lenwords = 32;
+ prs.words = (HLWORD *) palloc(sizeof(HLWORD) * prs.lenwords);
+ hlparsetext(cfg, &prs, query, VARDATA(in), VARSIZE(in) - VARHDRSZ);
+
+
+ FunctionCall3(
+ &(prsobj->headline_info),
+ PointerGetDatum(&prs),
+ PointerGetDatum(opt),
+ PointerGetDatum(query)
+ );
+
+ out = genhl(&prs);
+
+ PG_FREE_IF_COPY(in, 1);
+ PG_FREE_IF_COPY(query, 2);
+ if (opt)
+ PG_FREE_IF_COPY(opt, 3);
+ pfree(prs.words);
+ pfree(prs.startsel);
+ pfree(prs.stopsel);
+
+ PG_RETURN_POINTER(out);
+}
+
+
+PG_FUNCTION_INFO_V1(headline_byname);
+Datum headline_byname(PG_FUNCTION_ARGS);
+Datum
+headline_byname(PG_FUNCTION_ARGS)
+{
+ text *cfg = PG_GETARG_TEXT_P(0);
+
+ Datum out = DirectFunctionCall4(
+ headline,
+ ObjectIdGetDatum(name2id_cfg(cfg)),
+ PG_GETARG_DATUM(1),
+ PG_GETARG_DATUM(2),
+ (PG_NARGS() > 3) ? PG_GETARG_DATUM(3) : PointerGetDatum(NULL)
+ );
+
+ PG_FREE_IF_COPY(cfg, 0);
+ PG_RETURN_DATUM(out);
+}
+
+PG_FUNCTION_INFO_V1(headline_current);
+Datum headline_current(PG_FUNCTION_ARGS);
+Datum
+headline_current(PG_FUNCTION_ARGS)
+{
+ PG_RETURN_DATUM(DirectFunctionCall4(
+ headline,
+ ObjectIdGetDatum(get_currcfg()),
+ PG_GETARG_DATUM(0),
+ PG_GETARG_DATUM(1),
+ (PG_NARGS() > 2) ? PG_GETARG_DATUM(2) : PointerGetDatum(NULL)
+ ));
+}