mirror of
https://github.com/postgres/postgres.git
synced 2025-07-30 11:03:19 +03:00
Replace the now-incompatible-with-core contrib/tsearch2 module with a
compatibility package. This supports importing dumps from past versions using tsearch2, and provides the old names and API for most functions that were changed. (rewrite(ARRAY[...]) is a glaring omission, though.) Pavel Stehule and Tom Lane
This commit is contained in:
441
contrib/tsearch2/tsearch2.c
Normal file
441
contrib/tsearch2/tsearch2.c
Normal file
@ -0,0 +1,441 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* tsearch2.c
|
||||
* Backwards-compatibility package for old contrib/tsearch2 API
|
||||
*
|
||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/contrib/tsearch2/tsearch2.c,v 1.1 2007/11/13 21:02:29 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
||||
#include "catalog/namespace.h"
|
||||
#include "commands/trigger.h"
|
||||
#include "fmgr.h"
|
||||
#include "tsearch/ts_utils.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/guc.h"
|
||||
#include "utils/syscache.h"
|
||||
|
||||
PG_MODULE_MAGIC;
|
||||
|
||||
static Oid current_dictionary_oid = InvalidOid;
|
||||
static Oid current_parser_oid = InvalidOid;
|
||||
|
||||
/* insert given value at argument position 0 */
|
||||
#define INSERT_ARGUMENT0(argument, isnull) \
|
||||
do { \
|
||||
int i; \
|
||||
for (i = fcinfo->nargs; i > 0; i--) \
|
||||
{ \
|
||||
fcinfo->arg[i] = fcinfo->arg[i-1]; \
|
||||
fcinfo->argnull[i] = fcinfo->argnull[i-1]; \
|
||||
} \
|
||||
fcinfo->arg[0] = (argument); \
|
||||
fcinfo->argnull[0] = (isnull); \
|
||||
fcinfo->nargs++; \
|
||||
} while (0)
|
||||
|
||||
#define TextPGetCString(t) \
|
||||
DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(t)))
|
||||
#define CStringGetTextP(c) \
|
||||
DatumGetTextP(DirectFunctionCall1(textin, CStringGetDatum(c)))
|
||||
|
||||
#define TextGetObjectId(infunction, text) \
|
||||
DatumGetObjectId(DirectFunctionCall1(infunction, \
|
||||
DirectFunctionCall1(textout, PointerGetDatum(text))))
|
||||
|
||||
#define UNSUPPORTED_FUNCTION(name) \
|
||||
Datum name(PG_FUNCTION_ARGS); \
|
||||
Datum \
|
||||
name(PG_FUNCTION_ARGS) \
|
||||
{ \
|
||||
ereport(ERROR, \
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),\
|
||||
errmsg("function %s is no longer supported", \
|
||||
format_procedure(fcinfo->flinfo->fn_oid)), \
|
||||
errhint("Switch to new tsearch functionality."))); \
|
||||
/* keep compiler quiet */ \
|
||||
PG_RETURN_NULL(); \
|
||||
} \
|
||||
PG_FUNCTION_INFO_V1(name)
|
||||
|
||||
static Oid GetCurrentDict(void);
|
||||
static Oid GetCurrentParser(void);
|
||||
|
||||
Datum tsa_lexize_byname(PG_FUNCTION_ARGS);
|
||||
Datum tsa_lexize_bycurrent(PG_FUNCTION_ARGS);
|
||||
Datum tsa_set_curdict(PG_FUNCTION_ARGS);
|
||||
Datum tsa_set_curdict_byname(PG_FUNCTION_ARGS);
|
||||
Datum tsa_token_type_current(PG_FUNCTION_ARGS);
|
||||
Datum tsa_set_curprs(PG_FUNCTION_ARGS);
|
||||
Datum tsa_set_curprs_byname(PG_FUNCTION_ARGS);
|
||||
Datum tsa_parse_current(PG_FUNCTION_ARGS);
|
||||
Datum tsa_set_curcfg(PG_FUNCTION_ARGS);
|
||||
Datum tsa_set_curcfg_byname(PG_FUNCTION_ARGS);
|
||||
Datum tsa_show_curcfg(PG_FUNCTION_ARGS);
|
||||
Datum tsa_to_tsvector_name(PG_FUNCTION_ARGS);
|
||||
Datum tsa_to_tsquery_name(PG_FUNCTION_ARGS);
|
||||
Datum tsa_plainto_tsquery_name(PG_FUNCTION_ARGS);
|
||||
Datum tsa_headline_byname(PG_FUNCTION_ARGS);
|
||||
Datum tsa_ts_stat(PG_FUNCTION_ARGS);
|
||||
Datum tsa_tsearch2(PG_FUNCTION_ARGS);
|
||||
|
||||
PG_FUNCTION_INFO_V1(tsa_lexize_byname);
|
||||
PG_FUNCTION_INFO_V1(tsa_lexize_bycurrent);
|
||||
PG_FUNCTION_INFO_V1(tsa_set_curdict);
|
||||
PG_FUNCTION_INFO_V1(tsa_set_curdict_byname);
|
||||
PG_FUNCTION_INFO_V1(tsa_token_type_current);
|
||||
PG_FUNCTION_INFO_V1(tsa_set_curprs);
|
||||
PG_FUNCTION_INFO_V1(tsa_set_curprs_byname);
|
||||
PG_FUNCTION_INFO_V1(tsa_parse_current);
|
||||
PG_FUNCTION_INFO_V1(tsa_set_curcfg);
|
||||
PG_FUNCTION_INFO_V1(tsa_set_curcfg_byname);
|
||||
PG_FUNCTION_INFO_V1(tsa_show_curcfg);
|
||||
PG_FUNCTION_INFO_V1(tsa_to_tsvector_name);
|
||||
PG_FUNCTION_INFO_V1(tsa_to_tsquery_name);
|
||||
PG_FUNCTION_INFO_V1(tsa_plainto_tsquery_name);
|
||||
PG_FUNCTION_INFO_V1(tsa_headline_byname);
|
||||
PG_FUNCTION_INFO_V1(tsa_ts_stat);
|
||||
PG_FUNCTION_INFO_V1(tsa_tsearch2);
|
||||
|
||||
|
||||
/*
|
||||
* List of unsupported functions
|
||||
*
|
||||
* The parser and dictionary functions are defined only so that the former
|
||||
* contents of pg_ts_parser and pg_ts_dict can be loaded into the system,
|
||||
* for ease of reference while creating the new tsearch configuration.
|
||||
*/
|
||||
|
||||
UNSUPPORTED_FUNCTION(tsa_dex_init);
|
||||
UNSUPPORTED_FUNCTION(tsa_dex_lexize);
|
||||
|
||||
UNSUPPORTED_FUNCTION(tsa_snb_en_init);
|
||||
UNSUPPORTED_FUNCTION(tsa_snb_lexize);
|
||||
UNSUPPORTED_FUNCTION(tsa_snb_ru_init_koi8);
|
||||
UNSUPPORTED_FUNCTION(tsa_snb_ru_init_utf8);
|
||||
|
||||
UNSUPPORTED_FUNCTION(tsa_spell_init);
|
||||
UNSUPPORTED_FUNCTION(tsa_spell_lexize);
|
||||
|
||||
UNSUPPORTED_FUNCTION(tsa_syn_init);
|
||||
UNSUPPORTED_FUNCTION(tsa_syn_lexize);
|
||||
|
||||
UNSUPPORTED_FUNCTION(tsa_thesaurus_init);
|
||||
UNSUPPORTED_FUNCTION(tsa_thesaurus_lexize);
|
||||
|
||||
UNSUPPORTED_FUNCTION(tsa_prsd_start);
|
||||
UNSUPPORTED_FUNCTION(tsa_prsd_getlexeme);
|
||||
UNSUPPORTED_FUNCTION(tsa_prsd_end);
|
||||
UNSUPPORTED_FUNCTION(tsa_prsd_lextype);
|
||||
UNSUPPORTED_FUNCTION(tsa_prsd_headline);
|
||||
|
||||
UNSUPPORTED_FUNCTION(tsa_reset_tsearch);
|
||||
UNSUPPORTED_FUNCTION(tsa_get_covers);
|
||||
|
||||
UNSUPPORTED_FUNCTION(tsa_rewrite_accum);
|
||||
UNSUPPORTED_FUNCTION(tsa_rewrite_finish);
|
||||
|
||||
|
||||
/*
|
||||
* list of redefined functions
|
||||
*/
|
||||
|
||||
/* lexize(text, text) */
|
||||
Datum
|
||||
tsa_lexize_byname(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *dictname = PG_GETARG_TEXT_P(0);
|
||||
Datum arg1 = PG_GETARG_DATUM(1);
|
||||
|
||||
return DirectFunctionCall2(ts_lexize,
|
||||
ObjectIdGetDatum(TextGetObjectId(regdictionaryin, dictname)),
|
||||
arg1);
|
||||
}
|
||||
|
||||
/* lexize(text) */
|
||||
Datum
|
||||
tsa_lexize_bycurrent(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Datum arg0 = PG_GETARG_DATUM(0);
|
||||
Oid id = GetCurrentDict();
|
||||
|
||||
return DirectFunctionCall2(ts_lexize,
|
||||
ObjectIdGetDatum(id),
|
||||
arg0);
|
||||
}
|
||||
|
||||
/* set_curdict(int) */
|
||||
Datum
|
||||
tsa_set_curdict(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Oid dict_oid = PG_GETARG_OID(0);
|
||||
|
||||
if (!SearchSysCacheExists(TSDICTOID,
|
||||
ObjectIdGetDatum(dict_oid),
|
||||
0, 0, 0))
|
||||
elog(ERROR, "cache lookup failed for text search dictionary %u",
|
||||
dict_oid);
|
||||
|
||||
current_dictionary_oid = dict_oid;
|
||||
|
||||
PG_RETURN_VOID();
|
||||
}
|
||||
|
||||
/* set_curdict(text) */
|
||||
Datum
|
||||
tsa_set_curdict_byname(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *name = PG_GETARG_TEXT_P(0);
|
||||
Oid dict_oid;
|
||||
|
||||
dict_oid = TSDictionaryGetDictid(stringToQualifiedNameList(TextPGetCString(name)), false);
|
||||
|
||||
current_dictionary_oid = dict_oid;
|
||||
|
||||
PG_RETURN_VOID();
|
||||
}
|
||||
|
||||
/* token_type() */
|
||||
Datum
|
||||
tsa_token_type_current(PG_FUNCTION_ARGS)
|
||||
{
|
||||
INSERT_ARGUMENT0(ObjectIdGetDatum(GetCurrentParser()), false);
|
||||
return ts_token_type_byid(fcinfo);
|
||||
}
|
||||
|
||||
/* set_curprs(int) */
|
||||
Datum
|
||||
tsa_set_curprs(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Oid parser_oid = PG_GETARG_OID(0);
|
||||
|
||||
if (!SearchSysCacheExists(TSPARSEROID,
|
||||
ObjectIdGetDatum(parser_oid),
|
||||
0, 0, 0))
|
||||
elog(ERROR, "cache lookup failed for text search parser %u",
|
||||
parser_oid);
|
||||
|
||||
current_parser_oid = parser_oid;
|
||||
|
||||
PG_RETURN_VOID();
|
||||
}
|
||||
|
||||
/* set_curprs(text) */
|
||||
Datum
|
||||
tsa_set_curprs_byname(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *name = PG_GETARG_TEXT_P(0);
|
||||
Oid parser_oid;
|
||||
|
||||
parser_oid = TSParserGetPrsid(stringToQualifiedNameList(TextPGetCString(name)), false);
|
||||
|
||||
current_parser_oid = parser_oid;
|
||||
|
||||
PG_RETURN_VOID();
|
||||
}
|
||||
|
||||
/* parse(text) */
|
||||
Datum
|
||||
tsa_parse_current(PG_FUNCTION_ARGS)
|
||||
{
|
||||
INSERT_ARGUMENT0(ObjectIdGetDatum(GetCurrentParser()), false);
|
||||
return ts_parse_byid(fcinfo);
|
||||
}
|
||||
|
||||
/* set_curcfg(int) */
|
||||
Datum
|
||||
tsa_set_curcfg(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Oid arg0 = PG_GETARG_OID(0);
|
||||
char *name;
|
||||
|
||||
name = DatumGetCString(DirectFunctionCall1(regconfigout,
|
||||
ObjectIdGetDatum(arg0)));
|
||||
|
||||
set_config_option("default_text_search_config", name,
|
||||
PGC_USERSET,
|
||||
PGC_S_SESSION,
|
||||
GUC_ACTION_SET,
|
||||
true);
|
||||
|
||||
PG_RETURN_VOID();
|
||||
}
|
||||
|
||||
/* set_curcfg(text) */
|
||||
Datum
|
||||
tsa_set_curcfg_byname(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *arg0 = PG_GETARG_TEXT_P(0);
|
||||
char *name;
|
||||
|
||||
name = TextPGetCString(arg0);
|
||||
set_config_option("default_text_search_config", name,
|
||||
PGC_USERSET,
|
||||
PGC_S_SESSION,
|
||||
GUC_ACTION_SET,
|
||||
true);
|
||||
|
||||
PG_RETURN_VOID();
|
||||
}
|
||||
|
||||
/* show_curcfg() */
|
||||
Datum
|
||||
tsa_show_curcfg(PG_FUNCTION_ARGS)
|
||||
{
|
||||
char *cfgname;
|
||||
Oid config_oid;
|
||||
|
||||
cfgname = GetConfigOptionByName("default_text_search_config", NULL);
|
||||
config_oid = DatumGetObjectId(DirectFunctionCall1(regconfigin,
|
||||
CStringGetDatum(cfgname)));
|
||||
|
||||
PG_RETURN_OID(config_oid);
|
||||
}
|
||||
|
||||
/* to_tsvector(text, text) */
|
||||
Datum
|
||||
tsa_to_tsvector_name(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *cfgname = PG_GETARG_TEXT_P(0);
|
||||
Datum arg1 = PG_GETARG_DATUM(1);
|
||||
Oid config_oid;
|
||||
|
||||
config_oid = TextGetObjectId(regconfigin, cfgname);
|
||||
|
||||
return DirectFunctionCall2(to_tsvector_byid,
|
||||
ObjectIdGetDatum(config_oid), arg1);
|
||||
}
|
||||
|
||||
/* to_tsquery(text, text) */
|
||||
Datum
|
||||
tsa_to_tsquery_name(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *cfgname = PG_GETARG_TEXT_P(0);
|
||||
Datum arg1 = PG_GETARG_DATUM(1);
|
||||
Oid config_oid;
|
||||
|
||||
config_oid = TextGetObjectId(regconfigin, cfgname);
|
||||
|
||||
return DirectFunctionCall2(to_tsquery_byid,
|
||||
ObjectIdGetDatum(config_oid), arg1);
|
||||
}
|
||||
|
||||
|
||||
/* plainto_tsquery(text, text) */
|
||||
Datum
|
||||
tsa_plainto_tsquery_name(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *cfgname = PG_GETARG_TEXT_P(0);
|
||||
Datum arg1 = PG_GETARG_DATUM(1);
|
||||
Oid config_oid;
|
||||
|
||||
config_oid = TextGetObjectId(regconfigin, cfgname);
|
||||
|
||||
return DirectFunctionCall2(plainto_tsquery_byid,
|
||||
ObjectIdGetDatum(config_oid), arg1);
|
||||
}
|
||||
|
||||
/* headline(text, text, tsquery [,text]) */
|
||||
Datum
|
||||
tsa_headline_byname(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Datum arg0 = PG_GETARG_DATUM(0);
|
||||
Datum arg1 = PG_GETARG_DATUM(1);
|
||||
Datum arg2 = PG_GETARG_DATUM(2);
|
||||
Datum result;
|
||||
Oid config_oid;
|
||||
|
||||
/* first parameter has to be converted to oid */
|
||||
config_oid = DatumGetObjectId(DirectFunctionCall1(regconfigin,
|
||||
DirectFunctionCall1(textout, arg0)));
|
||||
|
||||
if (PG_NARGS() == 3)
|
||||
result = DirectFunctionCall3(ts_headline_byid,
|
||||
ObjectIdGetDatum(config_oid), arg1, arg2);
|
||||
else
|
||||
{
|
||||
Datum arg3 = PG_GETARG_DATUM(3);
|
||||
|
||||
result = DirectFunctionCall4(ts_headline_byid_opt,
|
||||
ObjectIdGetDatum(config_oid),
|
||||
arg1, arg2, arg3);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* tsearch2 version of update trigger
|
||||
*
|
||||
* We pass this on to the core trigger after inserting the default text
|
||||
* search configuration name as the second argument. Note that this isn't
|
||||
* a complete implementation of the original functionality; tsearch2 allowed
|
||||
* transformation function names to be included in the list. However, that
|
||||
* is deliberately removed as being a security risk.
|
||||
*/
|
||||
Datum
|
||||
tsa_tsearch2(PG_FUNCTION_ARGS)
|
||||
{
|
||||
TriggerData *trigdata;
|
||||
Trigger *trigger;
|
||||
char **tgargs;
|
||||
int i;
|
||||
|
||||
/* Check call context */
|
||||
if (!CALLED_AS_TRIGGER(fcinfo)) /* internal error */
|
||||
elog(ERROR, "tsvector_update_trigger: not fired by trigger manager");
|
||||
|
||||
trigdata = (TriggerData *) fcinfo->context;
|
||||
trigger = trigdata->tg_trigger;
|
||||
|
||||
if (trigger->tgnargs < 2)
|
||||
elog(ERROR, "TSearch: format tsearch2(tsvector_field, text_field1,...)");
|
||||
|
||||
/* create space for configuration name */
|
||||
tgargs = (char **) palloc((trigger->tgnargs + 1) * sizeof(char *));
|
||||
tgargs[0] = trigger->tgargs[0];
|
||||
for (i = 1; i < trigger->tgnargs; i++)
|
||||
tgargs[i+1] = trigger->tgargs[i];
|
||||
|
||||
tgargs[1] = pstrdup(GetConfigOptionByName("default_text_search_config",
|
||||
NULL));
|
||||
trigger->tgargs = tgargs;
|
||||
trigger->tgnargs++;
|
||||
|
||||
return tsvector_update_trigger_byid(fcinfo);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get Oid of current dictionary
|
||||
*/
|
||||
static Oid
|
||||
GetCurrentDict(void)
|
||||
{
|
||||
if (current_dictionary_oid == InvalidOid)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("no current dictionary"),
|
||||
errhint("Execute SELECT set_curdict(...).")));
|
||||
|
||||
return current_dictionary_oid;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get Oid of current parser
|
||||
*
|
||||
* Here, it seems reasonable to select the "default" parser if none has been
|
||||
* set.
|
||||
*/
|
||||
static Oid
|
||||
GetCurrentParser(void)
|
||||
{
|
||||
if (current_parser_oid == InvalidOid)
|
||||
current_parser_oid = TSParserGetPrsid(stringToQualifiedNameList("pg_catalog.default"), false);
|
||||
return current_parser_oid;
|
||||
}
|
Reference in New Issue
Block a user