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)

Definition at line 156 of file typcache.h.

◆ TYPECACHE_BTREE_OPFAMILY

#define TYPECACHE_BTREE_OPFAMILY   0x00200

Definition at line 146 of file typcache.h.

◆ TYPECACHE_CMP_PROC

#define TYPECACHE_CMP_PROC   0x00008

Definition at line 140 of file typcache.h.

◆ TYPECACHE_CMP_PROC_FINFO

#define TYPECACHE_CMP_PROC_FINFO   0x00040

Definition at line 143 of file typcache.h.

◆ TYPECACHE_DOMAIN_BASE_INFO

#define TYPECACHE_DOMAIN_BASE_INFO   0x01000

Definition at line 149 of file typcache.h.

◆ TYPECACHE_DOMAIN_CONSTR_INFO

#define TYPECACHE_DOMAIN_CONSTR_INFO   0x02000

Definition at line 150 of file typcache.h.

◆ TYPECACHE_EQ_OPR

#define TYPECACHE_EQ_OPR   0x00001

Definition at line 137 of file typcache.h.

◆ TYPECACHE_EQ_OPR_FINFO

#define TYPECACHE_EQ_OPR_FINFO   0x00020

Definition at line 142 of file typcache.h.

◆ TYPECACHE_GT_OPR

#define TYPECACHE_GT_OPR   0x00004

Definition at line 139 of file typcache.h.

◆ TYPECACHE_HASH_EXTENDED_PROC

#define TYPECACHE_HASH_EXTENDED_PROC   0x04000

Definition at line 151 of file typcache.h.

◆ TYPECACHE_HASH_EXTENDED_PROC_FINFO

#define TYPECACHE_HASH_EXTENDED_PROC_FINFO   0x08000

Definition at line 152 of file typcache.h.

◆ TYPECACHE_HASH_OPFAMILY

#define TYPECACHE_HASH_OPFAMILY   0x00400

Definition at line 147 of file typcache.h.

◆ TYPECACHE_HASH_PROC

#define TYPECACHE_HASH_PROC   0x00010

Definition at line 141 of file typcache.h.

◆ TYPECACHE_HASH_PROC_FINFO

#define TYPECACHE_HASH_PROC_FINFO   0x00080

Definition at line 144 of file typcache.h.

◆ TYPECACHE_LT_OPR

#define TYPECACHE_LT_OPR   0x00002

Definition at line 138 of file typcache.h.

◆ TYPECACHE_MULTIRANGE_INFO

#define TYPECACHE_MULTIRANGE_INFO   0x10000

Definition at line 153 of file typcache.h.

◆ TYPECACHE_RANGE_INFO

#define TYPECACHE_RANGE_INFO   0x00800

Definition at line 148 of file typcache.h.

◆ TYPECACHE_TUPDESC

#define TYPECACHE_TUPDESC   0x00100

Definition at line 145 of file typcache.h.

Typedef Documentation

◆ DomainConstraintCache

Definition at line 1 of file typcache.h.

◆ DomainConstraintRef

◆ SharedRecordTypmodRegistry

Definition at line 1 of file typcache.h.

◆ TypeCacheEntry

Function Documentation

◆ assign_record_type_identifier()

uint64 assign_record_type_identifier ( Oid  type_id,
int32  typmod 
)

Definition at line 2062 of file typcache.c.

