PostgreSQL Source Code  git master
ts_cache.c File Reference
#include "postgres.h"
#include "access/genam.h"
#include "access/htup_details.h"
#include "access/table.h"
#include "access/xact.h"
#include "catalog/namespace.h"
#include "catalog/pg_ts_config.h"
#include "catalog/pg_ts_config_map.h"
#include "catalog/pg_ts_dict.h"
#include "catalog/pg_ts_parser.h"
#include "catalog/pg_ts_template.h"
#include "commands/defrem.h"
#include "miscadmin.h"
#include "tsearch/ts_cache.h"
#include "utils/builtins.h"
#include "utils/catcache.h"
#include "utils/fmgroids.h"
#include "utils/guc_hooks.h"
#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/regproc.h"
#include "utils/syscache.h"
Include dependency graph for ts_cache.c:

Go to the source code of this file.

Macros

#define MAXTOKENTYPE   256
 
#define MAXDICTSPERTT   100
 

Functions

static void InvalidateTSCacheCallBack (Datum arg, int cacheid, uint32 hashvalue)
 
TSParserCacheEntrylookup_ts_parser_cache (Oid prsId)
 
TSDictionaryCacheEntrylookup_ts_dictionary_cache (Oid dictId)
 
static void init_ts_config_cache (void)
 
TSConfigCacheEntrylookup_ts_config_cache (Oid cfgId)
 
Oid getTSCurrentConfig (bool emitError)
 
bool check_default_text_search_config (char **newval, void **extra, GucSource source)
 
void assign_default_text_search_config (const char *newval, void *extra)
 

Variables

static HTABTSParserCacheHash = NULL
 
static TSParserCacheEntrylastUsedParser = NULL
 
static HTABTSDictionaryCacheHash = NULL
 
static TSDictionaryCacheEntrylastUsedDictionary = NULL
 
static HTABTSConfigCacheHash = NULL
 
static TSConfigCacheEntrylastUsedConfig = NULL
 
char * TSCurrentConfig = NULL
 
static Oid TSCurrentConfigCache = InvalidOid
 

Macro Definition Documentation

◆ MAXDICTSPERTT

#define MAXDICTSPERTT   100

Definition at line 60 of file ts_cache.c.

◆ MAXTOKENTYPE

#define MAXTOKENTYPE   256

Definition at line 59 of file ts_cache.c.

Function Documentation

◆ assign_default_text_search_config()

void assign_default_text_search_config ( const char *  newval,
void *  extra 
)

Definition at line 649 of file ts_cache.c.

650 {
651  /* Just reset the cache to force a lookup on first use */
653 }
#define InvalidOid
Definition: postgres_ext.h:36
static Oid TSCurrentConfigCache
Definition: ts_cache.c:77

References InvalidOid, and TSCurrentConfigCache.

◆ check_default_text_search_config()

bool check_default_text_search_config ( char **  newval,
void **  extra,
GucSource  source 
)

Definition at line 588 of file ts_cache.c.

