1 /*-------------------------------------------------------------------------
4 * Backwards-compatibility package for old contrib/tsearch2 API
6 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
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
= TSDictionaryGetDictid(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
= TSParserGetPrsid(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
;
373 /* Check call context */
374 if (!CALLED_AS_TRIGGER(fcinfo
)) /* internal error */
375 elog(ERROR
, "tsvector_update_trigger: not fired by trigger manager");
377 trigdata
= (TriggerData
*) fcinfo
->context
;
378 trigger
= trigdata
->tg_trigger
;
380 if (trigger
->tgnargs
< 2)
381 elog(ERROR
, "TSearch: format tsearch2(tsvector_field, text_field1,...)");
383 /* create space for configuration name */
384 tgargs
= (char **) palloc((trigger
->tgnargs
+ 1) * sizeof(char *));
385 tgargs
[0] = trigger
->tgargs
[0];
386 for (i
= 1; i
< trigger
->tgnargs
; i
++)
387 tgargs
[i
+ 1] = trigger
->tgargs
[i
];
389 tgargs
[1] = pstrdup(GetConfigOptionByName("default_text_search_config",
391 trigger
->tgargs
= tgargs
;
394 return tsvector_update_trigger_byid(fcinfo
);
399 tsa_rewrite_accum(PG_FUNCTION_ARGS
)
410 MemoryContext aggcontext
;
411 MemoryContext oldcontext
;
413 if (fcinfo
->context
&& IsA(fcinfo
->context
, AggState
))
414 aggcontext
= ((AggState
*) fcinfo
->context
)->aggcontext
;
415 else if (fcinfo
->context
&& IsA(fcinfo
->context
, WindowAggState
))
416 aggcontext
= ((WindowAggState
*) fcinfo
->context
)->wincontext
;
419 elog(ERROR
, "tsa_rewrite_accum called in non-aggregate context");
420 aggcontext
= NULL
; /* keep compiler quiet */
423 if (PG_ARGISNULL(0) || PG_GETARG_POINTER(0) == NULL
)
425 acc
= (TSQuery
) MemoryContextAlloc(aggcontext
, HDRSIZETQ
);
426 SET_VARSIZE(acc
, HDRSIZETQ
);
430 acc
= PG_GETARG_TSQUERY(0);
432 if (PG_ARGISNULL(1) || PG_GETARG_POINTER(1) == NULL
)
433 PG_RETURN_TSQUERY(acc
);
435 qa
= PG_GETARG_ARRAYTYPE_P_COPY(1);
437 if (ARR_NDIM(qa
) != 1)
438 elog(ERROR
, "array must be one-dimensional, not %d dimensions",
440 if (ArrayGetNItems(ARR_NDIM(qa
), ARR_DIMS(qa
)) != 3)
441 elog(ERROR
, "array must have three elements");
442 if (ARR_ELEMTYPE(qa
) != TSQUERYOID
)
443 elog(ERROR
, "array must contain tsquery elements");
445 deconstruct_array(qa
, TSQUERYOID
, -1, false, 'i', &elemsp
, NULL
, &nelemsp
);
447 q
= DatumGetTSQuery(elemsp
[0]);
451 PG_RETURN_POINTER(acc
);
456 if (VARSIZE(acc
) > HDRSIZETQ
)
459 PG_RETURN_POINTER(acc
);
462 acctree
= QT2QTN(GETQUERY(q
), GETOPERAND(q
));
465 acctree
= QT2QTN(GETQUERY(acc
), GETOPERAND(acc
));
470 q
= DatumGetTSQuery(elemsp
[1]);
474 PG_RETURN_POINTER(acc
);
476 qex
= QT2QTN(GETQUERY(q
), GETOPERAND(q
));
480 q
= DatumGetTSQuery(elemsp
[2]);
482 subs
= QT2QTN(GETQUERY(q
), GETOPERAND(q
));
484 acctree
= findsubquery(acctree
, qex
, subs
, &isfind
);
486 if (isfind
|| !acc
->size
)
488 /* pfree( acc ); do not pfree(p), because nodeAgg.c will */
492 oldcontext
= MemoryContextSwitchTo(aggcontext
);
493 acc
= QTN2QT(acctree
);
494 MemoryContextSwitchTo(oldcontext
);
498 acc
= (TSQuery
) MemoryContextAlloc(aggcontext
, HDRSIZETQ
);
499 SET_VARSIZE(acc
, HDRSIZETQ
);
509 PG_RETURN_TSQUERY(acc
);
513 tsa_rewrite_finish(PG_FUNCTION_ARGS
)
515 TSQuery acc
= PG_GETARG_TSQUERY(0);
518 if (acc
== NULL
|| PG_ARGISNULL(0) || acc
->size
== 0)
520 rewrited
= (TSQuery
) palloc(HDRSIZETQ
);
521 SET_VARSIZE(rewrited
, HDRSIZETQ
);
526 rewrited
= (TSQuery
) palloc(VARSIZE(acc
));
527 memcpy(rewrited
, acc
, VARSIZE(acc
));
531 PG_RETURN_POINTER(rewrited
);
536 * Get Oid of current dictionary
541 if (current_dictionary_oid
== InvalidOid
)
543 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
544 errmsg("no current dictionary"),
545 errhint("Execute SELECT set_curdict(...).")));
547 return current_dictionary_oid
;
551 * Get Oid of current parser
553 * Here, it seems reasonable to select the "default" parser if none has been
557 GetCurrentParser(void)
559 if (current_parser_oid
== InvalidOid
)
560 current_parser_oid
= TSParserGetPrsid(stringToQualifiedNameList("pg_catalog.default"), false);
561 return current_parser_oid
;