PostgreSQL Source Code  git master
ts_cache.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * ts_cache.c
4  * Tsearch related object caches.
5  *
6  * Tsearch performance is very sensitive to performance of parsers,
7  * dictionaries and mapping, so lookups should be cached as much
8  * as possible.
9  *
10  * Once a backend has created a cache entry for a particular TS object OID,
11  * the cache entry will exist for the life of the backend; hence it is
12  * safe to hold onto a pointer to the cache entry while doing things that
13  * might result in recognizing a cache invalidation. Beware however that
14  * subsidiary information might be deleted and reallocated somewhere else
15  * if a cache inval and reval happens! This does not look like it will be
16  * a big problem as long as parser and dictionary methods do not attempt
17  * any database access.
18  *
19  *
20  * Copyright (c) 2006-2020, PostgreSQL Global Development Group
21  *
22  * IDENTIFICATION
23  * src/backend/utils/cache/ts_cache.c
24  *
25  *-------------------------------------------------------------------------
26  */
27 #include "postgres.h"
28 
29 #include "access/genam.h"
30 #include "access/htup_details.h"
31 #include "access/table.h"
32 #include "access/xact.h"
33 #include "catalog/namespace.h"
34 #include "catalog/pg_ts_config.h"
36 #include "catalog/pg_ts_dict.h"
37 #include "catalog/pg_ts_parser.h"
38 #include "catalog/pg_ts_template.h"
39 #include "commands/defrem.h"
40 #include "miscadmin.h"
41 #include "tsearch/ts_cache.h"
42 #include "utils/builtins.h"
43 #include "utils/catcache.h"
44 #include "utils/fmgroids.h"
45 #include "utils/inval.h"
46 #include "utils/lsyscache.h"
47 #include "utils/memutils.h"
48 #include "utils/regproc.h"
49 #include "utils/syscache.h"
50 
51 
52 /*
53  * MAXTOKENTYPE/MAXDICTSPERTT are arbitrary limits on the workspace size
54  * used in lookup_ts_config_cache(). We could avoid hardwiring a limit
55  * by making the workspace dynamically enlargeable, but it seems unlikely
56  * to be worth the trouble.
57  */
58 #define MAXTOKENTYPE 256
59 #define MAXDICTSPERTT 100
60 
61 
62 static HTAB *TSParserCacheHash = NULL;
64 
65 static HTAB *TSDictionaryCacheHash = NULL;
67 
68 static HTAB *TSConfigCacheHash = NULL;
70 
71 /*
72  * GUC default_text_search_config, and a cache of the current config's OID
73  */
74 char *TSCurrentConfig = NULL;
75 
77 
78 
79 /*
80  * We use this syscache callback to detect when a visible change to a TS
81  * catalog entry has been made, by either our own backend or another one.
82  *
83  * In principle we could just flush the specific cache entry that changed,
84  * but given that TS configuration changes are probably infrequent, it
85  * doesn't seem worth the trouble to determine that; we just flush all the
86  * entries of the related hash table.
87  *
88  * We can use the same function for all TS caches by passing the hash
89  * table address as the "arg".
90  */
91 static void
92 InvalidateTSCacheCallBack(Datum arg, int cacheid, uint32 hashvalue)
93 {
94  HTAB *hash = (HTAB *) DatumGetPointer(arg);
96  TSAnyCacheEntry *entry;
97 
98  hash_seq_init(&status, hash);
99  while ((entry = (TSAnyCacheEntry *) hash_seq_search(&status)) != NULL)
100  entry->isvalid = false;
101 
102  /* Also invalidate the current-config cache if it's pg_ts_config */
103  if (hash == TSConfigCacheHash)
105 }
106 
107 /*
108  * Fetch parser cache entry
109  */
112 {
113  TSParserCacheEntry *entry;
114 
115  if (TSParserCacheHash == NULL)
116  {
117  /* First time through: initialize the hash table */
118  HASHCTL ctl;
119 
120  MemSet(&ctl, 0, sizeof(ctl));
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 */
127  PointerGetDatum(TSParserCacheHash));
128 
129  /* Also make sure CacheMemoryContext exists */
130  if (!CacheMemoryContext)
132  }
133 
134  /* Check single-entry cache */
135  if (lastUsedParser && lastUsedParser->prsId == prsId &&
136  lastUsedParser->isvalid)
137  return lastUsedParser;
138 
139  /* Try to look up an existing entry */
140  entry = (TSParserCacheEntry *) hash_search(TSParserCacheHash,
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 *)
174  hash_search(TSParserCacheHash,
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 }
204 
205 /*
206  * Fetch dictionary cache entry
207  */
210 {
211  TSDictionaryCacheEntry *entry;
212 
213  if (TSDictionaryCacheHash == NULL)
214  {
215  /* First time through: initialize the hash table */
216  HASHCTL ctl;
217 
218  MemSet(&ctl, 0, sizeof(ctl));
219  ctl.keysize = sizeof(Oid);
220  ctl.entrysize = sizeof(TSDictionaryCacheEntry);
221  TSDictionaryCacheHash = hash_create("Tsearch dictionary cache", 8,
222  &ctl, HASH_ELEM | HASH_BLOBS);
223  /* Flush cache on pg_ts_dict and pg_ts_template changes */
225  PointerGetDatum(TSDictionaryCacheHash));
227  PointerGetDatum(TSDictionaryCacheHash));
228 
229  /* Also make sure CacheMemoryContext exists */
230  if (!CacheMemoryContext)
232  }
233 
234  /* Check single-entry cache */
235  if (lastUsedDictionary && lastUsedDictionary->dictId == dictId &&
236  lastUsedDictionary->isvalid)
237  return lastUsedDictionary;
238 
239  /* Try to look up an existing entry */
240  entry = (TSDictionaryCacheEntry *) hash_search(TSDictionaryCacheHash,
241  (void *) &dictId,
242  HASH_FIND, NULL);
243  if (entry == NULL || !entry->isvalid)
244  {
245  /*
246  * If we didn't find one, we want to make one. But first look up the
247  * object to be sure the OID is real.
248  */
249  HeapTuple tpdict,
250  tptmpl;
251  Form_pg_ts_dict dict;
252  Form_pg_ts_template template;
253  MemoryContext saveCtx;
254 
255  tpdict = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dictId));
256  if (!HeapTupleIsValid(tpdict))
257  elog(ERROR, "cache lookup failed for text search dictionary %u",
258  dictId);
259  dict = (Form_pg_ts_dict) GETSTRUCT(tpdict);
260 
261  /*
262  * Sanity checks
263  */
264  if (!OidIsValid(dict->dicttemplate))
265  elog(ERROR, "text search dictionary %u has no template", dictId);
266 
267  /*
268  * Retrieve dictionary's template
269  */
271  ObjectIdGetDatum(dict->dicttemplate));
272  if (!HeapTupleIsValid(tptmpl))
273  elog(ERROR, "cache lookup failed for text search template %u",
274  dict->dicttemplate);
275  template = (Form_pg_ts_template) GETSTRUCT(tptmpl);
276 
277  /*
278  * Sanity checks
279  */
280  if (!OidIsValid(template->tmpllexize))
281  elog(ERROR, "text search template %u has no lexize method",
282  template->tmpllexize);
283 
284  if (entry == NULL)
285  {
286  bool found;
287 
288  /* Now make the cache entry */
289  entry = (TSDictionaryCacheEntry *)
290  hash_search(TSDictionaryCacheHash,
291  (void *) &dictId,
292  HASH_ENTER, &found);
293  Assert(!found); /* it wasn't there a moment ago */
294 
295  /* Create private memory context the first time through */
297  "TS dictionary",
299  MemoryContextCopyAndSetIdentifier(saveCtx, NameStr(dict->dictname));
300  }
301  else
302  {
303  /* Clear the existing entry's private context */
304  saveCtx = entry->dictCtx;
305  /* Don't let context's ident pointer dangle while we reset it */
306  MemoryContextSetIdentifier(saveCtx, NULL);
307  MemoryContextReset(saveCtx);
308  MemoryContextCopyAndSetIdentifier(saveCtx, NameStr(dict->dictname));
309  }
310 
311  MemSet(entry, 0, sizeof(TSDictionaryCacheEntry));
312  entry->dictId = dictId;
313  entry->dictCtx = saveCtx;
314 
315  entry->lexizeOid = template->tmpllexize;
316 
317  if (OidIsValid(template->tmplinit))
318  {
319  List *dictoptions;
320  Datum opt;
321  bool isnull;
322  MemoryContext oldcontext;
323 
324  /*
325  * Init method runs in dictionary's private memory context, and we
326  * make sure the options are stored there too
327  */
328  oldcontext = MemoryContextSwitchTo(entry->dictCtx);
329 
330  opt = SysCacheGetAttr(TSDICTOID, tpdict,
331  Anum_pg_ts_dict_dictinitoption,
332  &isnull);
333  if (isnull)
334  dictoptions = NIL;
335  else
336  dictoptions = deserialize_deflist(opt);
337 
338  entry->dictData =
339  DatumGetPointer(OidFunctionCall1(template->tmplinit,
340  PointerGetDatum(dictoptions)));
341 
342  MemoryContextSwitchTo(oldcontext);
343  }
344 
345  ReleaseSysCache(tptmpl);
346  ReleaseSysCache(tpdict);
347 
348  fmgr_info_cxt(entry->lexizeOid, &entry->lexize, entry->dictCtx);
349 
350  entry->isvalid = true;
351  }
352 
353  lastUsedDictionary = entry;
354 
355  return entry;
356 }
357 
358 /*
359  * Initialize config cache and prepare callbacks. This is split out of
360  * lookup_ts_config_cache because we need to activate the callback before
361  * caching TSCurrentConfigCache, too.
362  */
363 static void
365 {
366  HASHCTL ctl;
367 
368  MemSet(&ctl, 0, sizeof(ctl));
369  ctl.keysize = sizeof(Oid);
370  ctl.entrysize = sizeof(TSConfigCacheEntry);
371  TSConfigCacheHash = hash_create("Tsearch configuration cache", 16,
372  &ctl, HASH_ELEM | HASH_BLOBS);
373  /* Flush cache on pg_ts_config and pg_ts_config_map changes */
375  PointerGetDatum(TSConfigCacheHash));
377  PointerGetDatum(TSConfigCacheHash));
378 
379  /* Also make sure CacheMemoryContext exists */
380  if (!CacheMemoryContext)
382 }
383 
384 /*
385  * Fetch configuration cache entry
386  */
389 {
390  TSConfigCacheEntry *entry;
391 
392  if (TSConfigCacheHash == NULL)
393  {
394  /* First time through: initialize the hash table */
396  }
397 
398  /* Check single-entry cache */
399  if (lastUsedConfig && lastUsedConfig->cfgId == cfgId &&
400  lastUsedConfig->isvalid)
401  return lastUsedConfig;
402 
403  /* Try to look up an existing entry */
404  entry = (TSConfigCacheEntry *) hash_search(TSConfigCacheHash,
405  (void *) &cfgId,
406  HASH_FIND, NULL);
407  if (entry == NULL || !entry->isvalid)
408  {
409  /*
410  * If we didn't find one, we want to make one. But first look up the
411  * object to be sure the OID is real.
412  */
413  HeapTuple tp;
414  Form_pg_ts_config cfg;
415  Relation maprel;
416  Relation mapidx;
417  ScanKeyData mapskey;
418  SysScanDesc mapscan;
419  HeapTuple maptup;
420  ListDictionary maplists[MAXTOKENTYPE + 1];
421  Oid mapdicts[MAXDICTSPERTT];
422  int maxtokentype;
423  int ndicts;
424  int i;
425 
427  if (!HeapTupleIsValid(tp))
428  elog(ERROR, "cache lookup failed for text search configuration %u",
429  cfgId);
430  cfg = (Form_pg_ts_config) GETSTRUCT(tp);
431 
432  /*
433  * Sanity checks
434  */
435  if (!OidIsValid(cfg->cfgparser))
436  elog(ERROR, "text search configuration %u has no parser", cfgId);
437 
438  if (entry == NULL)
439  {
440  bool found;
441 
442  /* Now make the cache entry */
443  entry = (TSConfigCacheEntry *)
444  hash_search(TSConfigCacheHash,
445  (void *) &cfgId,
446  HASH_ENTER, &found);
447  Assert(!found); /* it wasn't there a moment ago */
448  }
449  else
450  {
451  /* Cleanup old contents */
452  if (entry->map)
453  {
454  for (i = 0; i < entry->lenmap; i++)
455  if (entry->map[i].dictIds)
456  pfree(entry->map[i].dictIds);
457  pfree(entry->map);
458  }
459  }
460 
461  MemSet(entry, 0, sizeof(TSConfigCacheEntry));
462  entry->cfgId = cfgId;
463  entry->prsId = cfg->cfgparser;
464 
465  ReleaseSysCache(tp);
466 
467  /*
468  * Scan pg_ts_config_map to gather dictionary list for each token type
469  *
470  * Because the index is on (mapcfg, maptokentype, mapseqno), we will
471  * see the entries in maptokentype order, and in mapseqno order for
472  * each token type, even though we didn't explicitly ask for that.
473  */
474  MemSet(maplists, 0, sizeof(maplists));
475  maxtokentype = 0;
476  ndicts = 0;
477 
478  ScanKeyInit(&mapskey,
479  Anum_pg_ts_config_map_mapcfg,
480  BTEqualStrategyNumber, F_OIDEQ,
481  ObjectIdGetDatum(cfgId));
482 
483  maprel = table_open(TSConfigMapRelationId, AccessShareLock);
485  mapscan = systable_beginscan_ordered(maprel, mapidx,
486  NULL, 1, &mapskey);
487 
488  while ((maptup = systable_getnext_ordered(mapscan, ForwardScanDirection)) != NULL)
489  {
491  int toktype = cfgmap->maptokentype;
492 
493  if (toktype <= 0 || toktype > MAXTOKENTYPE)
494  elog(ERROR, "maptokentype value %d is out of range", toktype);
495  if (toktype < maxtokentype)
496  elog(ERROR, "maptokentype entries are out of order");
497  if (toktype > maxtokentype)
498  {
499  /* starting a new token type, but first save the prior data */
500  if (ndicts > 0)
501  {
502  maplists[maxtokentype].len = ndicts;
503  maplists[maxtokentype].dictIds = (Oid *)
505  sizeof(Oid) * ndicts);
506  memcpy(maplists[maxtokentype].dictIds, mapdicts,
507  sizeof(Oid) * ndicts);
508  }
509  maxtokentype = toktype;
510  mapdicts[0] = cfgmap->mapdict;
511  ndicts = 1;
512  }
513  else
514  {
515  /* continuing data for current token type */
516  if (ndicts >= MAXDICTSPERTT)
517  elog(ERROR, "too many pg_ts_config_map entries for one token type");
518  mapdicts[ndicts++] = cfgmap->mapdict;
519  }
520  }
521 
522  systable_endscan_ordered(mapscan);
523  index_close(mapidx, AccessShareLock);
524  table_close(maprel, AccessShareLock);
525 
526  if (ndicts > 0)
527  {
528  /* save the last token type's dictionaries */
529  maplists[maxtokentype].len = ndicts;
530  maplists[maxtokentype].dictIds = (Oid *)
532  sizeof(Oid) * ndicts);
533  memcpy(maplists[maxtokentype].dictIds, mapdicts,
534  sizeof(Oid) * ndicts);
535  /* and save the overall map */
536  entry->lenmap = maxtokentype + 1;
537  entry->map = (ListDictionary *)
539  sizeof(ListDictionary) * entry->lenmap);
540  memcpy(entry->map, maplists,
541  sizeof(ListDictionary) * entry->lenmap);
542  }
543 
544  entry->isvalid = true;
545  }
546 
547  lastUsedConfig = entry;
548 
549  return entry;
550 }
551 
552 
553 /*---------------------------------------------------
554  * GUC variable "default_text_search_config"
555  *---------------------------------------------------
556  */
557 
558 Oid
559 getTSCurrentConfig(bool emitError)
560 {
561  /* if we have a cached value, return it */
563  return TSCurrentConfigCache;
564 
565  /* fail if GUC hasn't been set up yet */
566  if (TSCurrentConfig == NULL || *TSCurrentConfig == '\0')
567  {
568  if (emitError)
569  elog(ERROR, "text search configuration isn't set");
570  else
571  return InvalidOid;
572  }
573 
574  if (TSConfigCacheHash == NULL)
575  {
576  /* First time through: initialize the tsconfig inval callback */
578  }
579 
580  /* Look up the config */
583  !emitError);
584 
585  return TSCurrentConfigCache;
586 }
587 
588 /* GUC check_hook for default_text_search_config */
589 bool
591 {
592  /*
593  * If we aren't inside a transaction, or connected to a database, we
594  * cannot do the catalog accesses necessary to verify the config name.
595  * Must accept it on faith.
596  */
598  {
599  Oid cfgId;
600  HeapTuple tuple;
601  Form_pg_ts_config cfg;
602  char *buf;
603 
604  cfgId = get_ts_config_oid(stringToQualifiedNameList(*newval), true);
605 
606  /*
607  * When source == PGC_S_TEST, don't throw a hard error for a
608  * nonexistent configuration, only a NOTICE. See comments in guc.h.
609  */
610  if (!OidIsValid(cfgId))
611  {
612  if (source == PGC_S_TEST)
613  {
614  ereport(NOTICE,
615  (errcode(ERRCODE_UNDEFINED_OBJECT),
616  errmsg("text search configuration \"%s\" does not exist", *newval)));
617  return true;
618  }
619  else
620  return false;
621  }
622 
623  /*
624  * Modify the actually stored value to be fully qualified, to ensure
625  * later changes of search_path don't affect it.
626  */
628  if (!HeapTupleIsValid(tuple))
629  elog(ERROR, "cache lookup failed for text search configuration %u",
630  cfgId);
631  cfg = (Form_pg_ts_config) GETSTRUCT(tuple);
632 
633  buf = quote_qualified_identifier(get_namespace_name(cfg->cfgnamespace),
634  NameStr(cfg->cfgname));
635 
636  ReleaseSysCache(tuple);
637 
638  /* GUC wants it malloc'd not palloc'd */
639  free(*newval);
640  *newval = strdup(buf);
641  pfree(buf);
642  if (!*newval)
643  return false;
644  }
645 
646  return true;
647 }
648 
649 /* GUC assign_hook for default_text_search_config */
650 void
651 assign_TSCurrentConfig(const char *newval, void *extra)
652 {
653  /* Just reset the cache to force a lookup on first use */
655 }
#define NIL
Definition: pg_list.h:65
#define AllocSetContextCreate
Definition: memutils.h:170
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define MAXDICTSPERTT
Definition: ts_cache.c:59
#define HASH_ELEM
Definition: hsearch.h:85
FormData_pg_ts_config * Form_pg_ts_config
Definition: pg_ts_config.h:48
Oid getTSCurrentConfig(bool emitError)
Definition: ts_cache.c:559
FormData_pg_ts_config_map * Form_pg_ts_config_map
#define PointerGetDatum(X)
Definition: postgres.h:556
static TSDictionaryCacheEntry * lastUsedDictionary
Definition: ts_cache.c:66
List * deserialize_deflist(Datum txt)
Definition: tsearchcmds.c:1510
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:202
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define AccessShareLock
Definition: lockdefs.h:36
Size entrysize
Definition: hsearch.h:72
int errcode(int sqlerrcode)
Definition: elog.c:691
Oid get_ts_config_oid(List *names, bool missing_ok)
Definition: namespace.c:2678
#define MemSet(start, val, len)
Definition: c.h:1004
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:137
TSParserCacheEntry * lookup_ts_parser_cache(Oid prsId)
Definition: ts_cache.c:111
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:919
HeapTuple systable_getnext_ordered(SysScanDesc sysscan, ScanDirection direction)
Definition: genam.c:681
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:706
char * TSCurrentConfig
Definition: ts_cache.c:74
TSDictionaryCacheEntry * lookup_ts_dictionary_cache(Oid dictId)
Definition: ts_cache.c:209
GucSource
Definition: guc.h:105
static Oid TSCurrentConfigCache
Definition: ts_cache.c:76
Definition: dynahash.c:218
void pfree(void *pointer)
Definition: mcxt.c:1057
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
FmgrInfo prsend
Definition: ts_cache.h:47
TSConfigCacheEntry * lookup_ts_config_cache(Oid cfgId)
Definition: ts_cache.c:388
#define OidFunctionCall1(functionId, arg1)
Definition: fmgr.h:664
FormData_pg_ts_dict * Form_pg_ts_dict
Definition: pg_ts_dict.h:52
static HTAB * TSParserCacheHash
Definition: ts_cache.c:62
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3196
#define MemoryContextCopyAndSetIdentifier(cxt, id)
Definition: memutils.h:97
static char * buf
Definition: pg_test_fsync.c:68
#define MAXTOKENTYPE
Definition: ts_cache.c:58
Oid * dictIds
Definition: ts_cache.h:68
ListDictionary * map
Definition: ts_cache.h:80
unsigned int uint32
Definition: c.h:429
void assign_TSCurrentConfig(const char *newval, void *extra)
Definition: ts_cache.c:651
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:136
static void InvalidateTSCacheCallBack(Datum arg, int cacheid, uint32 hashvalue)
Definition: ts_cache.c:92
char * quote_qualified_identifier(const char *qualifier, const char *ident)
Definition: ruleutils.c:11018
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1115
#define HASH_BLOBS
Definition: hsearch.h:86
void CacheRegisterSyscacheCallback(int cacheid, SyscacheCallbackFunction func, Datum arg)
Definition: inval.c:1434
HTAB * hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)
Definition: dynahash.c:326
uintptr_t Datum
Definition: postgres.h:367
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1163
FormData_pg_ts_parser * Form_pg_ts_parser
Definition: pg_ts_parser.h:55
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1376
Oid MyDatabaseId
Definition: globals.c:85
void systable_endscan_ordered(SysScanDesc sysscan)
Definition: genam.c:706
Size keysize
Definition: hsearch.h:71
#define InvalidOid
Definition: postgres_ext.h:36
static void init_ts_config_cache(void)
Definition: ts_cache.c:364
#define ereport(elevel,...)
Definition: elog.h:155
#define TSConfigMapIndexId
static TSParserCacheEntry * lastUsedParser
Definition: ts_cache.c:63
#define NOTICE
Definition: elog.h:37
#define free(a)
Definition: header.h:65
static HTAB * TSConfigCacheHash
Definition: ts_cache.c:68
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:800
FmgrInfo prstoken
Definition: ts_cache.h:46
static rewind_source * source
Definition: pg_rewind.c:79
void CreateCacheMemoryContext(void)
Definition: catcache.c:620
#define newval
bool IsTransactionState(void)
Definition: xact.c:371
void MemoryContextSetIdentifier(MemoryContext context, const char *id)
Definition: mcxt.c:330
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1401
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1391
static TSConfigCacheEntry * lastUsedConfig
Definition: ts_cache.c:69
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:158
#define DatumGetPointer(X)
Definition: postgres.h:549
FmgrInfo prsstart
Definition: ts_cache.h:45
List * stringToQualifiedNameList(const char *string)
Definition: regproc.c:1876
int errmsg(const char *fmt,...)
Definition: elog.c:902
SysScanDesc systable_beginscan_ordered(Relation heapRelation, Relation indexRelation, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:616
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:797
FormData_pg_ts_template * Form_pg_ts_template
#define elog(elevel,...)
Definition: elog.h:228
struct TSParserCacheEntry TSParserCacheEntry
int i
#define NameStr(name)
Definition: c.h:677
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
static HTAB * TSDictionaryCacheHash
Definition: ts_cache.c:65
void * arg
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:227
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
struct TSDictionaryCacheEntry TSDictionaryCacheEntry
Definition: pg_list.h:50
static unsigned hash(unsigned *uv, int n)
Definition: rege_dfa.c:541
bool check_TSCurrentConfig(char **newval, void **extra, GucSource source)
Definition: ts_cache.c:590
MemoryContext dictCtx
Definition: ts_cache.h:61
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:132
#define BTEqualStrategyNumber
Definition: stratnum.h:31
MemoryContext CacheMemoryContext
Definition: mcxt.c:47
FmgrInfo prsheadline
Definition: ts_cache.h:48