589 {
590  /*
591  * If we aren't inside a transaction, or connected to a database, we
592  * cannot do the catalog accesses necessary to verify the config name.
593  * Must accept it on faith.
594  */
596  {
597  Oid cfgId;
598  HeapTuple tuple;
599  Form_pg_ts_config cfg;
600  char *buf;
601 
603 
604  /*
605  * When source == PGC_S_TEST, don't throw a hard error for a
606  * nonexistent configuration, only a NOTICE. See comments in guc.h.
607  */
608  if (!OidIsValid(cfgId))
609  {
610  if (source == PGC_S_TEST)
611  {
612  ereport(NOTICE,
613  (errcode(ERRCODE_UNDEFINED_OBJECT),
614  errmsg("text search configuration \"%s\" does not exist", *newval)));
615  return true;
616  }
617  else
618  return false;
619  }
620 
621  /*
622  * Modify the actually stored value to be fully qualified, to ensure
623  * later changes of search_path don't affect it.
624  */
626  if (!HeapTupleIsValid(tuple))
627  elog(ERROR, "cache lookup failed for text search configuration %u",
628  cfgId);
629  cfg = (Form_pg_ts_config) GETSTRUCT(tuple);
630 
632  NameStr(cfg->cfgname));
633 
634  ReleaseSysCache(tuple);
635 
636  /* GUC wants it guc_malloc'd not palloc'd */
637  guc_free(*newval);
638  *newval = guc_strdup(LOG, buf);
639  pfree(buf);
640  if (!*newval)
641  return false;
642  }
643 
644  return true;
645 }
#define NameStr(name)
Definition: c.h:682
#define OidIsValid(objectId)
Definition: c.h:711
int errcode(int sqlerrcode)
Definition: elog.c:695
int errmsg(const char *fmt,...)
Definition: elog.c:906
#define LOG
Definition: elog.h:27
#define ERROR
Definition: elog.h:35
#define NOTICE
Definition: elog.h:31
#define ereport(elevel,...)
Definition: elog.h:145
Oid MyDatabaseId
Definition: globals.c:89
void guc_free(void *ptr)
Definition: guc.c:682
#define newval
char * guc_strdup(int elevel, const char *src)
Definition: guc.c:670
@ PGC_S_TEST
Definition: guc.h:121
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:649
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3331
void pfree(void *pointer)
Definition: mcxt.c:1306
Oid get_ts_config_oid(List *names, bool missing_ok)
Definition: namespace.c:2722
static rewind_source * source
Definition: pg_rewind.c:81
static char * buf
Definition: pg_test_fsync.c:67
FormData_pg_ts_config * Form_pg_ts_config
Definition: pg_ts_config.h:48
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:600
unsigned int Oid
Definition: postgres_ext.h:31
List * stringToQualifiedNameList(const char *string)
Definition: regproc.c:1877
char * quote_qualified_identifier(const char *qualifier, const char *ident)
Definition: ruleutils.c:11613
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1221
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1173
@ TSCONFIGOID
Definition: syscache.h:106
bool IsTransactionState(void)
Definition: xact.c:377

References buf, elog(), ereport, errcode(), errmsg(), ERROR, get_namespace_name(), get_ts_config_oid(), GETSTRUCT, guc_free(), guc_strdup(), HeapTupleIsValid, InvalidOid, IsTransactionState(), LOG, MyDatabaseId, NameStr, newval, NOTICE, ObjectIdGetDatum(), OidIsValid, pfree(), PGC_S_TEST, quote_qualified_identifier(), ReleaseSysCache(), SearchSysCache1(), source, stringToQualifiedNameList(), and TSCONFIGOID.

◆ getTSCurrentConfig()

Oid getTSCurrentConfig ( bool  emitError)

Definition at line 557 of file ts_cache.c.

558 {
559  /* if we have a cached value, return it */
561  return TSCurrentConfigCache;
562 
563  /* fail if GUC hasn't been set up yet */
564  if (TSCurrentConfig == NULL || *TSCurrentConfig == '\0')
565  {
566  if (emitError)
567  elog(ERROR, "text search configuration isn't set");
568  else
569  return InvalidOid;
570  }
571 
572  if (TSConfigCacheHash == NULL)
573  {
574  /* First time through: initialize the tsconfig inval callback */
576  }
577 
578  /* Look up the config */
581  !emitError);
582 
583  return TSCurrentConfigCache;
584 }
static void init_ts_config_cache(void)
Definition: ts_cache.c:363
static HTAB * TSConfigCacheHash
Definition: ts_cache.c:69
char * TSCurrentConfig
Definition: ts_cache.c:75

References elog(), ERROR, get_ts_config_oid(), init_ts_config_cache(), InvalidOid, OidIsValid, stringToQualifiedNameList(), TSConfigCacheHash, TSCurrentConfig, and TSCurrentConfigCache.

Referenced by get_current_ts_config(), json_string_to_tsvector(), json_to_tsvector(), jsonb_string_to_tsvector(), jsonb_to_tsvector(), phraseto_tsquery(), plainto_tsquery(), to_tsquery(), to_tsvector(), ts_headline(), ts_headline_json(), ts_headline_json_opt(), ts_headline_jsonb(), ts_headline_jsonb_opt(), ts_headline_opt(), and websearch_to_tsquery().