2063 {
2064  if (type_id != RECORDOID)
2065  {
2066  /*
2067  * It's a named composite type, so use the regular typcache.
2068  */
2069  TypeCacheEntry *typentry;
2070 
2071  typentry = lookup_type_cache(type_id, TYPECACHE_TUPDESC);
2072  if (typentry->tupDesc == NULL)
2073  ereport(ERROR,
2074  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2075  errmsg("type %s is not composite",
2076  format_type_be(type_id))));
2077  Assert(typentry->tupDesc_identifier != 0);
2078  return typentry->tupDesc_identifier;
2079  }
2080  else
2081  {
2082  /*
2083  * It's a transient record type, so look in our record-type table.
2084  */
2085  if (typmod >= 0 && typmod < RecordCacheArrayLen &&
2086  RecordCacheArray[typmod].tupdesc != NULL)
2087  {
2088  Assert(RecordCacheArray[typmod].id != 0);
2089  return RecordCacheArray[typmod].id;
2090  }
2091 
2092  /* For anonymous or unrecognized record type, generate a new ID */
2093  return ++tupledesc_id_counter;
2094  }
2095 }
#define Assert(condition)
Definition: c.h:858
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
uint64 tupDesc_identifier
Definition: typcache.h:90
TupleDesc tupDesc
Definition: typcache.h:89
static RecordCacheArrayEntry * RecordCacheArray
Definition: typcache.c:285
static int32 RecordCacheArrayLen
Definition: typcache.c:286
static uint64 tupledesc_id_counter
Definition: typcache.c:294
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:356
#define TYPECACHE_TUPDESC
Definition: typcache.h:145

References Assert, ereport, errcode(), errmsg(), ERROR, format_type_be(), RecordCacheArrayEntry::id, lookup_type_cache(), RecordCacheArray, RecordCacheArrayLen, 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().

◆ assign_record_type_typmod()

void assign_record_type_typmod ( TupleDesc  tupDesc)

Definition at line 1970 of file typcache.c.

1971 {
1972  RecordCacheEntry *recentry;
1973  TupleDesc entDesc;
1974  bool found;
1975  MemoryContext oldcxt;
1976 
1977  Assert(tupDesc->tdtypeid == RECORDOID);
1978 
1979  if (RecordCacheHash == NULL)
1980  {
1981  /* First time through: initialize the hash table */
1982  HASHCTL ctl;
1983 
1984  ctl.keysize = sizeof(TupleDesc); /* just the pointer */
1985  ctl.entrysize = sizeof(RecordCacheEntry);
1988  RecordCacheHash = hash_create("Record information cache", 64,
1989  &ctl,
1991 
1992  /* Also make sure CacheMemoryContext exists */
1993  if (!CacheMemoryContext)
1995  }
1996 
1997  /*
1998  * Find a hashtable entry for this tuple descriptor. We don't use
1999  * HASH_ENTER yet, because if it's missing, we need to make sure that all
2000  * the allocations succeed before we create the new entry.
2001  */
2003  &tupDesc,
2004  HASH_FIND, &found);
2005  if (found && recentry->tupdesc != NULL)
2006  {
2007  tupDesc->tdtypmod = recentry->tupdesc->tdtypmod;
2008  return;
2009  }
2010 
2011  /* Not present, so need to manufacture an entry */
2013 
2014  /* Look in the SharedRecordTypmodRegistry, if attached */
2015  entDesc = find_or_make_matching_shared_tupledesc(tupDesc);
2016  if (entDesc == NULL)
2017  {
2018  /*
2019  * Make sure we have room before we CreateTupleDescCopy() or advance
2020  * NextRecordTypmod.
2021  */
2023 
2024  /* Reference-counted local cache only. */
2025  entDesc = CreateTupleDescCopy(tupDesc);
2026  entDesc->tdrefcount = 1;
2027  entDesc->tdtypmod = NextRecordTypmod++;
2028  }
2029  else
2030  {
2032  }
2033 
2034  RecordCacheArray[entDesc->tdtypmod].tupdesc = entDesc;
2035 
2036  /* Assign a unique tupdesc identifier, too. */
2038 
2039  /* Fully initialized; create the hash table entry */
2041  &tupDesc,
2042  HASH_ENTER, NULL);
2043  recentry->tupdesc = entDesc;
2044 
2045  /* Update the caller's tuple descriptor. */
2046  tupDesc->tdtypmod = entDesc->tdtypmod;
2047 
2048  MemoryContextSwitchTo(oldcxt);
2049 }
void CreateCacheMemoryContext(void)
Definition: catcache.c:680
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:955
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:352
@ HASH_FIND
Definition: hsearch.h:113
@ HASH_ENTER
Definition: hsearch.h:114
#define HASH_ELEM
Definition: hsearch.h:95
#define HASH_COMPARE
Definition: hsearch.h:99
#define HASH_FUNCTION
Definition: hsearch.h:98
MemoryContext CacheMemoryContext
Definition: mcxt.c:152
MemoryContextSwitchTo(old_ctx)
tree ctl
Definition: radixtree.h:1853
TupleDesc tupdesc
Definition: typcache.c:159
int tdrefcount
Definition: tupdesc.h:84
int32 tdtypmod
Definition: tupdesc.h:83
Oid tdtypeid
Definition: tupdesc.h:82
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:133
struct TupleDescData * TupleDesc
Definition: tupdesc.h:89
static TupleDesc find_or_make_matching_shared_tupledesc(TupleDesc tupdesc)
Definition: typcache.c:2781
static int32 NextRecordTypmod
Definition: typcache.c:287
static HTAB * RecordCacheHash
Definition: typcache.c:276
struct RecordCacheEntry RecordCacheEntry
static int record_type_typmod_compare(const void *a, const void *b, size_t size)
Definition: typcache.c:1954
static void ensure_record_cache_typmod_slot_exists(int32 typmod)
Definition: typcache.c:1727
static uint32 record_type_typmod_hash(const void *data, size_t size)
Definition: typcache.c:1943

