PostgreSQL Source Code  git master
typcache.h File Reference
#include "access/tupdesc.h"
#include "fmgr.h"
#include "storage/dsm.h"
#include "utils/dsa.h"
Include dependency graph for typcache.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  TypeCacheEntry
 
struct  DomainConstraintRef
 

Macros

#define TYPECACHE_EQ_OPR   0x00001
 
#define TYPECACHE_LT_OPR   0x00002
 
#define TYPECACHE_GT_OPR   0x00004
 
#define TYPECACHE_CMP_PROC   0x00008
 
#define TYPECACHE_HASH_PROC   0x00010
 
#define TYPECACHE_EQ_OPR_FINFO   0x00020
 
#define TYPECACHE_CMP_PROC_FINFO   0x00040
 
#define TYPECACHE_HASH_PROC_FINFO   0x00080
 
#define TYPECACHE_TUPDESC   0x00100
 
#define TYPECACHE_BTREE_OPFAMILY   0x00200
 
#define TYPECACHE_HASH_OPFAMILY   0x00400
 
#define TYPECACHE_RANGE_INFO   0x00800
 
#define TYPECACHE_DOMAIN_BASE_INFO   0x01000
 
#define TYPECACHE_DOMAIN_CONSTR_INFO   0x02000
 
#define TYPECACHE_HASH_EXTENDED_PROC   0x04000
 
#define TYPECACHE_HASH_EXTENDED_PROC_FINFO   0x08000
 
#define TYPECACHE_MULTIRANGE_INFO   0x10000
 
#define INVALID_TUPLEDESC_IDENTIFIER   ((uint64) 1)
 

Typedefs

typedef struct DomainConstraintCache DomainConstraintCache
 
typedef struct TypeCacheEntry TypeCacheEntry
 
typedef struct DomainConstraintRef DomainConstraintRef
 
typedef struct SharedRecordTypmodRegistry SharedRecordTypmodRegistry
 

Functions

TypeCacheEntrylookup_type_cache (Oid type_id, int flags)
 
void InitDomainConstraintRef (Oid type_id, DomainConstraintRef *ref, MemoryContext refctx, bool need_exprstate)
 
void UpdateDomainConstraintRef (DomainConstraintRef *ref)
 
bool DomainHasConstraints (Oid type_id)
 
TupleDesc lookup_rowtype_tupdesc (Oid type_id, int32 typmod)
 
TupleDesc lookup_rowtype_tupdesc_noerror (Oid type_id, int32 typmod, bool noError)
 
TupleDesc lookup_rowtype_tupdesc_copy (Oid type_id, int32 typmod)
 
TupleDesc lookup_rowtype_tupdesc_domain (Oid type_id, int32 typmod, bool noError)
 
void assign_record_type_typmod (TupleDesc tupDesc)
 
uint64 assign_record_type_identifier (Oid type_id, int32 typmod)
 
int compare_values_of_enum (TypeCacheEntry *tcache, Oid arg1, Oid arg2)
 
size_t SharedRecordTypmodRegistryEstimate (void)
 
void SharedRecordTypmodRegistryInit (SharedRecordTypmodRegistry *, dsm_segment *segment, dsa_area *area)
 
void SharedRecordTypmodRegistryAttach (SharedRecordTypmodRegistry *)
 

Macro Definition Documentation

◆ INVALID_TUPLEDESC_IDENTIFIER

#define INVALID_TUPLEDESC_IDENTIFIER   ((uint64) 1)

◆ TYPECACHE_BTREE_OPFAMILY

#define TYPECACHE_BTREE_OPFAMILY   0x00200

Definition at line 145 of file typcache.h.

Referenced by lookup_type_cache().

◆ TYPECACHE_CMP_PROC

◆ TYPECACHE_CMP_PROC_FINFO

#define TYPECACHE_CMP_PROC_FINFO   0x00040

◆ TYPECACHE_DOMAIN_BASE_INFO

◆ TYPECACHE_DOMAIN_CONSTR_INFO

#define TYPECACHE_DOMAIN_CONSTR_INFO   0x02000

Definition at line 149 of file typcache.h.

Referenced by DomainHasConstraints(), InitDomainConstraintRef(), and lookup_type_cache().

◆ TYPECACHE_EQ_OPR

◆ TYPECACHE_EQ_OPR_FINFO

#define TYPECACHE_EQ_OPR_FINFO   0x00020

◆ TYPECACHE_GT_OPR

#define TYPECACHE_GT_OPR   0x00004

◆ TYPECACHE_HASH_EXTENDED_PROC

◆ TYPECACHE_HASH_EXTENDED_PROC_FINFO

#define TYPECACHE_HASH_EXTENDED_PROC_FINFO   0x08000

◆ TYPECACHE_HASH_OPFAMILY

#define TYPECACHE_HASH_OPFAMILY   0x00400

Definition at line 146 of file typcache.h.

Referenced by lookup_type_cache().

◆ TYPECACHE_HASH_PROC

◆ TYPECACHE_HASH_PROC_FINFO

#define TYPECACHE_HASH_PROC_FINFO   0x00080

◆ TYPECACHE_LT_OPR

◆ TYPECACHE_MULTIRANGE_INFO

#define TYPECACHE_MULTIRANGE_INFO   0x10000

◆ TYPECACHE_RANGE_INFO

#define TYPECACHE_RANGE_INFO   0x00800

◆ TYPECACHE_TUPDESC

Typedef Documentation

◆ DomainConstraintCache

Definition at line 26 of file typcache.h.

◆ DomainConstraintRef

◆ SharedRecordTypmodRegistry

Definition at line 175 of file typcache.h.

◆ TypeCacheEntry

Function Documentation

◆ assign_record_type_identifier()

uint64 assign_record_type_identifier ( Oid  type_id,
int32  typmod 
)

Definition at line 2039 of file typcache.c.

References Assert, ereport, errcode(), errmsg(), ERROR, format_type_be(), lookup_type_cache(), RecordCacheArrayLen, RecordIdentifierArray, TypeCacheEntry::tupDesc, TypeCacheEntry::tupDesc_identifier, tupledesc_id_counter, and TYPECACHE_TUPDESC.

Referenced by expanded_record_fetch_tupdesc(), make_expanded_record_from_tupdesc(), and make_expanded_record_from_typeid().

2040 {
2041  if (type_id != RECORDOID)
2042  {
2043  /*
2044  * It's a named composite type, so use the regular typcache.
2045  */
2046  TypeCacheEntry *typentry;
2047 
2048  typentry = lookup_type_cache(type_id, TYPECACHE_TUPDESC);
2049  if (typentry->tupDesc == NULL)
2050  ereport(ERROR,
2051  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2052  errmsg("type %s is not composite",
2053  format_type_be(type_id))));
2054  Assert(typentry->tupDesc_identifier != 0);
2055  return typentry->tupDesc_identifier;
2056  }
2057  else
2058  {
2059  /*
2060  * It's a transient record type, so look in our record-type table.
2061  */
2062  if (typmod >= 0 && typmod < RecordCacheArrayLen &&
2063  RecordCacheArray[typmod] != NULL)
2064  {
2065  Assert(RecordIdentifierArray[typmod] != 0);
2066  return RecordIdentifierArray[typmod];
2067  }
2068 
2069  /* For anonymous or unrecognized record type, generate a new ID */
2070  return ++tupledesc_id_counter;
2071  }
2072 }
int errcode(int sqlerrcode)
Definition: elog.c:698
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
static uint64 tupledesc_id_counter
Definition: typcache.c:287
static TupleDesc * RecordCacheArray
Definition: typcache.c:277
#define ERROR
Definition: elog.h:46
static int32 RecordCacheArrayLen
Definition: typcache.c:279
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:339
#define ereport(elevel,...)
Definition: elog.h:157
#define Assert(condition)
Definition: c.h:804
uint64 tupDesc_identifier
Definition: typcache.h:90
int errmsg(const char *fmt,...)
Definition: elog.c:909
TupleDesc tupDesc
Definition: typcache.h:89
#define TYPECACHE_TUPDESC
Definition: typcache.h:144
static uint64 * RecordIdentifierArray
Definition: typcache.c:278

◆ assign_record_type_typmod()

void assign_record_type_typmod ( TupleDesc  tupDesc)

Definition at line 1947 of file typcache.c.

References Assert, CacheMemoryContext, CreateCacheMemoryContext(), CreateTupleDescCopy(), ensure_record_cache_typmod_slot_exists(), HASHCTL::entrysize, find_or_make_matching_shared_tupledesc(), HASHCTL::hash, HASH_COMPARE, hash_create(), HASH_ELEM, HASH_ENTER, HASH_FIND, HASH_FUNCTION, hash_search(), HASHCTL::keysize, HASHCTL::match, MemoryContextSwitchTo(), NextRecordTypmod, record_type_typmod_compare(), record_type_typmod_hash(), RecordIdentifierArray, TupleDescData::tdrefcount, TupleDescData::tdtypeid, TupleDescData::tdtypmod, RecordCacheEntry::tupdesc, and tupledesc_id_counter.

Referenced by BlessTupleDesc(), ER_get_flat_size(), internal_get_result_type(), and SPI_returntuple().

