Beispiel #1
0
Datum
ts_headline_byid_opt(PG_FUNCTION_ARGS)
{
	Oid			tsconfig = PG_GETARG_OID(0);
	text	   *in = PG_GETARG_TEXT_PP(1);
	TSQuery		query = PG_GETARG_TSQUERY(2);
	text	   *opt = (PG_NARGS() > 3 && PG_GETARG_POINTER(3)) ? PG_GETARG_TEXT_PP(3) : NULL;
	HeadlineParsedText prs;
	List	   *prsoptions;
	text	   *out;
	TSConfigCacheEntry *cfg;
	TSParserCacheEntry *prsobj;

	cfg = lookup_ts_config_cache(tsconfig);
	prsobj = lookup_ts_parser_cache(cfg->prsId);

	if (!OidIsValid(prsobj->headlineOid))
		ereport(ERROR,
				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
				 errmsg("text search parser does not support headline creation")));

	memset(&prs, 0, sizeof(HeadlineParsedText));
	prs.lenwords = 32;
	prs.words = (HeadlineWordEntry *) palloc(sizeof(HeadlineWordEntry) * prs.lenwords);

	hlparsetext(cfg->cfgId, &prs, query,
				VARDATA_ANY(in), VARSIZE_ANY_EXHDR(in));

	if (opt)
		prsoptions = deserialize_deflist(PointerGetDatum(opt));
	else
		prsoptions = NIL;

	FunctionCall3(&(prsobj->prsheadline),
				  PointerGetDatum(&prs),
				  PointerGetDatum(prsoptions),
				  PointerGetDatum(query));

	out = generateHeadline(&prs);

	PG_FREE_IF_COPY(in, 1);
	PG_FREE_IF_COPY(query, 2);
	if (opt)
		PG_FREE_IF_COPY(opt, 3);
	pfree(prs.words);
	pfree(prs.startsel);
	pfree(prs.stopsel);

	PG_RETURN_POINTER(out);
}
Beispiel #2
0
Datum
ts_headline_json_byid_opt(PG_FUNCTION_ARGS)
{
	Oid			tsconfig = PG_GETARG_OID(0);
	text	   *json = PG_GETARG_TEXT_P(1);
	TSQuery		query = PG_GETARG_TSQUERY(2);
	text	   *opt = (PG_NARGS() > 3 && PG_GETARG_POINTER(3)) ? PG_GETARG_TEXT_P(3) : NULL;
	text	   *out;
	JsonTransformStringValuesAction action = (JsonTransformStringValuesAction) headline_json_value;

	HeadlineParsedText prs;
	HeadlineJsonState *state = palloc0(sizeof(HeadlineJsonState));

	memset(&prs, 0, sizeof(HeadlineParsedText));
	prs.lenwords = 32;
	prs.words = (HeadlineWordEntry *) palloc(sizeof(HeadlineWordEntry) * prs.lenwords);

	state->prs = &prs;
	state->cfg = lookup_ts_config_cache(tsconfig);
	state->prsobj = lookup_ts_parser_cache(state->cfg->prsId);
	state->query = query;
	if (opt)
		state->prsoptions = deserialize_deflist(PointerGetDatum(opt));
	else
		state->prsoptions = NIL;

	if (!OidIsValid(state->prsobj->headlineOid))
		ereport(ERROR,
				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
				 errmsg("text search parser does not support headline creation")));

	out = transform_json_string_values(json, state, action);

	PG_FREE_IF_COPY(json, 1);
	PG_FREE_IF_COPY(query, 2);
	if (opt)
		PG_FREE_IF_COPY(opt, 3);
	pfree(prs.words);

	if (state->transformed)
	{
		pfree(prs.startsel);
		pfree(prs.stopsel);
	}

	PG_RETURN_TEXT_P(out);
}
Beispiel #3
0
/*
 * Fetch dictionary cache entry
 */