◆ init_ts_config_cache()

static void init_ts_config_cache ( void  )
static

Definition at line 363 of file ts_cache.c.

364 {
365  HASHCTL ctl;
366 
367  ctl.keysize = sizeof(Oid);
368  ctl.entrysize = sizeof(TSConfigCacheEntry);
369  TSConfigCacheHash = hash_create("Tsearch configuration cache", 16,
370  &ctl, HASH_ELEM | HASH_BLOBS);
371  /* Flush cache on pg_ts_config and pg_ts_config_map changes */
376 
377  /* Also make sure CacheMemoryContext exists */
378  if (!CacheMemoryContext)
380 }
void CreateCacheMemoryContext(void)
Definition: catcache.c:614
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:350
#define HASH_ELEM
Definition: hsearch.h:95
#define HASH_BLOBS
Definition: hsearch.h:97
void CacheRegisterSyscacheCallback(int cacheid, SyscacheCallbackFunction func, Datum arg)
Definition: inval.c:1519
MemoryContext CacheMemoryContext
Definition: mcxt.c:133
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:670
Size keysize
Definition: hsearch.h:75
Size entrysize
Definition: hsearch.h:76
@ TSCONFIGMAP
Definition: syscache.h:104
static void InvalidateTSCacheCallBack(Datum arg, int cacheid, uint32 hashvalue)
Definition: ts_cache.c:93

References CacheMemoryContext, CacheRegisterSyscacheCallback(), CreateCacheMemoryContext(), HASHCTL::entrysize, HASH_BLOBS, hash_create(), HASH_ELEM, InvalidateTSCacheCallBack(), HASHCTL::keysize, PointerGetDatum(), TSConfigCacheHash, TSCONFIGMAP, and TSCONFIGOID.

Referenced by getTSCurrentConfig(), and lookup_ts_config_cache().

◆ InvalidateTSCacheCallBack()

static void InvalidateTSCacheCallBack ( Datum  arg,
int  cacheid,
uint32  hashvalue 
)
static

Definition at line 93 of file ts_cache.c.

94 {
97  TSAnyCacheEntry *entry;
98 
100  while ((entry = (TSAnyCacheEntry *) hash_seq_search(&status)) != NULL)
101  entry->isvalid = false;
102 
103  /* Also invalidate the current-config cache if it's pg_ts_config */
104  if (hash == TSConfigCacheHash)
106 }
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1431
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1421
void * arg
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:225
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:660
static unsigned hash(unsigned *uv, int n)
Definition: rege_dfa.c:715
Definition: dynahash.c:220

References arg, DatumGetPointer(), hash(), hash_seq_init(), hash_seq_search(), InvalidOid, TSAnyCacheEntry::isvalid, status(), TSConfigCacheHash, and TSCurrentConfigCache.

Referenced by init_ts_config_cache(), lookup_ts_dictionary_cache(), and lookup_ts_parser_cache().

◆ lookup_ts_config_cache()

TSConfigCacheEntry* lookup_ts_config_cache ( Oid  cfgId)

Definition at line 386 of file ts_cache.c.

