mirror of
				https://github.com/postgres/postgres.git
				synced 2025-10-29 22:49:41 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			568 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			568 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*-------------------------------------------------------------------------
 | |
|  *
 | |
|  * tsearch2.c
 | |
|  *		Backwards-compatibility package for old contrib/tsearch2 API
 | |
|  *
 | |
|  * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
 | |
|  *
 | |
|  *
 | |
|  * IDENTIFICATION
 | |
|  *	  contrib/tsearch2/tsearch2.c
 | |
|  *
 | |
|  *-------------------------------------------------------------------------
 | |
|  */
 | |
| #include "postgres.h"
 | |
| 
 | |
| #include "catalog/namespace.h"
 | |
| #include "catalog/pg_type.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 TextGetObjectId(infunction, text) \
 | |
| 	DatumGetObjectId(DirectFunctionCall1(infunction, \
 | |
| 					 CStringGetDatum(text_to_cstring(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_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);
 | |
| Datum		tsa_rewrite_accum(PG_FUNCTION_ARGS);
 | |
| Datum		tsa_rewrite_finish(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_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);
 | |
| PG_FUNCTION_INFO_V1(tsa_rewrite_accum);
 | |
| PG_FUNCTION_INFO_V1(tsa_rewrite_finish);
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * 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_snb_ru_init);
 | |
| 
 | |
| 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);
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * list of redefined functions
 | |
|  */
 | |
| 
 | |
| /* lexize(text, text) */
 | |
| Datum
 | |
| tsa_lexize_byname(PG_FUNCTION_ARGS)
 | |
| {
 | |
| 	text	   *dictname = PG_GETARG_TEXT_PP(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_PP(0);
 | |
| 	Oid			dict_oid;
 | |
| 
 | |
| 	dict_oid = get_ts_dict_oid(stringToQualifiedNameList(text_to_cstring(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_PP(0);
 | |
| 	Oid			parser_oid;
 | |
| 
 | |
| 	parser_oid = get_ts_parser_oid(stringToQualifiedNameList(text_to_cstring(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_PP(0);
 | |
| 	char	   *name;
 | |
| 
 | |
| 	name = text_to_cstring(arg0);
 | |
| 
 | |
| 	set_config_option("default_text_search_config", name,
 | |
| 					  PGC_USERSET,
 | |
| 					  PGC_S_SESSION,
 | |
| 					  GUC_ACTION_SET,
 | |
| 					  true);
 | |
| 
 | |
| 	PG_RETURN_VOID();
 | |
| }
 | |
| 
 | |
| /* to_tsvector(text, text) */
 | |
| Datum
 | |
| tsa_to_tsvector_name(PG_FUNCTION_ARGS)
 | |
| {
 | |
| 	text	   *cfgname = PG_GETARG_TEXT_PP(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_PP(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_PP(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,
 | |
| 								CStringGetDatum(TextDatumGetCString(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,
 | |
| 			  **tgargs_old;
 | |
| 	int			i;
 | |
| 	Datum		res;
 | |
| 
 | |
| 	/* 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));
 | |
| 	tgargs_old = trigger->tgargs;
 | |
| 	trigger->tgargs = tgargs;
 | |
| 	trigger->tgnargs++;
 | |
| 
 | |
| 	res = tsvector_update_trigger_byid(fcinfo);
 | |
| 
 | |
| 	/* restore old trigger data */
 | |
| 	trigger->tgargs = tgargs_old;
 | |
| 	trigger->tgnargs--;
 | |
| 
 | |
| 	pfree(tgargs[1]);
 | |
| 	pfree(tgargs);
 | |
| 
 | |
| 	return res;
 | |
| }
 | |
| 
 | |
| 
 | |
| Datum
 | |
| tsa_rewrite_accum(PG_FUNCTION_ARGS)
 | |
| {
 | |
| 	TSQuery		acc;
 | |
| 	ArrayType  *qa;
 | |
| 	TSQuery		q;
 | |
| 	QTNode	   *qex = NULL,
 | |
| 			   *subs = NULL,
 | |
| 			   *acctree = NULL;
 | |
| 	bool		isfind = false;
 | |
| 	Datum	   *elemsp;
 | |
| 	int			nelemsp;
 | |
| 	MemoryContext aggcontext;
 | |
| 	MemoryContext oldcontext;
 | |
| 
 | |
| 	if (!AggCheckCallContext(fcinfo, &aggcontext))
 | |
| 		elog(ERROR, "tsa_rewrite_accum called in non-aggregate context");
 | |
| 
 | |
| 	if (PG_ARGISNULL(0) || PG_GETARG_POINTER(0) == NULL)
 | |
| 	{
 | |
| 		acc = (TSQuery) MemoryContextAlloc(aggcontext, HDRSIZETQ);
 | |
| 		SET_VARSIZE(acc, HDRSIZETQ);
 | |
| 		acc->size = 0;
 | |
| 	}
 | |
| 	else
 | |
| 		acc = PG_GETARG_TSQUERY(0);
 | |
| 
 | |
| 	if (PG_ARGISNULL(1) || PG_GETARG_POINTER(1) == NULL)
 | |
| 		PG_RETURN_TSQUERY(acc);
 | |
| 	else
 | |
| 		qa = PG_GETARG_ARRAYTYPE_P_COPY(1);
 | |
| 
 | |
| 	if (ARR_NDIM(qa) != 1)
 | |
| 		elog(ERROR, "array must be one-dimensional, not %d dimensions",
 | |
| 			 ARR_NDIM(qa));
 | |
| 	if (ArrayGetNItems(ARR_NDIM(qa), ARR_DIMS(qa)) != 3)
 | |
| 		elog(ERROR, "array must have three elements");
 | |
| 	if (ARR_ELEMTYPE(qa) != TSQUERYOID)
 | |
| 		elog(ERROR, "array must contain tsquery elements");
 | |
| 
 | |
| 	deconstruct_array(qa, TSQUERYOID, -1, false, 'i', &elemsp, NULL, &nelemsp);
 | |
| 
 | |
| 	q = DatumGetTSQuery(elemsp[0]);
 | |
| 	if (q->size == 0)
 | |
| 	{
 | |
| 		pfree(elemsp);
 | |
| 		PG_RETURN_POINTER(acc);
 | |
| 	}
 | |
| 
 | |
| 	if (!acc->size)
 | |
| 	{
 | |
| 		if (VARSIZE(acc) > HDRSIZETQ)
 | |
| 		{
 | |
| 			pfree(elemsp);
 | |
| 			PG_RETURN_POINTER(acc);
 | |
| 		}
 | |
| 		else
 | |
| 			acctree = QT2QTN(GETQUERY(q), GETOPERAND(q));
 | |
| 	}
 | |
| 	else
 | |
| 		acctree = QT2QTN(GETQUERY(acc), GETOPERAND(acc));
 | |
| 
 | |
| 	QTNTernary(acctree);
 | |
| 	QTNSort(acctree);
 | |
| 
 | |
| 	q = DatumGetTSQuery(elemsp[1]);
 | |
| 	if (q->size == 0)
 | |
| 	{
 | |
| 		pfree(elemsp);
 | |
| 		PG_RETURN_POINTER(acc);
 | |
| 	}
 | |
| 	qex = QT2QTN(GETQUERY(q), GETOPERAND(q));
 | |
| 	QTNTernary(qex);
 | |
| 	QTNSort(qex);
 | |
| 
 | |
| 	q = DatumGetTSQuery(elemsp[2]);
 | |
| 	if (q->size)
 | |
| 		subs = QT2QTN(GETQUERY(q), GETOPERAND(q));
 | |
| 
 | |
| 	acctree = findsubquery(acctree, qex, subs, &isfind);
 | |
| 
 | |
| 	if (isfind || !acc->size)
 | |
| 	{
 | |
| 		/* pfree( acc ); do not pfree(p), because nodeAgg.c will */
 | |
| 		if (acctree)
 | |
| 		{
 | |
| 			QTNBinary(acctree);
 | |
| 			oldcontext = MemoryContextSwitchTo(aggcontext);
 | |
| 			acc = QTN2QT(acctree);
 | |
| 			MemoryContextSwitchTo(oldcontext);
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			acc = (TSQuery) MemoryContextAlloc(aggcontext, HDRSIZETQ);
 | |
| 			SET_VARSIZE(acc, HDRSIZETQ);
 | |
| 			acc->size = 0;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	pfree(elemsp);
 | |
| 	QTNFree(qex);
 | |
| 	QTNFree(subs);
 | |
| 	QTNFree(acctree);
 | |
| 
 | |
| 	PG_RETURN_TSQUERY(acc);
 | |
| }
 | |
| 
 | |
| Datum
 | |
| tsa_rewrite_finish(PG_FUNCTION_ARGS)
 | |
| {
 | |
| 	TSQuery		acc = PG_GETARG_TSQUERY(0);
 | |
| 	TSQuery		rewrited;
 | |
| 
 | |
| 	if (acc == NULL || PG_ARGISNULL(0) || acc->size == 0)
 | |
| 	{
 | |
| 		rewrited = (TSQuery) palloc(HDRSIZETQ);
 | |
| 		SET_VARSIZE(rewrited, HDRSIZETQ);
 | |
| 		rewrited->size = 0;
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		rewrited = (TSQuery) palloc(VARSIZE(acc));
 | |
| 		memcpy(rewrited, acc, VARSIZE(acc));
 | |
| 		pfree(acc);
 | |
| 	}
 | |
| 
 | |
| 	PG_RETURN_POINTER(rewrited);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * 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 = get_ts_parser_oid(stringToQualifiedNameList("pg_catalog.default"), false);
 | |
| 	return current_parser_oid;
 | |
| }
 |