1948 {
1949  RecordCacheEntry *recentry;
1950  TupleDesc entDesc;
1951  bool found;
1952  MemoryContext oldcxt;
1953 
1954  Assert(tupDesc->tdtypeid == RECORDOID);
1955 
1956  if (RecordCacheHash == NULL)
1957  {
1958  /* First time through: initialize the hash table */
1959  HASHCTL ctl;
1960 
1961  ctl.keysize = sizeof(TupleDesc); /* just the pointer */
1962  ctl.entrysize = sizeof(RecordCacheEntry);
1965  RecordCacheHash = hash_create("Record information cache", 64,
1966  &ctl,
1968 
1969  /* Also make sure CacheMemoryContext exists */
1970  if (!CacheMemoryContext)
1972  }
1973 
1974  /*
1975  * Find a hashtable entry for this tuple descriptor. We don't use
1976  * HASH_ENTER yet, because if it's missing, we need to make sure that all
1977  * the allocations succeed before we create the new entry.
1978  */
1980  (void *) &tupDesc,
1981  HASH_FIND, &found);
1982  if (found && recentry->tupdesc != NULL)
1983  {
1984  tupDesc->tdtypmod = recentry->tupdesc->tdtypmod;
1985  return;
1986  }
1987 
1988  /* Not present, so need to manufacture an entry */
1990 
1991  /* Look in the SharedRecordTypmodRegistry, if attached */
1992  entDesc = find_or_make_matching_shared_tupledesc(tupDesc);
1993  if (entDesc == NULL)
1994  {
1995  /*
1996  * Make sure we have room before we CreateTupleDescCopy() or advance
1997  * NextRecordTypmod.
1998  */
2000 
2001  /* Reference-counted local cache only. */
2002  entDesc = CreateTupleDescCopy(tupDesc);
2003  entDesc->tdrefcount = 1;
2004  entDesc->tdtypmod = NextRecordTypmod++;
2005  }
2006  else
2007  {
2009  }
2010 
2011  RecordCacheArray[entDesc->tdtypmod] = entDesc;
2012 
2013  /* Assign a unique tupdesc identifier, too. */
2015 
2016  /* Fully initialized; create the hash table entry */
2018  (void *) &tupDesc,
2019  HASH_ENTER, NULL);
2020  recentry->tupdesc = entDesc;
2021 
2022  /* Update the caller's tuple descriptor. */
2023  tupDesc->tdtypmod = entDesc->tdtypmod;
2024 
2025  MemoryContextSwitchTo(oldcxt);
2026 }
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:111
#define HASH_ELEM
Definition: hsearch.h:95
static TupleDesc find_or_make_matching_shared_tupledesc(TupleDesc tupdesc)
Definition: typcache.c:2755
struct RecordCacheEntry RecordCacheEntry
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Size entrysize
Definition: hsearch.h:76
static uint64 tupledesc_id_counter
Definition: typcache.c:287
static HTAB * RecordCacheHash
Definition: typcache.c:274
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:954
static TupleDesc * RecordCacheArray
Definition: typcache.c:277
int32 tdtypmod
Definition: tupdesc.h:83
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:349
static int32 NextRecordTypmod
Definition: typcache.c:280
static void ensure_record_cache_typmod_slot_exists(int32 typmod)
Definition: typcache.c:1702
Size keysize
Definition: hsearch.h:75
HashCompareFunc match
Definition: hsearch.h:80
static uint32 record_type_typmod_hash(const void *data, size_t size)
Definition: typcache.c:1920
#define Assert(condition)
Definition: c.h:804
#define HASH_COMPARE
Definition: hsearch.h:99
void CreateCacheMemoryContext(void)
Definition: catcache.c:620
Oid tdtypeid
Definition: tupdesc.h:82
struct TupleDescData * TupleDesc
Definition: tupdesc.h:89
static int record_type_typmod_compare(const void *a, const void *b, size_t size)
Definition: typcache.c:1931
TupleDesc tupdesc
Definition: typcache.c:159
int tdrefcount
Definition: tupdesc.h:84
static uint64 * RecordIdentifierArray
Definition: typcache.c:278
HashValueFunc hash
Definition: hsearch.h:78
#define HASH_FUNCTION
Definition: hsearch.h:98
MemoryContext CacheMemoryContext
Definition: mcxt.c:51

◆ compare_values_of_enum()

int compare_values_of_enum ( TypeCacheEntry tcache,
Oid  arg1,
Oid  arg2 
)

Definition at line 2471 of file typcache.c.

References elog, enum_known_sorted(), TypeCacheEntry::enumData, ERROR, find_enumitem(), format_type_be(), load_enum_cache_data(), EnumItem::sort_order, and TypeCacheEntry::type_id.

Referenced by enum_cmp_internal().

2472 {
2473  TypeCacheEnumData *enumdata;
2474  EnumItem *item1;
2475  EnumItem *item2;
2476 
2477  /*
2478  * Equal OIDs are certainly equal --- this case was probably handled by
2479  * our caller, but we may as well check.
2480  */
2481  if (arg1 == arg2)
2482  return 0;
2483 
2484  /* Load up the cache if first time through */
2485  if (tcache->enumData == NULL)
2486  load_enum_cache_data(tcache);
2487  enumdata = tcache->enumData;
2488 
2489  /*
2490  * If both OIDs are known-sorted, we can just compare them directly.
2491  */
2492  if (enum_known_sorted(enumdata, arg1) &&
2493  enum_known_sorted(enumdata, arg2))
2494  {
2495  if (arg1 < arg2)
2496  return -1;
2497  else
2498  return 1;
2499  }
2500 
2501  /*
2502  * Slow path: we have to identify their actual sort-order positions.
2503  */
2504  item1 = find_enumitem(enumdata, arg1);
2505  item2 = find_enumitem(enumdata, arg2);
2506 
2507  if (item1 == NULL || item2 == NULL)
2508  {
2509  /*
2510  * We couldn't find one or both values. That means the enum has
2511  * changed under us, so re-initialize the cache and try again. We
2512  * don't bother retrying the known-sorted case in this path.
2513  */
2514  load_enum_cache_data(tcache);
2515  enumdata = tcache->enumData;
2516 
2517  item1 = find_enumitem(enumdata, arg1);
2518  item2 = find_enumitem(enumdata, arg2);
2519 
2520  /*
2521  * If we still can't find the values, complain: we must have corrupt
2522  * data.
2523  */
2524  if (item1 == NULL)
2525  elog(ERROR, "enum value %u not found in cache for enum %s",
2526  arg1, format_type_be(tcache->type_id));
2527  if (item2 == NULL)
2528  elog(ERROR, "enum value %u not found in cache for enum %s",
2529  arg2, format_type_be(tcache->type_id));
2530  }
2531 
2532  if (item1->sort_order < item2->sort_order)
2533  return -1;
2534  else if (item1->sort_order > item2->sort_order)
2535  return 1;
2536  else
2537  return 0;
2538 }
struct TypeCacheEnumData * enumData
Definition: typcache.h:129
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
#define ERROR
Definition: elog.h:46
static bool enum_known_sorted(TypeCacheEnumData *enumdata, Oid arg)
Definition: typcache.c:2442
static EnumItem * find_enumitem(TypeCacheEnumData *enumdata, Oid arg)
Definition: typcache.c:2699
static void load_enum_cache_data(TypeCacheEntry *tcache)
Definition: typcache.c:2544
float4 sort_order
Definition: typcache.c:135
#define elog(elevel,...)
Definition: elog.h:232

◆ DomainHasConstraints()

bool DomainHasConstraints ( Oid  type_id)

Definition at line 1392 of file typcache.c.

References TypeCacheEntry::domainData, lookup_type_cache(), and TYPECACHE_DOMAIN_CONSTR_INFO.

Referenced by ATColumnChangeRequiresRewrite(), ATExecAddColumn(), and eval_const_expressions_mutator().

1393 {
1394  TypeCacheEntry *typentry;
1395 
1396  /*
1397  * Note: a side effect is to cause the typcache's domain data to become
1398  * valid. This is fine since we'll likely need it soon if there is any.
1399  */
1400  typentry = lookup_type_cache(type_id, TYPECACHE_DOMAIN_CONSTR_INFO);
1401 
1402  return (typentry->domainData != NULL);
1403 }
DomainConstraintCache * domainData
Definition: typcache.h:120
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:339
#define TYPECACHE_DOMAIN_CONSTR_INFO
Definition: typcache.h:149

◆ InitDomainConstraintRef()

void InitDomainConstraintRef ( Oid  type_id,
DomainConstraintRef ref,
MemoryContext  refctx,
bool  need_exprstate 
)

Definition at line 1305 of file typcache.c.

References MemoryContextCallback::arg, DomainConstraintRef::callback, DomainConstraintCache::constraints, DomainConstraintRef::constraints, DomainConstraintRef::dcc, dccref_deletion_callback(), DomainConstraintCache::dccRefCount, TypeCacheEntry::domainData, MemoryContextCallback::func, lookup_type_cache(), MemoryContextRegisterResetCallback(), DomainConstraintRef::need_exprstate, NIL, prep_domain_constraints(), DomainConstraintRef::refctx, DomainConstraintRef::tcache, and TYPECACHE_DOMAIN_CONSTR_INFO.