References Assert, CacheMemoryContext, CreateCacheMemoryContext(), CreateTupleDescCopy(), ctl, ensure_record_cache_typmod_slot_exists(), find_or_make_matching_shared_tupledesc(), HASH_COMPARE, hash_create(), HASH_ELEM, HASH_ENTER, HASH_FIND, HASH_FUNCTION, hash_search(), RecordCacheArrayEntry::id, MemoryContextSwitchTo(), NextRecordTypmod, record_type_typmod_compare(), record_type_typmod_hash(), RecordCacheArray, RecordCacheHash, TupleDescData::tdrefcount, TupleDescData::tdtypeid, TupleDescData::tdtypmod, RecordCacheEntry::tupdesc, RecordCacheArrayEntry::tupdesc, and tupledesc_id_counter.

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

◆ compare_values_of_enum()

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

Definition at line 2502 of file typcache.c.

2503 {
2504  TypeCacheEnumData *enumdata;
2505  EnumItem *item1;
2506  EnumItem *item2;
2507 
2508  /*
2509  * Equal OIDs are certainly equal --- this case was probably handled by
2510  * our caller, but we may as well check.
2511  */
2512  if (arg1 == arg2)
2513  return 0;
2514 
2515  /* Load up the cache if first time through */
2516  if (tcache->enumData == NULL)
2517  load_enum_cache_data(tcache);
2518  enumdata = tcache->enumData;
2519 
2520  /*
2521  * If both OIDs are known-sorted, we can just compare them directly.
2522  */
2523  if (enum_known_sorted(enumdata, arg1) &&
2524  enum_known_sorted(enumdata, arg2))
2525  {
2526  if (arg1 < arg2)
2527  return -1;
2528  else
2529  return 1;
2530  }
2531 
2532  /*
2533  * Slow path: we have to identify their actual sort-order positions.
2534  */
2535  item1 = find_enumitem(enumdata, arg1);
2536  item2 = find_enumitem(enumdata, arg2);
2537 
2538  if (item1 == NULL || item2 == NULL)
2539  {
2540  /*
2541  * We couldn't find one or both values. That means the enum has
2542  * changed under us, so re-initialize the cache and try again. We
2543  * don't bother retrying the known-sorted case in this path.
2544  */
2545  load_enum_cache_data(tcache);
2546  enumdata = tcache->enumData;
2547 
2548  item1 = find_enumitem(enumdata, arg1);
2549  item2 = find_enumitem(enumdata, arg2);
2550 
2551  /*
2552  * If we still can't find the values, complain: we must have corrupt
2553  * data.
2554  */
2555  if (item1 == NULL)
2556  elog(ERROR, "enum value %u not found in cache for enum %s",
2557  arg1, format_type_be(tcache->type_id));
2558  if (item2 == NULL)
2559  elog(ERROR, "enum value %u not found in cache for enum %s",
2560  arg2, format_type_be(tcache->type_id));
2561  }
2562 
2563  if (item1->sort_order < item2->sort_order)
2564  return -1;
2565  else if (item1->sort_order > item2->sort_order)
2566  return 1;
2567  else
2568  return 0;
2569 }
#define elog(elevel,...)
Definition: elog.h:225
float4 sort_order
Definition: typcache.c:135
struct TypeCacheEnumData * enumData
Definition: typcache.h:130
static void load_enum_cache_data(TypeCacheEntry *tcache)
Definition: typcache.c:2575
static EnumItem * find_enumitem(TypeCacheEnumData *enumdata, Oid arg)
Definition: typcache.c:2730
static bool enum_known_sorted(TypeCacheEnumData *enumdata, Oid arg)
Definition: typcache.c:2473

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().

