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-2018, 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/heapam.h"
31 #include "access/htup_details.h"
32 #include "access/xact.h"
33 #include "catalog/indexing.h"
34 #include "catalog/namespace.h"
35 #include "catalog/pg_ts_config.h"
37 #include "catalog/pg_ts_dict.h"
38 #include "catalog/pg_ts_parser.h"
39 #include "catalog/pg_ts_template.h"
40 #include "commands/defrem.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 #include "utils/tqual.h"
51 
52 
53 /*
54  * MAXTOKENTYPE/MAXDICTSPERTT are arbitrary limits on the workspace size
55  * used in lookup_ts_config_cache(). We could avoid hardwiring a limit
56  * by making the workspace dynamically enlargeable, but it seems unlikely
57  * to be worth the trouble.
58  */
59 #define MAXTOKENTYPE 256
60 #define MAXDICTSPERTT 100
61 
62 
63 static HTAB *TSParserCacheHash = NULL;
65 
66 static HTAB *TSDictionaryCacheHash = NULL;
68 
69 static HTAB *TSConfigCacheHash = NULL;
71 
72 /*
73  * GUC default_text_search_config, and a cache of the current config's OID
74  */
75 char *TSCurrentConfig = NULL;
76 
78 
79 
80 /*
81  * We use this syscache callback to detect when a visible change to a TS
82  * catalog entry has been made, by either our own backend or another one.
83  *
84  * In principle we could just flush the specific cache entry that changed,
85  * but given that TS configuration changes are probably infrequent, it
86  * doesn't seem worth the trouble to determine that; we just flush all the
87  * entries of the related hash table.
88  *
89  * We can use the same function for all TS caches by passing the hash
90  * table address as the "arg".
91  */
92 static void
93 InvalidateTSCacheCallBack(Datum arg, int cacheid, uint32 hashvalue)
94 {
95  HTAB *hash = (HTAB *) DatumGetPointer(arg);
97  TSAnyCacheEntry *entry;
98 
99  hash_seq_init(&status, hash);
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 }
107 
108 /*
109  * Fetch parser cache entry
110  */
113 {
114  TSParserCacheEntry *entry;
115 
116  if (TSParserCacheHash == NULL)
117  {
118  /* First time through: initialize the hash table */
119  HASHCTL ctl;
120 
121  MemSet(&ctl, 0, sizeof(ctl));
122  ctl.keysize = sizeof(Oid);
123  ctl.entrysize = sizeof(TSParserCacheEntry);
124  TSParserCacheHash = hash_create("Tsearch parser cache", 4,
125  &ctl, HASH_ELEM | HASH_BLOBS);
126  /* Flush cache on pg_ts_parser changes */
128  PointerGetDatum(TSParserCacheHash));
129 
130  /* Also make sure CacheMemoryContext exists */
131  if (!CacheMemoryContext)
133  }
134 
135  /* Check single-entry cache */
136  if (lastUsedParser && lastUsedParser->prsId == prsId &&
137  lastUsedParser->isvalid)
138  return lastUsedParser;
139 
140  /* Try to look up an existing entry */
141  entry = (TSParserCacheEntry *) hash_search(TSParserCacheHash,
142  (void *) &prsId,
143  HASH_FIND, NULL);
144  if (entry == NULL || !entry->isvalid)
145  {
146  /*
147  * If we didn't find one, we want to make one. But first look up the
148  * object to be sure the OID is real.
149  */
150  HeapTuple tp;
151  Form_pg_ts_parser prs;
152 
154  if (!HeapTupleIsValid(tp))
155  elog(ERROR, "cache lookup failed for text search parser %u",
156  prsId);
157  prs = (Form_pg_ts_parser) GETSTRUCT(tp);
158 
159  /*
160  * Sanity checks
161  */
162  if (!OidIsValid(prs->prsstart))
163  elog(ERROR, "text search parser %u has no prsstart method", prsId);
164  if (!OidIsValid(prs->prstoken))
165  elog(ERROR, "text search parser %u has no prstoken method", prsId);
166  if (!OidIsValid(prs->prsend))
167  elog(ERROR, "text search parser %u has no prsend method", prsId);
168 
169  if (entry == NULL)
170  {
171  bool found;
172 
173  /* Now make the cache entry */
174  entry = (TSParserCacheEntry *)
175  hash_search(TSParserCacheHash,
176  (void *) &prsId,
177  HASH_ENTER, &found);
178  Assert(!found); /* it wasn't there a moment ago */
179  }
180 
181  MemSet(entry, 0, sizeof(TSParserCacheEntry));
182  entry->prsId = prsId;
183  entry->startOid = prs->prsstart;
184  entry->tokenOid = prs->prstoken;
185  entry->endOid = prs->prsend;
186  entry->headlineOid = prs->prsheadline;
187  entry->lextypeOid = prs->prslextype;
188 
189  ReleaseSysCache(tp);
190 
193  fmgr_info_cxt(entry->endOid, &entry->prsend, CacheMemoryContext);
194  if (OidIsValid(entry->headlineOid))
195  fmgr_info_cxt(entry->headlineOid, &entry->prsheadline,
197 
198  entry->isvalid = true;
199  }
200 
201  lastUsedParser = entry;
202 
203  return entry;
204 }
205 
206 /*
207  * Fetch dictionary cache entry
208  */
211 {
212  TSDictionaryCacheEntry *entry;
213 
214  if (TSDictionaryCacheHash == NULL)
215  {
216  /* First time through: initialize the hash table */
217  HASHCTL ctl;
218 
219  MemSet(&ctl, 0, sizeof(ctl));
220  ctl.keysize = sizeof(Oid);
221  ctl.entrysize = sizeof(TSDictionaryCacheEntry);
222  TSDictionaryCacheHash = hash_create("Tsearch dictionary cache", 8,
223  &ctl, HASH_ELEM | HASH_BLOBS);
224  /* Flush cache on pg_ts_dict and pg_ts_template changes */
226  PointerGetDatum(TSDictionaryCacheHash));
228  PointerGetDatum(TSDictionaryCacheHash));
229 
230  /* Also make sure CacheMemoryContext exists */
231  if (!CacheMemoryContext)
233  }
234 
235  /* Check single-entry cache */
236  if (lastUsedDictionary && lastUsedDictionary->dictId == dictId &&
237  lastUsedDictionary->isvalid)
238  return lastUsedDictionary;
239 
240  /* Try to look up an existing entry */
241  entry = (TSDictionaryCacheEntry *) hash_search(TSDictionaryCacheHash,
242  (void *) &dictId,
243  HASH_FIND, NULL);
244  if (entry == NULL || !entry->isvalid)
245  {
246  /*
247  * If we didn't find one, we want to make one. But first look up the
248  * object to be sure the OID is real.
249  */
250  HeapTuple tpdict,
251  tptmpl;
252  Form_pg_ts_dict dict;
253  Form_pg_ts_template template;
254  MemoryContext saveCtx;
255 
256  tpdict = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dictId));
257  if (!HeapTupleIsValid(tpdict))
258  elog(ERROR, "cache lookup failed for text search dictionary %u",
259  dictId);
260  dict = (Form_pg_ts_dict) GETSTRUCT(tpdict);
261 
262  /*
263  * Sanity checks
264  */
265  if (!OidIsValid(dict->dicttemplate))
266  elog(ERROR, "text search dictionary %u has no template", dictId);
267 
268  /*
269  * Retrieve dictionary's template
270  */
272  ObjectIdGetDatum(dict->dicttemplate));
273  if (!HeapTupleIsValid(tptmpl))
274  elog(ERROR, "cache lookup failed for text search template %u",
275  dict->dicttemplate);
276  template = (Form_pg_ts_template) GETSTRUCT(tptmpl);
277 
278  /*
279  * Sanity checks
280  */
281  if (!OidIsValid(template->tmpllexize))
282  elog(ERROR, "text search template %u has no lexize method",
283  template->tmpllexize);
284 
285  if (entry == NULL)
286  {
287  bool found;
288 
289  /* Now make the cache entry */
290  entry = (TSDictionaryCacheEntry *)
291  hash_search(TSDictionaryCacheHash,
292  (void *) &dictId,
293  HASH_ENTER, &found);
294  Assert(!found); /* it wasn't there a moment ago */
295 
296  /* Create private memory context the first time through */
298  "TS dictionary",
300  MemoryContextCopyAndSetIdentifier(saveCtx, NameStr(dict->dictname));
301  }
302  else
303  {
304  /* Clear the existing entry's private context */
305  saveCtx = entry->dictCtx;
306  /* Don't let context's ident pointer dangle while we reset it */
307  MemoryContextSetIdentifier(saveCtx, NULL);
308  MemoryContextReset(saveCtx);
309  MemoryContextCopyAndSetIdentifier(saveCtx, NameStr(dict->dictname));
310  }
311 
312  MemSet(entry, 0, sizeof(TSDictionaryCacheEntry));
313  entry->dictId = dictId;
314  entry->dictCtx = saveCtx;
315 
316  entry->lexizeOid = template->tmpllexize;
317 
318  if (OidIsValid(template->tmplinit))
319  {
320  List *dictoptions;
321  Datum opt;
322  bool isnull;
323  MemoryContext oldcontext;
324 
325  /*
326  * Init method runs in dictionary's private memory context, and we
327  * make sure the options are stored there too
328  */
329  oldcontext = MemoryContextSwitchTo(entry->dictCtx);
330 
331  opt = SysCacheGetAttr(TSDICTOID, tpdict,
332  Anum_pg_ts_dict_dictinitoption,
333  &isnull);
334  if (isnull)
335  dictoptions = NIL;
336  else
337  dictoptions = deserialize_deflist(opt);
338 
339  entry->dictData =
340  DatumGetPointer(OidFunctionCall1(template->tmplinit,
341  PointerGetDatum(dictoptions)));
342 
343  MemoryContextSwitchTo(oldcontext);
344  }
345 
346  ReleaseSysCache(tptmpl);
347  ReleaseSysCache(tpdict);
348 
349  fmgr_info_cxt(entry->lexizeOid, &entry->lexize, entry->dictCtx);
350 
351  entry->isvalid = true;
352  }
353 
354  lastUsedDictionary = entry;
355 
356  return entry;
357 }
358 
359 /*
360  * Initialize config cache and prepare callbacks. This is split out of
361  * lookup_ts_config_cache because we need to activate the callback before
362  * caching TSCurrentConfigCache, too.
363  */
364 static void
366 {
367  HASHCTL ctl;
368 
369  MemSet(&ctl, 0, sizeof(ctl));
370  ctl.keysize = sizeof(Oid);
371  ctl.entrysize = sizeof(TSConfigCacheEntry);
372  TSConfigCacheHash = hash_create("Tsearch configuration cache", 16,
373  &ctl, HASH_ELEM | HASH_BLOBS);
374  /* Flush cache on pg_ts_config and pg_ts_config_map changes */
376  PointerGetDatum(TSConfigCacheHash));
378  PointerGetDatum(TSConfigCacheHash));
379 
380  /* Also make sure CacheMemoryContext exists */
381  if (!CacheMemoryContext)
383 }
384 
385 /*
386  * Fetch configuration cache entry
387  */
390 {
391  TSConfigCacheEntry *entry;
392 
393  if (TSConfigCacheHash == NULL)
394  {
395  /* First time through: initialize the hash table */
397  }
398 
399  /* Check single-entry cache */
400  if (lastUsedConfig && lastUsedConfig->cfgId == cfgId &&
401  lastUsedConfig->isvalid)
402  return lastUsedConfig;
403 
404  /* Try to look up an existing entry */
405  entry = (TSConfigCacheEntry *) hash_search(TSConfigCacheHash,
406  (void *) &cfgId,
407  HASH_FIND, NULL);
408  if (entry == NULL || !entry->isvalid)
409  {
410  /*
411  * If we didn't find one, we want to make one. But first look up the
412  * object to be sure the OID is real.
413  */
414  HeapTuple tp;
415  Form_pg_ts_config cfg;
416  Relation maprel;
417  Relation mapidx;
418  ScanKeyData mapskey;
419  SysScanDesc mapscan;
420  HeapTuple maptup;
421  ListDictionary maplists[MAXTOKENTYPE + 1];
422  Oid mapdicts[MAXDICTSPERTT];
423  int maxtokentype;
424  int ndicts;
425  int i;
426 
428  if (!HeapTupleIsValid(tp))
429  elog(ERROR, "cache lookup failed for text search configuration %u",
430  cfgId);
431  cfg = (Form_pg_ts_config) GETSTRUCT(tp);
432 
433  /*
434  * Sanity checks
435  */
436  if (!OidIsValid(cfg->cfgparser))
437  elog(ERROR, "text search configuration %u has no parser", cfgId);
438 
439  if (entry == NULL)
440  {
441  bool found;
442 
443  /* Now make the cache entry */
444  entry = (TSConfigCacheEntry *)
445  hash_search(TSConfigCacheHash,
446  (void *) &cfgId,
447  HASH_ENTER, &found);
448  Assert(!found); /* it wasn't there a moment ago */
449  }
450  else
451  {
452  /* Cleanup old contents */
453  if (entry->map)
454  {
455  for (i = 0; i < entry->lenmap; i++)
456  if (entry->map[i].dictIds)
457  pfree(entry->map[i].dictIds);
458  pfree(entry->map);
459  }
460  }
461 
462  MemSet(entry, 0, sizeof(TSConfigCacheEntry));
463  entry->cfgId = cfgId;
464  entry->prsId = cfg->cfgparser;
465 
466  ReleaseSysCache(tp);
467 
468  /*
469  * Scan pg_ts_config_map to gather dictionary list for each token type
470  *
471  * Because the index is on (mapcfg, maptokentype, mapseqno), we will
472  * see the entries in maptokentype order, and in mapseqno order for
473  * each token type, even though we didn't explicitly ask for that.
474  */
475  MemSet(maplists, 0, sizeof(maplists));
476  maxtokentype = 0;
477  ndicts = 0;
478 
479  ScanKeyInit(&mapskey,
480  Anum_pg_ts_config_map_mapcfg,
481  BTEqualStrategyNumber, F_OIDEQ,
482  ObjectIdGetDatum(cfgId));
483 
484  maprel = heap_open(TSConfigMapRelationId, AccessShareLock);
486  mapscan = systable_beginscan_ordered(maprel, mapidx,
487  NULL, 1, &mapskey);
488 
489  while ((maptup = systable_getnext_ordered(mapscan, ForwardScanDirection)) != NULL)
490  {
492  int toktype = cfgmap->maptokentype;
493 
494  if (toktype <= 0 || toktype > MAXTOKENTYPE)
495  elog(ERROR, "maptokentype value %d is out of range", toktype);
496  if (toktype < maxtokentype)
497  elog(ERROR, "maptokentype entries are out of order");
498  if (toktype > maxtokentype)
499  {
500  /* starting a new token type, but first save the prior data */
501  if (ndicts > 0)
502  {
503  maplists[maxtokentype].len = ndicts;
504  maplists[maxtokentype].dictIds = (Oid *)
506  sizeof(Oid) * ndicts);
507  memcpy(maplists[maxtokentype].dictIds, mapdicts,
508  sizeof(Oid) * ndicts);
509  }
510  maxtokentype = toktype;
511  mapdicts[0] = cfgmap->mapdict;
512  ndicts = 1;
513  }
514  else
515  {
516  /* continuing data for current token type */
517  if (ndicts >= MAXDICTSPERTT)
518  elog(ERROR, "too many pg_ts_config_map entries for one token type");
519  mapdicts[ndicts++] = cfgmap->mapdict;
520  }
521  }
522 
523  systable_endscan_ordered(mapscan);
524  index_close(mapidx, AccessShareLock);
525  heap_close(maprel, AccessShareLock);
526 
527  if (ndicts > 0)
528  {
529  /* save the last token type's dictionaries */
530  maplists[maxtokentype].len = ndicts;
531  maplists[maxtokentype].dictIds = (Oid *)
533  sizeof(Oid) * ndicts);
534  memcpy(maplists[maxtokentype].dictIds, mapdicts,
535  sizeof(Oid) * ndicts);
536  /* and save the overall map */
537  entry->lenmap = maxtokentype + 1;
538  entry->map = (ListDictionary *)
540  sizeof(ListDictionary) * entry->lenmap);
541  memcpy(entry->map, maplists,
542  sizeof(ListDictionary) * entry->lenmap);
543  }
544 
545  entry->isvalid = true;
546  }
547 
548  lastUsedConfig = entry;
549 
550  return entry;
551 }
552 
553 
554 /*---------------------------------------------------
555  * GUC variable "default_text_search_config"
556  *---------------------------------------------------
557  */
558 
559 Oid
560 getTSCurrentConfig(bool emitError)
561 {
562  /* if we have a cached value, return it */
564  return TSCurrentConfigCache;
565 
566  /* fail if GUC hasn't been set up yet */
567  if (TSCurrentConfig == NULL || *TSCurrentConfig == '\0')
568  {
569  if (emitError)
570  elog(ERROR, "text search configuration isn't set");
571  else
572  return InvalidOid;
573  }
574 
575  if (TSConfigCacheHash == NULL)
576  {
577  /* First time through: initialize the tsconfig inval callback */
579  }
580 
581  /* Look up the config */
584  !emitError);
585 
586  return TSCurrentConfigCache;
587 }
588 
589 /* GUC check_hook for default_text_search_config */
590 bool
591 check_TSCurrentConfig(char **newval, void **extra, GucSource source)
592 {
593  /*
594  * If we aren't inside a transaction, we cannot do database access so
595  * cannot verify the config name. Must accept it on faith.
596  */
597  if (IsTransactionState())
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:69
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
#define MAXDICTSPERTT
Definition: ts_cache.c:60
#define HASH_ELEM
Definition: hsearch.h:87
FormData_pg_ts_config * Form_pg_ts_config
Definition: pg_ts_config.h:38
Oid getTSCurrentConfig(bool emitError)
Definition: ts_cache.c:560
FormData_pg_ts_config_map * Form_pg_ts_config_map
#define PointerGetDatum(X)
Definition: postgres.h:539
static TSDictionaryCacheEntry * lastUsedDictionary
Definition: ts_cache.c:67
List * deserialize_deflist(Datum txt)
Definition: tsearchcmds.c:1561
#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:73
int errcode(int sqlerrcode)
Definition: elog.c:575
Oid get_ts_config_oid(List *names, bool missing_ok)
Definition: namespace.c:2658
#define MemSet(start, val, len)
Definition: c.h:908
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:136
TSParserCacheEntry * lookup_ts_parser_cache(Oid prsId)
Definition: ts_cache.c:112
#define heap_close(r, l)
Definition: heapam.h:97
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:906
HeapTuple systable_getnext_ordered(SysScanDesc sysscan, ScanDirection direction)
Definition: genam.c:600
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:605
char * TSCurrentConfig
Definition: ts_cache.c:75
TSDictionaryCacheEntry * lookup_ts_dictionary_cache(Oid dictId)
Definition: ts_cache.c:210
GucSource
Definition: guc.h:105
static Oid TSCurrentConfigCache
Definition: ts_cache.c:77
Definition: dynahash.c:208
void pfree(void *pointer)
Definition: mcxt.c:1031
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
FmgrInfo prsend
Definition: ts_cache.h:47
TSConfigCacheEntry * lookup_ts_config_cache(Oid cfgId)
Definition: ts_cache.c:389
#define OidFunctionCall1(functionId, arg1)
Definition: fmgr.h:628
FormData_pg_ts_dict * Form_pg_ts_dict
Definition: pg_ts_dict.h:41
static HTAB * TSParserCacheHash
Definition: ts_cache.c:63
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3051
#define MemoryContextCopyAndSetIdentifier(cxt, id)
Definition: memutils.h:96
static char * buf
Definition: pg_test_fsync.c:67
#define MAXTOKENTYPE
Definition: ts_cache.c:59
Oid * dictIds
Definition: ts_cache.h:68
ListDictionary * map
Definition: ts_cache.h:80
unsigned int uint32
Definition: c.h:325
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:133
static void InvalidateTSCacheCallBack(Datum arg, int cacheid, uint32 hashvalue)
Definition: ts_cache.c:93
#define ereport(elevel, rest)
Definition: elog.h:122
#define AllocSetContextCreate(parent, name, allocparams)
Definition: memutils.h:170
char * quote_qualified_identifier(const char *qualifier, const char *ident)
Definition: ruleutils.c:10574
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
#define HASH_BLOBS
Definition: hsearch.h:88
void CacheRegisterSyscacheCallback(int cacheid, SyscacheCallbackFunction func, Datum arg)
Definition: inval.c:1389
HTAB * hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)
Definition: dynahash.c:316
uintptr_t Datum
Definition: postgres.h:365
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
FormData_pg_ts_parser * Form_pg_ts_parser
Definition: pg_ts_parser.h:53
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1368
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
void systable_endscan_ordered(SysScanDesc sysscan)
Definition: genam.c:617
Size keysize
Definition: hsearch.h:72
#define InvalidOid
Definition: postgres_ext.h:36
static void init_ts_config_cache(void)
Definition: ts_cache.c:365
static TSParserCacheEntry * lastUsedParser
Definition: ts_cache.c:64
#define NOTICE
Definition: elog.h:37
#define free(a)
Definition: header.h:65
static HTAB * TSConfigCacheHash
Definition: ts_cache.c:69
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:699
FmgrInfo prstoken
Definition: ts_cache.h:46
void CreateCacheMemoryContext(void)
Definition: catcache.c:636
#define newval
bool IsTransactionState(void)
Definition: xact.c:350
void MemoryContextSetIdentifier(MemoryContext context, const char *id)
Definition: mcxt.c:329
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1389
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1379
static TSConfigCacheEntry * lastUsedConfig
Definition: ts_cache.c:70
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:176
#define DatumGetPointer(X)
Definition: postgres.h:532
FmgrInfo prsstart
Definition: ts_cache.h:45
List * stringToQualifiedNameList(const char *string)
Definition: regproc.c:1687
int errmsg(const char *fmt,...)
Definition: elog.c:797
SysScanDesc systable_beginscan_ordered(Relation heapRelation, Relation indexRelation, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:536
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:771
FormData_pg_ts_template * Form_pg_ts_template
struct TSParserCacheEntry TSParserCacheEntry
int i
#define NameStr(name)
Definition: c.h:576
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
static HTAB * TSDictionaryCacheHash
Definition: ts_cache.c:66
#define TSConfigMapIndexId
Definition: indexing.h:266
void * arg
#define elog
Definition: elog.h:219
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:225
struct TSDictionaryCacheEntry TSDictionaryCacheEntry
Definition: pg_list.h:45
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:591
MemoryContext dictCtx
Definition: ts_cache.h:61
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:150
#define BTEqualStrategyNumber
Definition: stratnum.h:31
MemoryContext CacheMemoryContext
Definition: mcxt.c:47
FmgrInfo prsheadline
Definition: ts_cache.h:48