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-2019, 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 "catalog/pg_type.h"
18 #include "commands/defrem.h"
19 #include "funcapi.h"
20 #include "tsearch/ts_cache.h"
21 #include "tsearch/ts_utils.h"
22 #include "utils/builtins.h"
23 #include "utils/jsonapi.h"
24 #include "utils/varlena.h"
25 
26 /******sql-level interface******/
27 
28 typedef struct
29 {
30  int cur;
33 
34 /* state for ts_headline_json_* */
35 typedef struct HeadlineJsonState
36 {
44 
45 static text *headline_json_value(void *_state, char *elem_value, int elem_len);
46 
47 static void
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 = (void *) st;
67 
68  tupdesc = CreateTemplateTupleDesc(3);
69  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "tokid",
70  INT4OID, -1, 0);
71  TupleDescInitEntry(tupdesc, (AttrNumber) 2, "alias",
72  TEXTOID, -1, 0);
73  TupleDescInitEntry(tupdesc, (AttrNumber) 3, "description",
74  TEXTOID, -1, 0);
75 
76  funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
77  MemoryContextSwitchTo(oldcontext);
78 }
79 
80 static Datum
82 {
84 
85  st = (TSTokenTypeStorage *) funcctx->user_fctx;
86  if (st->list && st->list[st->cur].lexid)
87  {
88  Datum result;
89  char *values[3];
90  char txtid[16];
91  HeapTuple tuple;
92 
93  sprintf(txtid, "%d", st->list[st->cur].lexid);
94  values[0] = txtid;
95  values[1] = st->list[st->cur].alias;
96  values[2] = st->list[st->cur].descr;
97 
98  tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
99  result = HeapTupleGetDatum(tuple);
100 
101  pfree(values[1]);
102  pfree(values[2]);
103  st->cur++;
104  return result;
105  }
106  if (st->list)
107  pfree(st->list);
108  pfree(st);
109  return (Datum) 0;
110 }
111 
112 Datum
114 {
115  FuncCallContext *funcctx;
116  Datum result;
117 
118  if (SRF_IS_FIRSTCALL())
119  {
120  funcctx = SRF_FIRSTCALL_INIT();
121  tt_setup_firstcall(funcctx, PG_GETARG_OID(0));
122  }
123 
124  funcctx = SRF_PERCALL_SETUP();
125 
126  if ((result = tt_process_call(funcctx)) != (Datum) 0)
127  SRF_RETURN_NEXT(funcctx, result);
128  SRF_RETURN_DONE(funcctx);
129 }
130 
131 Datum
133 {
134  FuncCallContext *funcctx;
135  Datum result;
136 
137  if (SRF_IS_FIRSTCALL())
138  {
139  text *prsname = PG_GETARG_TEXT_PP(0);
140  Oid prsId;
141 
142  funcctx = SRF_FIRSTCALL_INIT();
143  prsId = get_ts_parser_oid(textToQualifiedNameList(prsname), false);
144  tt_setup_firstcall(funcctx, prsId);
145  }
146 
147  funcctx = SRF_PERCALL_SETUP();
148 
149  if ((result = tt_process_call(funcctx)) != (Datum) 0)
150  SRF_RETURN_NEXT(funcctx, result);
151  SRF_RETURN_DONE(funcctx);
152 }
153 
154 typedef struct
155 {
156  int type;
157  char *lexeme;
158 } LexemeEntry;
159 
160 typedef struct
161 {
162  int cur;
163  int len;
165 } PrsStorage;
166 
167 
168 static void
170 {
171  TupleDesc tupdesc;
172  MemoryContext oldcontext;
173  PrsStorage *st;
175  char *lex = NULL;
176  int llen = 0,
177  type = 0;
178  void *prsdata;
179 
180  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
181 
182  st = (PrsStorage *) palloc(sizeof(PrsStorage));
183  st->cur = 0;
184  st->len = 16;
185  st->list = (LexemeEntry *) palloc(sizeof(LexemeEntry) * st->len);
186 
187  prsdata = (void *) DatumGetPointer(FunctionCall2(&prs->prsstart,
190 
191  while ((type = DatumGetInt32(FunctionCall3(&prs->prstoken,
192  PointerGetDatum(prsdata),
193  PointerGetDatum(&lex),
194  PointerGetDatum(&llen)))) != 0)
195  {
196  if (st->cur >= st->len)
197  {
198  st->len = 2 * st->len;
199  st->list = (LexemeEntry *) repalloc(st->list, sizeof(LexemeEntry) * st->len);
200  }
201  st->list[st->cur].lexeme = palloc(llen + 1);
202  memcpy(st->list[st->cur].lexeme, lex, llen);
203  st->list[st->cur].lexeme[llen] = '\0';
204  st->list[st->cur].type = type;
205  st->cur++;
206  }
207 
208  FunctionCall1(&prs->prsend, PointerGetDatum(prsdata));
209 
210  st->len = st->cur;
211  st->cur = 0;
212 
213  funcctx->user_fctx = (void *) st;
214  tupdesc = CreateTemplateTupleDesc(2);
215  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "tokid",
216  INT4OID, -1, 0);
217  TupleDescInitEntry(tupdesc, (AttrNumber) 2, "token",
218  TEXTOID, -1, 0);
219 
220  funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
221  MemoryContextSwitchTo(oldcontext);
222 }
223 
224 static Datum
226 {
227  PrsStorage *st;
228 
229  st = (PrsStorage *) funcctx->user_fctx;
230  if (st->cur < st->len)
231  {
232  Datum result;
233  char *values[2];
234  char tid[16];
235  HeapTuple tuple;
236 
237  values[0] = tid;
238  sprintf(tid, "%d", st->list[st->cur].type);
239  values[1] = st->list[st->cur].lexeme;
240  tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
241  result = HeapTupleGetDatum(tuple);
242 
243  pfree(values[1]);
244  st->cur++;
245  return result;
246  }
247  else
248  {
249  if (st->list)
250  pfree(st->list);
251  pfree(st);
252  }
253  return (Datum) 0;
254 }
255 
256 Datum
258 {
259  FuncCallContext *funcctx;
260  Datum result;
261 
262  if (SRF_IS_FIRSTCALL())
263  {
264  text *txt = PG_GETARG_TEXT_PP(1);
265 
266  funcctx = SRF_FIRSTCALL_INIT();
267  prs_setup_firstcall(funcctx, PG_GETARG_OID(0), txt);
268  PG_FREE_IF_COPY(txt, 1);
269  }
270 
271  funcctx = SRF_PERCALL_SETUP();
272 
273  if ((result = prs_process_call(funcctx)) != (Datum) 0)
274  SRF_RETURN_NEXT(funcctx, result);
275  SRF_RETURN_DONE(funcctx);
276 }
277 
278 Datum
280 {
281  FuncCallContext *funcctx;
282  Datum result;
283 
284  if (SRF_IS_FIRSTCALL())
285  {
286  text *prsname = PG_GETARG_TEXT_PP(0);
287  text *txt = PG_GETARG_TEXT_PP(1);
288  Oid prsId;
289 
290  funcctx = SRF_FIRSTCALL_INIT();
291  prsId = get_ts_parser_oid(textToQualifiedNameList(prsname), false);
292  prs_setup_firstcall(funcctx, prsId, txt);
293  }
294 
295  funcctx = SRF_PERCALL_SETUP();
296 
297  if ((result = prs_process_call(funcctx)) != (Datum) 0)
298  SRF_RETURN_NEXT(funcctx, result);
299  SRF_RETURN_DONE(funcctx);
300 }
301 
302 Datum
304 {
305  Oid tsconfig = PG_GETARG_OID(0);
306  text *in = PG_GETARG_TEXT_PP(1);
308  text *opt = (PG_NARGS() > 3 && PG_GETARG_POINTER(3)) ? PG_GETARG_TEXT_PP(3) : NULL;
310  List *prsoptions;
311  text *out;
314 
315  cfg = lookup_ts_config_cache(tsconfig);
316  prsobj = lookup_ts_parser_cache(cfg->prsId);
317 
318  if (!OidIsValid(prsobj->headlineOid))
319  ereport(ERROR,
320  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
321  errmsg("text search parser does not support headline creation")));
322 
323  memset(&prs, 0, sizeof(HeadlineParsedText));
324  prs.lenwords = 32;
325  prs.words = (HeadlineWordEntry *) palloc(sizeof(HeadlineWordEntry) * prs.lenwords);
326 
327  hlparsetext(cfg->cfgId, &prs, query,
328  VARDATA_ANY(in), VARSIZE_ANY_EXHDR(in));
329 
330  if (opt)
331  prsoptions = deserialize_deflist(PointerGetDatum(opt));
332  else
333  prsoptions = NIL;
334 
335  FunctionCall3(&(prsobj->prsheadline),
336  PointerGetDatum(&prs),
337  PointerGetDatum(prsoptions),
338  PointerGetDatum(query));
339 
340  out = generateHeadline(&prs);
341 
342  PG_FREE_IF_COPY(in, 1);
343  PG_FREE_IF_COPY(query, 2);
344  if (opt)
345  PG_FREE_IF_COPY(opt, 3);
346  pfree(prs.words);
347  pfree(prs.startsel);
348  pfree(prs.stopsel);
349 
350  PG_RETURN_POINTER(out);
351 }
352 
353 Datum
355 {
357  PG_GETARG_DATUM(0),
358  PG_GETARG_DATUM(1),
359  PG_GETARG_DATUM(2)));
360 }
361 
362 Datum
364 {
367  PG_GETARG_DATUM(0),
368  PG_GETARG_DATUM(1)));
369 }
370 
371 Datum
373 {
376  PG_GETARG_DATUM(0),
377  PG_GETARG_DATUM(1),
378  PG_GETARG_DATUM(2)));
379 }
380 
381 Datum
383 {
384  Oid tsconfig = PG_GETARG_OID(0);
385  Jsonb *jb = PG_GETARG_JSONB_P(1);
387  text *opt = (PG_NARGS() > 3 && PG_GETARG_POINTER(3)) ? PG_GETARG_TEXT_P(3) : NULL;
388  Jsonb *out;
392 
393  memset(&prs, 0, sizeof(HeadlineParsedText));
394  prs.lenwords = 32;
395  prs.words = (HeadlineWordEntry *) palloc(sizeof(HeadlineWordEntry) * prs.lenwords);
396 
397  state->prs = &prs;
398  state->cfg = lookup_ts_config_cache(tsconfig);
399  state->prsobj = lookup_ts_parser_cache(state->cfg->prsId);
400  state->query = query;
401  if (opt)
403  else
404  state->prsoptions = NIL;
405 
406  if (!OidIsValid(state->prsobj->headlineOid))
407  ereport(ERROR,
408  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
409  errmsg("text search parser does not support headline creation")));
410 
411  out = transform_jsonb_string_values(jb, state, action);
412 
413  PG_FREE_IF_COPY(jb, 1);
414  PG_FREE_IF_COPY(query, 2);
415  if (opt)
416  PG_FREE_IF_COPY(opt, 3);
417 
418  pfree(prs.words);
419 
420  if (state->transformed)
421  {
422  pfree(prs.startsel);
423  pfree(prs.stopsel);
424  }
425 
426  PG_RETURN_JSONB_P(out);
427 }
428 
429 Datum
431 {
434  PG_GETARG_DATUM(0),
435  PG_GETARG_DATUM(1)));
436 }
437 
438 Datum
440 {
442  PG_GETARG_DATUM(0),
443  PG_GETARG_DATUM(1),
444  PG_GETARG_DATUM(2)));
445 }
446 
447 Datum
449 {
452  PG_GETARG_DATUM(0),
453  PG_GETARG_DATUM(1),
454  PG_GETARG_DATUM(2)));
455 }
456 
457 Datum
459 {
460  Oid tsconfig = PG_GETARG_OID(0);
461  text *json = PG_GETARG_TEXT_P(1);
463  text *opt = (PG_NARGS() > 3 && PG_GETARG_POINTER(3)) ? PG_GETARG_TEXT_P(3) : NULL;
464  text *out;
466 
469 
470  memset(&prs, 0, sizeof(HeadlineParsedText));
471  prs.lenwords = 32;
472  prs.words = (HeadlineWordEntry *) palloc(sizeof(HeadlineWordEntry) * prs.lenwords);
473 
474  state->prs = &prs;
475  state->cfg = lookup_ts_config_cache(tsconfig);
476  state->prsobj = lookup_ts_parser_cache(state->cfg->prsId);
477  state->query = query;
478  if (opt)
480  else
481  state->prsoptions = NIL;
482 
483  if (!OidIsValid(state->prsobj->headlineOid))
484  ereport(ERROR,
485  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
486  errmsg("text search parser does not support headline creation")));
487 
488  out = transform_json_string_values(json, state, action);
489 
490  PG_FREE_IF_COPY(json, 1);
491  PG_FREE_IF_COPY(query, 2);
492  if (opt)
493  PG_FREE_IF_COPY(opt, 3);
494  pfree(prs.words);
495 
496  if (state->transformed)
497  {
498  pfree(prs.startsel);
499  pfree(prs.stopsel);
500  }
501 
502  PG_RETURN_TEXT_P(out);
503 }
504 
505 Datum
507 {
510  PG_GETARG_DATUM(0),
511  PG_GETARG_DATUM(1)));
512 }
513 
514 Datum
516 {
518  PG_GETARG_DATUM(0),
519  PG_GETARG_DATUM(1),
520  PG_GETARG_DATUM(2)));
521 }
522 
523 Datum
525 {
528  PG_GETARG_DATUM(0),
529  PG_GETARG_DATUM(1),
530  PG_GETARG_DATUM(2)));
531 }
532 
533 
534 /*
535  * Return headline in text from, generated from a json(b) element
536  */
537 static text *
538 headline_json_value(void *_state, char *elem_value, int elem_len)
539 {
541 
542  HeadlineParsedText *prs = state->prs;
543  TSConfigCacheEntry *cfg = state->cfg;
544  TSParserCacheEntry *prsobj = state->prsobj;
545  TSQuery query = state->query;
546  List *prsoptions = state->prsoptions;
547 
548  prs->curwords = 0;
549  hlparsetext(cfg->cfgId, prs, query, elem_value, elem_len);
550  FunctionCall3(&(prsobj->prsheadline),
551  PointerGetDatum(prs),
552  PointerGetDatum(prsoptions),
553  PointerGetDatum(query));
554 
555  state->transformed = true;
556  return generateHeadline(prs);
557 }
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:351
#define NIL
Definition: pg_list.h:65
struct HeadlineJsonState HeadlineJsonState
static Datum prs_process_call(FuncCallContext *funcctx)
Definition: wparser.c:225
#define VARDATA_ANY(PTR)
Definition: postgres.h:348
Definition: jsonb.h:220
int type
Definition: wparser.c:156
Datum ts_headline_byid(PG_FUNCTION_ARGS)
Definition: wparser.c:354
Datum ts_headline_jsonb_opt(PG_FUNCTION_ARGS)
Definition: wparser.c:448
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:44
LexDescr * list
Definition: wparser.c:31
#define DatumGetInt32(X)
Definition: postgres.h:472
char * alias
Definition: ts_public.h:28
text *(* JsonTransformStringValuesAction)(void *state, char *elem_value, int elem_len)
Definition: jsonapi.h:152
Oid getTSCurrentConfig(bool emitError)
Definition: ts_cache.c:560
LexemeEntry * list
Definition: wparser.c:164
TSParserCacheEntry * prsobj
Definition: wparser.c:39
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:282
#define PointerGetDatum(X)
Definition: postgres.h:556
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:263
#define PG_GETARG_TSQUERY(n)
Definition: ts_type.h:238
List * deserialize_deflist(Datum txt)
Definition: tsearchcmds.c:1572
Datum ts_headline_json(PG_FUNCTION_ARGS)
Definition: wparser.c:506
int len
Definition: wparser.c:163
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define FunctionCall2(flinfo, arg1, arg2)
Definition: fmgr.h:635
int errcode(int sqlerrcode)
Definition: elog.c:608
Datum ts_token_type_byid(PG_FUNCTION_ARGS)
Definition: wparser.c:113
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:271
TSParserCacheEntry * lookup_ts_parser_cache(Oid prsId)
Definition: ts_cache.c:112
List * prsoptions
Definition: wparser.c:41
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:645
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:286
HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
Definition: execTuples.c:2116
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:303
#define FunctionCall3(flinfo, arg1, arg2, arg3)
Definition: fmgr.h:637
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:288
#define sprintf
Definition: port.h:194
Datum ts_parse_byid(PG_FUNCTION_ARGS)
Definition: wparser.c:257
void pfree(void *pointer)
Definition: mcxt.c:1056
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
FmgrInfo prsend
Definition: ts_cache.h:47
Datum ts_headline_byid_opt(PG_FUNCTION_ARGS)
Definition: wparser.c:303
Datum ts_headline_opt(PG_FUNCTION_ARGS)
Definition: wparser.c:372
text * transform_json_string_values(text *json, void *action_state, JsonTransformStringValuesAction transform_action)
Definition: jsonfuncs.c:5144
TSConfigCacheEntry * lookup_ts_config_cache(Oid cfgId)
Definition: ts_cache.c:389
Datum ts_parse_byname(PG_FUNCTION_ARGS)
Definition: wparser.c:279
#define OidFunctionCall1(functionId, arg1)
Definition: fmgr.h:653
Datum ts_token_type_byname(PG_FUNCTION_ARGS)
Definition: wparser.c:132
static Datum tt_process_call(FuncCallContext *funcctx)
Definition: wparser.c:81
Datum ts_headline(PG_FUNCTION_ARGS)
Definition: wparser.c:363
Jsonb * transform_jsonb_string_values(Jsonb *jsonb, void *action_state, JsonTransformStringValuesAction transform_action)
Definition: jsonfuncs.c:5099
#define DirectFunctionCall4(func, arg1, arg2, arg3, arg4)
Definition: fmgr.h:621
HeadlineWordEntry * words
Definition: ts_public.h:52
#define PG_GETARG_OID(n)
Definition: fmgr.h:270
AttInMetadata * attinmeta
Definition: funcapi.h:91
Datum ts_headline_jsonb_byid(PG_FUNCTION_ARGS)
Definition: wparser.c:439
bool transformed
Definition: wparser.c:42
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:603
Datum ts_headline_json_byid_opt(PG_FUNCTION_ARGS)
Definition: wparser.c:458
#define ereport(elevel, rest)
Definition: elog.h:141
List * textToQualifiedNameList(text *textval)
Definition: varlena.c:3594
#define DirectFunctionCall3(func, arg1, arg2, arg3)
Definition: fmgr.h:619
char * lexeme
Definition: wparser.c:157
char * descr
Definition: ts_public.h:29
int lexid
Definition: ts_public.h:27
int cur
Definition: wparser.c:162
static void tt_setup_firstcall(FuncCallContext *funcctx, Oid prsid)
Definition: wparser.c:48
void * palloc0(Size size)
Definition: mcxt.c:980
uintptr_t Datum
Definition: postgres.h:367
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:343
AttInMetadata * TupleDescGetAttInMetadata(TupleDesc tupdesc)
Definition: execTuples.c:2067
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:361
text * generateHeadline(HeadlineParsedText *prs)
Definition: ts_parse.c:598
TSQuery query
Definition: wparser.c:40
Oid get_ts_parser_oid(List *names, bool missing_ok)
Definition: namespace.c:2292
FmgrInfo prstoken
Definition: ts_cache.h:46
Definition: regguts.h:298
static void prs_setup_firstcall(FuncCallContext *funcctx, Oid prsid, text *txt)
Definition: wparser.c:169
void hlparsetext(Oid cfgId, HeadlineParsedText *prs, TSQuery query, char *buf, int buflen)
Definition: ts_parse.c:533
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:101
static text * headline_json_value(void *_state, char *elem_value, int elem_len)
Definition: wparser.c:538
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:255
#define PG_NARGS()
Definition: fmgr.h:198
#define HeapTupleGetDatum(tuple)
Definition: funcapi.h:220
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1069
#define DatumGetPointer(X)
Definition: postgres.h:549
TSConfigCacheEntry * cfg
Definition: wparser.c:38
static Datum values[MAXATTR]
Definition: bootstrap.c:167
Datum ts_headline_jsonb_byid_opt(PG_FUNCTION_ARGS)
Definition: wparser.c:382
FmgrInfo prsstart
Definition: ts_cache.h:45
#define Int32GetDatum(X)
Definition: postgres.h:479
Datum ts_headline_json_opt(PG_FUNCTION_ARGS)
Definition: wparser.c:524
void * user_fctx
Definition: funcapi.h:82
#define VARSIZE_ANY_EXHDR(PTR)
Definition: postgres.h:341
void * palloc(Size size)
Definition: mcxt.c:949
int errmsg(const char *fmt,...)
Definition: elog.c:822
#define PG_GETARG_TEXT_P(n)
Definition: fmgr.h:330
#define elog(elevel,...)
Definition: elog.h:228
Datum ts_headline_jsonb(PG_FUNCTION_ARGS)
Definition: wparser.c:430
#define FunctionCall1(flinfo, arg1)
Definition: fmgr.h:633
Definition: c.h:556
#define PG_FUNCTION_ARGS
Definition: fmgr.h:188
#define PG_RETURN_JSONB_P(x)
Definition: jsonb.h:76
Definition: pg_list.h:50
int16 AttrNumber
Definition: attnum.h:21
HeadlineParsedText * prs
Definition: wparser.c:37
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:306
#define PG_GETARG_JSONB_P(x)
Definition: jsonb.h:74
Datum ts_headline_json_byid(PG_FUNCTION_ARGS)
Definition: wparser.c:515
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:284
FmgrInfo prsheadline
Definition: ts_cache.h:48