◆ DomainHasConstraints()

bool DomainHasConstraints ( Oid  type_id)

Definition at line 1417 of file typcache.c.

1418 {
1419  TypeCacheEntry *typentry;
1420 
1421  /*
1422  * Note: a side effect is to cause the typcache's domain data to become
1423  * valid. This is fine since we'll likely need it soon if there is any.
1424  */
1425  typentry = lookup_type_cache(type_id, TYPECACHE_DOMAIN_CONSTR_INFO);
1426 
1427  return (typentry->domainData != NULL);
1428 }
DomainConstraintCache * domainData
Definition: typcache.h:121
#define TYPECACHE_DOMAIN_CONSTR_INFO
Definition: typcache.h:150

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

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

◆ InitDomainConstraintRef()

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

Definition at line 1330 of file typcache.c.

1332 {
1333  /* Look up the typcache entry --- we assume it survives indefinitely */
1335  ref->need_exprstate = need_exprstate;
1336  /* For safety, establish the callback before acquiring a refcount */
1337  ref->refctx = refctx;
1338  ref->dcc = NULL;
1340  ref->callback.arg = (void *) ref;
1342  /* Acquire refcount if there are constraints, and set up exported list */
1343  if (ref->tcache->domainData)
1344  {
1345  ref->dcc = ref->tcache->domainData;
1346  ref->dcc->dccRefCount++;
1347  if (ref->need_exprstate)
1349  ref->refctx);
1350  else
1351  ref->constraints = ref->dcc->constraints;
1352  }
1353  else
1354  ref->constraints = NIL;
1355 }
void MemoryContextRegisterResetCallback(MemoryContext context, MemoryContextCallback *cb)
Definition: mcxt.c:568
#define NIL
Definition: pg_list.h:68
DomainConstraintCache * dcc
Definition: typcache.h:172
MemoryContext refctx
Definition: typcache.h:167
MemoryContextCallback callback
Definition: typcache.h:173
TypeCacheEntry * tcache
Definition: typcache.h:168
MemoryContextCallbackFunction func
Definition: palloc.h:49
static List * prep_domain_constraints(List *constraints, MemoryContext execctx)
Definition: typcache.c:1292
static void dccref_deletion_callback(void *arg)
Definition: typcache.c:1271

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().

◆ lookup_rowtype_tupdesc()

◆ lookup_rowtype_tupdesc_copy()

TupleDesc lookup_rowtype_tupdesc_copy ( Oid  type_id,
int32  typmod 
)

Definition at line 1884 of file typcache.c.