Referenced by domain_state_setup(), and ExecInitCoerceToDomain().

1307 {
1308  /* Look up the typcache entry --- we assume it survives indefinitely */
1310  ref->need_exprstate = need_exprstate;
1311  /* For safety, establish the callback before acquiring a refcount */
1312  ref->refctx = refctx;
1313  ref->dcc = NULL;
1315  ref->callback.arg = (void *) ref;
1317  /* Acquire refcount if there are constraints, and set up exported list */
1318  if (ref->tcache->domainData)
1319  {
1320  ref->dcc = ref->tcache->domainData;
1321  ref->dcc->dccRefCount++;
1322  if (ref->need_exprstate)
1324  ref->refctx);
1325  else
1326  ref->constraints = ref->dcc->constraints;
1327  }
1328  else
1329  ref->constraints = NIL;
1330 }
MemoryContextCallback callback
Definition: typcache.h:172
MemoryContextCallbackFunction func
Definition: palloc.h:49
#define NIL
Definition: pg_list.h:65
DomainConstraintCache * dcc
Definition: typcache.h:171
static void dccref_deletion_callback(void *arg)
Definition: typcache.c:1246
DomainConstraintCache * domainData
Definition: typcache.h:120
MemoryContext refctx
Definition: typcache.h:166
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:339
static List * prep_domain_constraints(List *constraints, MemoryContext execctx)
Definition: typcache.c:1267
#define TYPECACHE_DOMAIN_CONSTR_INFO
Definition: typcache.h:149
TypeCacheEntry * tcache
Definition: typcache.h:167
void MemoryContextRegisterResetCallback(MemoryContext context, MemoryContextCallback *cb)
Definition: mcxt.c:292

◆ lookup_rowtype_tupdesc()

◆ lookup_rowtype_tupdesc_copy()

TupleDesc lookup_rowtype_tupdesc_copy ( Oid  type_id,
int32  typmod 
)

Definition at line 1861 of file typcache.c.

References CreateTupleDescCopyConstr(), and lookup_rowtype_tupdesc_internal().

Referenced by ExecInitExprRec(), ExecMakeTableFunctionResult(), get_expr_result_type(), internal_get_result_type(), and TypeGetTupleDesc().

1862 {
1863  TupleDesc tmp;
1864 
1865  tmp = lookup_rowtype_tupdesc_internal(type_id, typmod, false);
1866  return CreateTupleDescCopyConstr(tmp);
1867 }
TupleDesc CreateTupleDescCopyConstr(TupleDesc tupdesc)
Definition: tupdesc.c:151
static TupleDesc lookup_rowtype_tupdesc_internal(Oid type_id, int32 typmod, bool noError)
Definition: typcache.c:1736

◆ lookup_rowtype_tupdesc_domain()

TupleDesc lookup_rowtype_tupdesc_domain ( Oid  type_id,
int32  typmod,
bool  noError 
)

Definition at line 1883 of file typcache.c.

References TypeCacheEntry::domainBaseType, TypeCacheEntry::domainBaseTypmod, ereport, errcode(), errmsg(), ERROR, format_type_be(), lookup_rowtype_tupdesc_internal(), lookup_rowtype_tupdesc_noerror(), lookup_type_cache(), PinTupleDesc, TypeCacheEntry::tupDesc, TYPECACHE_DOMAIN_BASE_INFO, TYPECACHE_TUPDESC, and TypeCacheEntry::typtype.

Referenced by ExecEvalWholeRowVar(), hstore_from_record(), hstore_populate_record(), plperl_sv_to_datum(), and rowtype_field_matches().

1884 {
1885  TupleDesc tupDesc;
1886 
1887  if (type_id != RECORDOID)
1888  {
1889  /*
1890  * Check for domain or named composite type. We might as well load
1891  * whichever data is needed.
1892  */
1893  TypeCacheEntry *typentry;
1894 
1895  typentry = lookup_type_cache(type_id,
1898  if (typentry->typtype == TYPTYPE_DOMAIN)
1900  typentry->domainBaseTypmod,
1901  noError);
1902  if (typentry->tupDesc == NULL && !noError)
1903  ereport(ERROR,
1904  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1905  errmsg("type %s is not composite",
1906  format_type_be(type_id))));
1907  tupDesc = typentry->tupDesc;
1908  }
1909  else
1910  tupDesc = lookup_rowtype_tupdesc_internal(type_id, typmod, noError);
1911  if (tupDesc != NULL)
1912  PinTupleDesc(tupDesc);
1913  return tupDesc;
1914 }
int errcode(int sqlerrcode)
Definition: elog.c:698
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
Oid domainBaseType
Definition: typcache.h:113
#define ERROR
Definition: elog.h:46
int32 domainBaseTypmod
Definition: typcache.h:114
TupleDesc lookup_rowtype_tupdesc_noerror(Oid type_id, int32 typmod, bool noError)
Definition: typcache.c:1844
#define TYPECACHE_DOMAIN_BASE_INFO
Definition: typcache.h:148
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:339
#define ereport(elevel,...)
Definition: elog.h:157
char typtype
Definition: typcache.h:43
#define PinTupleDesc(tupdesc)
Definition: tupdesc.h:116
int errmsg(const char *fmt,...)
Definition: elog.c:909
TupleDesc tupDesc
Definition: typcache.h:89
static TupleDesc lookup_rowtype_tupdesc_internal(Oid type_id, int32 typmod, bool noError)
Definition: typcache.c:1736
#define TYPECACHE_TUPDESC
Definition: typcache.h:144

◆ lookup_rowtype_tupdesc_noerror()

TupleDesc lookup_rowtype_tupdesc_noerror ( Oid  type_id,
int32  typmod,
bool  noError 
)

Definition at line 1844 of file typcache.c.

References lookup_rowtype_tupdesc_internal(), and PinTupleDesc.

Referenced by lookup_rowtype_tupdesc_domain().

1845 {
1846  TupleDesc tupDesc;
1847 
1848  tupDesc = lookup_rowtype_tupdesc_internal(type_id, typmod, noError);
1849  if (tupDesc != NULL)
1850  PinTupleDesc(tupDesc);
1851  return tupDesc;
1852 }
#define PinTupleDesc(tupdesc)
Definition: tupdesc.h:116
static TupleDesc lookup_rowtype_tupdesc_internal(Oid type_id, int32 typmod, bool noError)
Definition: typcache.c:1736

◆ lookup_type_cache()

TypeCacheEntry* lookup_type_cache ( Oid  type_id,
int  flags 
)

Definition at line 339 of file typcache.c.

References array_element_has_compare(), array_element_has_equality(), array_element_has_extended_hashing(), array_element_has_hashing(), Assert, BTEqualStrategyNumber, BTGreaterStrategyNumber, BTLessStrategyNumber, BTORDER_PROC, TypeCacheEntry::btree_opf, TypeCacheEntry::btree_opintype, CacheMemoryContext, CacheRegisterRelcacheCallback(), CacheRegisterSyscacheCallback(), CLAOID, TypeCacheEntry::cmp_proc, TypeCacheEntry::cmp_proc_finfo, CONSTROID, CreateCacheMemoryContext(), TypeCacheEntry::domainBaseType, TypeCacheEntry::domainBaseTypmod, HASHCTL::entrysize, TypeCacheEntry::eq_opr, TypeCacheEntry::eq_opr_finfo, ereport, errcode(), errmsg(), ERROR, firstDomainTypeEntry, TypeCacheEntry::flags, fmgr_info_cxt(), FmgrInfo::fn_oid, get_opclass_family(), get_opclass_input_type(), get_opcode(), get_opfamily_member(), get_opfamily_proc(), getBaseTypeAndTypmod(), GetDefaultOpClass(), GETSTRUCT, GetSysCacheHashValue1, TypeCacheEntry::gt_opr, HASH_BLOBS, hash_create(), HASH_ELEM, HASH_ENTER, TypeCacheEntry::hash_extended_proc, TypeCacheEntry::hash_extended_proc_finfo, HASH_FIND, TypeCacheEntry::hash_opf, TypeCacheEntry::hash_opintype, TypeCacheEntry::hash_proc, TypeCacheEntry::hash_proc_finfo, hash_search(), HASHEXTENDED_PROC, HASHSTANDARD_PROC, HeapTupleIsValid, HTEqualStrategyNumber, InvalidOid, HASHCTL::keysize, load_domaintype_info(), load_multirangetype_info(), load_rangetype_info(), load_typcache_tupdesc(), lookup_type_cache(), TypeCacheEntry::lt_opr, MemSet, multirange_element_has_extended_hashing(), multirange_element_has_hashing(), NameStr, TypeCacheEntry::nextDomain, ObjectIdGetDatum, OidIsValid, range_element_has_extended_hashing(), range_element_has_hashing(), record_fields_have_compare(), record_fields_have_equality(), record_fields_have_extended_hashing(), record_fields_have_hashing(), ReleaseSysCache(), TypeCacheEntry::rngelemtype, TypeCacheEntry::rngtype, SearchSysCache1(), TCFLAGS_CHECKED_BTREE_OPCLASS, TCFLAGS_CHECKED_CMP_PROC, TCFLAGS_CHECKED_DOMAIN_CONSTRAINTS, TCFLAGS_CHECKED_EQ_OPR, TCFLAGS_CHECKED_GT_OPR, TCFLAGS_CHECKED_HASH_EXTENDED_PROC, TCFLAGS_CHECKED_HASH_OPCLASS, TCFLAGS_CHECKED_HASH_PROC, TCFLAGS_CHECKED_LT_OPR, TCFLAGS_HAVE_PG_TYPE_DATA, TypeCacheEntry::tupDesc, TypeCacheEntry::typalign, TypeCacheEntry::typbyval, TypeCacheEntry::typcollation, TypeCacheEntry::type_id, TypeCacheEntry::type_id_hash, TYPECACHE_BTREE_OPFAMILY, TYPECACHE_CMP_PROC, TYPECACHE_CMP_PROC_FINFO, TYPECACHE_DOMAIN_BASE_INFO, TYPECACHE_DOMAIN_CONSTR_INFO, TYPECACHE_EQ_OPR, TYPECACHE_EQ_OPR_FINFO, TYPECACHE_GT_OPR, TYPECACHE_HASH_EXTENDED_PROC, TYPECACHE_HASH_EXTENDED_PROC_FINFO, TYPECACHE_HASH_OPFAMILY, TYPECACHE_HASH_PROC, TYPECACHE_HASH_PROC_FINFO, TYPECACHE_LT_OPR, TYPECACHE_MULTIRANGE_INFO, TYPECACHE_RANGE_INFO, TYPECACHE_TUPDESC, TypeCacheConstrCallback(), TypeCacheOpcCallback(), TypeCacheRelCallback(), TypeCacheTypCallback(), TypeCacheEntry::typelem, TYPEOID, TypeCacheEntry::typlen, TypeCacheEntry::typrelid, TypeCacheEntry::typstorage, TypeCacheEntry::typsubscript, and TypeCacheEntry::typtype.