387 {
388  TSConfigCacheEntry *entry;
389 
390  if (TSConfigCacheHash == NULL)
391  {
392  /* First time through: initialize the hash table */
394  }
395 
396  /* Check single-entry cache */
397  if (lastUsedConfig && lastUsedConfig->cfgId == cfgId &&
399  return lastUsedConfig;
400 
401  /* Try to look up an existing entry */
403  (void *) &cfgId,
404  HASH_FIND, NULL);
405  if (entry == NULL || !entry->isvalid)
406  {
407  /*
408  * If we didn't find one, we want to make one. But first look up the
409  * object to be sure the OID is real.
410  */
411  HeapTuple tp;
412  Form_pg_ts_config cfg;
413  Relation maprel;
414  Relation mapidx;
415  ScanKeyData mapskey;
416  SysScanDesc mapscan;
417  HeapTuple maptup;
418  ListDictionary maplists[MAXTOKENTYPE + 1];
419  Oid mapdicts[MAXDICTSPERTT];
420  int maxtokentype;
421  int ndicts;
422  int i;
423 
425  if (!HeapTupleIsValid(tp))
426  elog(ERROR, "cache lookup failed for text search configuration %u",
427  cfgId);
428  cfg = (Form_pg_ts_config) GETSTRUCT(tp);
429 
430  /*
431  * Sanity checks
432  */
433  if (!OidIsValid(cfg->cfgparser))
434  elog(ERROR, "text search configuration %u has no parser", cfgId);
435 
436  if (entry == NULL)
437  {
438  bool found;
439 
440  /* Now make the cache entry */
441  entry = (TSConfigCacheEntry *)
443  (void *) &cfgId,
444  HASH_ENTER, &found);
445  Assert(!found); /* it wasn't there a moment ago */
446  }
447  else
448  {
449  /* Cleanup old contents */
450  if (entry->map)
451  {
452  for (i = 0; i < entry->lenmap; i++)
453  if (entry->map[i].dictIds)
454  pfree(entry->map[i].dictIds);
455  pfree(entry->map);
456  }
457  }
458 
459  MemSet(entry, 0, sizeof(TSConfigCacheEntry));
460  entry->cfgId = cfgId;
461  entry->prsId = cfg->cfgparser;
462 
463  ReleaseSysCache(tp);
464 
465  /*
466  * Scan pg_ts_config_map to gather dictionary list for each token type
467  *
468  * Because the index is on (mapcfg, maptokentype, mapseqno), we will
469  * see the entries in maptokentype order, and in mapseqno order for
470  * each token type, even though we didn't explicitly ask for that.
471  */
472  MemSet(maplists, 0, sizeof(maplists));
473  maxtokentype = 0;
474  ndicts = 0;
475 
476  ScanKeyInit(&mapskey,
477  Anum_pg_ts_config_map_mapcfg,
478  BTEqualStrategyNumber, F_OIDEQ,
479  ObjectIdGetDatum(cfgId));
480 
481  maprel = table_open(TSConfigMapRelationId, AccessShareLock);
482  mapidx = index_open(TSConfigMapIndexId, AccessShareLock);
483  mapscan = systable_beginscan_ordered(maprel, mapidx,
484  NULL, 1, &mapskey);
485 
486  while ((maptup = systable_getnext_ordered(mapscan, ForwardScanDirection)) != NULL)
487  {
489  int toktype = cfgmap->maptokentype;
490 
491  if (toktype <= 0 || toktype > MAXTOKENTYPE)
492  elog(ERROR, "maptokentype value %d is out of range", toktype);
493  if (toktype < maxtokentype)
494  elog(ERROR, "maptokentype entries are out of order");
495  if (toktype > maxtokentype)
496  {
497  /* starting a new token type, but first save the prior data */
498  if (ndicts > 0)
499  {
500  maplists[maxtokentype].len = ndicts;
501  maplists[maxtokentype].dictIds = (Oid *)
503  sizeof(Oid) * ndicts);
504  memcpy(maplists[maxtokentype].dictIds, mapdicts,
505  sizeof(Oid) * ndicts);
506  }
507  maxtokentype = toktype;
508  mapdicts[0] = cfgmap->mapdict;
509  ndicts = 1;
510  }
511  else
512  {
513  /* continuing data for current token type */
514  if (ndicts >= MAXDICTSPERTT)
515  elog(ERROR, "too many pg_ts_config_map entries for one token type");
516  mapdicts[ndicts++] = cfgmap->mapdict;
517  }
518  }
519 
520  systable_endscan_ordered(mapscan);
521  index_close(mapidx, AccessShareLock);
522  table_close(maprel, AccessShareLock);
523 
524  if (ndicts > 0)
525  {
526  /* save the last token type's dictionaries */
527  maplists[maxtokentype].len = ndicts;
528  maplists[maxtokentype].dictIds = (Oid *)
530  sizeof(Oid) * ndicts);
531  memcpy(maplists[maxtokentype].dictIds, mapdicts,
532  sizeof(Oid) * ndicts);
533  /* and save the overall map */
534  entry->lenmap = maxtokentype + 1;
535  entry->map = (ListDictionary *)
537  sizeof(ListDictionary) * entry->lenmap);
538  memcpy(entry->map, maplists,
539  sizeof(ListDictionary) * entry->lenmap);
540  }
541 
542  entry->isvalid = true;
543  }
544 
545  lastUsedConfig = entry;
546 
547  return entry;
548 }
#define MemSet(start, val, len)
Definition: c.h:953
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:953
SysScanDesc systable_beginscan_ordered(Relation heapRelation, Relation indexRelation, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:646
void systable_endscan_ordered(SysScanDesc sysscan)
Definition: genam.c:736
HeapTuple systable_getnext_ordered(SysScanDesc sysscan, ScanDirection direction)
Definition: genam.c:711
@ HASH_FIND
Definition: hsearch.h:113
@ HASH_ENTER
Definition: hsearch.h:114
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:158
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:132
int i
Definition: isn.c:73
Assert(fmt[strlen(fmt) - 1] !='\n')
#define AccessShareLock
Definition: lockdefs.h:36
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:994
FormData_pg_ts_config_map * Form_pg_ts_config_map
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
@ ForwardScanDirection
Definition: sdir.h:26
#define BTEqualStrategyNumber
Definition: stratnum.h:31
Oid * dictIds
Definition: ts_cache.h:68
ListDictionary * map
Definition: ts_cache.h:80
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
#define MAXTOKENTYPE
Definition: ts_cache.c:59
#define MAXDICTSPERTT
Definition: ts_cache.c:60
static TSConfigCacheEntry * lastUsedConfig
Definition: ts_cache.c:70

References AccessShareLock, Assert(), BTEqualStrategyNumber, CacheMemoryContext, TSConfigCacheEntry::cfgId, ListDictionary::dictIds, elog(), ERROR, ForwardScanDirection, GETSTRUCT, HASH_ENTER, HASH_FIND, hash_search(), HeapTupleIsValid, i, index_close(), index_open(), init_ts_config_cache(), TSConfigCacheEntry::isvalid, lastUsedConfig, ListDictionary::len, TSConfigCacheEntry::lenmap, TSConfigCacheEntry::map, MAXDICTSPERTT, MAXTOKENTYPE, MemoryContextAlloc(), MemSet, ObjectIdGetDatum(), OidIsValid, pfree(), TSConfigCacheEntry::prsId, ReleaseSysCache(), ScanKeyInit(), SearchSysCache1(), systable_beginscan_ordered(), systable_endscan_ordered(), systable_getnext_ordered(), table_close(), table_open(), TSConfigCacheHash, and TSCONFIGOID.

Referenced by hlparsetext(), parsetext(), ts_headline_byid_opt(), ts_headline_json_byid_opt(), and ts_headline_jsonb_byid_opt().

◆ lookup_ts_dictionary_cache()

TSDictionaryCacheEntry* lookup_ts_dictionary_cache ( Oid  dictId)

Definition at line 209 of file ts_cache.c.

210 {
211  TSDictionaryCacheEntry *entry;
212 
213  if (TSDictionaryCacheHash == NULL)
214  {
215  /* First time through: initialize the hash table */
216  HASHCTL ctl;
217 
218  ctl.keysize = sizeof(Oid);
219  ctl.entrysize = sizeof(TSDictionaryCacheEntry);
220  TSDictionaryCacheHash = hash_create("Tsearch dictionary cache", 8,
221  &ctl, HASH_ELEM | HASH_BLOBS);
222  /* Flush cache on pg_ts_dict and pg_ts_template changes */
227 
228  /* Also make sure CacheMemoryContext exists */
229  if (!CacheMemoryContext)
231  }
232 
233  /* Check single-entry cache */
234  if (lastUsedDictionary && lastUsedDictionary->dictId == dictId &&
236  return lastUsedDictionary;
237 
238  /* Try to look up an existing entry */
240  (void *) &dictId,
241  HASH_FIND, NULL);
242  if (entry == NULL || !entry->isvalid)
243  {
244  /*
245  * If we didn't find one, we want to make one. But first look up the
246  * object to be sure the OID is real.
247  */
248  HeapTuple tpdict,
249  tptmpl;
250  Form_pg_ts_dict dict;
251  Form_pg_ts_template template;
252  MemoryContext saveCtx;
253 
254  tpdict = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dictId));
255  if (!HeapTupleIsValid(tpdict))
256  elog(ERROR, "cache lookup failed for text search dictionary %u",
257  dictId);
258  dict = (Form_pg_ts_dict) GETSTRUCT(tpdict);
259 
260  /*
261  * Sanity checks
262  */
263  if (!OidIsValid(dict->dicttemplate))
264  elog(ERROR, "text search dictionary %u has no template", dictId);
265 
266  /*
267  * Retrieve dictionary's template
268  */
270  ObjectIdGetDatum(dict->dicttemplate));
271  if (!HeapTupleIsValid(tptmpl))
272  elog(ERROR, "cache lookup failed for text search template %u",
273  dict->dicttemplate);
274  template = (Form_pg_ts_template) GETSTRUCT(tptmpl);
275 
276  /*
277  * Sanity checks
278  */
279  if (!OidIsValid(template->tmpllexize))
280  elog(ERROR, "text search template %u has no lexize method",
281  template->tmpllexize);
282 
283  if (entry == NULL)
284  {
285  bool found;
286 
287  /* Now make the cache entry */
288  entry = (TSDictionaryCacheEntry *)
290  (void *) &dictId,
291  HASH_ENTER, &found);
292  Assert(!found); /* it wasn't there a moment ago */
293 
294  /* Create private memory context the first time through */
296  "TS dictionary",
298  MemoryContextCopyAndSetIdentifier(saveCtx, NameStr(dict->dictname));
299  }
300  else
301  {
302  /* Clear the existing entry's private context */
303  saveCtx = entry->dictCtx;
304  /* Don't let context's ident pointer dangle while we reset it */
305  MemoryContextSetIdentifier(saveCtx, NULL);
306  MemoryContextReset(saveCtx);
307  MemoryContextCopyAndSetIdentifier(saveCtx, NameStr(dict->dictname));
308  }
309 
310  MemSet(entry, 0, sizeof(TSDictionaryCacheEntry));
311  entry->dictId = dictId;
312  entry->dictCtx = saveCtx;
313 
314  entry->lexizeOid = template->tmpllexize;
315 
316  if (OidIsValid(template->tmplinit))
317  {
318  List *dictoptions;
319  Datum opt;
320  bool isnull;
321  MemoryContext oldcontext;
322 
323  /*
324  * Init method runs in dictionary's private memory context, and we
325  * make sure the options are stored there too
326  */
327  oldcontext = MemoryContextSwitchTo(entry->dictCtx);
328 
329  opt = SysCacheGetAttr(TSDICTOID, tpdict,
330  Anum_pg_ts_dict_dictinitoption,
331  &isnull);
332  if (isnull)
333  dictoptions = NIL;
334  else
335  dictoptions = deserialize_deflist(opt);
336 
337  entry->dictData =
338  DatumGetPointer(OidFunctionCall1(template->tmplinit,
339  PointerGetDatum(dictoptions)));
340 
341  MemoryContextSwitchTo(oldcontext);
342  }
343 
344  ReleaseSysCache(tptmpl);
345  ReleaseSysCache(tpdict);
346 
347  fmgr_info_cxt(entry->lexizeOid, &entry->lexize, entry->dictCtx);
348 
349  entry->isvalid = true;
350  }
351 
352  lastUsedDictionary = entry;
353 
354  return entry;
355 }
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:136
#define OidFunctionCall1(functionId, arg1)
Definition: fmgr.h:680
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:303
void MemoryContextSetIdentifier(MemoryContext context, const char *id)
Definition: mcxt.c:494
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:163
#define MemoryContextCopyAndSetIdentifier(cxt, id)
Definition: memutils.h:101
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:135
#define NIL
Definition: pg_list.h:66
FormData_pg_ts_dict * Form_pg_ts_dict
Definition: pg_ts_dict.h:52
FormData_pg_ts_template * Form_pg_ts_template
uintptr_t Datum
Definition: postgres.h:412
Definition: pg_list.h:52
MemoryContext dictCtx
Definition: ts_cache.h:61
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1434
@ TSTEMPLATEOID
Definition: syscache.h:112
@ TSDICTOID
Definition: syscache.h:108
static TSDictionaryCacheEntry * lastUsedDictionary
Definition: ts_cache.c:67
static HTAB * TSDictionaryCacheHash
Definition: ts_cache.c:66
struct TSDictionaryCacheEntry TSDictionaryCacheEntry
List * deserialize_deflist(Datum txt)
Definition: tsearchcmds.c:1584