1885 {
1886  TupleDesc tmp;
1887 
1888  tmp = lookup_rowtype_tupdesc_internal(type_id, typmod, false);
1889  return CreateTupleDescCopyConstr(tmp);
1890 }
TupleDesc CreateTupleDescCopyConstr(TupleDesc tupdesc)
Definition: tupdesc.c:173

References CreateTupleDescCopyConstr(), and lookup_rowtype_tupdesc_internal().

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

◆ lookup_rowtype_tupdesc_domain()

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

Definition at line 1906 of file typcache.c.

1907 {
1908  TupleDesc tupDesc;
1909 
1910  if (type_id != RECORDOID)
1911  {
1912  /*
1913  * Check for domain or named composite type. We might as well load
1914  * whichever data is needed.
1915  */
1916  TypeCacheEntry *typentry;
1917 
1918  typentry = lookup_type_cache(type_id,
1921  if (typentry->typtype == TYPTYPE_DOMAIN)
1923  typentry->domainBaseTypmod,
1924  noError);
1925  if (typentry->tupDesc == NULL && !noError)
1926  ereport(ERROR,
1927  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1928  errmsg("type %s is not composite",
1929  format_type_be(type_id))));
1930  tupDesc = typentry->tupDesc;
1931  }
1932  else
1933  tupDesc = lookup_rowtype_tupdesc_internal(type_id, typmod, noError);
1934  if (tupDesc != NULL)
1935  PinTupleDesc(tupDesc);
1936  return tupDesc;
1937 }
int32 domainBaseTypmod
Definition: typcache.h:115
char typtype
Definition: typcache.h:43
Oid domainBaseType
Definition: typcache.h:114
TupleDesc lookup_rowtype_tupdesc_noerror(Oid type_id, int32 typmod, bool noError)
Definition: typcache.c:1867
#define TYPECACHE_DOMAIN_BASE_INFO
Definition: typcache.h:149

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().

◆ lookup_rowtype_tupdesc_noerror()

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

Definition at line 1867 of file typcache.c.

1868 {
1869  TupleDesc tupDesc;
1870 
1871  tupDesc = lookup_rowtype_tupdesc_internal(type_id, typmod, noError);
1872  if (tupDesc != NULL)
1873  PinTupleDesc(tupDesc);
1874  return tupDesc;
1875 }

References lookup_rowtype_tupdesc_internal(), and PinTupleDesc.

Referenced by lookup_rowtype_tupdesc_domain().

◆ lookup_type_cache()

TypeCacheEntry* lookup_type_cache ( Oid  type_id,
int  flags 
)

Definition at line 356 of file typcache.c.

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

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(), TypeCacheEntry::cmp_proc, TypeCacheEntry::cmp_proc_finfo, CreateCacheMemoryContext(), ctl, TypeCacheEntry::domainBaseType, TypeCacheEntry::domainBaseTypmod, TypeCacheEntry::eq_opr, TypeCacheEntry::eq_opr_finfo, ereport, errcode(), errmsg(), ERROR, firstDomainTypeEntry, TypeCacheEntry::flags, fmgr_info_cxt(), FmgrInfo::fn_oid, get_hash_value(), get_opclass_family(), get_opclass_input_type(), get_opcode(), get_opfamily_member(), get_opfamily_proc(), getBaseTypeAndTypmod(), GetDefaultOpClass(), GETSTRUCT, TypeCacheEntry::gt_opr, hash_create(), HASH_ELEM, HASH_ENTER, TypeCacheEntry::hash_extended_proc, TypeCacheEntry::hash_extended_proc_finfo, HASH_FIND, HASH_FUNCTION, TypeCacheEntry::hash_opf, TypeCacheEntry::hash_opintype, TypeCacheEntry::hash_proc, TypeCacheEntry::hash_proc_finfo, hash_search(), HASHEXTENDED_PROC, HASHSTANDARD_PROC, HeapTupleIsValid, HTEqualStrategyNumber, InvalidOid, load_domaintype_info(), load_multirangetype_info(), load_rangetype_info(), load_typcache_tupdesc(), 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, type_cache_syshash(), 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(), TypeCacheHash, TypeCacheOpcCallback(), TypeCacheRelCallback(), TypeCacheTypCallback(), TypeCacheEntry::typelem, TypeCacheEntry::typlen, TypeCacheEntry::typrelid, TypeCacheEntry::typstorage, TypeCacheEntry::typsubscript, and TypeCacheEntry::typtype.