Referenced by analyzeCTE(), appendAggOrderBy(), array_cmp(), array_contain_compare(), array_eq(), array_position_common(), array_positions(), array_replace_internal(), array_typanalyze(), assign_record_type_identifier(), brin_bloom_opcinfo(), brin_inclusion_opcinfo(), brin_minmax_multi_opcinfo(), brin_minmax_opcinfo(), build_datatype(), build_mss(), cache_array_element_properties(), cache_multirange_element_properties(), cache_range_element_properties(), cache_record_field_properties(), calc_arraycontsel(), check_memoizable(), contain_leaked_vars_walker(), CreateStatistics(), dependency_degree(), domain_state_setup(), DomainHasConstraints(), enum_cmp_internal(), ExecInitExprRec(), foreign_expr_walker(), get_cached_rowtype(), get_multirange_io_data(), get_range_io_data(), get_rule_orderby(), get_sort_group_operators(), hash_array(), hash_array_extended(), hash_multirange(), hash_multirange_extended(), hash_range(), hash_range_extended(), hash_record(), hash_record_extended(), InitDomainConstraintRef(), initGinState(), load_multirangetype_info(), load_rangetype_info(), lookup_rowtype_tupdesc_domain(), lookup_rowtype_tupdesc_internal(), lookup_type_cache(), make_expanded_record_from_tupdesc(), make_expanded_record_from_typeid(), multirange_get_typcache(), multirange_unnest(), ndistinct_for_combination(), op_hashjoinable(), op_mergejoinable(), paraminfo_get_equal_hashops(), PLy_input_setup_func(), PLy_output_setup_func(), range_get_typcache(), record_cmp(), record_eq(), revalidate_rectypeid(), scalararraysel(), scalararraysel_containment(), show_sortorder_options(), statext_mcv_serialize(), tuples_equal(), and width_bucket_array().