References ALLOCSET_SMALL_SIZES, AllocSetContextCreate, Assert(), CacheMemoryContext, CacheRegisterSyscacheCallback(), CreateCacheMemoryContext(), DatumGetPointer(), deserialize_deflist(), TSDictionaryCacheEntry::dictCtx, TSDictionaryCacheEntry::dictData, TSDictionaryCacheEntry::dictId, elog(), HASHCTL::entrysize, ERROR, fmgr_info_cxt(), GETSTRUCT, HASH_BLOBS, hash_create(), HASH_ELEM, HASH_ENTER, HASH_FIND, hash_search(), HeapTupleIsValid, InvalidateTSCacheCallBack(), TSDictionaryCacheEntry::isvalid, HASHCTL::keysize, lastUsedDictionary, TSDictionaryCacheEntry::lexize, TSDictionaryCacheEntry::lexizeOid, MemoryContextCopyAndSetIdentifier, MemoryContextReset(), MemoryContextSetIdentifier(), MemoryContextSwitchTo(), MemSet, NameStr, NIL, ObjectIdGetDatum(), OidFunctionCall1, OidIsValid, PointerGetDatum(), ReleaseSysCache(), SearchSysCache1(), SysCacheGetAttr(), TSDictionaryCacheHash, TSDICTOID, and TSTEMPLATEOID.