Referenced by analyzeCTE(), appendOrderBySuffix(), array_cmp(), array_contain_compare(), array_eq(), array_position_common(), array_positions(), array_replace_internal(), array_sample(), array_shuffle(), 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(), find_simplified_clause(), 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(), 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().

◆ SharedRecordTypmodRegistryAttach()

void SharedRecordTypmodRegistryAttach ( SharedRecordTypmodRegistry registry)

Definition at line 2224 of file typcache.c.

2225 {
2226  MemoryContext old_context;
2227  dshash_table *record_table;
2228  dshash_table *typmod_table;
2229 
2231 
2232  /* We can't already be attached to a shared registry. */
2233  Assert(CurrentSession != NULL);
2234  Assert(CurrentSession->segment != NULL);
2235  Assert(CurrentSession->area != NULL);
2239 
2240  /*
2241  * We can't already have typmods in our local cache, because they'd clash
2242  * with those imported by SharedRecordTypmodRegistryInit. This should be
2243  * a freshly started parallel worker. If we ever support worker
2244  * recycling, a worker would need to zap its local cache in between
2245  * servicing different queries, in order to be able to call this and
2246  * synchronize typmods with a new leader; but that's problematic because
2247  * we can't be very sure that record-typmod-related state hasn't escaped
2248  * to anywhere else in the process.
2249  */
2250  Assert(NextRecordTypmod == 0);
2251 
2252  old_context = MemoryContextSwitchTo(TopMemoryContext);
2253 
2254  /* Attach to the two hash tables. */
2255  record_table = dshash_attach(CurrentSession->area,
2257  registry->record_table_handle,
2258  CurrentSession->area);
2259  typmod_table = dshash_attach(CurrentSession->area,
2261  registry->typmod_table_handle,
2262  NULL);
2263 
2264  MemoryContextSwitchTo(old_context);
2265 
2266  /*
2267  * Set up detach hook to run at worker exit. Currently this is the same
2268  * as the leader's detach hook, but in future they might need to be
2269  * different.
2270  */
2273  PointerGetDatum(registry));
2274 
2275  /*
2276  * Set up the session state that will tell assign_record_type_typmod and
2277  * lookup_rowtype_tupdesc_internal about the shared registry.
2278  */
2280  CurrentSession->shared_record_table = record_table;
2281  CurrentSession->shared_typmod_table = typmod_table;
2282 }
dshash_table * dshash_attach(dsa_area *area, const dshash_parameters *params, dshash_table_handle handle, void *arg)
Definition: dshash.c:270
void on_dsm_detach(dsm_segment *seg, on_dsm_detach_callback function, Datum arg)
Definition: dsm.c:1132
#define IsParallelWorker()
Definition: parallel.h:60
MemoryContext TopMemoryContext
Definition: mcxt.c:149
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
Session * CurrentSession
Definition: session.c:48
dsm_segment * segment
Definition: session.h:27
dshash_table * shared_record_table
Definition: session.h:32
struct SharedRecordTypmodRegistry * shared_typmod_registry
Definition: session.h:31
dsa_area * area
Definition: session.h:28
dshash_table * shared_typmod_table
Definition: session.h:33
dshash_table_handle typmod_table_handle
Definition: typcache.c:171
dshash_table_handle record_table_handle
Definition: typcache.c:169
static const dshash_parameters srtr_typmod_table_params
Definition: typcache.c:266
static void shared_record_typmod_registry_detach(dsm_segment *segment, Datum datum)
Definition: typcache.c:2893
static const dshash_parameters srtr_record_table_params
Definition: typcache.c:256

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, srtr_record_table_params, srtr_typmod_table_params, TopMemoryContext, and SharedRecordTypmodRegistry::typmod_table_handle.

