summaryrefslogtreecommitdiff
path: root/contrib/tsearch2/tsearch2.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/tsearch2/tsearch2.c')
-rw-r--r--contrib/tsearch2/tsearch2.c441
1 files changed, 441 insertions, 0 deletions
diff --git a/contrib/tsearch2/tsearch2.c b/contrib/tsearch2/tsearch2.c
new file mode 100644
index 0000000000..d51ba7ede7
--- /dev/null
+++ b/contrib/tsearch2/tsearch2.c
@@ -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;
+}