Referenced by LexizeExec(), thesaurus_init(), thesaurus_lexize(), ts_lexize(), and unaccent_dict().

◆ lookup_ts_parser_cache()

TSParserCacheEntry* lookup_ts_parser_cache ( Oid  prsId)

Definition at line 112 of file ts_cache.c.

113 {
114  TSParserCacheEntry *entry;
115 
116  if (TSParserCacheHash == NULL)
117  {
118  /* First time through: initialize the hash table */
119  HASHCTL ctl;
120 
121  ctl.keysize = sizeof(Oid);
122  ctl.entrysize = sizeof(TSParserCacheEntry);
123  TSParserCacheHash = hash_create("Tsearch parser cache", 4,
124  &ctl, HASH_ELEM | HASH_BLOBS);
125  /* Flush cache on pg_ts_parser changes */
128 
129  /* Also make sure CacheMemoryContext exists */
130  if (!CacheMemoryContext)
132  }
133 
134  /* Check single-entry cache */
135  if (lastUsedParser && lastUsedParser->prsId == prsId &&
137  return lastUsedParser;
138 
139  /* Try to look up an existing entry */
141  (void *) &prsId,
142  HASH_FIND, NULL);
143  if (entry == NULL || !entry->isvalid)
144  {
145  /*
146  * If we didn't find one, we want to make one. But first look up the
147  * object to be sure the OID is real.
148  */
149  HeapTuple tp;
150  Form_pg_ts_parser prs;
151 
153  if (!HeapTupleIsValid(tp))
154  elog(ERROR, "cache lookup failed for text search parser %u",
155  prsId);
156  prs = (Form_pg_ts_parser) GETSTRUCT(tp);
157 
158  /*
159  * Sanity checks
160  */
161  if (!OidIsValid(prs->prsstart))
162  elog(ERROR, "text search parser %u has no prsstart method", prsId);
163  if (!OidIsValid(prs->prstoken))
164  elog(ERROR, "text search parser %u has no prstoken method", prsId);
165  if (!OidIsValid(prs->prsend))
166  elog(ERROR, "text search parser %u has no prsend method", prsId);
167 
168  if (entry == NULL)
169  {
170  bool found;
171 
172  /* Now make the cache entry */
173  entry = (TSParserCacheEntry *)
175  (void *) &prsId,
176  HASH_ENTER, &found);
177  Assert(!found); /* it wasn't there a moment ago */
178  }
179 
180  MemSet(entry, 0, sizeof(TSParserCacheEntry));
181  entry->prsId = prsId;
182  entry->startOid = prs->prsstart;
183  entry->tokenOid = prs->prstoken;
184  entry->endOid = prs->prsend;
185  entry->headlineOid = prs->prsheadline;
186  entry->lextypeOid = prs->prslextype;
187 
188  ReleaseSysCache(tp);
189 
192  fmgr_info_cxt(entry->endOid, &entry->prsend, CacheMemoryContext);
193  if (OidIsValid(entry->headlineOid))
194  fmgr_info_cxt(entry->headlineOid, &entry->prsheadline,
196 
197  entry->isvalid = true;
198  }
199 
200  lastUsedParser = entry;
201 
202  return entry;
203 }
FormData_pg_ts_parser * Form_pg_ts_parser
Definition: pg_ts_parser.h:55
FmgrInfo prstoken
Definition: ts_cache.h:46
FmgrInfo prsstart
Definition: ts_cache.h:45
FmgrInfo prsheadline
Definition: ts_cache.h:48
FmgrInfo prsend
Definition: ts_cache.h:47
@ TSPARSEROID
Definition: syscache.h:110
static TSParserCacheEntry * lastUsedParser
Definition: ts_cache.c:64
static HTAB * TSParserCacheHash
Definition: ts_cache.c:63
struct TSParserCacheEntry TSParserCacheEntry