TSDictionaryCacheEntry *
lookup_ts_dictionary_cache(Oid dictId)
{
	TSDictionaryCacheEntry *entry;

	if (TSDictionaryCacheHash == NULL)
	{
		/* First time through: initialize the hash table */
		HASHCTL		ctl;

		MemSet(&ctl, 0, sizeof(ctl));
		ctl.keysize = sizeof(Oid);
		ctl.entrysize = sizeof(TSDictionaryCacheEntry);
		TSDictionaryCacheHash = hash_create("Tsearch dictionary cache", 8,
											&ctl, HASH_ELEM | HASH_BLOBS);
		/* Flush cache on pg_ts_dict and pg_ts_template changes */
		CacheRegisterSyscacheCallback(TSDICTOID, InvalidateTSCacheCallBack,
									  PointerGetDatum(TSDictionaryCacheHash));
		CacheRegisterSyscacheCallback(TSTEMPLATEOID, InvalidateTSCacheCallBack,
									  PointerGetDatum(TSDictionaryCacheHash));

		/* Also make sure CacheMemoryContext exists */
		if (!CacheMemoryContext)
			CreateCacheMemoryContext();
	}

	/* Check single-entry cache */
	if (lastUsedDictionary && lastUsedDictionary->dictId == dictId &&
		lastUsedDictionary->isvalid)
		return lastUsedDictionary;

	/* Try to look up an existing entry */
	entry = (TSDictionaryCacheEntry *) hash_search(TSDictionaryCacheHash,
												   (void *) &dictId,
												   HASH_FIND, NULL);
	if (entry == NULL || !entry->isvalid)
	{
		/*
		 * If we didn't find one, we want to make one. But first look up the
		 * object to be sure the OID is real.
		 */
		HeapTuple	tpdict,
					tptmpl;
		Form_pg_ts_dict dict;
		Form_pg_ts_template ctemplate;
		MemoryContext saveCtx;

		tpdict = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dictId));
		if (!HeapTupleIsValid(tpdict))
			elog(ERROR, "cache lookup failed for text search dictionary %u",
				 dictId);
		dict = (Form_pg_ts_dict) GETSTRUCT(tpdict);

		/*
		 * Sanity checks
		 */
		if (!OidIsValid(dict->dicttemplate))
			elog(ERROR, "text search dictionary %u has no ctemplate", dictId);

		/*
		 * Retrieve dictionary's ctemplate
		 */
		tptmpl = SearchSysCache1(TSTEMPLATEOID,
								 ObjectIdGetDatum(dict->dicttemplate));
		if (!HeapTupleIsValid(tptmpl))
			elog(ERROR, "cache lookup failed for text search ctemplate %u",
				 dict->dicttemplate);
		ctemplate = (Form_pg_ts_template) GETSTRUCT(tptmpl);

		/*
		 * Sanity checks
		 */
		if (!OidIsValid(ctemplate->tmpllexize))
			elog(ERROR, "text search ctemplate %u has no lexize method",
				 ctemplate->tmpllexize);

		if (entry == NULL)
		{
			bool		found;

			/* Now make the cache entry */
			entry = (TSDictionaryCacheEntry *)
				hash_search(TSDictionaryCacheHash,
							(void *) &dictId,
							HASH_ENTER, &found);
			Assert(!found);		/* it wasn't there a moment ago */

			/* Create private___ memory context the first time through */
			saveCtx = AllocSetContextCreate(CacheMemoryContext,
			                                NameStr(dict->dictname),
			                                ALLOCSET_SMALL_MINSIZE,
			                                ALLOCSET_SMALL_INITSIZE,
			                                ALLOCSET_SMALL_MAXSIZE);
		}
		else
		{
			/* Clear the existing entry's private___ context */
			saveCtx = entry->dictCtx;
			MemoryContextResetAndDeleteChildren(saveCtx);
		}

		MemSet(entry, 0, sizeof(TSDictionaryCacheEntry));
		entry->dictId = dictId;
		entry->dictCtx = saveCtx;

		entry->lexizeOid = ctemplate->tmpllexize;

		if (OidIsValid(ctemplate->tmplinit))
		{
			List	   *dictoptions;
			Datum		opt;
			bool		isnull;
			MemoryContext oldcontext;

			/*
			 * Init method runs in dictionary's private___ memory context, and we
			 * make sure the options are stored there too
			 */
			oldcontext = MemoryContextSwitchTo(entry->dictCtx);

			opt = SysCacheGetAttr(TSDICTOID, tpdict,
								  Anum_pg_ts_dict_dictinitoption,
								  &isnull);
			if (isnull)
				dictoptions = NIL;
			else
				dictoptions = deserialize_deflist(opt);

			entry->dictData =
				DatumGetPointer(OidFunctionCall1(ctemplate->tmplinit,
											  PointerGetDatum(dictoptions)));

			MemoryContextSwitchTo(oldcontext);
		}

		ReleaseSysCache(tptmpl);
		ReleaseSysCache(tpdict);

		fmgr_info_cxt(entry->lexizeOid, &entry->lexize, entry->dictCtx);

		entry->isvalid = true;
	}

	lastUsedDictionary = entry;

	return entry;
}