PostgreSQL Source Code  git master
wparser.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * wparser.c
4  * Standard interface to word parser
5  *
6  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7  *
8  *
9  * IDENTIFICATION
10  * src/backend/tsearch/wparser.c
11  *
12  *-------------------------------------------------------------------------
13  */
14 #include "postgres.h"
15 
16 #include "catalog/namespace.h"
17 #include "commands/defrem.h"
18 #include "funcapi.h"
19 #include "tsearch/ts_cache.h"
20 #include "tsearch/ts_utils.h"
21 #include "utils/fmgrprotos.h"
22 #include "utils/jsonfuncs.h"
23 #include "utils/varlena.h"
24 
25 /******sql-level interface******/
26 
27 typedef struct
28 {
29  int cur;
32 
33 /* state for ts_headline_json_* */
34 typedef struct HeadlineJsonState
35 {
43 
44 static text *headline_json_value(void *_state, char *elem_value, int elem_len);
45 
46 static void
48  Oid prsid)
49 {
50  TupleDesc tupdesc;
51  MemoryContext oldcontext;
54 
55  if (!OidIsValid(prs->lextypeOid))
56  elog(ERROR, "method lextype isn't defined for text search parser %u",
57  prsid);
58 
59  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
60 
62  st->cur = 0;
63  /* lextype takes one dummy argument */
65  (Datum) 0));
66  funcctx->user_fctx = st;
67 
68  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
69  elog(ERROR, "return type must be a row type");
70  funcctx->tuple_desc = tupdesc;
71  funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
72 
73  MemoryContextSwitchTo(oldcontext);
74 }
75 
76 static Datum
78 {
80 
81  st = (TSTokenTypeStorage *) funcctx->user_fctx;
82  if (st->list && st->list[st->cur].lexid)
83  {
84  Datum result;
85  char *values[3];
86  char txtid[16];
87  HeapTuple tuple;
88 
89  sprintf(txtid, "%d", st->list[st->cur].lexid);
90  values[0] = txtid;
91  values[1] = st->list[st->cur].alias;
92  values[2] = st->list[st->cur].descr;
93 
94  tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
95  result = HeapTupleGetDatum(tuple);
96 
97  pfree(values[1]);
98  pfree(values[2]);
99  st->cur++;
100  return result;
101  }
102  return (Datum) 0;
103 }
104 
105 Datum
107 {
108  FuncCallContext *funcctx;
109  Datum result;
110 
111  if (SRF_IS_FIRSTCALL())
112  {
113  funcctx = SRF_FIRSTCALL_INIT();
114  tt_setup_firstcall(funcctx, fcinfo, PG_GETARG_OID(0));
115  }
116 
117  funcctx = SRF_PERCALL_SETUP();
118 
119  if ((result = tt_process_call(funcctx)) != (Datum) 0)
120  SRF_RETURN_NEXT(funcctx, result);
121  SRF_RETURN_DONE(funcctx);
122 }
123 
124 Datum
126 {
127  FuncCallContext *funcctx;
128  Datum result;
129 
130  if (SRF_IS_FIRSTCALL())
131  {
132  text *prsname = PG_GETARG_TEXT_PP(0);
133  Oid prsId;
134 
135  funcctx = SRF_FIRSTCALL_INIT();
136  prsId = get_ts_parser_oid(textToQualifiedNameList(prsname), false);
137  tt_setup_firstcall(funcctx, fcinfo, prsId);
138  }
139 
140  funcctx = SRF_PERCALL_SETUP();
141 
142  if ((result = tt_process_call(funcctx)) != (Datum) 0)
143  SRF_RETURN_NEXT(funcctx, result);
144  SRF_RETURN_DONE(funcctx);
145 }
146 
147 typedef struct
148 {
149  int type;
150  char *lexeme;
151 } LexemeEntry;
152 
153 typedef struct
154 {
155  int cur;
156  int len;
158 } PrsStorage;
159 
160 
161 static void
163  Oid prsid, text *txt)
164 {
165  TupleDesc tupdesc;
166  MemoryContext oldcontext;
167  PrsStorage *st;
169  char *lex = NULL;
170  int llen = 0,
171  type = 0;
172  void *prsdata;
173 
174  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
175 
176  st = (PrsStorage *) palloc(sizeof(PrsStorage));
177  st->cur = 0;
178  st->len = 16;
179  st->list = (LexemeEntry *) palloc(sizeof(LexemeEntry) * st->len);
180 
181  prsdata = DatumGetPointer(FunctionCall2(&prs->prsstart,
184 
185  while ((type = DatumGetInt32(FunctionCall3(&prs->prstoken,
186  PointerGetDatum(prsdata),
187  PointerGetDatum(&lex),
188  PointerGetDatum(&llen)))) != 0)
189  {
190  if (st->cur >= st->len)
191  {
192  st->len = 2 * st->len;
193  st->list = (LexemeEntry *) repalloc(st->list, sizeof(LexemeEntry) * st->len);
194  }
195  st->list[st->cur].lexeme = palloc(llen + 1);
196  memcpy(st->list[st->cur].lexeme, lex, llen);
197  st->list[st->cur].lexeme[llen] = '\0';
198  st->list[st->cur].type = type;
199  st->cur++;
200  }
201 
202  FunctionCall1(&prs->prsend, PointerGetDatum(prsdata));
203 
204  st->len = st->cur;
205  st->cur = 0;
206 
207  funcctx->user_fctx = (void *) st;
208  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
209  elog(ERROR, "return type must be a row type");
210  funcctx->tuple_desc = tupdesc;
211  funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
212  MemoryContextSwitchTo(oldcontext);
213 }
214 
215 static Datum
217 {
218  PrsStorage *st;
219 
220  st = (PrsStorage *) funcctx->user_fctx;
221  if (st->cur < st->len)
222  {
223  Datum result;
224  char *values[2];
225  char tid[16];
226  HeapTuple tuple;
227 
228  values[0] = tid;
229  sprintf(tid, "%d", st->list[st->cur].type);
230  values[1] = st->list[st->cur].lexeme;
231  tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
232  result = HeapTupleGetDatum(tuple);
233 
234  pfree(values[1]);
235  st->cur++;
236  return result;
237  }
238  return (Datum) 0;
239 }
240 
241 Datum
243 {
244  FuncCallContext *funcctx;
245  Datum result;
246 
247  if (SRF_IS_FIRSTCALL())
248  {
249  text *txt = PG_GETARG_TEXT_PP(1);
250 
251  funcctx = SRF_FIRSTCALL_INIT();
252  prs_setup_firstcall(funcctx, fcinfo, PG_GETARG_OID(0), txt);
253  PG_FREE_IF_COPY(txt, 1);
254  }
255 
256  funcctx = SRF_PERCALL_SETUP();
257 
258  if ((result = prs_process_call(funcctx)) != (Datum) 0)
259  SRF_RETURN_NEXT(funcctx, result);
260  SRF_RETURN_DONE(funcctx);
261 }
262 
263 Datum
265 {
266  FuncCallContext *funcctx;
267  Datum result;
268 
269  if (SRF_IS_FIRSTCALL())
270  {
271  text *prsname = PG_GETARG_TEXT_PP(0);
272  text *txt = PG_GETARG_TEXT_PP(1);
273  Oid prsId;
274 
275  funcctx = SRF_FIRSTCALL_INIT();
276  prsId = get_ts_parser_oid(textToQualifiedNameList(prsname), false);
277  prs_setup_firstcall(funcctx, fcinfo, prsId, txt);
278  }
279 
280  funcctx = SRF_PERCALL_SETUP();
281 
282  if ((result = prs_process_call(funcctx)) != (Datum) 0)
283  SRF_RETURN_NEXT(funcctx, result);
284  SRF_RETURN_DONE(funcctx);
285 }
286 
287 Datum
289 {
290  Oid tsconfig = PG_GETARG_OID(0);
291  text *in = PG_GETARG_TEXT_PP(1);
292  TSQuery query = PG_GETARG_TSQUERY(2);
293  text *opt = (PG_NARGS() > 3 && PG_GETARG_POINTER(3)) ? PG_GETARG_TEXT_PP(3) : NULL;
294  HeadlineParsedText prs;
295  List *prsoptions;
296  text *out;
297  TSConfigCacheEntry *cfg;
298  TSParserCacheEntry *prsobj;
299 
300  cfg = lookup_ts_config_cache(tsconfig);
301  prsobj = lookup_ts_parser_cache(cfg->prsId);
302 
303  if (!OidIsValid(prsobj->headlineOid))
304  ereport(ERROR,
305  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
306  errmsg("text search parser does not support headline creation")));
307 
308  memset(&prs, 0, sizeof(HeadlineParsedText));
309  prs.lenwords = 32;
310  prs.words = (HeadlineWordEntry *) palloc(sizeof(HeadlineWordEntry) * prs.lenwords);
311 
312  hlparsetext(cfg->cfgId, &prs, query,
313  VARDATA_ANY(in), VARSIZE_ANY_EXHDR(in));
314 
315  if (opt)
316  prsoptions = deserialize_deflist(PointerGetDatum(opt));
317  else
318  prsoptions = NIL;
319 
320  FunctionCall3(&(prsobj->prsheadline),
321  PointerGetDatum(&prs),
322  PointerGetDatum(prsoptions),
323  PointerGetDatum(query));
324 
325  out = generateHeadline(&prs);
326 
327  PG_FREE_IF_COPY(in, 1);
328  PG_FREE_IF_COPY(query, 2);
329  if (opt)
330  PG_FREE_IF_COPY(opt, 3);
331  pfree(prs.words);
332  pfree(prs.startsel);
333  pfree(prs.stopsel);
334 
335  PG_RETURN_POINTER(out);
336 }
337 
338 Datum
340 {
342  PG_GETARG_DATUM(0),
343  PG_GETARG_DATUM(1),
344  PG_GETARG_DATUM(2)));
345 }
346 
347 Datum
349 {
352  PG_GETARG_DATUM(0),
353  PG_GETARG_DATUM(1)));
354 }
355 
356 Datum
358 {
361  PG_GETARG_DATUM(0),
362  PG_GETARG_DATUM(1),
363  PG_GETARG_DATUM(2)));
364 }
365 
366 Datum
368 {
369  Oid tsconfig = PG_GETARG_OID(0);
370  Jsonb *jb = PG_GETARG_JSONB_P(1);
371  TSQuery query = PG_GETARG_TSQUERY(2);
372  text *opt = (PG_NARGS() > 3 && PG_GETARG_POINTER(3)) ? PG_GETARG_TEXT_P(3) : NULL;
373  Jsonb *out;
375  HeadlineParsedText prs;
377 
378  memset(&prs, 0, sizeof(HeadlineParsedText));
379  prs.lenwords = 32;
380  prs.words = (HeadlineWordEntry *) palloc(sizeof(HeadlineWordEntry) * prs.lenwords);
381 
382  state->prs = &prs;
383  state->cfg = lookup_ts_config_cache(tsconfig);
384  state->prsobj = lookup_ts_parser_cache(state->cfg->prsId);
385  state->query = query;
386  if (opt)
387  state->prsoptions = deserialize_deflist(PointerGetDatum(opt));
388  else
389  state->prsoptions = NIL;
390 
391  if (!OidIsValid(state->prsobj->headlineOid))
392  ereport(ERROR,
393  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
394  errmsg("text search parser does not support headline creation")));
395 
397 
398  PG_FREE_IF_COPY(jb, 1);
399  PG_FREE_IF_COPY(query, 2);
400  if (opt)
401  PG_FREE_IF_COPY(opt, 3);
402 
403  pfree(prs.words);
404 
405  if (state->transformed)
406  {
407  pfree(prs.startsel);
408  pfree(prs.stopsel);
409  }
410 
411  PG_RETURN_JSONB_P(out);
412 }
413 
414 Datum
416 {
419  PG_GETARG_DATUM(0),
420  PG_GETARG_DATUM(1)));
421 }
422 
423 Datum
425 {
427  PG_GETARG_DATUM(0),
428  PG_GETARG_DATUM(1),
429  PG_GETARG_DATUM(2)));
430 }
431 
432 Datum
434 {
437  PG_GETARG_DATUM(0),
438  PG_GETARG_DATUM(1),
439  PG_GETARG_DATUM(2)));
440 }
441 
442 Datum
444 {
445  Oid tsconfig = PG_GETARG_OID(0);
446  text *json = PG_GETARG_TEXT_P(1);
447  TSQuery query = PG_GETARG_TSQUERY(2);
448  text *opt = (PG_NARGS() > 3 && PG_GETARG_POINTER(3)) ? PG_GETARG_TEXT_P(3) : NULL;
449  text *out;
451 
452  HeadlineParsedText prs;
454 
455  memset(&prs, 0, sizeof(HeadlineParsedText));
456  prs.lenwords = 32;
457  prs.words = (HeadlineWordEntry *) palloc(sizeof(HeadlineWordEntry) * prs.lenwords);
458 
459  state->prs = &prs;
460  state->cfg = lookup_ts_config_cache(tsconfig);
461  state->prsobj = lookup_ts_parser_cache(state->cfg->prsId);
462  state->query = query;
463  if (opt)
464  state->prsoptions = deserialize_deflist(PointerGetDatum(opt));
465  else
466  state->prsoptions = NIL;
467 
468  if (!OidIsValid(state->prsobj->headlineOid))
469  ereport(ERROR,
470  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
471  errmsg("text search parser does not support headline creation")));
472 
474 
475  PG_FREE_IF_COPY(json, 1);
476  PG_FREE_IF_COPY(query, 2);
477  if (opt)
478  PG_FREE_IF_COPY(opt, 3);
479  pfree(prs.words);
480 
481  if (state->transformed)
482  {
483  pfree(prs.startsel);
484  pfree(prs.stopsel);
485  }
486 
487  PG_RETURN_TEXT_P(out);
488 }
489 
490 Datum
492 {
495  PG_GETARG_DATUM(0),
496  PG_GETARG_DATUM(1)));
497 }
498 
499 Datum
501 {
503  PG_GETARG_DATUM(0),
504  PG_GETARG_DATUM(1),
505  PG_GETARG_DATUM(2)));
506 }
507 
508 Datum
510 {
513  PG_GETARG_DATUM(0),
514  PG_GETARG_DATUM(1),
515  PG_GETARG_DATUM(2)));
516 }
517 
518 
519 /*
520  * Return headline in text from, generated from a json(b) element
521  */
522 static text *
523 headline_json_value(void *_state, char *elem_value, int elem_len)
524 {
526 
527  HeadlineParsedText *prs = state->prs;
528  TSConfigCacheEntry *cfg = state->cfg;
529  TSParserCacheEntry *prsobj = state->prsobj;
530  TSQuery query = state->query;
531  List *prsoptions = state->prsoptions;
532 
533  prs->curwords = 0;
534  hlparsetext(cfg->cfgId, prs, query, elem_value, elem_len);
535  FunctionCall3(&(prsobj->prsheadline),
536  PointerGetDatum(prs),
537  PointerGetDatum(prsoptions),
538  PointerGetDatum(query));
539 
540  state->transformed = true;
541  return generateHeadline(prs);
542 }
static Datum values[MAXATTR]
Definition: bootstrap.c:151
#define OidIsValid(objectId)
Definition: c.h:729
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define ereport(elevel,...)
Definition: elog.h:149
HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
Definition: execTuples.c:2222
AttInMetadata * TupleDescGetAttInMetadata(TupleDesc tupdesc)
Definition: execTuples.c:2173
#define OidFunctionCall1(functionId, arg1)
Definition: fmgr.h:679
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:260
#define PG_GETARG_OID(n)
Definition: fmgr.h:275
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:309
#define DirectFunctionCall4(func, arg1, arg2, arg3, arg4)
Definition: fmgr.h:647
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:268
#define PG_NARGS()
Definition: fmgr.h:203
#define FunctionCall1(flinfo, arg1)
Definition: fmgr.h:659
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:372
#define FunctionCall2(flinfo, arg1, arg2)
Definition: fmgr.h:661
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:353
#define DirectFunctionCall3(func, arg1, arg2, arg3)
Definition: fmgr.h:645
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
#define FunctionCall3(flinfo, arg1, arg2, arg3)
Definition: fmgr.h:663
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
#define PG_GETARG_TEXT_P(n)
Definition: fmgr.h:336
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition: funcapi.c:276
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:304
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:308
@ TYPEFUNC_COMPOSITE
Definition: funcapi.h:149
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:310
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:306
static Datum HeapTupleGetDatum(const HeapTupleData *tuple)
Definition: funcapi.h:230
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:328
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:76
#define PG_RETURN_JSONB_P(x)
Definition: jsonb.h:393
#define PG_GETARG_JSONB_P(x)
Definition: jsonb.h:391
text * transform_json_string_values(text *json, void *action_state, JsonTransformStringValuesAction transform_action)
Definition: jsonfuncs.c:5830
Jsonb * transform_jsonb_string_values(Jsonb *jsonb, void *action_state, JsonTransformStringValuesAction transform_action)
Definition: jsonfuncs.c:5783
text *(* JsonTransformStringValuesAction)(void *state, char *elem_value, int elem_len)
Definition: jsonfuncs.h:38
void pfree(void *pointer)
Definition: mcxt.c:1521
void * palloc0(Size size)
Definition: mcxt.c:1347
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1541
void * palloc(Size size)
Definition: mcxt.c:1317
Oid get_ts_parser_oid(List *names, bool missing_ok)
Definition: namespace.c:2716
#define NIL
Definition: pg_list.h:68
#define sprintf
Definition: port.h:240
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
uintptr_t Datum
Definition: postgres.h:64
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212
static int32 DatumGetInt32(Datum X)
Definition: postgres.h:202
unsigned int Oid
Definition: postgres_ext.h:31
MemoryContextSwitchTo(old_ctx)
void * user_fctx
Definition: funcapi.h:82
AttInMetadata * attinmeta
Definition: funcapi.h:91
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:101
TupleDesc tuple_desc
Definition: funcapi.h:112
List * prsoptions
Definition: wparser.c:40
TSConfigCacheEntry * cfg
Definition: wparser.c:37
TSParserCacheEntry * prsobj
Definition: wparser.c:38
bool transformed
Definition: wparser.c:41
HeadlineParsedText * prs
Definition: wparser.c:36
TSQuery query
Definition: wparser.c:39
HeadlineWordEntry * words
Definition: ts_public.h:76
Definition: jsonb.h:213
char * alias
Definition: ts_public.h:28
int lexid
Definition: ts_public.h:27
char * descr
Definition: ts_public.h:29
int type
Definition: wparser.c:149
char * lexeme
Definition: wparser.c:150
Definition: pg_list.h:54
int len
Definition: wparser.c:156
int cur
Definition: wparser.c:155
LexemeEntry * list
Definition: wparser.c:157
FmgrInfo prstoken
Definition: ts_cache.h:46
FmgrInfo prsstart
Definition: ts_cache.h:45
FmgrInfo prsheadline
Definition: ts_cache.h:48
FmgrInfo prsend
Definition: ts_cache.h:47
LexDescr * list
Definition: wparser.c:30
Definition: regguts.h:323
Definition: c.h:641
Oid getTSCurrentConfig(bool emitError)
Definition: ts_cache.c:556
TSConfigCacheEntry * lookup_ts_config_cache(Oid cfgId)
Definition: ts_cache.c:385
TSParserCacheEntry * lookup_ts_parser_cache(Oid prsId)
Definition: ts_cache.c:113
void hlparsetext(Oid cfgId, HeadlineParsedText *prs, TSQuery query, char *buf, int buflen)
Definition: ts_parse.c:540
text * generateHeadline(HeadlineParsedText *prs)
Definition: ts_parse.c:607
#define PG_GETARG_TSQUERY(n)
Definition: ts_type.h:266
List * deserialize_deflist(Datum txt)
Definition: tsearchcmds.c:1621
#define VARDATA_ANY(PTR)
Definition: varatt.h:324
#define VARSIZE_ANY_EXHDR(PTR)
Definition: varatt.h:317
List * textToQualifiedNameList(text *textval)
Definition: varlena.c:3374
const char * type
static void prs_setup_firstcall(FuncCallContext *funcctx, FunctionCallInfo fcinfo, Oid prsid, text *txt)
Definition: wparser.c:162
Datum ts_headline_opt(PG_FUNCTION_ARGS)
Definition: wparser.c:357
Datum ts_parse_byname(PG_FUNCTION_ARGS)
Definition: wparser.c:264
Datum ts_token_type_byid(PG_FUNCTION_ARGS)
Definition: wparser.c:106
Datum ts_headline(PG_FUNCTION_ARGS)
Definition: wparser.c:348
Datum ts_headline_byid_opt(PG_FUNCTION_ARGS)
Definition: wparser.c:288
static Datum prs_process_call(FuncCallContext *funcctx)
Definition: wparser.c:216
Datum ts_headline_json_byid_opt(PG_FUNCTION_ARGS)
Definition: wparser.c:443
Datum ts_headline_jsonb_byid_opt(PG_FUNCTION_ARGS)
Definition: wparser.c:367
Datum ts_parse_byid(PG_FUNCTION_ARGS)
Definition: wparser.c:242
Datum ts_headline_byid(PG_FUNCTION_ARGS)
Definition: wparser.c:339
struct HeadlineJsonState HeadlineJsonState
Datum ts_headline_jsonb_byid(PG_FUNCTION_ARGS)
Definition: wparser.c:424
static void tt_setup_firstcall(FuncCallContext *funcctx, FunctionCallInfo fcinfo, Oid prsid)
Definition: wparser.c:47
Datum ts_token_type_byname(PG_FUNCTION_ARGS)
Definition: wparser.c:125
Datum ts_headline_json_opt(PG_FUNCTION_ARGS)
Definition: wparser.c:509
Datum ts_headline_jsonb(PG_FUNCTION_ARGS)
Definition: wparser.c:415
Datum ts_headline_jsonb_opt(PG_FUNCTION_ARGS)
Definition: wparser.c:433
Datum ts_headline_json(PG_FUNCTION_ARGS)
Definition: wparser.c:491
static text * headline_json_value(void *_state, char *elem_value, int elem_len)
Definition: wparser.c:523
static Datum tt_process_call(FuncCallContext *funcctx)
Definition: wparser.c:77
Datum ts_headline_json_byid(PG_FUNCTION_ARGS)
Definition: wparser.c:500