Referenced by AttachSession().

◆ SharedRecordTypmodRegistryEstimate()

size_t SharedRecordTypmodRegistryEstimate ( void  )

Definition at line 2103 of file typcache.c.

2104 {
2105  return sizeof(SharedRecordTypmodRegistry);
2106 }
struct SharedRecordTypmodRegistry SharedRecordTypmodRegistry
Definition: typcache.h:176

Referenced by GetSessionDsmHandle().

◆ SharedRecordTypmodRegistryInit()

void SharedRecordTypmodRegistryInit ( SharedRecordTypmodRegistry registry,
dsm_segment segment,
dsa_area area 
)

Definition at line 2125 of file typcache.c.

2128 {
2129  MemoryContext old_context;
2130  dshash_table *record_table;
2131  dshash_table *typmod_table;
2132  int32 typmod;
2133 
2135 
2136  /* We can't already be attached to a shared registry. */
2140 
2141  old_context = MemoryContextSwitchTo(TopMemoryContext);
2142 
2143  /* Create the hash table of tuple descriptors indexed by themselves. */
2144  record_table = dshash_create(area, &srtr_record_table_params, area);
2145 
2146  /* Create the hash table of tuple descriptors indexed by typmod. */
2147  typmod_table = dshash_create(area, &srtr_typmod_table_params, NULL);
2148 
2149  MemoryContextSwitchTo(old_context);
2150 
2151  /* Initialize the SharedRecordTypmodRegistry. */
2152  registry->record_table_handle = dshash_get_hash_table_handle(record_table);
2153  registry->typmod_table_handle = dshash_get_hash_table_handle(typmod_table);
2155 
2156  /*
2157  * Copy all entries from this backend's private registry into the shared
2158  * registry.
2159  */
2160  for (typmod = 0; typmod < NextRecordTypmod; ++typmod)
2161  {
2162  SharedTypmodTableEntry *typmod_table_entry;
2163  SharedRecordTableEntry *record_table_entry;
2164  SharedRecordTableKey record_table_key;
2165  dsa_pointer shared_dp;
2166  TupleDesc tupdesc;
2167  bool found;
2168 
2169  tupdesc = RecordCacheArray[typmod].tupdesc;
2170  if (tupdesc == NULL)
2171  continue;
2172 
2173  /* Copy the TupleDesc into shared memory. */
2174  shared_dp = share_tupledesc(area, tupdesc, typmod);
2175 
2176  /* Insert into the typmod table. */
2177  typmod_table_entry = dshash_find_or_insert(typmod_table,
2178  &tupdesc->tdtypmod,
2179  &found);
2180  if (found)
2181  elog(ERROR, "cannot create duplicate shared record typmod");
2182  typmod_table_entry->typmod = tupdesc->tdtypmod;
2183  typmod_table_entry->shared_tupdesc = shared_dp;
2184  dshash_release_lock(typmod_table, typmod_table_entry);
2185 
2186  /* Insert into the record table. */
2187  record_table_key.shared = false;
2188  record_table_key.u.local_tupdesc = tupdesc;
2189  record_table_entry = dshash_find_or_insert(record_table,
2190  &record_table_key,
2191  &found);
2192  if (!found)
2193  {
2194  record_table_entry->key.shared = true;
2195  record_table_entry->key.u.shared_tupdesc = shared_dp;
2196  }
2197  dshash_release_lock(record_table, record_table_entry);
2198  }
2199 
2200  /*
2201  * Set up the global state that will tell assign_record_type_typmod and
2202  * lookup_rowtype_tupdesc_internal about the shared registry.
2203  */
2204  CurrentSession->shared_record_table = record_table;
2205  CurrentSession->shared_typmod_table = typmod_table;
2207 
2208  /*
2209  * We install a detach hook in the leader, but only to handle cleanup on
2210  * failure during GetSessionDsmHandle(). Once GetSessionDsmHandle() pins
2211  * the memory, the leader process will use a shared registry until it
2212  * exits.
2213  */
2215 }
static void pg_atomic_init_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
Definition: atomics.h:221
signed int int32
Definition: c.h:494
uint64 dsa_pointer
Definition: dsa.h:62
void dshash_release_lock(dshash_table *hash_table, void *entry)
Definition: dshash.c:558
dshash_table_handle dshash_get_hash_table_handle(dshash_table *hash_table)
Definition: dshash.c:367
void * dshash_find_or_insert(dshash_table *hash_table, const void *key, bool *found)
Definition: dshash.c:433
dshash_table * dshash_create(dsa_area *area, const dshash_parameters *params, void *arg)
Definition: dshash.c:206
SharedRecordTableKey key
Definition: typcache.c:198
TupleDesc local_tupdesc
Definition: typcache.c:186
union SharedRecordTableKey::@33 u
dsa_pointer shared_tupdesc
Definition: typcache.c:187
pg_atomic_uint32 next_typmod
Definition: typcache.c:173
dsa_pointer shared_tupdesc
Definition: typcache.c:208
static dsa_pointer share_tupledesc(dsa_area *area, TupleDesc tupdesc, uint32 typmod)
Definition: typcache.c:2760

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, RecordCacheArray, 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, srtr_record_table_params, srtr_typmod_table_params, TupleDescData::tdtypmod, TopMemoryContext, RecordCacheArrayEntry::tupdesc, SharedTypmodTableEntry::typmod, SharedRecordTypmodRegistry::typmod_table_handle, and SharedRecordTableKey::u.

