PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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-2025, 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
27typedef struct
28{
29 int cur;
32
33/* state for ts_headline_json_* */
34typedef struct HeadlineJsonState
35{
43
44static text *headline_json_value(void *_state, char *elem_value, int elem_len);
45
46static 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
76static 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
105Datum
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
124Datum
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
147typedef struct
148{
149 int type;
150 char *lexeme;
152
153typedef struct
154{
155 int cur;
156 int len;
158} PrsStorage;
159
160
161static 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
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
215static 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
241Datum
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
263Datum
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
287Datum
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;
295 List *prsoptions;
296 text *out;
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))
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;
311
312 hlparsetext(cfg->cfgId, &prs, query,
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
336}
337
338Datum
340{
344 PG_GETARG_DATUM(2)));
345}
346
347Datum
349{
353 PG_GETARG_DATUM(1)));
354}
355
356Datum
358{
363 PG_GETARG_DATUM(2)));
364}
365
366Datum
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;
377
378 memset(&prs, 0, sizeof(HeadlineParsedText));
379 prs.lenwords = 32;
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))
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
412}
413
414Datum
416{
420 PG_GETARG_DATUM(1)));
421}
422
423Datum
425{
429 PG_GETARG_DATUM(2)));
430}
431
432Datum
434{
439 PG_GETARG_DATUM(2)));
440}
441
442Datum
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
454
455 memset(&prs, 0, sizeof(HeadlineParsedText));
456 prs.lenwords = 32;
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))
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
490Datum
492{
496 PG_GETARG_DATUM(1)));
497}
498
499Datum
501{
505 PG_GETARG_DATUM(2)));
506}
507
508Datum
510{
515 PG_GETARG_DATUM(2)));
516}
517
518
519/*
520 * Return headline in text from, generated from a json(b) element
521 */
522static text *
523headline_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:746
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:226
#define ereport(elevel,...)
Definition: elog.h:149
HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
Definition: execTuples.c:2324
AttInMetadata * TupleDescGetAttInMetadata(TupleDesc tupdesc)
Definition: execTuples.c:2275
#define OidFunctionCall1(functionId, arg1)
Definition: fmgr.h:720
#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:688
#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:700
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:372
#define FunctionCall2(flinfo, arg1, arg2)
Definition: fmgr.h:702
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:353
#define DirectFunctionCall3(func, arg1, arg2, arg3)
Definition: fmgr.h:686
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
#define FunctionCall3(flinfo, arg1, arg2, arg3)
Definition: fmgr.h:704
#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:81
#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:5853
Jsonb * transform_jsonb_string_values(Jsonb *jsonb, void *action_state, JsonTransformStringValuesAction transform_action)
Definition: jsonfuncs.c:5806
text *(* JsonTransformStringValuesAction)(void *state, char *elem_value, int elem_len)
Definition: jsonfuncs.h:38
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:2170
void pfree(void *pointer)
Definition: mcxt.c:2150
void * palloc0(Size size)
Definition: mcxt.c:1973
void * palloc(Size size)
Definition: mcxt.c:1943
Oid get_ts_parser_oid(List *names, bool missing_ok)
Definition: namespace.c:2716
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
#define NIL
Definition: pg_list.h:68
#define sprintf
Definition: port.h:241
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:327
uintptr_t Datum
Definition: postgres.h:69
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:317
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:217
static int32 DatumGetInt32(Datum X)
Definition: postgres.h:207
unsigned int Oid
Definition: postgres_ext.h:30
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:658
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
text * generateHeadline(HeadlineParsedText *prs)
Definition: ts_parse.c:607
void hlparsetext(Oid cfgId, HeadlineParsedText *prs, TSQuery query, char *buf, int buflen)
Definition: ts_parse.c:540
#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:3467
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