340 {
341  TypeCacheEntry *typentry;
342  bool found;
343 
344  if (TypeCacheHash == NULL)
345  {
346  /* First time through: initialize the hash table */
347  HASHCTL ctl;
348 
349  ctl.keysize = sizeof(Oid);
350  ctl.entrysize = sizeof(TypeCacheEntry);
351  TypeCacheHash = hash_create("Type information cache", 64,
352  &ctl, HASH_ELEM | HASH_BLOBS);
353 
354  /* Also set up callbacks for SI invalidations */
359 
360  /* Also make sure CacheMemoryContext exists */
361  if (!CacheMemoryContext)
363  }
364 
365  /* Try to look up an existing entry */
367  (void *) &type_id,
368  HASH_FIND, NULL);
369  if (typentry == NULL)
370  {
371  /*
372  * If we didn't find one, we want to make one. But first look up the
373  * pg_type row, just to make sure we don't make a cache entry for an
374  * invalid type OID. If the type OID is not valid, present a
375  * user-facing error, since some code paths such as domain_in() allow
376  * this function to be reached with a user-supplied OID.
377  */
378  HeapTuple tp;
379  Form_pg_type typtup;
380 
381  tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_id));
382  if (!HeapTupleIsValid(tp))
383  ereport(ERROR,
384  (errcode(ERRCODE_UNDEFINED_OBJECT),
385  errmsg("type with OID %u does not exist", type_id)));
386  typtup = (Form_pg_type) GETSTRUCT(tp);
387  if (!typtup->typisdefined)
388  ereport(ERROR,
389  (errcode(ERRCODE_UNDEFINED_OBJECT),
390  errmsg("type \"%s\" is only a shell",
391  NameStr(typtup->typname))));
392 
393  /* Now make the typcache entry */
395  (void *) &type_id,
396  HASH_ENTER, &found);
397  Assert(!found); /* it wasn't there a moment ago */
398 
399  MemSet(typentry, 0, sizeof(TypeCacheEntry));
400 
401  /* These fields can never change, by definition */
402  typentry->type_id = type_id;
404  ObjectIdGetDatum(type_id));
405 
406  /* Keep this part in sync with the code below */
407  typentry->typlen = typtup->typlen;
408  typentry->typbyval = typtup->typbyval;
409  typentry->typalign = typtup->typalign;
410  typentry->typstorage = typtup->typstorage;
411  typentry->typtype = typtup->typtype;
412  typentry->typrelid = typtup->typrelid;
413  typentry->typsubscript = typtup->typsubscript;
414  typentry->typelem = typtup->typelem;
415  typentry->typcollation = typtup->typcollation;
416  typentry->flags |= TCFLAGS_HAVE_PG_TYPE_DATA;
417 
418  /* If it's a domain, immediately thread it into the domain cache list */
419  if (typentry->typtype == TYPTYPE_DOMAIN)
420  {
421  typentry->nextDomain = firstDomainTypeEntry;
422  firstDomainTypeEntry = typentry;
423  }
424 
425  ReleaseSysCache(tp);
426  }
427  else if (!(typentry->flags & TCFLAGS_HAVE_PG_TYPE_DATA))
428  {
429  /*
430  * We have an entry, but its pg_type row got changed, so reload the
431  * data obtained directly from pg_type.
432  */
433  HeapTuple tp;
434  Form_pg_type typtup;
435 
436  tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_id));
437  if (!HeapTupleIsValid(tp))
438  ereport(ERROR,
439  (errcode(ERRCODE_UNDEFINED_OBJECT),
440  errmsg("type with OID %u does not exist", type_id)));
441  typtup = (Form_pg_type) GETSTRUCT(tp);
442  if (!typtup->typisdefined)
443  ereport(ERROR,
444  (errcode(ERRCODE_UNDEFINED_OBJECT),
445  errmsg("type \"%s\" is only a shell",
446  NameStr(typtup->typname))));
447 
448  /*
449  * Keep this part in sync with the code above. Many of these fields
450  * shouldn't ever change, particularly typtype, but copy 'em anyway.
451  */
452  typentry->typlen = typtup->typlen;
453  typentry->typbyval = typtup->typbyval;
454  typentry->typalign = typtup->typalign;
455  typentry->typstorage = typtup->typstorage;
456  typentry->typtype = typtup->typtype;
457  typentry->typrelid = typtup->typrelid;
458  typentry->typsubscript = typtup->typsubscript;
459  typentry->typelem = typtup->typelem;
460  typentry->typcollation = typtup->typcollation;
461  typentry->flags |= TCFLAGS_HAVE_PG_TYPE_DATA;
462 
463  ReleaseSysCache(tp);
464  }
465 
466  /*
467  * Look up opclasses if we haven't already and any dependent info is
468  * requested.
469  */
474  !(typentry->flags & TCFLAGS_CHECKED_BTREE_OPCLASS))
475  {
476  Oid opclass;
477 
478  opclass = GetDefaultOpClass(type_id, BTREE_AM_OID);
479  if (OidIsValid(opclass))
480  {
481  typentry->btree_opf = get_opclass_family(opclass);
482  typentry->btree_opintype = get_opclass_input_type(opclass);
483  }
484  else
485  {
486  typentry->btree_opf = typentry->btree_opintype = InvalidOid;
487  }
488 
489  /*
490  * Reset information derived from btree opclass. Note in particular
491  * that we'll redetermine the eq_opr even if we previously found one;
492  * this matters in case a btree opclass has been added to a type that
493  * previously had only a hash opclass.
494  */
495  typentry->flags &= ~(TCFLAGS_CHECKED_EQ_OPR |
500  }
501 
502  /*
503  * If we need to look up equality operator, and there's no btree opclass,
504  * force lookup of hash opclass.
505  */
506  if ((flags & (TYPECACHE_EQ_OPR | TYPECACHE_EQ_OPR_FINFO)) &&
507  !(typentry->flags & TCFLAGS_CHECKED_EQ_OPR) &&
508  typentry->btree_opf == InvalidOid)
509  flags |= TYPECACHE_HASH_OPFAMILY;
510 
515  !(typentry->flags & TCFLAGS_CHECKED_HASH_OPCLASS))
516  {
517  Oid opclass;
518 
519  opclass = GetDefaultOpClass(type_id, HASH_AM_OID);
520  if (OidIsValid(opclass))
521  {
522  typentry->hash_opf = get_opclass_family(opclass);
523  typentry->hash_opintype = get_opclass_input_type(opclass);
524  }
525  else
526  {
527  typentry->hash_opf = typentry->hash_opintype = InvalidOid;
528  }
529 
530  /*
531  * Reset information derived from hash opclass. We do *not* reset the
532  * eq_opr; if we already found one from the btree opclass, that
533  * decision is still good.
534  */
535  typentry->flags &= ~(TCFLAGS_CHECKED_HASH_PROC |
537  typentry->flags |= TCFLAGS_CHECKED_HASH_OPCLASS;
538  }
539 
540  /*
541  * Look for requested operators and functions, if we haven't already.
542  */
543  if ((flags & (TYPECACHE_EQ_OPR | TYPECACHE_EQ_OPR_FINFO)) &&
544  !(typentry->flags & TCFLAGS_CHECKED_EQ_OPR))
545  {
546  Oid eq_opr = InvalidOid;
547 
548  if (typentry->btree_opf != InvalidOid)
549  eq_opr = get_opfamily_member(typentry->btree_opf,
550  typentry->btree_opintype,
551  typentry->btree_opintype,
553  if (eq_opr == InvalidOid &&
554  typentry->hash_opf != InvalidOid)
555  eq_opr = get_opfamily_member(typentry->hash_opf,
556  typentry->hash_opintype,
557  typentry->hash_opintype,
559 
560  /*
561  * If the proposed equality operator is array_eq or record_eq, check
562  * to see if the element type or column types support equality. If
563  * not, array_eq or record_eq would fail at runtime, so we don't want
564  * to report that the type has equality. (We can omit similar
565  * checking for ranges and multiranges because ranges can't be created
566  * in the first place unless their subtypes support equality.)
567  */
568  if (eq_opr == ARRAY_EQ_OP &&
569  !array_element_has_equality(typentry))
570  eq_opr = InvalidOid;
571  else if (eq_opr == RECORD_EQ_OP &&
572  !record_fields_have_equality(typentry))
573  eq_opr = InvalidOid;
574 
575  /* Force update of eq_opr_finfo only if we're changing state */
576  if (typentry->eq_opr != eq_opr)
577  typentry->eq_opr_finfo.fn_oid = InvalidOid;
578 
579  typentry->eq_opr = eq_opr;
580 
581  /*
582  * Reset info about hash functions whenever we pick up new info about
583  * equality operator. This is so we can ensure that the hash
584  * functions match the operator.
585  */
586  typentry->flags &= ~(TCFLAGS_CHECKED_HASH_PROC |
588  typentry->flags |= TCFLAGS_CHECKED_EQ_OPR;
589  }
590  if ((flags & TYPECACHE_LT_OPR) &&
591  !(typentry->flags & TCFLAGS_CHECKED_LT_OPR))
592  {
593  Oid lt_opr = InvalidOid;
594 
595  if (typentry->btree_opf != InvalidOid)
596  lt_opr = get_opfamily_member(typentry->btree_opf,
597  typentry->btree_opintype,
598  typentry->btree_opintype,
600 
601  /*
602  * As above, make sure array_cmp or record_cmp will succeed; but again
603  * we need no special check for ranges or multiranges.
604  */
605  if (lt_opr == ARRAY_LT_OP &&
606  !array_element_has_compare(typentry))
607  lt_opr = InvalidOid;
608  else if (lt_opr == RECORD_LT_OP &&
609  !record_fields_have_compare(typentry))
610  lt_opr = InvalidOid;
611 
612  typentry->lt_opr = lt_opr;
613  typentry->flags |= TCFLAGS_CHECKED_LT_OPR;
614  }
615  if ((flags & TYPECACHE_GT_OPR) &&
616  !(typentry->flags & TCFLAGS_CHECKED_GT_OPR))
617  {
618  Oid gt_opr = InvalidOid;
619 
620  if (typentry->btree_opf != InvalidOid)
621  gt_opr = get_opfamily_member(typentry->btree_opf,
622  typentry->btree_opintype,
623  typentry->btree_opintype,
625 
626  /*
627  * As above, make sure array_cmp or record_cmp will succeed; but again
628  * we need no special check for ranges or multiranges.
629  */
630  if (gt_opr == ARRAY_GT_OP &&
631  !array_element_has_compare(typentry))
632  gt_opr = InvalidOid;
633  else if (gt_opr == RECORD_GT_OP &&
634  !record_fields_have_compare(typentry))
635  gt_opr = InvalidOid;
636 
637  typentry->gt_opr = gt_opr;
638  typentry->flags |= TCFLAGS_CHECKED_GT_OPR;
639  }
640  if ((flags & (TYPECACHE_CMP_PROC | TYPECACHE_CMP_PROC_FINFO)) &&
641  !(typentry->flags & TCFLAGS_CHECKED_CMP_PROC))
642  {
643  Oid cmp_proc = InvalidOid;
644 
645  if (typentry->btree_opf != InvalidOid)
646  cmp_proc = get_opfamily_proc(typentry->btree_opf,
647  typentry->btree_opintype,
648  typentry->btree_opintype,
649  BTORDER_PROC);
650 
651  /*
652  * As above, make sure array_cmp or record_cmp will succeed; but again
653  * we need no special check for ranges or multiranges.
654  */
655  if (cmp_proc == F_BTARRAYCMP &&
656  !array_element_has_compare(typentry))
657  cmp_proc = InvalidOid;
658  else if (cmp_proc == F_BTRECORDCMP &&
659  !record_fields_have_compare(typentry))
660  cmp_proc = InvalidOid;
661 
662  /* Force update of cmp_proc_finfo only if we're changing state */
663  if (typentry->cmp_proc != cmp_proc)
664  typentry->cmp_proc_finfo.fn_oid = InvalidOid;
665 
666  typentry->cmp_proc = cmp_proc;
667  typentry->flags |= TCFLAGS_CHECKED_CMP_PROC;
668  }
670  !(typentry->flags & TCFLAGS_CHECKED_HASH_PROC))
671  {
672  Oid hash_proc = InvalidOid;
673 
674  /*
675  * We insist that the eq_opr, if one has been determined, match the
676  * hash opclass; else report there is no hash function.
677  */
678  if (typentry->hash_opf != InvalidOid &&
679  (!OidIsValid(typentry->eq_opr) ||
680  typentry->eq_opr == get_opfamily_member(typentry->hash_opf,
681  typentry->hash_opintype,
682  typentry->hash_opintype,
684  hash_proc = get_opfamily_proc(typentry->hash_opf,
685  typentry->hash_opintype,
686  typentry->hash_opintype,
688 
689  /*
690  * As above, make sure hash_array, hash_record, or hash_range will
691  * succeed.
692  */
693  if (hash_proc == F_HASH_ARRAY &&
694  !array_element_has_hashing(typentry))
695  hash_proc = InvalidOid;
696  else if (hash_proc == F_HASH_RECORD &&
697  !record_fields_have_hashing(typentry))
698  hash_proc = InvalidOid;
699  else if (hash_proc == F_HASH_RANGE &&
700  !range_element_has_hashing(typentry))
701  hash_proc = InvalidOid;
702 
703  /*
704  * Likewise for hash_multirange.
705  */
706  if (hash_proc == F_HASH_MULTIRANGE &&
708  hash_proc = InvalidOid;
709 
710  /* Force update of hash_proc_finfo only if we're changing state */
711  if (typentry->hash_proc != hash_proc)
712  typentry->hash_proc_finfo.fn_oid = InvalidOid;
713 
714  typentry->hash_proc = hash_proc;
715  typentry->flags |= TCFLAGS_CHECKED_HASH_PROC;
716  }
717  if ((flags & (TYPECACHE_HASH_EXTENDED_PROC |
720  {
721  Oid hash_extended_proc = InvalidOid;
722 
723  /*
724  * We insist that the eq_opr, if one has been determined, match the
725  * hash opclass; else report there is no hash function.
726  */
727  if (typentry->hash_opf != InvalidOid &&
728  (!OidIsValid(typentry->eq_opr) ||
729  typentry->eq_opr == get_opfamily_member(typentry->hash_opf,
730  typentry->hash_opintype,
731  typentry->hash_opintype,
733  hash_extended_proc = get_opfamily_proc(typentry->hash_opf,
734  typentry->hash_opintype,
735  typentry->hash_opintype,
737 
738  /*
739  * As above, make sure hash_array_extended, hash_record_extended, or
740  * hash_range_extended will succeed.
741  */
742  if (hash_extended_proc == F_HASH_ARRAY_EXTENDED &&
744  hash_extended_proc = InvalidOid;
745  else if (hash_extended_proc == F_HASH_RECORD_EXTENDED &&
747  hash_extended_proc = InvalidOid;
748  else if (hash_extended_proc == F_HASH_RANGE_EXTENDED &&
750  hash_extended_proc = InvalidOid;
751 
752  /*
753  * Likewise for hash_multirange_extended.
754  */
755  if (hash_extended_proc == F_HASH_MULTIRANGE_EXTENDED &&
757  hash_extended_proc = InvalidOid;
758 
759  /* Force update of proc finfo only if we're changing state */
760  if (typentry->hash_extended_proc != hash_extended_proc)
762 
763  typentry->hash_extended_proc = hash_extended_proc;
765  }
766 
767  /*
768  * Set up fmgr lookup info as requested
769  *
770  * Note: we tell fmgr the finfo structures live in CacheMemoryContext,
771  * which is not quite right (they're really in the hash table's private
772  * memory context) but this will do for our purposes.
773  *
774  * Note: the code above avoids invalidating the finfo structs unless the
775  * referenced operator/function OID actually changes. This is to prevent
776  * unnecessary leakage of any subsidiary data attached to an finfo, since
777  * that would cause session-lifespan memory leaks.
778  */
779  if ((flags & TYPECACHE_EQ_OPR_FINFO) &&
780  typentry->eq_opr_finfo.fn_oid == InvalidOid &&
781  typentry->eq_opr != InvalidOid)
782  {
783  Oid eq_opr_func;
784 
785  eq_opr_func = get_opcode(typentry->eq_opr);
786  if (eq_opr_func != InvalidOid)
787  fmgr_info_cxt(eq_opr_func, &typentry->eq_opr_finfo,
789  }
790  if ((flags & TYPECACHE_CMP_PROC_FINFO) &&
791  typentry->cmp_proc_finfo.fn_oid == InvalidOid &&
792  typentry->cmp_proc != InvalidOid)
793  {
794  fmgr_info_cxt(typentry->cmp_proc, &typentry->cmp_proc_finfo,
796  }
797  if ((flags & TYPECACHE_HASH_PROC_FINFO) &&
798  typentry->hash_proc_finfo.fn_oid == InvalidOid &&
799  typentry->hash_proc != InvalidOid)
800  {
801  fmgr_info_cxt(typentry->hash_proc, &typentry->hash_proc_finfo,
803  }
804  if ((flags & TYPECACHE_HASH_EXTENDED_PROC_FINFO) &&
806  typentry->hash_extended_proc != InvalidOid)
807  {
809  &typentry->hash_extended_proc_finfo,
811  }
812 
813  /*
814  * If it's a composite type (row type), get tupdesc if requested
815  */
816  if ((flags & TYPECACHE_TUPDESC) &&
817  typentry->tupDesc == NULL &&
818  typentry->typtype == TYPTYPE_COMPOSITE)
819  {
820  load_typcache_tupdesc(typentry);
821  }
822 
823  /*
824  * If requested, get information about a range type
825  *
826  * This includes making sure that the basic info about the range element
827  * type is up-to-date.
828  */
829  if ((flags & TYPECACHE_RANGE_INFO) &&
830  typentry->typtype == TYPTYPE_RANGE)
831  {
832  if (typentry->rngelemtype == NULL)
833  load_rangetype_info(typentry);
834  else if (!(typentry->rngelemtype->flags & TCFLAGS_HAVE_PG_TYPE_DATA))
835  (void) lookup_type_cache(typentry->rngelemtype->type_id, 0);
836  }
837 
838  /*
839  * If requested, get information about a multirange type
840  */
841  if ((flags & TYPECACHE_MULTIRANGE_INFO) &&
842  typentry->rngtype == NULL &&
843  typentry->typtype == TYPTYPE_MULTIRANGE)
844  {
845  load_multirangetype_info(typentry);
846  }
847 
848  /*
849  * If requested, get information about a domain type
850  */
851  if ((flags & TYPECACHE_DOMAIN_BASE_INFO) &&
852  typentry->domainBaseType == InvalidOid &&
853  typentry->typtype == TYPTYPE_DOMAIN)
854  {
855  typentry->domainBaseTypmod = -1;
856  typentry->domainBaseType =
857  getBaseTypeAndTypmod(type_id, &typentry->domainBaseTypmod);
858  }
859  if ((flags & TYPECACHE_DOMAIN_CONSTR_INFO) &&
860  (typentry->flags & TCFLAGS_CHECKED_DOMAIN_CONSTRAINTS) == 0 &&
861  typentry->typtype == TYPTYPE_DOMAIN)
862  {
863  load_domaintype_info(typentry);
864  }
865 
866  return typentry;
867 }
static bool array_element_has_hashing(TypeCacheEntry *typentry)
Definition: typcache.c:1435
static void load_typcache_tupdesc(TypeCacheEntry *typentry)
Definition: typcache.c:873
Oid getBaseTypeAndTypmod(Oid typid, int32 *typmod)
Definition: lsyscache.c:2485
#define BTORDER_PROC
Definition: nbtree.h:700
#define TYPECACHE_RANGE_INFO
Definition: typcache.h:147
Oid GetDefaultOpClass(Oid type_id, Oid am_id)
Definition: indexcmds.c:2089
#define BTGreaterStrategyNumber
Definition: stratnum.h:33
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
Oid hash_opintype
Definition: typcache.h:60
#define TCFLAGS_CHECKED_EQ_OPR
Definition: typcache.c:87
#define HASH_ELEM
Definition: hsearch.h:95
static TypeCacheEntry * firstDomainTypeEntry
Definition: typcache.c:81
uint32 type_id_hash
Definition: typcache.h:36
#define TYPECACHE_HASH_EXTENDED_PROC_FINFO
Definition: typcache.h:151
static bool multirange_element_has_extended_hashing(TypeCacheEntry *typentry)
Definition: typcache.c:1666
static bool record_fields_have_extended_hashing(TypeCacheEntry *typentry)
Definition: typcache.c:1505
#define TCFLAGS_CHECKED_HASH_EXTENDED_PROC
Definition: typcache.c:92
#define TYPECACHE_MULTIRANGE_INFO
Definition: typcache.h:152
struct TypeCacheEntry TypeCacheEntry
Oid typcollation
Definition: typcache.h:47
#define TYPECACHE_EQ_OPR_FINFO
Definition: typcache.h:141
#define TYPECACHE_HASH_PROC_FINFO
Definition: typcache.h:143
Size entrysize
Definition: hsearch.h:76
#define TYPECACHE_EQ_OPR
Definition: typcache.h:136
int errcode(int sqlerrcode)
Definition: elog.c:698
#define HASHEXTENDED_PROC
Definition: hash.h:354
#define MemSet(start, val, len)
Definition: c.h:1008
#define GetSysCacheHashValue1(cacheId, key1)
Definition: syscache.h:202
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:954
unsigned int Oid
Definition: postgres_ext.h:31
int16 typlen
Definition: typcache.h:39
#define OidIsValid(objectId)
Definition: c.h:710
bool typbyval
Definition: typcache.h:40
void CacheRegisterRelcacheCallback(RelcacheCallbackFunction func, Datum arg)
Definition: inval.c:1540
Oid domainBaseType
Definition: typcache.h:113
FmgrInfo cmp_proc_finfo
Definition: typcache.h:76
struct TypeCacheEntry * nextDomain
Definition: typcache.h:132
#define TCFLAGS_CHECKED_GT_OPR
Definition: typcache.c:89
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
#define TCFLAGS_HAVE_PG_TYPE_DATA
Definition: typcache.c:84
#define HTEqualStrategyNumber
Definition: stratnum.h:41
static void load_multirangetype_info(TypeCacheEntry *typentry)
Definition: typcache.c:964
char typstorage
Definition: typcache.h:42
static void TypeCacheRelCallback(Datum arg, Oid relid)
Definition: typcache.c:2284
static bool array_element_has_compare(TypeCacheEntry *typentry)
Definition: typcache.c:1427
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:164
int32 domainBaseTypmod
Definition: typcache.h:114
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:349
Oid hash_extended_proc
Definition: typcache.h:66
FmgrInfo hash_proc_finfo
Definition: typcache.h:77
#define TYPECACHE_GT_OPR
Definition: typcache.h:138
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:136
#define HASHSTANDARD_PROC
Definition: hash.h:353
#define TYPECACHE_BTREE_OPFAMILY
Definition: typcache.h:145
struct TypeCacheEntry * rngelemtype
Definition: typcache.h:98
#define TYPECACHE_DOMAIN_BASE_INFO
Definition: typcache.h:148
static void TypeCacheTypCallback(Datum arg, int cacheid, uint32 hashvalue)
Definition: typcache.c:2349
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1127
static bool range_element_has_hashing(TypeCacheEntry *typentry)
Definition: typcache.c:1618
#define HASH_BLOBS
Definition: hsearch.h:97
FmgrInfo hash_extended_proc_finfo
Definition: typcache.h:78
void CacheRegisterSyscacheCallback(int cacheid, SyscacheCallbackFunction func, Datum arg)
Definition: inval.c:1498
#define TYPECACHE_HASH_EXTENDED_PROC
Definition: typcache.h:150
uintptr_t Datum
Definition: postgres.h:411
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1175
Oid btree_opintype
Definition: typcache.h:58
Size keysize
Definition: hsearch.h:75
FmgrInfo eq_opr_finfo
Definition: typcache.h:75
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:339
#define InvalidOid
Definition: postgres_ext.h:36
static void load_rangetype_info(TypeCacheEntry *typentry)
Definition: typcache.c:907
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1256
static bool multirange_element_has_hashing(TypeCacheEntry *typentry)
Definition: typcache.c:1658
Oid fn_oid
Definition: fmgr.h:59
#define ereport(elevel,...)
Definition: elog.h:157
#define TYPECACHE_CMP_PROC
Definition: typcache.h:139
char typtype
Definition: typcache.h:43
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:804
#define TYPECACHE_DOMAIN_CONSTR_INFO
Definition: typcache.h:149
Oid get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum)
Definition: lsyscache.c:794
void CreateCacheMemoryContext(void)
Definition: catcache.c:620
FormData_pg_type * Form_pg_type
Definition: pg_type.h:261
#define TCFLAGS_CHECKED_BTREE_OPCLASS
Definition: typcache.c:85
#define TCFLAGS_CHECKED_DOMAIN_CONSTRAINTS
Definition: typcache.c:103
struct TypeCacheEntry * rngtype
Definition: typcache.h:107
static bool record_fields_have_compare(TypeCacheEntry *typentry)
Definition: typcache.c:1489
Oid get_opclass_family(Oid opclass)
Definition: lsyscache.c:1183
static bool record_fields_have_hashing(TypeCacheEntry *typentry)
Definition: typcache.c:1497
static bool array_element_has_equality(TypeCacheEntry *typentry)
Definition: typcache.c:1419
static void load_domaintype_info(TypeCacheEntry *typentry)
Definition: typcache.c:986
Oid typsubscript
Definition: typcache.h:45
#define TCFLAGS_CHECKED_HASH_PROC
Definition: typcache.c:91
char typalign
Definition: typcache.h:41
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define TYPECACHE_LT_OPR
Definition: typcache.h:137
#define TCFLAGS_CHECKED_LT_OPR
Definition: typcache.c:88
#define NameStr(name)
Definition: c.h:681
#define TYPECACHE_CMP_PROC_FINFO
Definition: typcache.h:142
#define TCFLAGS_CHECKED_HASH_OPCLASS
Definition: typcache.c:86
static bool range_element_has_extended_hashing(TypeCacheEntry *typentry)
Definition: typcache.c:1626
#define TYPECACHE_HASH_OPFAMILY
Definition: typcache.h:146
static bool record_fields_have_equality(TypeCacheEntry *typentry)
Definition: typcache.c:1481
#define TCFLAGS_CHECKED_CMP_PROC
Definition: typcache.c:90
#define BTLessStrategyNumber
Definition: stratnum.h:29
static bool array_element_has_extended_hashing(TypeCacheEntry *typentry)
Definition: typcache.c:1443
TupleDesc tupDesc
Definition: typcache.h:89
static void TypeCacheConstrCallback(Datum arg, int cacheid, uint32 hashvalue)
Definition: typcache.c:2418
static HTAB * TypeCacheHash
Definition: typcache.c:78
#define TYPECACHE_HASH_PROC
Definition: typcache.h:140
#define TYPECACHE_TUPDESC
Definition: typcache.h:144
#define BTEqualStrategyNumber
Definition: stratnum.h:31
static void TypeCacheOpcCallback(Datum arg, int cacheid, uint32 hashvalue)
Definition: typcache.c:2389
MemoryContext CacheMemoryContext
Definition: mcxt.c:51
Oid get_opclass_input_type(Oid opclass)
Definition: lsyscache.c:1205

◆ SharedRecordTypmodRegistryAttach()

void SharedRecordTypmodRegistryAttach ( SharedRecordTypmodRegistry )

Definition at line 2201 of file typcache.c.

References Session::area, Assert, CurrentSession, dshash_attach(), IsParallelWorker, MemoryContextSwitchTo(), NextRecordTypmod, on_dsm_detach(), PointerGetDatum, SharedRecordTypmodRegistry::record_table_handle, Session::segment, Session::shared_record_table, shared_record_typmod_registry_detach(), Session::shared_typmod_registry, Session::shared_typmod_table, TopMemoryContext, and SharedRecordTypmodRegistry::typmod_table_handle.

Referenced by AttachSession().

2202 {
2203  MemoryContext old_context;
2204  dshash_table *record_table;
2205  dshash_table *typmod_table;
2206 
2208 
2209  /* We can't already be attached to a shared registry. */
2210  Assert(CurrentSession != NULL);
2211  Assert(CurrentSession->segment != NULL);
2212  Assert(CurrentSession->area != NULL);
2216 
2217  /*
2218  * We can't already have typmods in our local cache, because they'd clash
2219  * with those imported by SharedRecordTypmodRegistryInit. This should be
2220  * a freshly started parallel worker. If we ever support worker
2221  * recycling, a worker would need to zap its local cache in between
2222  * servicing different queries, in order to be able to call this and
2223  * synchronize typmods with a new leader; but that's problematic because
2224  * we can't be very sure that record-typmod-related state hasn't escaped
2225  * to anywhere else in the process.
2226  */
2227  Assert(NextRecordTypmod == 0);
2228 
2229  old_context = MemoryContextSwitchTo(TopMemoryContext);
2230 
2231  /* Attach to the two hash tables. */
2232  record_table = dshash_attach(CurrentSession->area,
2234  registry->record_table_handle,
2235  CurrentSession->area);
2236  typmod_table = dshash_attach(CurrentSession->area,
2238  registry->typmod_table_handle,
2239  NULL);
2240 
2241  MemoryContextSwitchTo(old_context);
2242 
2243  /*
2244  * Set up detach hook to run at worker exit. Currently this is the same
2245  * as the leader's detach hook, but in future they might need to be
2246  * different.
2247  */
2250  PointerGetDatum(registry));
2251 
2252  /*
2253  * Set up the session state that will tell assign_record_type_typmod and
2254  * lookup_rowtype_tupdesc_internal about the shared registry.
2255  */
2257  CurrentSession->shared_record_table = record_table;
2258  CurrentSession->shared_typmod_table = typmod_table;
2259 }
dshash_table * dshash_attach(dsa_area *area, const dshash_parameters *params, dshash_table_handle handle, void *arg)
Definition: dshash.c:263
#define PointerGetDatum(X)
Definition: postgres.h:600
Session * CurrentSession
Definition: session.c:48
static const dshash_parameters srtr_record_table_params
Definition: typcache.c:256
dshash_table * shared_record_table
Definition: session.h:32
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void on_dsm_detach(dsm_segment *seg, on_dsm_detach_callback function, Datum arg)
Definition: dsm.c:1096
dsa_area * area
Definition: session.h:28
#define IsParallelWorker()
Definition: parallel.h:61
MemoryContext TopMemoryContext
Definition: mcxt.c:48
static const dshash_parameters srtr_typmod_table_params
Definition: typcache.c:265
static void shared_record_typmod_registry_detach(dsm_segment *segment, Datum datum)
Definition: typcache.c:2867
static int32 NextRecordTypmod
Definition: typcache.c:280
struct SharedRecordTypmodRegistry * shared_typmod_registry
Definition: session.h:31
dshash_table * shared_typmod_table
Definition: session.h:33
#define Assert(condition)
Definition: c.h:804
dsm_segment * segment
Definition: session.h:27

◆ SharedRecordTypmodRegistryEstimate()

size_t SharedRecordTypmodRegistryEstimate ( void  )

Definition at line 2080 of file typcache.c.

Referenced by GetSessionDsmHandle().

2081 {
2082  return sizeof(SharedRecordTypmodRegistry);
2083 }
struct SharedRecordTypmodRegistry SharedRecordTypmodRegistry
Definition: typcache.h:175

◆ SharedRecordTypmodRegistryInit()

void SharedRecordTypmodRegistryInit ( SharedRecordTypmodRegistry ,
dsm_segment segment,
dsa_area area 
)

Definition at line 2102 of file typcache.c.

References Assert, CurrentSession, dshash_create(), dshash_find_or_insert(), dshash_get_hash_table_handle(), dshash_release_lock(), elog, ERROR, IsParallelWorker, SharedRecordTableEntry::key, SharedRecordTableKey::local_tupdesc, MemoryContextSwitchTo(), SharedRecordTypmodRegistry::next_typmod, NextRecordTypmod, on_dsm_detach(), pg_atomic_init_u32(), SharedRecordTypmodRegistry::record_table_handle, share_tupledesc(), SharedRecordTableKey::shared, Session::shared_record_table, shared_record_typmod_registry_detach(), SharedRecordTableKey::shared_tupdesc, SharedTypmodTableEntry::shared_tupdesc, Session::shared_typmod_registry, Session::shared_typmod_table, TupleDescData::tdtypmod, TopMemoryContext, SharedTypmodTableEntry::typmod, SharedRecordTypmodRegistry::typmod_table_handle, and SharedRecordTableKey::u.

Referenced by GetSessionDsmHandle().

2105 {
2106  MemoryContext old_context;
2107  dshash_table *record_table;
2108  dshash_table *typmod_table;
2109  int32 typmod;
2110 
2112 
2113  /* We can't already be attached to a shared registry. */
2117 
2118  old_context = MemoryContextSwitchTo(TopMemoryContext);
2119 
2120  /* Create the hash table of tuple descriptors indexed by themselves. */
2121  record_table = dshash_create(area, &srtr_record_table_params, area);
2122 
2123  /* Create the hash table of tuple descriptors indexed by typmod. */
2124  typmod_table = dshash_create(area, &srtr_typmod_table_params, NULL);
2125 
2126  MemoryContextSwitchTo(old_context);
2127 
2128  /* Initialize the SharedRecordTypmodRegistry. */
2129  registry->record_table_handle = dshash_get_hash_table_handle(record_table);
2130  registry->typmod_table_handle = dshash_get_hash_table_handle(typmod_table);
2131  pg_atomic_init_u32(&registry->next_typmod, NextRecordTypmod);
2132 
2133  /*
2134  * Copy all entries from this backend's private registry into the shared
2135  * registry.
2136  */
2137  for (typmod = 0; typmod < NextRecordTypmod; ++typmod)
2138  {
2139  SharedTypmodTableEntry *typmod_table_entry;
2140  SharedRecordTableEntry *record_table_entry;
2141  SharedRecordTableKey record_table_key;
2142  dsa_pointer shared_dp;
2143  TupleDesc tupdesc;
2144  bool found;
2145 
2146  tupdesc = RecordCacheArray[typmod];
2147  if (tupdesc == NULL)
2148  continue;
2149 
2150  /* Copy the TupleDesc into shared memory. */
2151  shared_dp = share_tupledesc(area, tupdesc, typmod);
2152 
2153  /* Insert into the typmod table. */
2154  typmod_table_entry = dshash_find_or_insert(typmod_table,
2155  &tupdesc->tdtypmod,
2156  &found);
2157  if (found)
2158  elog(ERROR, "cannot create duplicate shared record typmod");
2159  typmod_table_entry->typmod = tupdesc->tdtypmod;
2160  typmod_table_entry->shared_tupdesc = shared_dp;
2161  dshash_release_lock(typmod_table, typmod_table_entry);
2162 
2163  /* Insert into the record table. */
2164  record_table_key.shared = false;
2165  record_table_key.u.local_tupdesc = tupdesc;
2166  record_table_entry = dshash_find_or_insert(record_table,
2167  &record_table_key,
2168  &found);
2169  if (!found)
2170  {
2171  record_table_entry->key.shared = true;
2172  record_table_entry->key.u.shared_tupdesc = shared_dp;
2173  }
2174  dshash_release_lock(record_table, record_table_entry);
2175  }
2176 
2177  /*
2178  * Set up the global state that will tell assign_record_type_typmod and
2179  * lookup_rowtype_tupdesc_internal about the shared registry.
2180  */
2181  CurrentSession->shared_record_table = record_table;
2182  CurrentSession->shared_typmod_table = typmod_table;
2184 
2185  /*
2186  * We install a detach hook in the leader, but only to handle cleanup on
2187  * failure during GetSessionDsmHandle(). Once GetSessionDsmHandle() pins
2188  * the memory, the leader process will use a shared registry until it
2189  * exits.
2190  */
2192 }
Session * CurrentSession
Definition: session.c:48
static const dshash_parameters srtr_record_table_params
Definition: typcache.c:256
dshash_table * shared_record_table
Definition: session.h:32
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
SharedRecordTableKey key
Definition: typcache.c:198
void on_dsm_detach(dsm_segment *seg, on_dsm_detach_callback function, Datum arg)
Definition: dsm.c:1096
void dshash_release_lock(dshash_table *hash_table, void *entry)
Definition: dshash.c:561
uint64 dsa_pointer
Definition: dsa.h:62
signed int int32
Definition: c.h:429
static TupleDesc * RecordCacheArray
Definition: typcache.c:277
dsa_pointer shared_tupdesc
Definition: typcache.c:208
#define ERROR
Definition: elog.h:46
int32 tdtypmod
Definition: tupdesc.h:83
dshash_table_handle dshash_get_hash_table_handle(dshash_table *hash_table)
Definition: dshash.c:362
union SharedRecordTableKey::@28 u
dsa_pointer shared_tupdesc
Definition: typcache.c:187
#define IsParallelWorker()
Definition: parallel.h:61
MemoryContext TopMemoryContext
Definition: mcxt.c:48
static const dshash_parameters srtr_typmod_table_params
Definition: typcache.c:265
static void shared_record_typmod_registry_detach(dsm_segment *segment, Datum datum)
Definition: typcache.c:2867
static int32 NextRecordTypmod
Definition: typcache.c:280
struct SharedRecordTypmodRegistry * shared_typmod_registry
Definition: session.h:31
uintptr_t Datum
Definition: postgres.h:411
dshash_table * dshash_create(dsa_area *area, const dshash_parameters *params, void *arg)
Definition: dshash.c:196
dshash_table * shared_typmod_table
Definition: session.h:33
#define Assert(condition)
Definition: c.h:804
static dsa_pointer share_tupledesc(dsa_area *area, TupleDesc tupdesc, uint32 typmod)
Definition: typcache.c:2734
#define elog(elevel,...)
Definition: elog.h:232
void * dshash_find_or_insert(dshash_table *hash_table, const void *key, bool *found)
Definition: dshash.c:430
TupleDesc local_tupdesc
Definition: typcache.c:186
static void pg_atomic_init_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
Definition: atomics.h:223

◆ UpdateDomainConstraintRef()

void UpdateDomainConstraintRef ( DomainConstraintRef ref)

Definition at line 1343 of file typcache.c.

References DomainConstraintCache::constraints, DomainConstraintRef::constraints, DomainConstraintRef::dcc, DomainConstraintCache::dccRefCount, decr_dcc_refcount(), TypeCacheEntry::domainData, TypeCacheEntry::flags, load_domaintype_info(), DomainConstraintRef::need_exprstate, NIL, prep_domain_constraints(), DomainConstraintRef::refctx, DomainConstraintRef::tcache, TCFLAGS_CHECKED_DOMAIN_CONSTRAINTS, and TypeCacheEntry::typtype.

Referenced by domain_check_input().

1344 {
1345  TypeCacheEntry *typentry = ref->tcache;
1346 
1347  /* Make sure typcache entry's data is up to date */
1348  if ((typentry->flags & TCFLAGS_CHECKED_DOMAIN_CONSTRAINTS) == 0 &&
1349  typentry->typtype == TYPTYPE_DOMAIN)
1350  load_domaintype_info(typentry);
1351 
1352  /* Transfer to ref object if there's new info, adjusting refcounts */
1353  if (ref->dcc != typentry->domainData)
1354  {
1355  /* Paranoia --- be sure link is nulled before trying to release */
1356  DomainConstraintCache *dcc = ref->dcc;
1357 
1358  if (dcc)
1359  {
1360  /*
1361  * Note: we just leak the previous list of executable domain
1362  * constraints. Alternatively, we could keep those in a child
1363  * context of ref->refctx and free that context at this point.
1364  * However, in practice this code path will be taken so seldom
1365  * that the extra bookkeeping for a child context doesn't seem
1366  * worthwhile; we'll just allow a leak for the lifespan of refctx.
1367  */
1368  ref->constraints = NIL;
1369  ref->dcc = NULL;
1370  decr_dcc_refcount(dcc);
1371  }
1372  dcc = typentry->domainData;
1373  if (dcc)
1374  {
1375  ref->dcc = dcc;
1376  dcc->dccRefCount++;
1377  if (ref->need_exprstate)
1379  ref->refctx);
1380  else
1381  ref->constraints = dcc->constraints;
1382  }
1383  }
1384 }
#define NIL
Definition: pg_list.h:65
DomainConstraintCache * dcc
Definition: typcache.h:171
DomainConstraintCache * domainData
Definition: typcache.h:120
MemoryContext refctx
Definition: typcache.h:166
char typtype
Definition: typcache.h:43
static List * prep_domain_constraints(List *constraints, MemoryContext execctx)
Definition: typcache.c:1267
TypeCacheEntry * tcache
Definition: typcache.h:167
#define TCFLAGS_CHECKED_DOMAIN_CONSTRAINTS
Definition: typcache.c:103
static void load_domaintype_info(TypeCacheEntry *typentry)
Definition: typcache.c:986
static void decr_dcc_refcount(DomainConstraintCache *dcc)
Definition: typcache.c:1235