Referenced by GetSessionDsmHandle().

◆ UpdateDomainConstraintRef()

void UpdateDomainConstraintRef ( DomainConstraintRef ref)

Definition at line 1368 of file typcache.c.

1369 {
1370  TypeCacheEntry *typentry = ref->tcache;
1371 
1372  /* Make sure typcache entry's data is up to date */
1373  if ((typentry->flags & TCFLAGS_CHECKED_DOMAIN_CONSTRAINTS) == 0 &&
1374  typentry->typtype == TYPTYPE_DOMAIN)
1375  load_domaintype_info(typentry);
1376 
1377  /* Transfer to ref object if there's new info, adjusting refcounts */
1378  if (ref->dcc != typentry->domainData)
1379  {
1380  /* Paranoia --- be sure link is nulled before trying to release */
1381  DomainConstraintCache *dcc = ref->dcc;
1382 
1383  if (dcc)
1384  {
1385  /*
1386  * Note: we just leak the previous list of executable domain
1387  * constraints. Alternatively, we could keep those in a child
1388  * context of ref->refctx and free that context at this point.
1389  * However, in practice this code path will be taken so seldom
1390  * that the extra bookkeeping for a child context doesn't seem
1391  * worthwhile; we'll just allow a leak for the lifespan of refctx.
1392  */
1393  ref->constraints = NIL;
1394  ref->dcc = NULL;
1395  decr_dcc_refcount(dcc);
1396  }
1397  dcc = typentry->domainData;
1398  if (dcc)
1399  {
1400  ref->dcc = dcc;
1401  dcc->dccRefCount++;
1402  if (ref->need_exprstate)
1404  ref->refctx);
1405  else
1406  ref->constraints = dcc->constraints;
1407  }
1408  }
1409 }
static void decr_dcc_refcount(DomainConstraintCache *dcc)
Definition: typcache.c:1260

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().