References Assert(), CacheMemoryContext, CacheRegisterSyscacheCallback(), CreateCacheMemoryContext(), elog(), TSParserCacheEntry::endOid, HASHCTL::entrysize, ERROR, fmgr_info_cxt(), GETSTRUCT, HASH_BLOBS, hash_create(), HASH_ELEM, HASH_ENTER, HASH_FIND, hash_search(), TSParserCacheEntry::headlineOid, HeapTupleIsValid, InvalidateTSCacheCallBack(), TSParserCacheEntry::isvalid, HASHCTL::keysize, lastUsedParser, TSParserCacheEntry::lextypeOid, MemSet, ObjectIdGetDatum(), OidIsValid, PointerGetDatum(), TSParserCacheEntry::prsend, TSParserCacheEntry::prsheadline, TSParserCacheEntry::prsId, TSParserCacheEntry::prsstart, TSParserCacheEntry::prstoken, ReleaseSysCache(), SearchSysCache1(), TSParserCacheEntry::startOid, TSParserCacheEntry::tokenOid, TSParserCacheHash, and TSPARSEROID.

Referenced by getTokenTypes(), hlparsetext(), parsetext(), prs_setup_firstcall(), ts_headline_byid_opt(), ts_headline_json_byid_opt(), ts_headline_jsonb_byid_opt(), and tt_setup_firstcall().

