1
/*-------------------------------------------------------------------------
4
* Backwards-compatibility package for old contrib/tsearch2 API
6
* Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
10
* contrib/tsearch2/tsearch2.c
12
*-------------------------------------------------------------------------
16
#include "catalog/namespace.h"
17
#include "catalog/pg_type.h"
18
#include "commands/trigger.h"
20
#include "tsearch/ts_utils.h"
21
#include "utils/builtins.h"
22
#include "utils/guc.h"
23
#include "utils/syscache.h"
27
static Oid current_dictionary_oid = InvalidOid;
28
static Oid current_parser_oid = InvalidOid;
30
/* insert given value at argument position 0 */
31
#define INSERT_ARGUMENT0(argument, isnull) \
34
for (i = fcinfo->nargs; i > 0; i--) \
36
fcinfo->arg[i] = fcinfo->arg[i-1]; \
37
fcinfo->argnull[i] = fcinfo->argnull[i-1]; \
39
fcinfo->arg[0] = (argument); \
40
fcinfo->argnull[0] = (isnull); \
44
#define TextGetObjectId(infunction, text) \
45
DatumGetObjectId(DirectFunctionCall1(infunction, \
46
CStringGetDatum(text_to_cstring(text))))
48
#define UNSUPPORTED_FUNCTION(name) \
49
Datum name(PG_FUNCTION_ARGS); \
51
name(PG_FUNCTION_ARGS) \
54
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),\
55
errmsg("function %s is no longer supported", \
56
format_procedure(fcinfo->flinfo->fn_oid)), \
57
errhint("Switch to new tsearch functionality."))); \
58
/* keep compiler quiet */ \
61
PG_FUNCTION_INFO_V1(name)
63
static Oid GetCurrentDict(void);
64
static Oid GetCurrentParser(void);
66
Datum tsa_lexize_byname(PG_FUNCTION_ARGS);
67
Datum tsa_lexize_bycurrent(PG_FUNCTION_ARGS);
68
Datum tsa_set_curdict(PG_FUNCTION_ARGS);
69
Datum tsa_set_curdict_byname(PG_FUNCTION_ARGS);
70
Datum tsa_token_type_current(PG_FUNCTION_ARGS);
71
Datum tsa_set_curprs(PG_FUNCTION_ARGS);
72
Datum tsa_set_curprs_byname(PG_FUNCTION_ARGS);
73
Datum tsa_parse_current(PG_FUNCTION_ARGS);
74
Datum tsa_set_curcfg(PG_FUNCTION_ARGS);
75
Datum tsa_set_curcfg_byname(PG_FUNCTION_ARGS);
76
Datum tsa_to_tsvector_name(PG_FUNCTION_ARGS);
77
Datum tsa_to_tsquery_name(PG_FUNCTION_ARGS);
78
Datum tsa_plainto_tsquery_name(PG_FUNCTION_ARGS);
79
Datum tsa_headline_byname(PG_FUNCTION_ARGS);
80
Datum tsa_ts_stat(PG_FUNCTION_ARGS);
81
Datum tsa_tsearch2(PG_FUNCTION_ARGS);
82
Datum tsa_rewrite_accum(PG_FUNCTION_ARGS);
83
Datum tsa_rewrite_finish(PG_FUNCTION_ARGS);
85
PG_FUNCTION_INFO_V1(tsa_lexize_byname);
86
PG_FUNCTION_INFO_V1(tsa_lexize_bycurrent);
87
PG_FUNCTION_INFO_V1(tsa_set_curdict);
88
PG_FUNCTION_INFO_V1(tsa_set_curdict_byname);
89
PG_FUNCTION_INFO_V1(tsa_token_type_current);
90
PG_FUNCTION_INFO_V1(tsa_set_curprs);
91
PG_FUNCTION_INFO_V1(tsa_set_curprs_byname);
92
PG_FUNCTION_INFO_V1(tsa_parse_current);
93
PG_FUNCTION_INFO_V1(tsa_set_curcfg);
94
PG_FUNCTION_INFO_V1(tsa_set_curcfg_byname);
95
PG_FUNCTION_INFO_V1(tsa_to_tsvector_name);
96
PG_FUNCTION_INFO_V1(tsa_to_tsquery_name);
97
PG_FUNCTION_INFO_V1(tsa_plainto_tsquery_name);
98
PG_FUNCTION_INFO_V1(tsa_headline_byname);
99
PG_FUNCTION_INFO_V1(tsa_ts_stat);
100
PG_FUNCTION_INFO_V1(tsa_tsearch2);
101
PG_FUNCTION_INFO_V1(tsa_rewrite_accum);
102
PG_FUNCTION_INFO_V1(tsa_rewrite_finish);
106
* List of unsupported functions
108
* The parser and dictionary functions are defined only so that the former
109
* contents of pg_ts_parser and pg_ts_dict can be loaded into the system,
110
* for ease of reference while creating the new tsearch configuration.
113
UNSUPPORTED_FUNCTION(tsa_dex_init);
114
UNSUPPORTED_FUNCTION(tsa_dex_lexize);
116
UNSUPPORTED_FUNCTION(tsa_snb_en_init);
117
UNSUPPORTED_FUNCTION(tsa_snb_lexize);
118
UNSUPPORTED_FUNCTION(tsa_snb_ru_init_koi8);
119
UNSUPPORTED_FUNCTION(tsa_snb_ru_init_utf8);
120
UNSUPPORTED_FUNCTION(tsa_snb_ru_init);
122
UNSUPPORTED_FUNCTION(tsa_spell_init);
123
UNSUPPORTED_FUNCTION(tsa_spell_lexize);
125
UNSUPPORTED_FUNCTION(tsa_syn_init);
126
UNSUPPORTED_FUNCTION(tsa_syn_lexize);
128
UNSUPPORTED_FUNCTION(tsa_thesaurus_init);
129
UNSUPPORTED_FUNCTION(tsa_thesaurus_lexize);
131
UNSUPPORTED_FUNCTION(tsa_prsd_start);
132
UNSUPPORTED_FUNCTION(tsa_prsd_getlexeme);
133
UNSUPPORTED_FUNCTION(tsa_prsd_end);
134
UNSUPPORTED_FUNCTION(tsa_prsd_lextype);
135
UNSUPPORTED_FUNCTION(tsa_prsd_headline);
137
UNSUPPORTED_FUNCTION(tsa_reset_tsearch);
138
UNSUPPORTED_FUNCTION(tsa_get_covers);
142
* list of redefined functions
145
/* lexize(text, text) */
147
tsa_lexize_byname(PG_FUNCTION_ARGS)
149
text *dictname = PG_GETARG_TEXT_PP(0);
150
Datum arg1 = PG_GETARG_DATUM(1);
152
return DirectFunctionCall2(ts_lexize,
153
ObjectIdGetDatum(TextGetObjectId(regdictionaryin, dictname)),
159
tsa_lexize_bycurrent(PG_FUNCTION_ARGS)
161
Datum arg0 = PG_GETARG_DATUM(0);
162
Oid id = GetCurrentDict();
164
return DirectFunctionCall2(ts_lexize,
165
ObjectIdGetDatum(id),
169
/* set_curdict(int) */
171
tsa_set_curdict(PG_FUNCTION_ARGS)
173
Oid dict_oid = PG_GETARG_OID(0);
175
if (!SearchSysCacheExists(TSDICTOID,
176
ObjectIdGetDatum(dict_oid),
178
elog(ERROR, "cache lookup failed for text search dictionary %u",
181
current_dictionary_oid = dict_oid;
186
/* set_curdict(text) */
188
tsa_set_curdict_byname(PG_FUNCTION_ARGS)
190
text *name = PG_GETARG_TEXT_PP(0);
193
dict_oid = get_ts_dict_oid(stringToQualifiedNameList(text_to_cstring(name)), false);
195
current_dictionary_oid = dict_oid;
202
tsa_token_type_current(PG_FUNCTION_ARGS)
204
INSERT_ARGUMENT0(ObjectIdGetDatum(GetCurrentParser()), false);
205
return ts_token_type_byid(fcinfo);
208
/* set_curprs(int) */
210
tsa_set_curprs(PG_FUNCTION_ARGS)
212
Oid parser_oid = PG_GETARG_OID(0);
214
if (!SearchSysCacheExists(TSPARSEROID,
215
ObjectIdGetDatum(parser_oid),
217
elog(ERROR, "cache lookup failed for text search parser %u",
220
current_parser_oid = parser_oid;
225
/* set_curprs(text) */
227
tsa_set_curprs_byname(PG_FUNCTION_ARGS)
229
text *name = PG_GETARG_TEXT_PP(0);
232
parser_oid = get_ts_parser_oid(stringToQualifiedNameList(text_to_cstring(name)), false);
234
current_parser_oid = parser_oid;
241
tsa_parse_current(PG_FUNCTION_ARGS)
243
INSERT_ARGUMENT0(ObjectIdGetDatum(GetCurrentParser()), false);
244
return ts_parse_byid(fcinfo);
247
/* set_curcfg(int) */
249
tsa_set_curcfg(PG_FUNCTION_ARGS)
251
Oid arg0 = PG_GETARG_OID(0);
254
name = DatumGetCString(DirectFunctionCall1(regconfigout,
255
ObjectIdGetDatum(arg0)));
257
set_config_option("default_text_search_config", name,
266
/* set_curcfg(text) */
268
tsa_set_curcfg_byname(PG_FUNCTION_ARGS)
270
text *arg0 = PG_GETARG_TEXT_PP(0);
273
name = text_to_cstring(arg0);
275
set_config_option("default_text_search_config", name,
284
/* to_tsvector(text, text) */
286
tsa_to_tsvector_name(PG_FUNCTION_ARGS)
288
text *cfgname = PG_GETARG_TEXT_PP(0);
289
Datum arg1 = PG_GETARG_DATUM(1);
292
config_oid = TextGetObjectId(regconfigin, cfgname);
294
return DirectFunctionCall2(to_tsvector_byid,
295
ObjectIdGetDatum(config_oid), arg1);
298
/* to_tsquery(text, text) */
300
tsa_to_tsquery_name(PG_FUNCTION_ARGS)
302
text *cfgname = PG_GETARG_TEXT_PP(0);
303
Datum arg1 = PG_GETARG_DATUM(1);
306
config_oid = TextGetObjectId(regconfigin, cfgname);
308
return DirectFunctionCall2(to_tsquery_byid,
309
ObjectIdGetDatum(config_oid), arg1);
313
/* plainto_tsquery(text, text) */
315
tsa_plainto_tsquery_name(PG_FUNCTION_ARGS)
317
text *cfgname = PG_GETARG_TEXT_PP(0);
318
Datum arg1 = PG_GETARG_DATUM(1);
321
config_oid = TextGetObjectId(regconfigin, cfgname);
323
return DirectFunctionCall2(plainto_tsquery_byid,
324
ObjectIdGetDatum(config_oid), arg1);
327
/* headline(text, text, tsquery [,text]) */
329
tsa_headline_byname(PG_FUNCTION_ARGS)
331
Datum arg0 = PG_GETARG_DATUM(0);
332
Datum arg1 = PG_GETARG_DATUM(1);
333
Datum arg2 = PG_GETARG_DATUM(2);
337
/* first parameter has to be converted to oid */
338
config_oid = DatumGetObjectId(DirectFunctionCall1(regconfigin,
339
CStringGetDatum(TextDatumGetCString(arg0))));
342
result = DirectFunctionCall3(ts_headline_byid,
343
ObjectIdGetDatum(config_oid), arg1, arg2);
346
Datum arg3 = PG_GETARG_DATUM(3);
348
result = DirectFunctionCall4(ts_headline_byid_opt,
349
ObjectIdGetDatum(config_oid),
357
* tsearch2 version of update trigger
359
* We pass this on to the core trigger after inserting the default text
360
* search configuration name as the second argument. Note that this isn't
361
* a complete implementation of the original functionality; tsearch2 allowed
362
* transformation function names to be included in the list. However, that
363
* is deliberately removed as being a security risk.
366
tsa_tsearch2(PG_FUNCTION_ARGS)
368
TriggerData *trigdata;
375
/* Check call context */
376
if (!CALLED_AS_TRIGGER(fcinfo)) /* internal error */
377
elog(ERROR, "tsvector_update_trigger: not fired by trigger manager");
379
trigdata = (TriggerData *) fcinfo->context;
380
trigger = trigdata->tg_trigger;
382
if (trigger->tgnargs < 2)
383
elog(ERROR, "TSearch: format tsearch2(tsvector_field, text_field1,...)");
385
/* create space for configuration name */
386
tgargs = (char **) palloc((trigger->tgnargs + 1) * sizeof(char *));
387
tgargs[0] = trigger->tgargs[0];
388
for (i = 1; i < trigger->tgnargs; i++)
389
tgargs[i + 1] = trigger->tgargs[i];
391
tgargs[1] = pstrdup(GetConfigOptionByName("default_text_search_config",
393
tgargs_old = trigger->tgargs;
394
trigger->tgargs = tgargs;
397
res = tsvector_update_trigger_byid(fcinfo);
399
/* restore old trigger data */
400
trigger->tgargs = tgargs_old;
411
tsa_rewrite_accum(PG_FUNCTION_ARGS)
422
MemoryContext aggcontext;
423
MemoryContext oldcontext;
425
if (!AggCheckCallContext(fcinfo, &aggcontext))
426
elog(ERROR, "tsa_rewrite_accum called in non-aggregate context");
428
if (PG_ARGISNULL(0) || PG_GETARG_POINTER(0) == NULL)
430
acc = (TSQuery) MemoryContextAlloc(aggcontext, HDRSIZETQ);
431
SET_VARSIZE(acc, HDRSIZETQ);
435
acc = PG_GETARG_TSQUERY(0);
437
if (PG_ARGISNULL(1) || PG_GETARG_POINTER(1) == NULL)
438
PG_RETURN_TSQUERY(acc);
440
qa = PG_GETARG_ARRAYTYPE_P_COPY(1);
442
if (ARR_NDIM(qa) != 1)
443
elog(ERROR, "array must be one-dimensional, not %d dimensions",
445
if (ArrayGetNItems(ARR_NDIM(qa), ARR_DIMS(qa)) != 3)
446
elog(ERROR, "array must have three elements");
447
if (ARR_ELEMTYPE(qa) != TSQUERYOID)
448
elog(ERROR, "array must contain tsquery elements");
450
deconstruct_array(qa, TSQUERYOID, -1, false, 'i', &elemsp, NULL, &nelemsp);
452
q = DatumGetTSQuery(elemsp[0]);
456
PG_RETURN_POINTER(acc);
461
if (VARSIZE(acc) > HDRSIZETQ)
464
PG_RETURN_POINTER(acc);
467
acctree = QT2QTN(GETQUERY(q), GETOPERAND(q));
470
acctree = QT2QTN(GETQUERY(acc), GETOPERAND(acc));
475
q = DatumGetTSQuery(elemsp[1]);
479
PG_RETURN_POINTER(acc);
481
qex = QT2QTN(GETQUERY(q), GETOPERAND(q));
485
q = DatumGetTSQuery(elemsp[2]);
487
subs = QT2QTN(GETQUERY(q), GETOPERAND(q));
489
acctree = findsubquery(acctree, qex, subs, &isfind);
491
if (isfind || !acc->size)
493
/* pfree( acc ); do not pfree(p), because nodeAgg.c will */
497
oldcontext = MemoryContextSwitchTo(aggcontext);
498
acc = QTN2QT(acctree);
499
MemoryContextSwitchTo(oldcontext);
503
acc = (TSQuery) MemoryContextAlloc(aggcontext, HDRSIZETQ);
504
SET_VARSIZE(acc, HDRSIZETQ);
514
PG_RETURN_TSQUERY(acc);
518
tsa_rewrite_finish(PG_FUNCTION_ARGS)
520
TSQuery acc = PG_GETARG_TSQUERY(0);
523
if (acc == NULL || PG_ARGISNULL(0) || acc->size == 0)
525
rewrited = (TSQuery) palloc(HDRSIZETQ);
526
SET_VARSIZE(rewrited, HDRSIZETQ);
531
rewrited = (TSQuery) palloc(VARSIZE(acc));
532
memcpy(rewrited, acc, VARSIZE(acc));
536
PG_RETURN_POINTER(rewrited);
541
* Get Oid of current dictionary
546
if (current_dictionary_oid == InvalidOid)
548
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
549
errmsg("no current dictionary"),
550
errhint("Execute SELECT set_curdict(...).")));
552
return current_dictionary_oid;
556
* Get Oid of current parser
558
* Here, it seems reasonable to select the "default" parser if none has been
562
GetCurrentParser(void)
564
if (current_parser_oid == InvalidOid)
565
current_parser_oid = get_ts_parser_oid(stringToQualifiedNameList("pg_catalog.default"), false);
566
return current_parser_oid;