Variable Documentation

◆ lastUsedConfig

TSConfigCacheEntry* lastUsedConfig = NULL
static

Definition at line 70 of file ts_cache.c.

Referenced by lookup_ts_config_cache().

◆ lastUsedDictionary

TSDictionaryCacheEntry* lastUsedDictionary = NULL
static

Definition at line 67 of file ts_cache.c.

Referenced by lookup_ts_dictionary_cache().

◆ lastUsedParser

TSParserCacheEntry* lastUsedParser = NULL
static

Definition at line 64 of file ts_cache.c.

Referenced by lookup_ts_parser_cache().

◆ TSConfigCacheHash

HTAB* TSConfigCacheHash = NULL
static

◆ TSCurrentConfig

char* TSCurrentConfig = NULL

Definition at line 75 of file ts_cache.c.

Referenced by getTSCurrentConfig().

◆ TSCurrentConfigCache

Oid TSCurrentConfigCache = InvalidOid
static

◆ TSDictionaryCacheHash

HTAB* TSDictionaryCacheHash = NULL
static

Definition at line 66 of file ts_cache.c.

Referenced by lookup_ts_dictionary_cache().

◆ TSParserCacheHash

HTAB* TSParserCacheHash = NULL
static

Definition at line 63 of file ts_cache.c.

Referenced by lookup_ts_parser_cache().