PostgreSQL Source Code  git master
typcache.c File Reference
#include "postgres.h"
#include <limits.h>
#include "access/hash.h"
#include "access/htup_details.h"
#include "access/nbtree.h"
#include "access/parallel.h"
#include "access/relation.h"
#include "access/session.h"
#include "access/table.h"
#include "catalog/pg_am.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_enum.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_range.h"
#include "catalog/pg_type.h"
#include "commands/defrem.h"
#include "common/int.h"
#include "executor/executor.h"
#include "lib/dshash.h"
#include "optimizer/optimizer.h"
#include "port/pg_bitutils.h"
#include "storage/lwlock.h"
#include "utils/builtins.h"
#include "utils/catcache.h"
#include "utils/fmgroids.h"
#include "utils/injection_point.h"
#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/syscache.h"
#include "utils/typcache.h"
Include dependency graph for typcache.c:

Go to the source code of this file.

Data Structures

struct  RelIdToTypeIdCacheEntry
 
struct  DomainConstraintCache
 
struct  EnumItem
 
struct  TypeCacheEnumData
 
struct  RecordCacheEntry
 
struct  SharedRecordTypmodRegistry
 
struct  SharedRecordTableKey
 
struct  SharedRecordTableEntry
 
struct  SharedTypmodTableEntry
 
struct  RecordCacheArrayEntry
 

Macros

#define TCFLAGS_HAVE_PG_TYPE_DATA   0x000001
 
#define TCFLAGS_CHECKED_BTREE_OPCLASS   0x000002
 
#define TCFLAGS_CHECKED_HASH_OPCLASS   0x000004
 
#define TCFLAGS_CHECKED_EQ_OPR   0x000008
 
#define TCFLAGS_CHECKED_LT_OPR   0x000010
 
#define TCFLAGS_CHECKED_GT_OPR   0x000020
 
#define TCFLAGS_CHECKED_CMP_PROC   0x000040
 
#define TCFLAGS_CHECKED_HASH_PROC   0x000080
 
#define TCFLAGS_CHECKED_HASH_EXTENDED_PROC   0x000100
 
#define TCFLAGS_CHECKED_ELEM_PROPERTIES   0x000200
 
#define TCFLAGS_HAVE_ELEM_EQUALITY   0x000400
 
#define TCFLAGS_HAVE_ELEM_COMPARE   0x000800
 
#define TCFLAGS_HAVE_ELEM_HASHING   0x001000
 
#define TCFLAGS_HAVE_ELEM_EXTENDED_HASHING   0x002000
 
#define TCFLAGS_CHECKED_FIELD_PROPERTIES   0x004000
 
#define TCFLAGS_HAVE_FIELD_EQUALITY   0x008000
 
#define TCFLAGS_HAVE_FIELD_COMPARE   0x010000
 
#define TCFLAGS_HAVE_FIELD_HASHING   0x020000
 
#define TCFLAGS_HAVE_FIELD_EXTENDED_HASHING   0x040000
 
#define TCFLAGS_CHECKED_DOMAIN_CONSTRAINTS   0x080000
 
#define TCFLAGS_DOMAIN_BASE_IS_COMPOSITE   0x100000
 
#define TCFLAGS_OPERATOR_FLAGS
 

Typedefs

typedef struct RelIdToTypeIdCacheEntry RelIdToTypeIdCacheEntry
 
typedef struct TypeCacheEnumData TypeCacheEnumData
 
typedef struct RecordCacheEntry RecordCacheEntry
 
typedef struct SharedRecordTableKey SharedRecordTableKey
 
typedef struct SharedRecordTableEntry SharedRecordTableEntry
 
typedef struct SharedTypmodTableEntry SharedTypmodTableEntry
 
typedef struct RecordCacheArrayEntry RecordCacheArrayEntry
 

Functions

static int shared_record_table_compare (const void *a, const void *b, size_t size, void *arg)
 
static uint32 shared_record_table_hash (const void *a, size_t size, void *arg)
 
static void load_typcache_tupdesc (TypeCacheEntry *typentry)
 
static void load_rangetype_info (TypeCacheEntry *typentry)
 
static void load_multirangetype_info (TypeCacheEntry *typentry)
 
static void load_domaintype_info (TypeCacheEntry *typentry)
 
static int dcs_cmp (const void *a, const void *b)
 
static void decr_dcc_refcount (DomainConstraintCache *dcc)
 
static void dccref_deletion_callback (void *arg)
 
static Listprep_domain_constraints (List *constraints, MemoryContext execctx)
 
static bool array_element_has_equality (TypeCacheEntry *typentry)
 
static bool array_element_has_compare (TypeCacheEntry *typentry)
 
static bool array_element_has_hashing (TypeCacheEntry *typentry)
 
static bool array_element_has_extended_hashing (TypeCacheEntry *typentry)
 
static void cache_array_element_properties (TypeCacheEntry *typentry)
 
static bool record_fields_have_equality (TypeCacheEntry *typentry)
 
static bool record_fields_have_compare (TypeCacheEntry *typentry)
 
static bool record_fields_have_hashing (TypeCacheEntry *typentry)
 
static bool record_fields_have_extended_hashing (TypeCacheEntry *typentry)
 
static void cache_record_field_properties (TypeCacheEntry *typentry)
 
static bool range_element_has_hashing (TypeCacheEntry *typentry)
 
static bool range_element_has_extended_hashing (TypeCacheEntry *typentry)
 
static void cache_range_element_properties (TypeCacheEntry *typentry)
 
static bool multirange_element_has_hashing (TypeCacheEntry *typentry)
 
static bool multirange_element_has_extended_hashing (TypeCacheEntry *typentry)
 
static void cache_multirange_element_properties (TypeCacheEntry *typentry)
 
static void TypeCacheRelCallback (Datum arg, Oid relid)
 
static void TypeCacheTypCallback (Datum arg, int cacheid, uint32 hashvalue)
 
static void TypeCacheOpcCallback (Datum arg, int cacheid, uint32 hashvalue)
 
static void TypeCacheConstrCallback (Datum arg, int cacheid, uint32 hashvalue)
 
static void load_enum_cache_data (TypeCacheEntry *tcache)
 
static EnumItemfind_enumitem (TypeCacheEnumData *enumdata, Oid arg)
 
static int enum_oid_cmp (const void *left, const void *right)
 
static void shared_record_typmod_registry_detach (dsm_segment *segment, Datum datum)
 
static TupleDesc find_or_make_matching_shared_tupledesc (TupleDesc tupdesc)
 
static dsa_pointer share_tupledesc (dsa_area *area, TupleDesc tupdesc, uint32 typmod)
 
static void insert_rel_type_cache_if_needed (TypeCacheEntry *typentry)
 
static void delete_rel_type_cache_if_needed (TypeCacheEntry *typentry)
 
static uint32 type_cache_syshash (const void *key, Size keysize)
 
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)
 
static void ensure_record_cache_typmod_slot_exists (int32 typmod)
 
static TupleDesc lookup_rowtype_tupdesc_internal (Oid type_id, int32 typmod, bool noError)
 
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)
 
static uint32 record_type_typmod_hash (const void *data, size_t size)
 
static int record_type_typmod_compare (const void *a, const void *b, size_t size)
 
void assign_record_type_typmod (TupleDesc tupDesc)
 
uint64 assign_record_type_identifier (Oid type_id, int32 typmod)
 
size_t SharedRecordTypmodRegistryEstimate (void)
 
void SharedRecordTypmodRegistryInit (SharedRecordTypmodRegistry *registry, dsm_segment *segment, dsa_area *area)
 
void SharedRecordTypmodRegistryAttach (SharedRecordTypmodRegistry *registry)
 
static void InvalidateCompositeTypeCacheEntry (TypeCacheEntry *typentry)
 
static bool enum_known_sorted (TypeCacheEnumData *enumdata, Oid arg)
 
int compare_values_of_enum (TypeCacheEntry *tcache, Oid arg1, Oid arg2)
 
static void finalize_in_progress_typentries (void)
 
void AtEOXact_TypeCache (void)
 
void AtEOSubXact_TypeCache (void)
 

Variables

static HTABTypeCacheHash = NULL
 
static HTABRelIdToTypeIdCacheHash = NULL
 
static TypeCacheEntryfirstDomainTypeEntry = NULL
 
static Oidin_progress_list
 
static int in_progress_list_len
 
static int in_progress_list_maxlen
 
static const dshash_parameters srtr_record_table_params
 
static const dshash_parameters srtr_typmod_table_params
 
static HTABRecordCacheHash = NULL
 
static RecordCacheArrayEntryRecordCacheArray = NULL
 
static int32 RecordCacheArrayLen = 0
 
static int32 NextRecordTypmod = 0
 
static uint64 tupledesc_id_counter = INVALID_TUPLEDESC_IDENTIFIER
 

Macro Definition Documentation

◆ TCFLAGS_CHECKED_BTREE_OPCLASS

#define TCFLAGS_CHECKED_BTREE_OPCLASS   0x000002

Definition at line 100 of file typcache.c.

◆ TCFLAGS_CHECKED_CMP_PROC

#define TCFLAGS_CHECKED_CMP_PROC   0x000040

Definition at line 105 of file typcache.c.

◆ TCFLAGS_CHECKED_DOMAIN_CONSTRAINTS

#define TCFLAGS_CHECKED_DOMAIN_CONSTRAINTS   0x080000

Definition at line 118 of file typcache.c.

◆ TCFLAGS_CHECKED_ELEM_PROPERTIES

#define TCFLAGS_CHECKED_ELEM_PROPERTIES   0x000200

Definition at line 108 of file typcache.c.

◆ TCFLAGS_CHECKED_EQ_OPR

#define TCFLAGS_CHECKED_EQ_OPR   0x000008

Definition at line 102 of file typcache.c.

◆ TCFLAGS_CHECKED_FIELD_PROPERTIES

#define TCFLAGS_CHECKED_FIELD_PROPERTIES   0x004000

Definition at line 113 of file typcache.c.

◆ TCFLAGS_CHECKED_GT_OPR

#define TCFLAGS_CHECKED_GT_OPR   0x000020

Definition at line 104 of file typcache.c.

◆ TCFLAGS_CHECKED_HASH_EXTENDED_PROC

#define TCFLAGS_CHECKED_HASH_EXTENDED_PROC   0x000100

Definition at line 107 of file typcache.c.

◆ TCFLAGS_CHECKED_HASH_OPCLASS

#define TCFLAGS_CHECKED_HASH_OPCLASS   0x000004

Definition at line 101 of file typcache.c.

◆ TCFLAGS_CHECKED_HASH_PROC

#define TCFLAGS_CHECKED_HASH_PROC   0x000080

Definition at line 106 of file typcache.c.

◆ TCFLAGS_CHECKED_LT_OPR

#define TCFLAGS_CHECKED_LT_OPR   0x000010

Definition at line 103 of file typcache.c.

◆ TCFLAGS_DOMAIN_BASE_IS_COMPOSITE

#define TCFLAGS_DOMAIN_BASE_IS_COMPOSITE   0x100000

Definition at line 119 of file typcache.c.

◆ TCFLAGS_HAVE_ELEM_COMPARE

#define TCFLAGS_HAVE_ELEM_COMPARE   0x000800

Definition at line 110 of file typcache.c.

◆ TCFLAGS_HAVE_ELEM_EQUALITY

#define TCFLAGS_HAVE_ELEM_EQUALITY   0x000400

Definition at line 109 of file typcache.c.

◆ TCFLAGS_HAVE_ELEM_EXTENDED_HASHING

#define TCFLAGS_HAVE_ELEM_EXTENDED_HASHING   0x002000

Definition at line 112 of file typcache.c.

◆ TCFLAGS_HAVE_ELEM_HASHING

#define TCFLAGS_HAVE_ELEM_HASHING   0x001000

Definition at line 111 of file typcache.c.

◆ TCFLAGS_HAVE_FIELD_COMPARE

#define TCFLAGS_HAVE_FIELD_COMPARE   0x010000

Definition at line 115 of file typcache.c.

◆ TCFLAGS_HAVE_FIELD_EQUALITY

#define TCFLAGS_HAVE_FIELD_EQUALITY   0x008000

Definition at line 114 of file typcache.c.

◆ TCFLAGS_HAVE_FIELD_EXTENDED_HASHING

#define TCFLAGS_HAVE_FIELD_EXTENDED_HASHING   0x040000

Definition at line 117 of file typcache.c.

◆ TCFLAGS_HAVE_FIELD_HASHING

#define TCFLAGS_HAVE_FIELD_HASHING   0x020000

Definition at line 116 of file typcache.c.

◆ TCFLAGS_HAVE_PG_TYPE_DATA

#define TCFLAGS_HAVE_PG_TYPE_DATA   0x000001

Definition at line 99 of file typcache.c.

◆ TCFLAGS_OPERATOR_FLAGS

#define TCFLAGS_OPERATOR_FLAGS
Value:
TCFLAGS_CHECKED_DOMAIN_CONSTRAINTS | \
TCFLAGS_DOMAIN_BASE_IS_COMPOSITE))
#define TCFLAGS_HAVE_PG_TYPE_DATA
Definition: typcache.c:99

Definition at line 122 of file typcache.c.

Typedef Documentation

◆ RecordCacheArrayEntry

◆ RecordCacheEntry

◆ RelIdToTypeIdCacheEntry

◆ SharedRecordTableEntry

◆ SharedRecordTableKey

◆ SharedTypmodTableEntry

◆ TypeCacheEnumData

Function Documentation

◆ array_element_has_compare()

static bool array_element_has_compare ( TypeCacheEntry typentry)
static

Definition at line 1522 of file typcache.c.

1523 {
1524  if (!(typentry->flags & TCFLAGS_CHECKED_ELEM_PROPERTIES))
1526  return (typentry->flags & TCFLAGS_HAVE_ELEM_COMPARE) != 0;
1527 }
#define TCFLAGS_HAVE_ELEM_COMPARE
Definition: typcache.c:110
static void cache_array_element_properties(TypeCacheEntry *typentry)
Definition: typcache.c:1546
#define TCFLAGS_CHECKED_ELEM_PROPERTIES
Definition: typcache.c:108

References cache_array_element_properties(), TypeCacheEntry::flags, TCFLAGS_CHECKED_ELEM_PROPERTIES, and TCFLAGS_HAVE_ELEM_COMPARE.

Referenced by lookup_type_cache().

◆ array_element_has_equality()

static bool array_element_has_equality ( TypeCacheEntry typentry)
static

Definition at line 1514 of file typcache.c.

1515 {
1516  if (!(typentry->flags & TCFLAGS_CHECKED_ELEM_PROPERTIES))
1518  return (typentry->flags & TCFLAGS_HAVE_ELEM_EQUALITY) != 0;
1519 }
#define TCFLAGS_HAVE_ELEM_EQUALITY
Definition: typcache.c:109

References cache_array_element_properties(), TypeCacheEntry::flags, TCFLAGS_CHECKED_ELEM_PROPERTIES, and TCFLAGS_HAVE_ELEM_EQUALITY.

Referenced by lookup_type_cache().

◆ array_element_has_extended_hashing()

static bool array_element_has_extended_hashing ( TypeCacheEntry typentry)
static

Definition at line 1538 of file typcache.c.

1539 {
1540  if (!(typentry->flags & TCFLAGS_CHECKED_ELEM_PROPERTIES))
1542  return (typentry->flags & TCFLAGS_HAVE_ELEM_EXTENDED_HASHING) != 0;
1543 }
#define TCFLAGS_HAVE_ELEM_EXTENDED_HASHING
Definition: typcache.c:112

References cache_array_element_properties(), TypeCacheEntry::flags, TCFLAGS_CHECKED_ELEM_PROPERTIES, and TCFLAGS_HAVE_ELEM_EXTENDED_HASHING.

Referenced by lookup_type_cache().

◆ array_element_has_hashing()

static bool array_element_has_hashing ( TypeCacheEntry typentry)
static

Definition at line 1530 of file typcache.c.

1531 {
1532  if (!(typentry->flags & TCFLAGS_CHECKED_ELEM_PROPERTIES))
1534  return (typentry->flags & TCFLAGS_HAVE_ELEM_HASHING) != 0;
1535 }
#define TCFLAGS_HAVE_ELEM_HASHING
Definition: typcache.c:111

References cache_array_element_properties(), TypeCacheEntry::flags, TCFLAGS_CHECKED_ELEM_PROPERTIES, and TCFLAGS_HAVE_ELEM_HASHING.

Referenced by lookup_type_cache().

◆ assign_record_type_identifier()

uint64 assign_record_type_identifier ( Oid  type_id,
int32  typmod 
)

Definition at line 2132 of file typcache.c.

2133 {
2134  if (type_id != RECORDOID)
2135  {
2136  /*
2137  * It's a named composite type, so use the regular typcache.
2138  */
2139  TypeCacheEntry *typentry;
2140 
2141  typentry = lookup_type_cache(type_id, TYPECACHE_TUPDESC);
2142  if (typentry->tupDesc == NULL)
2143  ereport(ERROR,
2144  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2145  errmsg("type %s is not composite",
2146  format_type_be(type_id))));
2147  Assert(typentry->tupDesc_identifier != 0);
2148  return typentry->tupDesc_identifier;
2149  }
2150  else
2151  {
2152  /*
2153  * It's a transient record type, so look in our record-type table.
2154  */
2155  if (typmod >= 0 && typmod < RecordCacheArrayLen &&
2156  RecordCacheArray[typmod].tupdesc != NULL)
2157  {
2158  Assert(RecordCacheArray[typmod].id != 0);
2159  return RecordCacheArray[typmod].id;
2160  }
2161 
2162  /* For anonymous or unrecognized record type, generate a new ID */
2163  return ++tupledesc_id_counter;
2164  }
2165 }
#define Assert(condition)
Definition: c.h:812
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:304
static int32 RecordCacheArrayLen
Definition: typcache.c:305
static uint64 tupledesc_id_counter
Definition: typcache.c:313
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:386
#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 2040 of file typcache.c.

2041 {
2042  RecordCacheEntry *recentry;
2043  TupleDesc entDesc;
2044  bool found;
2045  MemoryContext oldcxt;
2046 
2047  Assert(tupDesc->tdtypeid == RECORDOID);
2048 
2049  if (RecordCacheHash == NULL)
2050  {
2051  /* First time through: initialize the hash table */
2052  HASHCTL ctl;
2053 
2054  ctl.keysize = sizeof(TupleDesc); /* just the pointer */
2055  ctl.entrysize = sizeof(RecordCacheEntry);
2058  RecordCacheHash = hash_create("Record information cache", 64,
2059  &ctl,
2061 
2062  /* Also make sure CacheMemoryContext exists */
2063  if (!CacheMemoryContext)
2065  }
2066 
2067  /*
2068  * Find a hashtable entry for this tuple descriptor. We don't use
2069  * HASH_ENTER yet, because if it's missing, we need to make sure that all
2070  * the allocations succeed before we create the new entry.
2071  */
2073  &tupDesc,
2074  HASH_FIND, &found);
2075  if (found && recentry->tupdesc != NULL)
2076  {
2077  tupDesc->tdtypmod = recentry->tupdesc->tdtypmod;
2078  return;
2079  }
2080 
2081  /* Not present, so need to manufacture an entry */
2083 
2084  /* Look in the SharedRecordTypmodRegistry, if attached */
2085  entDesc = find_or_make_matching_shared_tupledesc(tupDesc);
2086  if (entDesc == NULL)
2087  {
2088  /*
2089  * Make sure we have room before we CreateTupleDescCopy() or advance
2090  * NextRecordTypmod.
2091  */
2093 
2094  /* Reference-counted local cache only. */
2095  entDesc = CreateTupleDescCopy(tupDesc);
2096  entDesc->tdrefcount = 1;
2097  entDesc->tdtypmod = NextRecordTypmod++;
2098  }
2099  else
2100  {
2102  }
2103 
2104  RecordCacheArray[entDesc->tdtypmod].tupdesc = entDesc;
2105 
2106  /* Assign a unique tupdesc identifier, too. */
2108 
2109  /* Fully initialized; create the hash table entry */
2111  &tupDesc,
2112  HASH_ENTER, NULL);
2113  recentry->tupdesc = entDesc;
2114 
2115  /* Update the caller's tuple descriptor. */
2116  tupDesc->tdtypmod = entDesc->tdtypmod;
2117 
2118  MemoryContextSwitchTo(oldcxt);
2119 }
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:174
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:2929
static int32 NextRecordTypmod
Definition: typcache.c:306
static HTAB * RecordCacheHash
Definition: typcache.c:295
struct RecordCacheEntry RecordCacheEntry
static int record_type_typmod_compare(const void *a, const void *b, size_t size)
Definition: typcache.c:2024
static void ensure_record_cache_typmod_slot_exists(int32 typmod)
Definition: typcache.c:1797
static uint32 record_type_typmod_hash(const void *data, size_t size)
Definition: typcache.c:2013

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

◆ AtEOSubXact_TypeCache()

void AtEOSubXact_TypeCache ( void  )

Definition at line 3184 of file typcache.c.

3185 {
3187 }
static void finalize_in_progress_typentries(void)
Definition: typcache.c:3159

References finalize_in_progress_typentries().

Referenced by AbortSubTransaction(), and CommitSubTransaction().

◆ AtEOXact_TypeCache()

void AtEOXact_TypeCache ( void  )

Definition at line 3178 of file typcache.c.

3179 {
3181 }

References finalize_in_progress_typentries().

Referenced by AbortTransaction(), CommitTransaction(), and PrepareTransaction().

◆ cache_array_element_properties()

static void cache_array_element_properties ( TypeCacheEntry typentry)
static

Definition at line 1546 of file typcache.c.

1547 {
1548  Oid elem_type = get_base_element_type(typentry->type_id);
1549 
1550  if (OidIsValid(elem_type))
1551  {
1552  TypeCacheEntry *elementry;
1553 
1554  elementry = lookup_type_cache(elem_type,
1559  if (OidIsValid(elementry->eq_opr))
1560  typentry->flags |= TCFLAGS_HAVE_ELEM_EQUALITY;
1561  if (OidIsValid(elementry->cmp_proc))
1562  typentry->flags |= TCFLAGS_HAVE_ELEM_COMPARE;
1563  if (OidIsValid(elementry->hash_proc))
1564  typentry->flags |= TCFLAGS_HAVE_ELEM_HASHING;
1565  if (OidIsValid(elementry->hash_extended_proc))
1567  }
1569 }
#define OidIsValid(objectId)
Definition: c.h:729
Oid get_base_element_type(Oid typid)
Definition: lsyscache.c:2832
unsigned int Oid
Definition: postgres_ext.h:31
Oid hash_extended_proc
Definition: typcache.h:66
#define TYPECACHE_EQ_OPR
Definition: typcache.h:137
#define TYPECACHE_HASH_EXTENDED_PROC
Definition: typcache.h:151
#define TYPECACHE_CMP_PROC
Definition: typcache.h:140
#define TYPECACHE_HASH_PROC
Definition: typcache.h:141

References TypeCacheEntry::cmp_proc, TypeCacheEntry::eq_opr, TypeCacheEntry::flags, get_base_element_type(), TypeCacheEntry::hash_extended_proc, TypeCacheEntry::hash_proc, lookup_type_cache(), OidIsValid, TCFLAGS_CHECKED_ELEM_PROPERTIES, TCFLAGS_HAVE_ELEM_COMPARE, TCFLAGS_HAVE_ELEM_EQUALITY, TCFLAGS_HAVE_ELEM_EXTENDED_HASHING, TCFLAGS_HAVE_ELEM_HASHING, TypeCacheEntry::type_id, TYPECACHE_CMP_PROC, TYPECACHE_EQ_OPR, TYPECACHE_HASH_EXTENDED_PROC, and TYPECACHE_HASH_PROC.

Referenced by array_element_has_compare(), array_element_has_equality(), array_element_has_extended_hashing(), and array_element_has_hashing().

◆ cache_multirange_element_properties()

static void cache_multirange_element_properties ( TypeCacheEntry typentry)
static

Definition at line 1769 of file typcache.c.

1770 {
1771  /* load up range link if we didn't already */
1772  if (typentry->rngtype == NULL &&
1773  typentry->typtype == TYPTYPE_MULTIRANGE)
1774  load_multirangetype_info(typentry);
1775 
1776  if (typentry->rngtype != NULL && typentry->rngtype->rngelemtype != NULL)
1777  {
1778  TypeCacheEntry *elementry;
1779 
1780  /* might need to calculate subtype's hash function properties */
1781  elementry = lookup_type_cache(typentry->rngtype->rngelemtype->type_id,
1784  if (OidIsValid(elementry->hash_proc))
1785  typentry->flags |= TCFLAGS_HAVE_ELEM_HASHING;
1786  if (OidIsValid(elementry->hash_extended_proc))
1788  }
1790 }
struct TypeCacheEntry * rngelemtype
Definition: typcache.h:98
char typtype
Definition: typcache.h:43
struct TypeCacheEntry * rngtype
Definition: typcache.h:108
static void load_multirangetype_info(TypeCacheEntry *typentry)
Definition: typcache.c:1059

References TypeCacheEntry::flags, TypeCacheEntry::hash_extended_proc, TypeCacheEntry::hash_proc, load_multirangetype_info(), lookup_type_cache(), OidIsValid, TypeCacheEntry::rngelemtype, TypeCacheEntry::rngtype, TCFLAGS_CHECKED_ELEM_PROPERTIES, TCFLAGS_HAVE_ELEM_EXTENDED_HASHING, TCFLAGS_HAVE_ELEM_HASHING, TypeCacheEntry::type_id, TYPECACHE_HASH_EXTENDED_PROC, TYPECACHE_HASH_PROC, and TypeCacheEntry::typtype.

Referenced by multirange_element_has_extended_hashing(), and multirange_element_has_hashing().

◆ cache_range_element_properties()

static void cache_range_element_properties ( TypeCacheEntry typentry)
static

Definition at line 1729 of file typcache.c.

1730 {
1731  /* load up subtype link if we didn't already */
1732  if (typentry->rngelemtype == NULL &&
1733  typentry->typtype == TYPTYPE_RANGE)
1734  load_rangetype_info(typentry);
1735 
1736  if (typentry->rngelemtype != NULL)
1737  {
1738  TypeCacheEntry *elementry;
1739 
1740  /* might need to calculate subtype's hash function properties */
1741  elementry = lookup_type_cache(typentry->rngelemtype->type_id,
1744  if (OidIsValid(elementry->hash_proc))
1745  typentry->flags |= TCFLAGS_HAVE_ELEM_HASHING;
1746  if (OidIsValid(elementry->hash_extended_proc))
1748  }
1750 }
static void load_rangetype_info(TypeCacheEntry *typentry)
Definition: typcache.c:1001

References TypeCacheEntry::flags, TypeCacheEntry::hash_extended_proc, TypeCacheEntry::hash_proc, load_rangetype_info(), lookup_type_cache(), OidIsValid, TypeCacheEntry::rngelemtype, TCFLAGS_CHECKED_ELEM_PROPERTIES, TCFLAGS_HAVE_ELEM_EXTENDED_HASHING, TCFLAGS_HAVE_ELEM_HASHING, TypeCacheEntry::type_id, TYPECACHE_HASH_EXTENDED_PROC, TYPECACHE_HASH_PROC, and TypeCacheEntry::typtype.

Referenced by range_element_has_extended_hashing(), and range_element_has_hashing().

◆ cache_record_field_properties()

static void cache_record_field_properties ( TypeCacheEntry typentry)
static

Definition at line 1608 of file typcache.c.

1609 {
1610  /*
1611  * For type RECORD, we can't really tell what will work, since we don't
1612  * have access here to the specific anonymous type. Just assume that
1613  * equality and comparison will (we may get a failure at runtime). We
1614  * could also claim that hashing works, but then if code that has the
1615  * option between a comparison-based (sort-based) and a hash-based plan
1616  * chooses hashing, stuff could fail that would otherwise work if it chose
1617  * a comparison-based plan. In practice more types support comparison
1618  * than hashing.
1619  */
1620  if (typentry->type_id == RECORDOID)
1621  {
1622  typentry->flags |= (TCFLAGS_HAVE_FIELD_EQUALITY |
1624  }
1625  else if (typentry->typtype == TYPTYPE_COMPOSITE)
1626  {
1627  TupleDesc tupdesc;
1628  int newflags;
1629  int i;
1630 
1631  /* Fetch composite type's tupdesc if we don't have it already */
1632  if (typentry->tupDesc == NULL)
1633  load_typcache_tupdesc(typentry);
1634  tupdesc = typentry->tupDesc;
1635 
1636  /* Must bump the refcount while we do additional catalog lookups */
1637  IncrTupleDescRefCount(tupdesc);
1638 
1639  /* Have each property if all non-dropped fields have the property */
1640  newflags = (TCFLAGS_HAVE_FIELD_EQUALITY |
1644  for (i = 0; i < tupdesc->natts; i++)
1645  {
1646  TypeCacheEntry *fieldentry;
1647  Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
1648 
1649  if (attr->attisdropped)
1650  continue;
1651 
1652  fieldentry = lookup_type_cache(attr->atttypid,
1657  if (!OidIsValid(fieldentry->eq_opr))
1658  newflags &= ~TCFLAGS_HAVE_FIELD_EQUALITY;
1659  if (!OidIsValid(fieldentry->cmp_proc))
1660  newflags &= ~TCFLAGS_HAVE_FIELD_COMPARE;
1661  if (!OidIsValid(fieldentry->hash_proc))
1662  newflags &= ~TCFLAGS_HAVE_FIELD_HASHING;
1663  if (!OidIsValid(fieldentry->hash_extended_proc))
1665 
1666  /* We can drop out of the loop once we disprove all bits */
1667  if (newflags == 0)
1668  break;
1669  }
1670  typentry->flags |= newflags;
1671 
1672  DecrTupleDescRefCount(tupdesc);
1673  }
1674  else if (typentry->typtype == TYPTYPE_DOMAIN)
1675  {
1676  /* If it's domain over composite, copy base type's properties */
1677  TypeCacheEntry *baseentry;
1678 
1679  /* load up basetype info if we didn't already */
1680  if (typentry->domainBaseType == InvalidOid)
1681  {
1682  typentry->domainBaseTypmod = -1;
1683  typentry->domainBaseType =
1684  getBaseTypeAndTypmod(typentry->type_id,
1685  &typentry->domainBaseTypmod);
1686  }
1687  baseentry = lookup_type_cache(typentry->domainBaseType,
1692  if (baseentry->typtype == TYPTYPE_COMPOSITE)
1693  {
1695  typentry->flags |= baseentry->flags & (TCFLAGS_HAVE_FIELD_EQUALITY |
1699  }
1700  }
1702 }
int i
Definition: isn.c:72
Oid getBaseTypeAndTypmod(Oid typid, int32 *typmod)
Definition: lsyscache.c:2538
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
#define InvalidOid
Definition: postgres_ext.h:36
int32 domainBaseTypmod
Definition: typcache.h:115
Oid domainBaseType
Definition: typcache.h:114
void DecrTupleDescRefCount(TupleDesc tupdesc)
Definition: tupdesc.c:406
void IncrTupleDescRefCount(TupleDesc tupdesc)
Definition: tupdesc.c:388
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
#define TCFLAGS_CHECKED_FIELD_PROPERTIES
Definition: typcache.c:113
#define TCFLAGS_HAVE_FIELD_COMPARE
Definition: typcache.c:115
#define TCFLAGS_DOMAIN_BASE_IS_COMPOSITE
Definition: typcache.c:119
#define TCFLAGS_HAVE_FIELD_EQUALITY
Definition: typcache.c:114
#define TCFLAGS_HAVE_FIELD_EXTENDED_HASHING
Definition: typcache.c:117
#define TCFLAGS_HAVE_FIELD_HASHING
Definition: typcache.c:116
static void load_typcache_tupdesc(TypeCacheEntry *typentry)
Definition: typcache.c:967

References TypeCacheEntry::cmp_proc, DecrTupleDescRefCount(), TypeCacheEntry::domainBaseType, TypeCacheEntry::domainBaseTypmod, TypeCacheEntry::eq_opr, TypeCacheEntry::flags, getBaseTypeAndTypmod(), TypeCacheEntry::hash_extended_proc, TypeCacheEntry::hash_proc, i, IncrTupleDescRefCount(), InvalidOid, load_typcache_tupdesc(), lookup_type_cache(), TupleDescData::natts, OidIsValid, TCFLAGS_CHECKED_FIELD_PROPERTIES, TCFLAGS_DOMAIN_BASE_IS_COMPOSITE, TCFLAGS_HAVE_FIELD_COMPARE, TCFLAGS_HAVE_FIELD_EQUALITY, TCFLAGS_HAVE_FIELD_EXTENDED_HASHING, TCFLAGS_HAVE_FIELD_HASHING, TypeCacheEntry::tupDesc, TupleDescAttr, TypeCacheEntry::type_id, TYPECACHE_CMP_PROC, TYPECACHE_EQ_OPR, TYPECACHE_HASH_EXTENDED_PROC, TYPECACHE_HASH_PROC, and TypeCacheEntry::typtype.

Referenced by record_fields_have_compare(), record_fields_have_equality(), record_fields_have_extended_hashing(), and record_fields_have_hashing().

◆ compare_values_of_enum()

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

Definition at line 2650 of file typcache.c.

2651 {
2652  TypeCacheEnumData *enumdata;
2653  EnumItem *item1;
2654  EnumItem *item2;
2655 
2656  /*
2657  * Equal OIDs are certainly equal --- this case was probably handled by
2658  * our caller, but we may as well check.
2659  */
2660  if (arg1 == arg2)
2661  return 0;
2662 
2663  /* Load up the cache if first time through */
2664  if (tcache->enumData == NULL)
2665  load_enum_cache_data(tcache);
2666  enumdata = tcache->enumData;
2667 
2668  /*
2669  * If both OIDs are known-sorted, we can just compare them directly.
2670  */
2671  if (enum_known_sorted(enumdata, arg1) &&
2672  enum_known_sorted(enumdata, arg2))
2673  {
2674  if (arg1 < arg2)
2675  return -1;
2676  else
2677  return 1;
2678  }
2679 
2680  /*
2681  * Slow path: we have to identify their actual sort-order positions.
2682  */
2683  item1 = find_enumitem(enumdata, arg1);
2684  item2 = find_enumitem(enumdata, arg2);
2685 
2686  if (item1 == NULL || item2 == NULL)
2687  {
2688  /*
2689  * We couldn't find one or both values. That means the enum has
2690  * changed under us, so re-initialize the cache and try again. We
2691  * don't bother retrying the known-sorted case in this path.
2692  */
2693  load_enum_cache_data(tcache);
2694  enumdata = tcache->enumData;
2695 
2696  item1 = find_enumitem(enumdata, arg1);
2697  item2 = find_enumitem(enumdata, arg2);
2698 
2699  /*
2700  * If we still can't find the values, complain: we must have corrupt
2701  * data.
2702  */
2703  if (item1 == NULL)
2704  elog(ERROR, "enum value %u not found in cache for enum %s",
2705  arg1, format_type_be(tcache->type_id));
2706  if (item2 == NULL)
2707  elog(ERROR, "enum value %u not found in cache for enum %s",
2708  arg2, format_type_be(tcache->type_id));
2709  }
2710 
2711  if (item1->sort_order < item2->sort_order)
2712  return -1;
2713  else if (item1->sort_order > item2->sort_order)
2714  return 1;
2715  else
2716  return 0;
2717 }
#define elog(elevel,...)
Definition: elog.h:225
float4 sort_order
Definition: typcache.c:150
struct TypeCacheEnumData * enumData
Definition: typcache.h:130
static void load_enum_cache_data(TypeCacheEntry *tcache)
Definition: typcache.c:2723
static EnumItem * find_enumitem(TypeCacheEnumData *enumdata, Oid arg)
Definition: typcache.c:2878
static bool enum_known_sorted(TypeCacheEnumData *enumdata, Oid arg)
Definition: typcache.c:2621

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

◆ dccref_deletion_callback()

static void dccref_deletion_callback ( void *  arg)
static

Definition at line 1341 of file typcache.c.

1342 {
1344  DomainConstraintCache *dcc = ref->dcc;
1345 
1346  /* Paranoia --- be sure link is nulled before trying to release */
1347  if (dcc)
1348  {
1349  ref->constraints = NIL;
1350  ref->dcc = NULL;
1351  decr_dcc_refcount(dcc);
1352  }
1353 }
void * arg
#define NIL
Definition: pg_list.h:68
DomainConstraintCache * dcc
Definition: typcache.h:172
static void decr_dcc_refcount(DomainConstraintCache *dcc)
Definition: typcache.c:1330

References arg, DomainConstraintRef::constraints, DomainConstraintRef::dcc, decr_dcc_refcount(), and NIL.

Referenced by InitDomainConstraintRef().

◆ dcs_cmp()

static int dcs_cmp ( const void *  a,
const void *  b 
)
static

Definition at line 1317 of file typcache.c.

1318 {
1319  const DomainConstraintState *const *ca = (const DomainConstraintState *const *) a;
1320  const DomainConstraintState *const *cb = (const DomainConstraintState *const *) b;
1321 
1322  return strcmp((*ca)->name, (*cb)->name);
1323 }
int b
Definition: isn.c:69
int a
Definition: isn.c:68

References a, and b.

Referenced by load_domaintype_info().

◆ decr_dcc_refcount()

static void decr_dcc_refcount ( DomainConstraintCache dcc)
static

Definition at line 1330 of file typcache.c.

1331 {
1332  Assert(dcc->dccRefCount > 0);
1333  if (--(dcc->dccRefCount) <= 0)
1335 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:454
MemoryContext dccContext
Definition: typcache.c:142

References Assert, DomainConstraintCache::dccContext, DomainConstraintCache::dccRefCount, and MemoryContextDelete().

Referenced by dccref_deletion_callback(), load_domaintype_info(), and UpdateDomainConstraintRef().

◆ delete_rel_type_cache_if_needed()

static void delete_rel_type_cache_if_needed ( TypeCacheEntry typentry)
static

Definition at line 3095 of file typcache.c.

3096 {
3097 #ifdef USE_ASSERT_CHECKING
3098  int i;
3099  bool is_in_progress = false;
3100 
3101  for (i = 0; i < in_progress_list_len; i++)
3102  {
3103  if (in_progress_list[i] == typentry->type_id)
3104  {
3105  is_in_progress = true;
3106  break;
3107  }
3108  }
3109 #endif
3110 
3111  /* Immediately quit for non-composite types */
3112  if (typentry->typtype != TYPTYPE_COMPOSITE)
3113  return;
3114 
3115  /* typrelid should be given for composite types */
3116  Assert(OidIsValid(typentry->typrelid));
3117 
3118  /*
3119  * Delete a RelIdToTypeIdCacheHash entry if the typentry doesn't have any
3120  * information indicating entry should be still there.
3121  */
3122  if (!(typentry->flags & TCFLAGS_HAVE_PG_TYPE_DATA) &&
3123  !(typentry->flags & TCFLAGS_OPERATOR_FLAGS) &&
3124  typentry->tupDesc == NULL)
3125  {
3126  bool found;
3127 
3129  &typentry->typrelid,
3130  HASH_REMOVE, &found);
3131  Assert(found || is_in_progress);
3132  }
3133  else
3134  {
3135 #ifdef USE_ASSERT_CHECKING
3136  /*
3137  * In assert-enabled builds otherwise check for RelIdToTypeIdCacheHash
3138  * entry if it should exist.
3139  */
3140  bool found;
3141 
3142  if (!is_in_progress)
3143  {
3145  &typentry->typrelid,
3146  HASH_FIND, &found);
3147  Assert(found);
3148  }
3149 #endif
3150  }
3151 }
@ HASH_REMOVE
Definition: hsearch.h:115
#define TCFLAGS_OPERATOR_FLAGS
Definition: typcache.c:122
static HTAB * RelIdToTypeIdCacheHash
Definition: typcache.c:87
static Oid * in_progress_list
Definition: typcache.c:226
static int in_progress_list_len
Definition: typcache.c:227

References Assert, TypeCacheEntry::flags, HASH_FIND, HASH_REMOVE, hash_search(), i, in_progress_list, in_progress_list_len, OidIsValid, RelIdToTypeIdCacheHash, TCFLAGS_HAVE_PG_TYPE_DATA, TCFLAGS_OPERATOR_FLAGS, TypeCacheEntry::tupDesc, TypeCacheEntry::type_id, TypeCacheEntry::typrelid, and TypeCacheEntry::typtype.

Referenced by InvalidateCompositeTypeCacheEntry(), and TypeCacheTypCallback().

◆ DomainHasConstraints()

bool DomainHasConstraints ( Oid  type_id)

Definition at line 1487 of file typcache.c.

1488 {
1489  TypeCacheEntry *typentry;
1490 
1491  /*
1492  * Note: a side effect is to cause the typcache's domain data to become
1493  * valid. This is fine since we'll likely need it soon if there is any.
1494  */
1495  typentry = lookup_type_cache(type_id, TYPECACHE_DOMAIN_CONSTR_INFO);
1496 
1497  return (typentry->domainData != NULL);
1498 }
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().

◆ ensure_record_cache_typmod_slot_exists()

static void ensure_record_cache_typmod_slot_exists ( int32  typmod)
static

Definition at line 1797 of file typcache.c.

1798 {
1799  if (RecordCacheArray == NULL)
1800  {
1803  64 * sizeof(RecordCacheArrayEntry));
1804  RecordCacheArrayLen = 64;
1805  }
1806 
1807  if (typmod >= RecordCacheArrayLen)
1808  {
1809  int32 newlen = pg_nextpower2_32(typmod + 1);
1810 
1814  newlen);
1815  RecordCacheArrayLen = newlen;
1816  }
1817 }
int32_t int32
Definition: c.h:481
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1215
#define repalloc0_array(pointer, type, oldcount, count)
Definition: palloc.h:109
static uint32 pg_nextpower2_32(uint32 num)
Definition: pg_bitutils.h:189

References CacheMemoryContext, MemoryContextAllocZero(), pg_nextpower2_32(), RecordCacheArray, RecordCacheArrayLen, and repalloc0_array.

Referenced by assign_record_type_typmod(), and lookup_rowtype_tupdesc_internal().

◆ enum_known_sorted()

static bool enum_known_sorted ( TypeCacheEnumData enumdata,
Oid  arg 
)
inlinestatic

Definition at line 2621 of file typcache.c.

2622 {
2623  Oid offset;
2624 
2625  if (arg < enumdata->bitmap_base)
2626  return false;
2627  offset = arg - enumdata->bitmap_base;
2628  if (offset > (Oid) INT_MAX)
2629  return false;
2630  return bms_is_member((int) offset, enumdata->sorted_values);
2631 }
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:510
Bitmapset * sorted_values
Definition: typcache.c:156

References arg, TypeCacheEnumData::bitmap_base, bms_is_member(), and TypeCacheEnumData::sorted_values.

Referenced by compare_values_of_enum().

◆ enum_oid_cmp()

static int enum_oid_cmp ( const void *  left,
const void *  right 
)
static

Definition at line 2895 of file typcache.c.

2896 {
2897  const EnumItem *l = (const EnumItem *) left;
2898  const EnumItem *r = (const EnumItem *) right;
2899 
2900  return pg_cmp_u32(l->enum_oid, r->enum_oid);
2901 }
static int pg_cmp_u32(uint32 a, uint32 b)
Definition: int.h:604
Oid enum_oid
Definition: typcache.c:149

References EnumItem::enum_oid, and pg_cmp_u32().

Referenced by find_enumitem(), and load_enum_cache_data().

◆ finalize_in_progress_typentries()

static void finalize_in_progress_typentries ( void  )
static

Definition at line 3159 of file typcache.c.

3160 {
3161  int i;
3162 
3163  for (i = 0; i < in_progress_list_len; i++)
3164  {
3165  TypeCacheEntry *typentry;
3166 
3167  typentry = (TypeCacheEntry *) hash_search(TypeCacheHash,
3168  &in_progress_list[i],
3169  HASH_FIND, NULL);
3170  if (typentry)
3172  }
3173 
3175 }
static void insert_rel_type_cache_if_needed(TypeCacheEntry *typentry)
Definition: typcache.c:3061
static HTAB * TypeCacheHash
Definition: typcache.c:79

References HASH_FIND, hash_search(), i, in_progress_list, in_progress_list_len, insert_rel_type_cache_if_needed(), and TypeCacheHash.

Referenced by AtEOSubXact_TypeCache(), and AtEOXact_TypeCache().

◆ find_enumitem()

static EnumItem * find_enumitem ( TypeCacheEnumData enumdata,
Oid  arg 
)
static

Definition at line 2878 of file typcache.c.

2879 {
2880  EnumItem srch;
2881 
2882  /* On some versions of Solaris, bsearch of zero items dumps core */
2883  if (enumdata->num_values <= 0)
2884  return NULL;
2885 
2886  srch.enum_oid = arg;
2887  return bsearch(&srch, enumdata->enum_values, enumdata->num_values,
2888  sizeof(EnumItem), enum_oid_cmp);
2889 }
EnumItem enum_values[FLEXIBLE_ARRAY_MEMBER]
Definition: typcache.c:158
static int enum_oid_cmp(const void *left, const void *right)
Definition: typcache.c:2895

References arg, EnumItem::enum_oid, enum_oid_cmp(), TypeCacheEnumData::enum_values, and TypeCacheEnumData::num_values.

Referenced by compare_values_of_enum().

◆ find_or_make_matching_shared_tupledesc()

static TupleDesc find_or_make_matching_shared_tupledesc ( TupleDesc  tupdesc)
static

Definition at line 2929 of file typcache.c.

2930 {
2931  TupleDesc result;
2933  SharedRecordTableEntry *record_table_entry;
2934  SharedTypmodTableEntry *typmod_table_entry;
2935  dsa_pointer shared_dp;
2936  bool found;
2937  uint32 typmod;
2938 
2939  /* If not even attached, nothing to do. */
2941  return NULL;
2942 
2943  /* Try to find a matching tuple descriptor in the record table. */
2944  key.shared = false;
2945  key.u.local_tupdesc = tupdesc;
2946  record_table_entry = (SharedRecordTableEntry *)
2948  if (record_table_entry)
2949  {
2950  Assert(record_table_entry->key.shared);
2952  record_table_entry);
2953  result = (TupleDesc)
2955  record_table_entry->key.u.shared_tupdesc);
2956  Assert(result->tdrefcount == -1);
2957 
2958  return result;
2959  }
2960 
2961  /* Allocate a new typmod number. This will be wasted if we error out. */
2962  typmod = (int)
2964  1);
2965 
2966  /* Copy the TupleDesc into shared memory. */
2967  shared_dp = share_tupledesc(CurrentSession->area, tupdesc, typmod);
2968 
2969  /*
2970  * Create an entry in the typmod table so that others will understand this
2971  * typmod number.
2972  */
2973  PG_TRY();
2974  {
2975  typmod_table_entry = (SharedTypmodTableEntry *)
2977  &typmod, &found);
2978  if (found)
2979  elog(ERROR, "cannot create duplicate shared record typmod");
2980  }
2981  PG_CATCH();
2982  {
2983  dsa_free(CurrentSession->area, shared_dp);
2984  PG_RE_THROW();
2985  }
2986  PG_END_TRY();
2987  typmod_table_entry->typmod = typmod;
2988  typmod_table_entry->shared_tupdesc = shared_dp;
2990  typmod_table_entry);
2991 
2992  /*
2993  * Finally create an entry in the record table so others with matching
2994  * tuple descriptors can reuse the typmod.
2995  */
2996  record_table_entry = (SharedRecordTableEntry *)
2998  &found);
2999  if (found)
3000  {
3001  /*
3002  * Someone concurrently inserted a matching tuple descriptor since the
3003  * first time we checked. Use that one instead.
3004  */
3006  record_table_entry);
3007 
3008  /* Might as well free up the space used by the one we created. */
3010  &typmod);
3011  Assert(found);
3012  dsa_free(CurrentSession->area, shared_dp);
3013 
3014  /* Return the one we found. */
3015  Assert(record_table_entry->key.shared);
3016  result = (TupleDesc)
3018  record_table_entry->key.u.shared_tupdesc);
3019  Assert(result->tdrefcount == -1);
3020 
3021  return result;
3022  }
3023 
3024  /* Store it and return it. */
3025  record_table_entry->key.shared = true;
3026  record_table_entry->key.u.shared_tupdesc = shared_dp;
3028  record_table_entry);
3029  result = (TupleDesc)
3030  dsa_get_address(CurrentSession->area, shared_dp);
3031  Assert(result->tdrefcount == -1);
3032 
3033  return result;
3034 }
static uint32 pg_atomic_fetch_add_u32(volatile pg_atomic_uint32 *ptr, int32 add_)
Definition: atomics.h:366
uint32_t uint32
Definition: c.h:485
void * dsa_get_address(dsa_area *area, dsa_pointer dp)
Definition: dsa.c:942
void dsa_free(dsa_area *area, dsa_pointer dp)
Definition: dsa.c:826
uint64 dsa_pointer
Definition: dsa.h:62
bool dshash_delete_key(dshash_table *hash_table, const void *key)
Definition: dshash.c:503
void dshash_release_lock(dshash_table *hash_table, void *entry)
Definition: dshash.c:558
void * dshash_find(dshash_table *hash_table, const void *key, bool exclusive)
Definition: dshash.c:390
void * dshash_find_or_insert(dshash_table *hash_table, const void *key, bool *found)
Definition: dshash.c:433
#define PG_RE_THROW()
Definition: elog.h:412
#define PG_TRY(...)
Definition: elog.h:371
#define PG_END_TRY(...)
Definition: elog.h:396
#define PG_CATCH(...)
Definition: elog.h:381
Session * CurrentSession
Definition: session.c:48
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
SharedRecordTableKey key
Definition: typcache.c:213
dsa_pointer shared_tupdesc
Definition: typcache.c:202
union SharedRecordTableKey::@31 u
pg_atomic_uint32 next_typmod
Definition: typcache.c:188
dsa_pointer shared_tupdesc
Definition: typcache.c:223
static dsa_pointer share_tupledesc(dsa_area *area, TupleDesc tupdesc, uint32 typmod)
Definition: typcache.c:2908

References Session::area, Assert, CurrentSession, dsa_free(), dsa_get_address(), dshash_delete_key(), dshash_find(), dshash_find_or_insert(), dshash_release_lock(), elog, ERROR, SharedRecordTableEntry::key, sort-test::key, SharedRecordTypmodRegistry::next_typmod, pg_atomic_fetch_add_u32(), PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, share_tupledesc(), SharedRecordTableKey::shared, Session::shared_record_table, SharedRecordTableKey::shared_tupdesc, SharedTypmodTableEntry::shared_tupdesc, Session::shared_typmod_registry, Session::shared_typmod_table, TupleDescData::tdrefcount, SharedTypmodTableEntry::typmod, and SharedRecordTableKey::u.

Referenced by assign_record_type_typmod().

◆ InitDomainConstraintRef()

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

Definition at line 1400 of file typcache.c.

1402 {
1403  /* Look up the typcache entry --- we assume it survives indefinitely */
1405  ref->need_exprstate = need_exprstate;
1406  /* For safety, establish the callback before acquiring a refcount */
1407  ref->refctx = refctx;
1408  ref->dcc = NULL;
1410  ref->callback.arg = ref;
1412  /* Acquire refcount if there are constraints, and set up exported list */
1413  if (ref->tcache->domainData)
1414  {
1415  ref->dcc = ref->tcache->domainData;
1416  ref->dcc->dccRefCount++;
1417  if (ref->need_exprstate)
1419  ref->refctx);
1420  else
1421  ref->constraints = ref->dcc->constraints;
1422  }
1423  else
1424  ref->constraints = NIL;
1425 }
void MemoryContextRegisterResetCallback(MemoryContext context, MemoryContextCallback *cb)
Definition: mcxt.c:568
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:1362
static void dccref_deletion_callback(void *arg)
Definition: typcache.c:1341

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

◆ insert_rel_type_cache_if_needed()

static void insert_rel_type_cache_if_needed ( TypeCacheEntry typentry)
static

Definition at line 3061 of file typcache.c.

3062 {
3063  /* Immediately quit for non-composite types */
3064  if (typentry->typtype != TYPTYPE_COMPOSITE)
3065  return;
3066 
3067  /* typrelid should be given for composite types */
3068  Assert(OidIsValid(typentry->typrelid));
3069 
3070  /*
3071  * Insert a RelIdToTypeIdCacheHash entry if the typentry have any
3072  * information indicating it should be here.
3073  */
3074  if ((typentry->flags & TCFLAGS_HAVE_PG_TYPE_DATA) ||
3075  (typentry->flags & TCFLAGS_OPERATOR_FLAGS) ||
3076  typentry->tupDesc != NULL)
3077  {
3078  RelIdToTypeIdCacheEntry *relentry;
3079  bool found;
3080 
3082  &typentry->typrelid,
3083  HASH_ENTER, &found);
3084  relentry->relid = typentry->typrelid;
3085  relentry->composite_typid = typentry->type_id;
3086  }
3087 }

References Assert, RelIdToTypeIdCacheEntry::composite_typid, TypeCacheEntry::flags, HASH_ENTER, hash_search(), OidIsValid, RelIdToTypeIdCacheEntry::relid, RelIdToTypeIdCacheHash, TCFLAGS_HAVE_PG_TYPE_DATA, TCFLAGS_OPERATOR_FLAGS, TypeCacheEntry::tupDesc, TypeCacheEntry::type_id, TypeCacheEntry::typrelid, and TypeCacheEntry::typtype.

Referenced by finalize_in_progress_typentries(), and lookup_type_cache().

◆ InvalidateCompositeTypeCacheEntry()

static void InvalidateCompositeTypeCacheEntry ( TypeCacheEntry typentry)
static

Definition at line 2363 of file typcache.c.

2364 {
2365  bool hadTupDescOrOpclass;
2366 
2367  Assert(typentry->typtype == TYPTYPE_COMPOSITE &&
2368  OidIsValid(typentry->typrelid));
2369 
2370  hadTupDescOrOpclass = (typentry->tupDesc != NULL) ||
2371  (typentry->flags & TCFLAGS_OPERATOR_FLAGS);
2372 
2373  /* Delete tupdesc if we have it */
2374  if (typentry->tupDesc != NULL)
2375  {
2376  /*
2377  * Release our refcount and free the tupdesc if none remain. We can't
2378  * use DecrTupleDescRefCount here because this reference is not logged
2379  * by the current resource owner.
2380  */
2381  Assert(typentry->tupDesc->tdrefcount > 0);
2382  if (--typentry->tupDesc->tdrefcount == 0)
2383  FreeTupleDesc(typentry->tupDesc);
2384  typentry->tupDesc = NULL;
2385 
2386  /*
2387  * Also clear tupDesc_identifier, so that anyone watching it will
2388  * realize that the tupdesc has changed.
2389  */
2390  typentry->tupDesc_identifier = 0;
2391  }
2392 
2393  /* Reset equality/comparison/hashing validity information */
2394  typentry->flags &= ~TCFLAGS_OPERATOR_FLAGS;
2395 
2396  /* Call delete_rel_type_cache() if we actually cleared something */
2397  if (hadTupDescOrOpclass)
2399 }
void FreeTupleDesc(TupleDesc tupdesc)
Definition: tupdesc.c:331
static void delete_rel_type_cache_if_needed(TypeCacheEntry *typentry)
Definition: typcache.c:3095

References Assert, delete_rel_type_cache_if_needed(), TypeCacheEntry::flags, FreeTupleDesc(), OidIsValid, TCFLAGS_OPERATOR_FLAGS, TupleDescData::tdrefcount, TypeCacheEntry::tupDesc, TypeCacheEntry::tupDesc_identifier, TypeCacheEntry::typrelid, and TypeCacheEntry::typtype.

Referenced by TypeCacheRelCallback().

◆ load_domaintype_info()

static void load_domaintype_info ( TypeCacheEntry typentry)
static

Definition at line 1081 of file typcache.c.

1082 {
1083  Oid typeOid = typentry->type_id;
1084  DomainConstraintCache *dcc;
1085  bool notNull = false;
1086  DomainConstraintState **ccons;
1087  int cconslen;
1088  Relation conRel;
1089  MemoryContext oldcxt;
1090 
1091  /*
1092  * If we're here, any existing constraint info is stale, so release it.
1093  * For safety, be sure to null the link before trying to delete the data.
1094  */
1095  if (typentry->domainData)
1096  {
1097  dcc = typentry->domainData;
1098  typentry->domainData = NULL;
1099  decr_dcc_refcount(dcc);
1100  }
1101 
1102  /*
1103  * We try to optimize the common case of no domain constraints, so don't
1104  * create the dcc object and context until we find a constraint. Likewise
1105  * for the temp sorting array.
1106  */
1107  dcc = NULL;
1108  ccons = NULL;
1109  cconslen = 0;
1110 
1111  /*
1112  * Scan pg_constraint for relevant constraints. We want to find
1113  * constraints for not just this domain, but any ancestor domains, so the
1114  * outer loop crawls up the domain stack.
1115  */
1116  conRel = table_open(ConstraintRelationId, AccessShareLock);
1117 
1118  for (;;)
1119  {
1120  HeapTuple tup;
1121  HeapTuple conTup;
1122  Form_pg_type typTup;
1123  int nccons = 0;
1124  ScanKeyData key[1];
1125  SysScanDesc scan;
1126 
1127  tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
1128  if (!HeapTupleIsValid(tup))
1129  elog(ERROR, "cache lookup failed for type %u", typeOid);
1130  typTup = (Form_pg_type) GETSTRUCT(tup);
1131 
1132  if (typTup->typtype != TYPTYPE_DOMAIN)
1133  {
1134  /* Not a domain, so done */
1135  ReleaseSysCache(tup);
1136  break;
1137  }
1138 
1139  /* Test for NOT NULL Constraint */
1140  if (typTup->typnotnull)
1141  notNull = true;
1142 
1143  /* Look for CHECK Constraints on this domain */
1144  ScanKeyInit(&key[0],
1145  Anum_pg_constraint_contypid,
1146  BTEqualStrategyNumber, F_OIDEQ,
1147  ObjectIdGetDatum(typeOid));
1148 
1149  scan = systable_beginscan(conRel, ConstraintTypidIndexId, true,
1150  NULL, 1, key);
1151 
1152  while (HeapTupleIsValid(conTup = systable_getnext(scan)))
1153  {
1155  Datum val;
1156  bool isNull;
1157  char *constring;
1158  Expr *check_expr;
1160 
1161  /* Ignore non-CHECK constraints */
1162  if (c->contype != CONSTRAINT_CHECK)
1163  continue;
1164 
1165  /* Not expecting conbin to be NULL, but we'll test for it anyway */
1166  val = fastgetattr(conTup, Anum_pg_constraint_conbin,
1167  conRel->rd_att, &isNull);
1168  if (isNull)
1169  elog(ERROR, "domain \"%s\" constraint \"%s\" has NULL conbin",
1170  NameStr(typTup->typname), NameStr(c->conname));
1171 
1172  /* Convert conbin to C string in caller context */
1173  constring = TextDatumGetCString(val);
1174 
1175  /* Create the DomainConstraintCache object and context if needed */
1176  if (dcc == NULL)
1177  {
1178  MemoryContext cxt;
1179 
1181  "Domain constraints",
1183  dcc = (DomainConstraintCache *)
1185  dcc->constraints = NIL;
1186  dcc->dccContext = cxt;
1187  dcc->dccRefCount = 0;
1188  }
1189 
1190  /* Create node trees in DomainConstraintCache's context */
1191  oldcxt = MemoryContextSwitchTo(dcc->dccContext);
1192 
1193  check_expr = (Expr *) stringToNode(constring);
1194 
1195  /*
1196  * Plan the expression, since ExecInitExpr will expect that.
1197  *
1198  * Note: caching the result of expression_planner() is not very
1199  * good practice. Ideally we'd use a CachedExpression here so
1200  * that we would react promptly to, eg, changes in inlined
1201  * functions. However, because we don't support mutable domain
1202  * CHECK constraints, it's not really clear that it's worth the
1203  * extra overhead to do that.
1204  */
1205  check_expr = expression_planner(check_expr);
1206 
1209  r->name = pstrdup(NameStr(c->conname));
1210  r->check_expr = check_expr;
1211  r->check_exprstate = NULL;
1212 
1213  MemoryContextSwitchTo(oldcxt);
1214 
1215  /* Accumulate constraints in an array, for sorting below */
1216  if (ccons == NULL)
1217  {
1218  cconslen = 8;
1219  ccons = (DomainConstraintState **)
1220  palloc(cconslen * sizeof(DomainConstraintState *));
1221  }
1222  else if (nccons >= cconslen)
1223  {
1224  cconslen *= 2;
1225  ccons = (DomainConstraintState **)
1226  repalloc(ccons, cconslen * sizeof(DomainConstraintState *));
1227  }
1228  ccons[nccons++] = r;
1229  }
1230 
1231  systable_endscan(scan);
1232 
1233  if (nccons > 0)
1234  {
1235  /*
1236  * Sort the items for this domain, so that CHECKs are applied in a
1237  * deterministic order.
1238  */
1239  if (nccons > 1)
1240  qsort(ccons, nccons, sizeof(DomainConstraintState *), dcs_cmp);
1241 
1242  /*
1243  * Now attach them to the overall list. Use lcons() here because
1244  * constraints of parent domains should be applied earlier.
1245  */
1246  oldcxt = MemoryContextSwitchTo(dcc->dccContext);
1247  while (nccons > 0)
1248  dcc->constraints = lcons(ccons[--nccons], dcc->constraints);
1249  MemoryContextSwitchTo(oldcxt);
1250  }
1251 
1252  /* loop to next domain in stack */
1253  typeOid = typTup->typbasetype;
1254  ReleaseSysCache(tup);
1255  }
1256 
1257  table_close(conRel, AccessShareLock);
1258 
1259  /*
1260  * Only need to add one NOT NULL check regardless of how many domains in
1261  * the stack request it.
1262  */
1263  if (notNull)
1264  {
1266 
1267  /* Create the DomainConstraintCache object and context if needed */
1268  if (dcc == NULL)
1269  {
1270  MemoryContext cxt;
1271 
1273  "Domain constraints",
1275  dcc = (DomainConstraintCache *)
1277  dcc->constraints = NIL;
1278  dcc->dccContext = cxt;
1279  dcc->dccRefCount = 0;
1280  }
1281 
1282  /* Create node trees in DomainConstraintCache's context */
1283  oldcxt = MemoryContextSwitchTo(dcc->dccContext);
1284 
1286 
1288  r->name = pstrdup("NOT NULL");
1289  r->check_expr = NULL;
1290  r->check_exprstate = NULL;
1291 
1292  /* lcons to apply the nullness check FIRST */
1293  dcc->constraints = lcons(r, dcc->constraints);
1294 
1295  MemoryContextSwitchTo(oldcxt);
1296  }
1297 
1298  /*
1299  * If we made a constraint object, move it into CacheMemoryContext and
1300  * attach it to the typcache entry.
1301  */
1302  if (dcc)
1303  {
1305  typentry->domainData = dcc;
1306  dcc->dccRefCount++; /* count the typcache's reference */
1307  }
1308 
1309  /* Either way, the typcache entry's domain data is now valid. */
1311 }
#define TextDatumGetCString(d)
Definition: builtins.h:98
#define NameStr(name)
Definition: c.h:700
@ DOM_CONSTRAINT_CHECK
Definition: execnodes.h:1012
@ DOM_CONSTRAINT_NOTNULL
Definition: execnodes.h:1011
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:606
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:513
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:387
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
static Datum fastgetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:749
long val
Definition: informix.c:689
List * lcons(void *datum, List *list)
Definition: list.c:495
#define AccessShareLock
Definition: lockdefs.h:36
void MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
Definition: mcxt.c:637
char * pstrdup(const char *in)
Definition: mcxt.c:1696
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1541
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1181
void * palloc(Size size)
Definition: mcxt.c:1317
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:170
#define makeNode(_type_)
Definition: nodes.h:155
FormData_pg_constraint * Form_pg_constraint
FormData_pg_type * Form_pg_type
Definition: pg_type.h:261
Expr * expression_planner(Expr *expr)
Definition: planner.c:6735
#define qsort(a, b, c, d)
Definition: port.h:447
uintptr_t Datum
Definition: postgres.h:64
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
char * c
void * stringToNode(const char *str)
Definition: read.c:90
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define BTEqualStrategyNumber
Definition: stratnum.h:31
DomainConstraintType constrainttype
Definition: execnodes.h:1018
ExprState * check_exprstate
Definition: execnodes.h:1021
TupleDesc rd_att
Definition: rel.h:112
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
static int dcs_cmp(const void *a, const void *b)
Definition: typcache.c:1317
#define TCFLAGS_CHECKED_DOMAIN_CONSTRAINTS
Definition: typcache.c:118

References AccessShareLock, ALLOCSET_SMALL_SIZES, AllocSetContextCreate, BTEqualStrategyNumber, CacheMemoryContext, DomainConstraintState::check_expr, DomainConstraintState::check_exprstate, DomainConstraintCache::constraints, DomainConstraintState::constrainttype, CurrentMemoryContext, DomainConstraintCache::dccContext, DomainConstraintCache::dccRefCount, dcs_cmp(), decr_dcc_refcount(), DOM_CONSTRAINT_CHECK, DOM_CONSTRAINT_NOTNULL, TypeCacheEntry::domainData, elog, ERROR, expression_planner(), fastgetattr(), TypeCacheEntry::flags, GETSTRUCT, HeapTupleIsValid, sort-test::key, lcons(), makeNode, MemoryContextAlloc(), MemoryContextSetParent(), MemoryContextSwitchTo(), DomainConstraintState::name, NameStr, NIL, ObjectIdGetDatum(), palloc(), pstrdup(), qsort, RelationData::rd_att, ReleaseSysCache(), repalloc(), ScanKeyInit(), SearchSysCache1(), stringToNode(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), TCFLAGS_CHECKED_DOMAIN_CONSTRAINTS, TextDatumGetCString, TypeCacheEntry::type_id, and val.

Referenced by lookup_type_cache(), and UpdateDomainConstraintRef().

◆ load_enum_cache_data()

static void load_enum_cache_data ( TypeCacheEntry tcache)
static

Definition at line 2723 of file typcache.c.

2724 {
2725  TypeCacheEnumData *enumdata;
2726  Relation enum_rel;
2727  SysScanDesc enum_scan;
2728  HeapTuple enum_tuple;
2729  ScanKeyData skey;
2730  EnumItem *items;
2731  int numitems;
2732  int maxitems;
2733  Oid bitmap_base;
2734  Bitmapset *bitmap;
2735  MemoryContext oldcxt;
2736  int bm_size,
2737  start_pos;
2738 
2739  /* Check that this is actually an enum */
2740  if (tcache->typtype != TYPTYPE_ENUM)
2741  ereport(ERROR,
2742  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2743  errmsg("%s is not an enum",
2744  format_type_be(tcache->type_id))));
2745 
2746  /*
2747  * Read all the information for members of the enum type. We collect the
2748  * info in working memory in the caller's context, and then transfer it to
2749  * permanent memory in CacheMemoryContext. This minimizes the risk of
2750  * leaking memory from CacheMemoryContext in the event of an error partway
2751  * through.
2752  */
2753  maxitems = 64;
2754  items = (EnumItem *) palloc(sizeof(EnumItem) * maxitems);
2755  numitems = 0;
2756 
2757  /* Scan pg_enum for the members of the target enum type. */
2758  ScanKeyInit(&skey,
2759  Anum_pg_enum_enumtypid,
2760  BTEqualStrategyNumber, F_OIDEQ,
2761  ObjectIdGetDatum(tcache->type_id));
2762 
2763  enum_rel = table_open(EnumRelationId, AccessShareLock);
2764  enum_scan = systable_beginscan(enum_rel,
2765  EnumTypIdLabelIndexId,
2766  true, NULL,
2767  1, &skey);
2768 
2769  while (HeapTupleIsValid(enum_tuple = systable_getnext(enum_scan)))
2770  {
2771  Form_pg_enum en = (Form_pg_enum) GETSTRUCT(enum_tuple);
2772 
2773  if (numitems >= maxitems)
2774  {
2775  maxitems *= 2;
2776  items = (EnumItem *) repalloc(items, sizeof(EnumItem) * maxitems);
2777  }
2778  items[numitems].enum_oid = en->oid;
2779  items[numitems].sort_order = en->enumsortorder;
2780  numitems++;
2781  }
2782 
2783  systable_endscan(enum_scan);
2784  table_close(enum_rel, AccessShareLock);
2785 
2786  /* Sort the items into OID order */
2787  qsort(items, numitems, sizeof(EnumItem), enum_oid_cmp);
2788 
2789  /*
2790  * Here, we create a bitmap listing a subset of the enum's OIDs that are
2791  * known to be in order and can thus be compared with just OID comparison.
2792  *
2793  * The point of this is that the enum's initial OIDs were certainly in
2794  * order, so there is some subset that can be compared via OID comparison;
2795  * and we'd rather not do binary searches unnecessarily.
2796  *
2797  * This is somewhat heuristic, and might identify a subset of OIDs that
2798  * isn't exactly what the type started with. That's okay as long as the
2799  * subset is correctly sorted.
2800  */
2801  bitmap_base = InvalidOid;
2802  bitmap = NULL;
2803  bm_size = 1; /* only save sets of at least 2 OIDs */
2804 
2805  for (start_pos = 0; start_pos < numitems - 1; start_pos++)
2806  {
2807  /*
2808  * Identify longest sorted subsequence starting at start_pos
2809  */
2810  Bitmapset *this_bitmap = bms_make_singleton(0);
2811  int this_bm_size = 1;
2812  Oid start_oid = items[start_pos].enum_oid;
2813  float4 prev_order = items[start_pos].sort_order;
2814  int i;
2815 
2816  for (i = start_pos + 1; i < numitems; i++)
2817  {
2818  Oid offset;
2819 
2820  offset = items[i].enum_oid - start_oid;
2821  /* quit if bitmap would be too large; cutoff is arbitrary */
2822  if (offset >= 8192)
2823  break;
2824  /* include the item if it's in-order */
2825  if (items[i].sort_order > prev_order)
2826  {
2827  prev_order = items[i].sort_order;
2828  this_bitmap = bms_add_member(this_bitmap, (int) offset);
2829  this_bm_size++;
2830  }
2831  }
2832 
2833  /* Remember it if larger than previous best */
2834  if (this_bm_size > bm_size)
2835  {
2836  bms_free(bitmap);
2837  bitmap_base = start_oid;
2838  bitmap = this_bitmap;
2839  bm_size = this_bm_size;
2840  }
2841  else
2842  bms_free(this_bitmap);
2843 
2844  /*
2845  * Done if it's not possible to find a longer sequence in the rest of
2846  * the list. In typical cases this will happen on the first
2847  * iteration, which is why we create the bitmaps on the fly instead of
2848  * doing a second pass over the list.
2849  */
2850  if (bm_size >= (numitems - start_pos - 1))
2851  break;
2852  }
2853 
2854  /* OK, copy the data into CacheMemoryContext */
2856  enumdata = (TypeCacheEnumData *)
2857  palloc(offsetof(TypeCacheEnumData, enum_values) +
2858  numitems * sizeof(EnumItem));
2859  enumdata->bitmap_base = bitmap_base;
2860  enumdata->sorted_values = bms_copy(bitmap);
2861  enumdata->num_values = numitems;
2862  memcpy(enumdata->enum_values, items, numitems * sizeof(EnumItem));
2863  MemoryContextSwitchTo(oldcxt);
2864 
2865  pfree(items);
2866  bms_free(bitmap);
2867 
2868  /* And link the finished cache struct into the typcache */
2869  if (tcache->enumData != NULL)
2870  pfree(tcache->enumData);
2871  tcache->enumData = enumdata;
2872 }
void bms_free(Bitmapset *a)
Definition: bitmapset.c:239
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:216
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:815
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:122
float float4
Definition: c.h:583
void pfree(void *pointer)
Definition: mcxt.c:1521
FormData_pg_enum * Form_pg_enum
Definition: pg_enum.h:44
static ItemArray items
Definition: test_tidstore.c:48

References AccessShareLock, TypeCacheEnumData::bitmap_base, bms_add_member(), bms_copy(), bms_free(), bms_make_singleton(), BTEqualStrategyNumber, CacheMemoryContext, enum_oid_cmp(), TypeCacheEnumData::enum_values, TypeCacheEntry::enumData, ereport, errcode(), errmsg(), ERROR, format_type_be(), GETSTRUCT, HeapTupleIsValid, i, InvalidOid, items, MemoryContextSwitchTo(), TypeCacheEnumData::num_values, ObjectIdGetDatum(), palloc(), pfree(), qsort, repalloc(), ScanKeyInit(), TypeCacheEnumData::sorted_values, systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), TypeCacheEntry::type_id, and TypeCacheEntry::typtype.

Referenced by compare_values_of_enum().

◆ load_multirangetype_info()

static void load_multirangetype_info ( TypeCacheEntry typentry)
static

Definition at line 1059 of file typcache.c.

1060 {
1061  Oid rangetypeOid;
1062 
1063  rangetypeOid = get_multirange_range(typentry->type_id);
1064  if (!OidIsValid(rangetypeOid))
1065  elog(ERROR, "cache lookup failed for multirange type %u",
1066  typentry->type_id);
1067 
1068  typentry->rngtype = lookup_type_cache(rangetypeOid, TYPECACHE_RANGE_INFO);
1069 }
Oid get_multirange_range(Oid multirangeOid)
Definition: lsyscache.c:3483
#define TYPECACHE_RANGE_INFO
Definition: typcache.h:148

References elog, ERROR, get_multirange_range(), lookup_type_cache(), OidIsValid, TypeCacheEntry::rngtype, TypeCacheEntry::type_id, and TYPECACHE_RANGE_INFO.

Referenced by cache_multirange_element_properties(), and lookup_type_cache().

◆ load_rangetype_info()

static void load_rangetype_info ( TypeCacheEntry typentry)
static

Definition at line 1001 of file typcache.c.

1002 {
1003  Form_pg_range pg_range;
1004  HeapTuple tup;
1005  Oid subtypeOid;
1006  Oid opclassOid;
1007  Oid canonicalOid;
1008  Oid subdiffOid;
1009  Oid opfamilyOid;
1010  Oid opcintype;
1011  Oid cmpFnOid;
1012 
1013  /* get information from pg_range */
1014  tup = SearchSysCache1(RANGETYPE, ObjectIdGetDatum(typentry->type_id));
1015  /* should not fail, since we already checked typtype ... */
1016  if (!HeapTupleIsValid(tup))
1017  elog(ERROR, "cache lookup failed for range type %u",
1018  typentry->type_id);
1019  pg_range = (Form_pg_range) GETSTRUCT(tup);
1020 
1021  subtypeOid = pg_range->rngsubtype;
1022  typentry->rng_collation = pg_range->rngcollation;
1023  opclassOid = pg_range->rngsubopc;
1024  canonicalOid = pg_range->rngcanonical;
1025  subdiffOid = pg_range->rngsubdiff;
1026 
1027  ReleaseSysCache(tup);
1028 
1029  /* get opclass properties and look up the comparison function */
1030  opfamilyOid = get_opclass_family(opclassOid);
1031  opcintype = get_opclass_input_type(opclassOid);
1032  typentry->rng_opfamily = opfamilyOid;
1033 
1034  cmpFnOid = get_opfamily_proc(opfamilyOid, opcintype, opcintype,
1035  BTORDER_PROC);
1036  if (!RegProcedureIsValid(cmpFnOid))
1037  elog(ERROR, "missing support function %d(%u,%u) in opfamily %u",
1038  BTORDER_PROC, opcintype, opcintype, opfamilyOid);
1039 
1040  /* set up cached fmgrinfo structs */
1041  fmgr_info_cxt(cmpFnOid, &typentry->rng_cmp_proc_finfo,
1043  if (OidIsValid(canonicalOid))
1044  fmgr_info_cxt(canonicalOid, &typentry->rng_canonical_finfo,
1046  if (OidIsValid(subdiffOid))
1047  fmgr_info_cxt(subdiffOid, &typentry->rng_subdiff_finfo,
1049 
1050  /* Lastly, set up link to the element type --- this marks data valid */
1051  typentry->rngelemtype = lookup_type_cache(subtypeOid, 0);
1052 }
#define RegProcedureIsValid(p)
Definition: c.h:731
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:137
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
#define BTORDER_PROC
Definition: nbtree.h:707
FormData_pg_range * Form_pg_range
Definition: pg_range.h:58
FmgrInfo rng_cmp_proc_finfo
Definition: typcache.h:101
Oid rng_collation
Definition: typcache.h:100
FmgrInfo rng_subdiff_finfo
Definition: typcache.h:103
FmgrInfo rng_canonical_finfo
Definition: typcache.h:102
Oid rng_opfamily
Definition: typcache.h:99

References BTORDER_PROC, CacheMemoryContext, elog, ERROR, fmgr_info_cxt(), get_opclass_family(), get_opclass_input_type(), get_opfamily_proc(), GETSTRUCT, HeapTupleIsValid, lookup_type_cache(), ObjectIdGetDatum(), OidIsValid, RegProcedureIsValid, ReleaseSysCache(), TypeCacheEntry::rng_canonical_finfo, TypeCacheEntry::rng_cmp_proc_finfo, TypeCacheEntry::rng_collation, TypeCacheEntry::rng_opfamily, TypeCacheEntry::rng_subdiff_finfo, TypeCacheEntry::rngelemtype, SearchSysCache1(), and TypeCacheEntry::type_id.

Referenced by cache_range_element_properties(), and lookup_type_cache().

◆ load_typcache_tupdesc()

static void load_typcache_tupdesc ( TypeCacheEntry typentry)
static

Definition at line 967 of file typcache.c.

968 {
969  Relation rel;
970 
971  if (!OidIsValid(typentry->typrelid)) /* should not happen */
972  elog(ERROR, "invalid typrelid for composite type %u",
973  typentry->type_id);
974  rel = relation_open(typentry->typrelid, AccessShareLock);
975  Assert(rel->rd_rel->reltype == typentry->type_id);
976 
977  /*
978  * Link to the tupdesc and increment its refcount (we assert it's a
979  * refcounted descriptor). We don't use IncrTupleDescRefCount() for this,
980  * because the reference mustn't be entered in the current resource owner;
981  * it can outlive the current query.
982  */
983  typentry->tupDesc = RelationGetDescr(rel);
984 
985  Assert(typentry->tupDesc->tdrefcount > 0);
986  typentry->tupDesc->tdrefcount++;
987 
988  /*
989  * In future, we could take some pains to not change tupDesc_identifier if
990  * the tupdesc didn't really change; but for now it's not worth it.
991  */
993 
995 }
#define RelationGetDescr(relation)
Definition: rel.h:531
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:205
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:47
Form_pg_class rd_rel
Definition: rel.h:111

References AccessShareLock, Assert, elog, ERROR, OidIsValid, RelationData::rd_rel, relation_close(), relation_open(), RelationGetDescr, TupleDescData::tdrefcount, TypeCacheEntry::tupDesc, TypeCacheEntry::tupDesc_identifier, tupledesc_id_counter, TypeCacheEntry::type_id, and TypeCacheEntry::typrelid.

Referenced by cache_record_field_properties(), and lookup_type_cache().

◆ lookup_rowtype_tupdesc()

◆ lookup_rowtype_tupdesc_copy()

TupleDesc lookup_rowtype_tupdesc_copy ( Oid  type_id,
int32  typmod 
)

Definition at line 1954 of file typcache.c.

1955 {
1956  TupleDesc tmp;
1957 
1958  tmp = lookup_rowtype_tupdesc_internal(type_id, typmod, false);
1959  return CreateTupleDescCopyConstr(tmp);
1960 }
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 1976 of file typcache.c.

1977 {
1978  TupleDesc tupDesc;
1979 
1980  if (type_id != RECORDOID)
1981  {
1982  /*
1983  * Check for domain or named composite type. We might as well load
1984  * whichever data is needed.
1985  */
1986  TypeCacheEntry *typentry;
1987 
1988  typentry = lookup_type_cache(type_id,
1991  if (typentry->typtype == TYPTYPE_DOMAIN)
1993  typentry->domainBaseTypmod,
1994  noError);
1995  if (typentry->tupDesc == NULL && !noError)
1996  ereport(ERROR,
1997  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1998  errmsg("type %s is not composite",
1999  format_type_be(type_id))));
2000  tupDesc = typentry->tupDesc;
2001  }
2002  else
2003  tupDesc = lookup_rowtype_tupdesc_internal(type_id, typmod, noError);
2004  if (tupDesc != NULL)
2005  PinTupleDesc(tupDesc);
2006  return tupDesc;
2007 }
TupleDesc lookup_rowtype_tupdesc_noerror(Oid type_id, int32 typmod, bool noError)
Definition: typcache.c:1937
#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_internal()

static TupleDesc lookup_rowtype_tupdesc_internal ( Oid  type_id,
int32  typmod,
bool  noError 
)
static

Definition at line 1826 of file typcache.c.

1827 {
1828  if (type_id != RECORDOID)
1829  {
1830  /*
1831  * It's a named composite type, so use the regular typcache.
1832  */
1833  TypeCacheEntry *typentry;
1834 
1835  typentry = lookup_type_cache(type_id, TYPECACHE_TUPDESC);
1836  if (typentry->tupDesc == NULL && !noError)
1837  ereport(ERROR,
1838  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1839  errmsg("type %s is not composite",
1840  format_type_be(type_id))));
1841  return typentry->tupDesc;
1842  }
1843  else
1844  {
1845  /*
1846  * It's a transient record type, so look in our record-type table.
1847  */
1848  if (typmod >= 0)
1849  {
1850  /* It is already in our local cache? */
1851  if (typmod < RecordCacheArrayLen &&
1852  RecordCacheArray[typmod].tupdesc != NULL)
1853  return RecordCacheArray[typmod].tupdesc;
1854 
1855  /* Are we attached to a shared record typmod registry? */
1857  {
1858  SharedTypmodTableEntry *entry;
1859 
1860  /* Try to find it in the shared typmod index. */
1862  &typmod, false);
1863  if (entry != NULL)
1864  {
1865  TupleDesc tupdesc;
1866 
1867  tupdesc = (TupleDesc)
1869  entry->shared_tupdesc);
1870  Assert(typmod == tupdesc->tdtypmod);
1871 
1872  /* We may need to extend the local RecordCacheArray. */
1874 
1875  /*
1876  * Our local array can now point directly to the TupleDesc
1877  * in shared memory, which is non-reference-counted.
1878  */
1879  RecordCacheArray[typmod].tupdesc = tupdesc;
1880  Assert(tupdesc->tdrefcount == -1);
1881 
1882  /*
1883  * We don't share tupdesc identifiers across processes, so
1884  * assign one locally.
1885  */
1887 
1889  entry);
1890 
1891  return RecordCacheArray[typmod].tupdesc;
1892  }
1893  }
1894  }
1895 
1896  if (!noError)
1897  ereport(ERROR,
1898  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1899  errmsg("record type has not been registered")));
1900  return NULL;
1901  }
1902 }

References Session::area, Assert, CurrentSession, dsa_get_address(), dshash_find(), dshash_release_lock(), ensure_record_cache_typmod_slot_exists(), ereport, errcode(), errmsg(), ERROR, format_type_be(), RecordCacheArrayEntry::id, lookup_type_cache(), RecordCacheArray, RecordCacheArrayLen, SharedTypmodTableEntry::shared_tupdesc, Session::shared_typmod_registry, Session::shared_typmod_table, TupleDescData::tdrefcount, TupleDescData::tdtypmod, RecordCacheArrayEntry::tupdesc, TypeCacheEntry::tupDesc, tupledesc_id_counter, and TYPECACHE_TUPDESC.

Referenced by lookup_rowtype_tupdesc(), lookup_rowtype_tupdesc_copy(), lookup_rowtype_tupdesc_domain(), and lookup_rowtype_tupdesc_noerror().

◆ lookup_rowtype_tupdesc_noerror()

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

Definition at line 1937 of file typcache.c.

1938 {
1939  TupleDesc tupDesc;
1940 
1941  tupDesc = lookup_rowtype_tupdesc_internal(type_id, typmod, noError);
1942  if (tupDesc != NULL)
1943  PinTupleDesc(tupDesc);
1944  return tupDesc;
1945 }

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 386 of file typcache.c.

387 {
388  TypeCacheEntry *typentry;
389  bool found;
390  int in_progress_offset;
391 
392  if (TypeCacheHash == NULL)
393  {
394  /* First time through: initialize the hash table */
395  HASHCTL ctl;
396  int allocsize;
397 
398  ctl.keysize = sizeof(Oid);
399  ctl.entrysize = sizeof(TypeCacheEntry);
400 
401  /*
402  * TypeCacheEntry takes hash value from the system cache. For
403  * TypeCacheHash we use the same hash in order to speedup search by
404  * hash value. This is used by hash_seq_init_with_hash_value().
405  */
406  ctl.hash = type_cache_syshash;
407 
408  TypeCacheHash = hash_create("Type information cache", 64,
410 
412 
413  ctl.keysize = sizeof(Oid);
414  ctl.entrysize = sizeof(RelIdToTypeIdCacheEntry);
415  RelIdToTypeIdCacheHash = hash_create("Map from relid to OID of cached composite type", 64,
416  &ctl, HASH_ELEM | HASH_BLOBS);
417 
418  /* Also set up callbacks for SI invalidations */
423 
424  /* Also make sure CacheMemoryContext exists */
425  if (!CacheMemoryContext)
427 
428  /*
429  * reserve enough in_progress_list slots for many cases
430  */
431  allocsize = 4;
434  allocsize * sizeof(*in_progress_list));
435  in_progress_list_maxlen = allocsize;
436  }
437 
438  Assert(TypeCacheHash != NULL && RelIdToTypeIdCacheHash != NULL);
439 
440  /* Register to catch invalidation messages */
442  {
443  int allocsize;
444 
445  allocsize = in_progress_list_maxlen * 2;
447  allocsize * sizeof(*in_progress_list));
448  in_progress_list_maxlen = allocsize;
449  }
450  in_progress_offset = in_progress_list_len++;
451  in_progress_list[in_progress_offset] = type_id;
452 
453  /* Try to look up an existing entry */
455  &type_id,
456  HASH_FIND, NULL);
457  if (typentry == NULL)
458  {
459  /*
460  * If we didn't find one, we want to make one. But first look up the
461  * pg_type row, just to make sure we don't make a cache entry for an
462  * invalid type OID. If the type OID is not valid, present a
463  * user-facing error, since some code paths such as domain_in() allow
464  * this function to be reached with a user-supplied OID.
465  */
466  HeapTuple tp;
467  Form_pg_type typtup;
468 
469  tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_id));
470  if (!HeapTupleIsValid(tp))
471  ereport(ERROR,
472  (errcode(ERRCODE_UNDEFINED_OBJECT),
473  errmsg("type with OID %u does not exist", type_id)));
474  typtup = (Form_pg_type) GETSTRUCT(tp);
475  if (!typtup->typisdefined)
476  ereport(ERROR,
477  (errcode(ERRCODE_UNDEFINED_OBJECT),
478  errmsg("type \"%s\" is only a shell",
479  NameStr(typtup->typname))));
480 
481  /* Now make the typcache entry */
483  &type_id,
484  HASH_ENTER, &found);
485  Assert(!found); /* it wasn't there a moment ago */
486 
487  MemSet(typentry, 0, sizeof(TypeCacheEntry));
488 
489  /* These fields can never change, by definition */
490  typentry->type_id = type_id;
491  typentry->type_id_hash = get_hash_value(TypeCacheHash, &type_id);
492 
493  /* Keep this part in sync with the code below */
494  typentry->typlen = typtup->typlen;
495  typentry->typbyval = typtup->typbyval;
496  typentry->typalign = typtup->typalign;
497  typentry->typstorage = typtup->typstorage;
498  typentry->typtype = typtup->typtype;
499  typentry->typrelid = typtup->typrelid;
500  typentry->typsubscript = typtup->typsubscript;
501  typentry->typelem = typtup->typelem;
502  typentry->typcollation = typtup->typcollation;
503  typentry->flags |= TCFLAGS_HAVE_PG_TYPE_DATA;
504 
505  /* If it's a domain, immediately thread it into the domain cache list */
506  if (typentry->typtype == TYPTYPE_DOMAIN)
507  {
508  typentry->nextDomain = firstDomainTypeEntry;
509  firstDomainTypeEntry = typentry;
510  }
511 
512  ReleaseSysCache(tp);
513  }
514  else if (!(typentry->flags & TCFLAGS_HAVE_PG_TYPE_DATA))
515  {
516  /*
517  * We have an entry, but its pg_type row got changed, so reload the
518  * data obtained directly from pg_type.
519  */
520  HeapTuple tp;
521  Form_pg_type typtup;
522 
523  tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_id));
524  if (!HeapTupleIsValid(tp))
525  ereport(ERROR,
526  (errcode(ERRCODE_UNDEFINED_OBJECT),
527  errmsg("type with OID %u does not exist", type_id)));
528  typtup = (Form_pg_type) GETSTRUCT(tp);
529  if (!typtup->typisdefined)
530  ereport(ERROR,
531  (errcode(ERRCODE_UNDEFINED_OBJECT),
532  errmsg("type \"%s\" is only a shell",
533  NameStr(typtup->typname))));
534 
535  /*
536  * Keep this part in sync with the code above. Many of these fields
537  * shouldn't ever change, particularly typtype, but copy 'em anyway.
538  */
539  typentry->typlen = typtup->typlen;
540  typentry->typbyval = typtup->typbyval;
541  typentry->typalign = typtup->typalign;
542  typentry->typstorage = typtup->typstorage;
543  typentry->typtype = typtup->typtype;
544  typentry->typrelid = typtup->typrelid;
545  typentry->typsubscript = typtup->typsubscript;
546  typentry->typelem = typtup->typelem;
547  typentry->typcollation = typtup->typcollation;
548  typentry->flags |= TCFLAGS_HAVE_PG_TYPE_DATA;
549 
550  ReleaseSysCache(tp);
551  }
552 
553  /*
554  * Look up opclasses if we haven't already and any dependent info is
555  * requested.
556  */
561  !(typentry->flags & TCFLAGS_CHECKED_BTREE_OPCLASS))
562  {
563  Oid opclass;
564 
565  opclass = GetDefaultOpClass(type_id, BTREE_AM_OID);
566  if (OidIsValid(opclass))
567  {
568  typentry->btree_opf = get_opclass_family(opclass);
569  typentry->btree_opintype = get_opclass_input_type(opclass);
570  }
571  else
572  {
573  typentry->btree_opf = typentry->btree_opintype = InvalidOid;
574  }
575 
576  /*
577  * Reset information derived from btree opclass. Note in particular
578  * that we'll redetermine the eq_opr even if we previously found one;
579  * this matters in case a btree opclass has been added to a type that
580  * previously had only a hash opclass.
581  */
582  typentry->flags &= ~(TCFLAGS_CHECKED_EQ_OPR |
587  }
588 
589  /*
590  * If we need to look up equality operator, and there's no btree opclass,
591  * force lookup of hash opclass.
592  */
593  if ((flags & (TYPECACHE_EQ_OPR | TYPECACHE_EQ_OPR_FINFO)) &&
594  !(typentry->flags & TCFLAGS_CHECKED_EQ_OPR) &&
595  typentry->btree_opf == InvalidOid)
596  flags |= TYPECACHE_HASH_OPFAMILY;
597 
602  !(typentry->flags & TCFLAGS_CHECKED_HASH_OPCLASS))
603  {
604  Oid opclass;
605 
606  opclass = GetDefaultOpClass(type_id, HASH_AM_OID);
607  if (OidIsValid(opclass))
608  {
609  typentry->hash_opf = get_opclass_family(opclass);
610  typentry->hash_opintype = get_opclass_input_type(opclass);
611  }
612  else
613  {
614  typentry->hash_opf = typentry->hash_opintype = InvalidOid;
615  }
616 
617  /*
618  * Reset information derived from hash opclass. We do *not* reset the
619  * eq_opr; if we already found one from the btree opclass, that
620  * decision is still good.
621  */
622  typentry->flags &= ~(TCFLAGS_CHECKED_HASH_PROC |
624  typentry->flags |= TCFLAGS_CHECKED_HASH_OPCLASS;
625  }
626 
627  /*
628  * Look for requested operators and functions, if we haven't already.
629  */
630  if ((flags & (TYPECACHE_EQ_OPR | TYPECACHE_EQ_OPR_FINFO)) &&
631  !(typentry->flags & TCFLAGS_CHECKED_EQ_OPR))
632  {
633  Oid eq_opr = InvalidOid;
634 
635  if (typentry->btree_opf != InvalidOid)
636  eq_opr = get_opfamily_member(typentry->btree_opf,
637  typentry->btree_opintype,
638  typentry->btree_opintype,
640  if (eq_opr == InvalidOid &&
641  typentry->hash_opf != InvalidOid)
642  eq_opr = get_opfamily_member(typentry->hash_opf,
643  typentry->hash_opintype,
644  typentry->hash_opintype,
646 
647  /*
648  * If the proposed equality operator is array_eq or record_eq, check
649  * to see if the element type or column types support equality. If
650  * not, array_eq or record_eq would fail at runtime, so we don't want
651  * to report that the type has equality. (We can omit similar
652  * checking for ranges and multiranges because ranges can't be created
653  * in the first place unless their subtypes support equality.)
654  */
655  if (eq_opr == ARRAY_EQ_OP &&
656  !array_element_has_equality(typentry))
657  eq_opr = InvalidOid;
658  else if (eq_opr == RECORD_EQ_OP &&
659  !record_fields_have_equality(typentry))
660  eq_opr = InvalidOid;
661 
662  /* Force update of eq_opr_finfo only if we're changing state */
663  if (typentry->eq_opr != eq_opr)
664  typentry->eq_opr_finfo.fn_oid = InvalidOid;
665 
666  typentry->eq_opr = eq_opr;
667 
668  /*
669  * Reset info about hash functions whenever we pick up new info about
670  * equality operator. This is so we can ensure that the hash
671  * functions match the operator.
672  */
673  typentry->flags &= ~(TCFLAGS_CHECKED_HASH_PROC |
675  typentry->flags |= TCFLAGS_CHECKED_EQ_OPR;
676  }
677  if ((flags & TYPECACHE_LT_OPR) &&
678  !(typentry->flags & TCFLAGS_CHECKED_LT_OPR))
679  {
680  Oid lt_opr = InvalidOid;
681 
682  if (typentry->btree_opf != InvalidOid)
683  lt_opr = get_opfamily_member(typentry->btree_opf,
684  typentry->btree_opintype,
685  typentry->btree_opintype,
687 
688  /*
689  * As above, make sure array_cmp or record_cmp will succeed; but again
690  * we need no special check for ranges or multiranges.
691  */
692  if (lt_opr == ARRAY_LT_OP &&
693  !array_element_has_compare(typentry))
694  lt_opr = InvalidOid;
695  else if (lt_opr == RECORD_LT_OP &&
696  !record_fields_have_compare(typentry))
697  lt_opr = InvalidOid;
698 
699  typentry->lt_opr = lt_opr;
700  typentry->flags |= TCFLAGS_CHECKED_LT_OPR;
701  }
702  if ((flags & TYPECACHE_GT_OPR) &&
703  !(typentry->flags & TCFLAGS_CHECKED_GT_OPR))
704  {
705  Oid gt_opr = InvalidOid;
706 
707  if (typentry->btree_opf != InvalidOid)
708  gt_opr = get_opfamily_member(typentry->btree_opf,
709  typentry->btree_opintype,
710  typentry->btree_opintype,
712 
713  /*
714  * As above, make sure array_cmp or record_cmp will succeed; but again
715  * we need no special check for ranges or multiranges.
716  */
717  if (gt_opr == ARRAY_GT_OP &&
718  !array_element_has_compare(typentry))
719  gt_opr = InvalidOid;
720  else if (gt_opr == RECORD_GT_OP &&
721  !record_fields_have_compare(typentry))
722  gt_opr = InvalidOid;
723 
724  typentry->gt_opr = gt_opr;
725  typentry->flags |= TCFLAGS_CHECKED_GT_OPR;
726  }
727  if ((flags & (TYPECACHE_CMP_PROC | TYPECACHE_CMP_PROC_FINFO)) &&
728  !(typentry->flags & TCFLAGS_CHECKED_CMP_PROC))
729  {
730  Oid cmp_proc = InvalidOid;
731 
732  if (typentry->btree_opf != InvalidOid)
733  cmp_proc = get_opfamily_proc(typentry->btree_opf,
734  typentry->btree_opintype,
735  typentry->btree_opintype,
736  BTORDER_PROC);
737 
738  /*
739  * As above, make sure array_cmp or record_cmp will succeed; but again
740  * we need no special check for ranges or multiranges.
741  */
742  if (cmp_proc == F_BTARRAYCMP &&
743  !array_element_has_compare(typentry))
744  cmp_proc = InvalidOid;
745  else if (cmp_proc == F_BTRECORDCMP &&
746  !record_fields_have_compare(typentry))
747  cmp_proc = InvalidOid;
748 
749  /* Force update of cmp_proc_finfo only if we're changing state */
750  if (typentry->cmp_proc != cmp_proc)
751  typentry->cmp_proc_finfo.fn_oid = InvalidOid;
752 
753  typentry->cmp_proc = cmp_proc;
754  typentry->flags |= TCFLAGS_CHECKED_CMP_PROC;
755  }
757  !(typentry->flags & TCFLAGS_CHECKED_HASH_PROC))
758  {
759  Oid hash_proc = InvalidOid;
760 
761  /*
762  * We insist that the eq_opr, if one has been determined, match the
763  * hash opclass; else report there is no hash function.
764  */
765  if (typentry->hash_opf != InvalidOid &&
766  (!OidIsValid(typentry->eq_opr) ||
767  typentry->eq_opr == get_opfamily_member(typentry->hash_opf,
768  typentry->hash_opintype,
769  typentry->hash_opintype,
771  hash_proc = get_opfamily_proc(typentry->hash_opf,
772  typentry->hash_opintype,
773  typentry->hash_opintype,
775 
776  /*
777  * As above, make sure hash_array, hash_record, or hash_range will
778  * succeed.
779  */
780  if (hash_proc == F_HASH_ARRAY &&
781  !array_element_has_hashing(typentry))
782  hash_proc = InvalidOid;
783  else if (hash_proc == F_HASH_RECORD &&
784  !record_fields_have_hashing(typentry))
785  hash_proc = InvalidOid;
786  else if (hash_proc == F_HASH_RANGE &&
787  !range_element_has_hashing(typentry))
788  hash_proc = InvalidOid;
789 
790  /*
791  * Likewise for hash_multirange.
792  */
793  if (hash_proc == F_HASH_MULTIRANGE &&
795  hash_proc = InvalidOid;
796 
797  /* Force update of hash_proc_finfo only if we're changing state */
798  if (typentry->hash_proc != hash_proc)
799  typentry->hash_proc_finfo.fn_oid = InvalidOid;
800 
801  typentry->hash_proc = hash_proc;
802  typentry->flags |= TCFLAGS_CHECKED_HASH_PROC;
803  }
804  if ((flags & (TYPECACHE_HASH_EXTENDED_PROC |
807  {
808  Oid hash_extended_proc = InvalidOid;
809 
810  /*
811  * We insist that the eq_opr, if one has been determined, match the
812  * hash opclass; else report there is no hash function.
813  */
814  if (typentry->hash_opf != InvalidOid &&
815  (!OidIsValid(typentry->eq_opr) ||
816  typentry->eq_opr == get_opfamily_member(typentry->hash_opf,
817  typentry->hash_opintype,
818  typentry->hash_opintype,
820  hash_extended_proc = get_opfamily_proc(typentry->hash_opf,
821  typentry->hash_opintype,
822  typentry->hash_opintype,
824 
825  /*
826  * As above, make sure hash_array_extended, hash_record_extended, or
827  * hash_range_extended will succeed.
828  */
829  if (hash_extended_proc == F_HASH_ARRAY_EXTENDED &&
831  hash_extended_proc = InvalidOid;
832  else if (hash_extended_proc == F_HASH_RECORD_EXTENDED &&
834  hash_extended_proc = InvalidOid;
835  else if (hash_extended_proc == F_HASH_RANGE_EXTENDED &&
837  hash_extended_proc = InvalidOid;
838 
839  /*
840  * Likewise for hash_multirange_extended.
841  */
842  if (hash_extended_proc == F_HASH_MULTIRANGE_EXTENDED &&
844  hash_extended_proc = InvalidOid;
845 
846  /* Force update of proc finfo only if we're changing state */
847  if (typentry->hash_extended_proc != hash_extended_proc)
849 
850  typentry->hash_extended_proc = hash_extended_proc;
852  }
853 
854  /*
855  * Set up fmgr lookup info as requested
856  *
857  * Note: we tell fmgr the finfo structures live in CacheMemoryContext,
858  * which is not quite right (they're really in the hash table's private
859  * memory context) but this will do for our purposes.
860  *
861  * Note: the code above avoids invalidating the finfo structs unless the
862  * referenced operator/function OID actually changes. This is to prevent
863  * unnecessary leakage of any subsidiary data attached to an finfo, since
864  * that would cause session-lifespan memory leaks.
865  */
866  if ((flags & TYPECACHE_EQ_OPR_FINFO) &&
867  typentry->eq_opr_finfo.fn_oid == InvalidOid &&
868  typentry->eq_opr != InvalidOid)
869  {
870  Oid eq_opr_func;
871 
872  eq_opr_func = get_opcode(typentry->eq_opr);
873  if (eq_opr_func != InvalidOid)
874  fmgr_info_cxt(eq_opr_func, &typentry->eq_opr_finfo,
876  }
877  if ((flags & TYPECACHE_CMP_PROC_FINFO) &&
878  typentry->cmp_proc_finfo.fn_oid == InvalidOid &&
879  typentry->cmp_proc != InvalidOid)
880  {
881  fmgr_info_cxt(typentry->cmp_proc, &typentry->cmp_proc_finfo,
883  }
884  if ((flags & TYPECACHE_HASH_PROC_FINFO) &&
885  typentry->hash_proc_finfo.fn_oid == InvalidOid &&
886  typentry->hash_proc != InvalidOid)
887  {
888  fmgr_info_cxt(typentry->hash_proc, &typentry->hash_proc_finfo,
890  }
891  if ((flags & TYPECACHE_HASH_EXTENDED_PROC_FINFO) &&
893  typentry->hash_extended_proc != InvalidOid)
894  {
896  &typentry->hash_extended_proc_finfo,
898  }
899 
900  /*
901  * If it's a composite type (row type), get tupdesc if requested
902  */
903  if ((flags & TYPECACHE_TUPDESC) &&
904  typentry->tupDesc == NULL &&
905  typentry->typtype == TYPTYPE_COMPOSITE)
906  {
907  load_typcache_tupdesc(typentry);
908  }
909 
910  /*
911  * If requested, get information about a range type
912  *
913  * This includes making sure that the basic info about the range element
914  * type is up-to-date.
915  */
916  if ((flags & TYPECACHE_RANGE_INFO) &&
917  typentry->typtype == TYPTYPE_RANGE)
918  {
919  if (typentry->rngelemtype == NULL)
920  load_rangetype_info(typentry);
921  else if (!(typentry->rngelemtype->flags & TCFLAGS_HAVE_PG_TYPE_DATA))
922  (void) lookup_type_cache(typentry->rngelemtype->type_id, 0);
923  }
924 
925  /*
926  * If requested, get information about a multirange type
927  */
928  if ((flags & TYPECACHE_MULTIRANGE_INFO) &&
929  typentry->rngtype == NULL &&
930  typentry->typtype == TYPTYPE_MULTIRANGE)
931  {
932  load_multirangetype_info(typentry);
933  }
934 
935  /*
936  * If requested, get information about a domain type
937  */
938  if ((flags & TYPECACHE_DOMAIN_BASE_INFO) &&
939  typentry->domainBaseType == InvalidOid &&
940  typentry->typtype == TYPTYPE_DOMAIN)
941  {
942  typentry->domainBaseTypmod = -1;
943  typentry->domainBaseType =
944  getBaseTypeAndTypmod(type_id, &typentry->domainBaseTypmod);
945  }
946  if ((flags & TYPECACHE_DOMAIN_CONSTR_INFO) &&
947  (typentry->flags & TCFLAGS_CHECKED_DOMAIN_CONSTRAINTS) == 0 &&
948  typentry->typtype == TYPTYPE_DOMAIN)
949  {
950  load_domaintype_info(typentry);
951  }
952 
953  INJECTION_POINT("typecache-before-rel-type-cache-insert");
954 
955  Assert(in_progress_offset + 1 == in_progress_list_len);
957 
959 
960  return typentry;
961 }
#define MemSet(start, val, len)
Definition: c.h:974
uint32 get_hash_value(HTAB *hashp, const void *keyPtr)
Definition: dynahash.c:911
#define HASHSTANDARD_PROC
Definition: hash.h:355
#define HASHEXTENDED_PROC
Definition: hash.h:356
#define HASH_BLOBS
Definition: hsearch.h:97
Oid GetDefaultOpClass(Oid type_id, Oid am_id)
Definition: indexcmds.c:2338
#define INJECTION_POINT(name)
void CacheRegisterRelcacheCallback(RelcacheCallbackFunction func, Datum arg)
Definition: inval.c:1746
void CacheRegisterSyscacheCallback(int cacheid, SyscacheCallbackFunction func, Datum arg)
Definition: inval.c:1704
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
#define BTGreaterStrategyNumber
Definition: stratnum.h:33
#define HTEqualStrategyNumber
Definition: stratnum.h:41
#define BTLessStrategyNumber
Definition: stratnum.h:29
Oid fn_oid
Definition: fmgr.h:59
uint32 type_id_hash
Definition: typcache.h:36
FmgrInfo hash_proc_finfo
Definition: typcache.h:77
Oid typsubscript
Definition: typcache.h:45
FmgrInfo cmp_proc_finfo
Definition: typcache.h:76
char typalign
Definition: typcache.h:41
FmgrInfo hash_extended_proc_finfo
Definition: typcache.h:78
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
#define TCFLAGS_CHECKED_BTREE_OPCLASS
Definition: typcache.c:100
#define TCFLAGS_CHECKED_HASH_OPCLASS
Definition: typcache.c:101
static bool range_element_has_hashing(TypeCacheEntry *typentry)
Definition: typcache.c:1713
static bool record_fields_have_hashing(TypeCacheEntry *typentry)
Definition: typcache.c:1592
static bool record_fields_have_extended_hashing(TypeCacheEntry *typentry)
Definition: typcache.c:1600
static int in_progress_list_maxlen
Definition: typcache.c:228
#define TCFLAGS_CHECKED_GT_OPR
Definition: typcache.c:104
static bool multirange_element_has_hashing(TypeCacheEntry *typentry)
Definition: typcache.c:1753
static bool record_fields_have_equality(TypeCacheEntry *typentry)
Definition: typcache.c:1576
#define TCFLAGS_CHECKED_LT_OPR
Definition: typcache.c:103
#define TCFLAGS_CHECKED_HASH_PROC
Definition: typcache.c:106
static bool array_element_has_extended_hashing(TypeCacheEntry *typentry)
Definition: typcache.c:1538
static bool array_element_has_hashing(TypeCacheEntry *typentry)
Definition: typcache.c:1530
static uint32 type_cache_syshash(const void *key, Size keysize)
Definition: typcache.c:359
#define TCFLAGS_CHECKED_CMP_PROC
Definition: typcache.c:105
static bool multirange_element_has_extended_hashing(TypeCacheEntry *typentry)
Definition: typcache.c:1761
static bool array_element_has_equality(TypeCacheEntry *typentry)
Definition: typcache.c:1514
static bool range_element_has_extended_hashing(TypeCacheEntry *typentry)
Definition: typcache.c:1721
static TypeCacheEntry * firstDomainTypeEntry
Definition: typcache.c:96
struct RelIdToTypeIdCacheEntry RelIdToTypeIdCacheEntry
#define TCFLAGS_CHECKED_HASH_EXTENDED_PROC
Definition: typcache.c:107
static void TypeCacheTypCallback(Datum arg, int cacheid, uint32 hashvalue)
Definition: typcache.c:2511
static void TypeCacheConstrCallback(Datum arg, int cacheid, uint32 hashvalue)
Definition: typcache.c:2597
static void TypeCacheOpcCallback(Datum arg, int cacheid, uint32 hashvalue)
Definition: typcache.c:2568
static void load_domaintype_info(TypeCacheEntry *typentry)
Definition: typcache.c:1081
static void TypeCacheRelCallback(Datum arg, Oid relid)
Definition: typcache.c:2415
static bool array_element_has_compare(TypeCacheEntry *typentry)
Definition: typcache.c:1522
static bool record_fields_have_compare(TypeCacheEntry *typentry)
Definition: typcache.c:1584
#define TCFLAGS_CHECKED_EQ_OPR
Definition: typcache.c:102
#define TYPECACHE_HASH_PROC_FINFO
Definition: typcache.h:144
#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_BTREE_OPFAMILY
Definition: typcache.h:146
#define TYPECACHE_GT_OPR
Definition: typcache.h:139
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

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_BLOBS, 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, in_progress_list, in_progress_list_len, in_progress_list_maxlen, INJECTION_POINT, insert_rel_type_cache_if_needed(), InvalidOid, load_domaintype_info(), load_multirangetype_info(), load_rangetype_info(), load_typcache_tupdesc(), TypeCacheEntry::lt_opr, MemoryContextAlloc(), 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(), RelIdToTypeIdCacheHash, repalloc(), 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_reverse(), 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_exclusion_or_unique_constraint(), check_memoizable(), contain_leaked_vars_walker(), CreateStatistics(), dependency_degree(), domain_state_setup(), DomainHasConstraints(), enum_cmp_internal(), ExecInitExprRec(), find_simplified_clause(), foreign_expr_walker(), get_attr_stat_type(), get_cached_rowtype(), get_elem_stat_type(), 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().

◆ multirange_element_has_extended_hashing()

static bool multirange_element_has_extended_hashing ( TypeCacheEntry typentry)
static

Definition at line 1761 of file typcache.c.

1762 {
1763  if (!(typentry->flags & TCFLAGS_CHECKED_ELEM_PROPERTIES))
1765  return (typentry->flags & TCFLAGS_HAVE_ELEM_EXTENDED_HASHING) != 0;
1766 }
static void cache_multirange_element_properties(TypeCacheEntry *typentry)
Definition: typcache.c:1769

References cache_multirange_element_properties(), TypeCacheEntry::flags, TCFLAGS_CHECKED_ELEM_PROPERTIES, and TCFLAGS_HAVE_ELEM_EXTENDED_HASHING.

Referenced by lookup_type_cache().

◆ multirange_element_has_hashing()

static bool multirange_element_has_hashing ( TypeCacheEntry typentry)
static

Definition at line 1753 of file typcache.c.

1754 {
1755  if (!(typentry->flags & TCFLAGS_CHECKED_ELEM_PROPERTIES))
1757  return (typentry->flags & TCFLAGS_HAVE_ELEM_HASHING) != 0;
1758 }

References cache_multirange_element_properties(), TypeCacheEntry::flags, TCFLAGS_CHECKED_ELEM_PROPERTIES, and TCFLAGS_HAVE_ELEM_HASHING.

Referenced by lookup_type_cache().

◆ prep_domain_constraints()

static List * prep_domain_constraints ( List constraints,
MemoryContext  execctx 
)
static

Definition at line 1362 of file typcache.c.

1363 {
1364  List *result = NIL;
1365  MemoryContext oldcxt;
1366  ListCell *lc;
1367 
1368  oldcxt = MemoryContextSwitchTo(execctx);
1369 
1370  foreach(lc, constraints)
1371  {
1373  DomainConstraintState *newr;
1374 
1376  newr->constrainttype = r->constrainttype;
1377  newr->name = r->name;
1378  newr->check_expr = r->check_expr;
1379  newr->check_exprstate = ExecInitExpr(r->check_expr, NULL);
1380 
1381  result = lappend(result, newr);
1382  }
1383 
1384  MemoryContextSwitchTo(oldcxt);
1385 
1386  return result;
1387 }
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:138
List * lappend(List *list, void *datum)
Definition: list.c:339
#define lfirst(lc)
Definition: pg_list.h:172
Definition: pg_list.h:54

References DomainConstraintState::check_expr, DomainConstraintState::check_exprstate, DomainConstraintState::constrainttype, ExecInitExpr(), lappend(), lfirst, makeNode, MemoryContextSwitchTo(), DomainConstraintState::name, and NIL.

Referenced by InitDomainConstraintRef(), and UpdateDomainConstraintRef().

◆ range_element_has_extended_hashing()

static bool range_element_has_extended_hashing ( TypeCacheEntry typentry)
static

Definition at line 1721 of file typcache.c.

1722 {
1723  if (!(typentry->flags & TCFLAGS_CHECKED_ELEM_PROPERTIES))
1725  return (typentry->flags & TCFLAGS_HAVE_ELEM_EXTENDED_HASHING) != 0;
1726 }
static void cache_range_element_properties(TypeCacheEntry *typentry)
Definition: typcache.c:1729

References cache_range_element_properties(), TypeCacheEntry::flags, TCFLAGS_CHECKED_ELEM_PROPERTIES, and TCFLAGS_HAVE_ELEM_EXTENDED_HASHING.

Referenced by lookup_type_cache().

◆ range_element_has_hashing()

static bool range_element_has_hashing ( TypeCacheEntry typentry)
static

Definition at line 1713 of file typcache.c.

1714 {
1715  if (!(typentry->flags & TCFLAGS_CHECKED_ELEM_PROPERTIES))
1717  return (typentry->flags & TCFLAGS_HAVE_ELEM_HASHING) != 0;
1718 }

References cache_range_element_properties(), TypeCacheEntry::flags, TCFLAGS_CHECKED_ELEM_PROPERTIES, and TCFLAGS_HAVE_ELEM_HASHING.

Referenced by lookup_type_cache().

◆ record_fields_have_compare()

static bool record_fields_have_compare ( TypeCacheEntry typentry)
static

Definition at line 1584 of file typcache.c.

1585 {
1586  if (!(typentry->flags & TCFLAGS_CHECKED_FIELD_PROPERTIES))
1588  return (typentry->flags & TCFLAGS_HAVE_FIELD_COMPARE) != 0;
1589 }
static void cache_record_field_properties(TypeCacheEntry *typentry)
Definition: typcache.c:1608

References cache_record_field_properties(), TypeCacheEntry::flags, TCFLAGS_CHECKED_FIELD_PROPERTIES, and TCFLAGS_HAVE_FIELD_COMPARE.

Referenced by lookup_type_cache().

◆ record_fields_have_equality()

static bool record_fields_have_equality ( TypeCacheEntry typentry)
static

Definition at line 1576 of file typcache.c.

1577 {
1578  if (!(typentry->flags & TCFLAGS_CHECKED_FIELD_PROPERTIES))
1580  return (typentry->flags & TCFLAGS_HAVE_FIELD_EQUALITY) != 0;
1581 }

References cache_record_field_properties(), TypeCacheEntry::flags, TCFLAGS_CHECKED_FIELD_PROPERTIES, and TCFLAGS_HAVE_FIELD_EQUALITY.

Referenced by lookup_type_cache().

◆ record_fields_have_extended_hashing()

static bool record_fields_have_extended_hashing ( TypeCacheEntry typentry)
static

◆ record_fields_have_hashing()

static bool record_fields_have_hashing ( TypeCacheEntry typentry)
static

Definition at line 1592 of file typcache.c.

1593 {
1594  if (!(typentry->flags & TCFLAGS_CHECKED_FIELD_PROPERTIES))
1596  return (typentry->flags & TCFLAGS_HAVE_FIELD_HASHING) != 0;
1597 }

References cache_record_field_properties(), TypeCacheEntry::flags, TCFLAGS_CHECKED_FIELD_PROPERTIES, and TCFLAGS_HAVE_FIELD_HASHING.

Referenced by lookup_type_cache().

◆ record_type_typmod_compare()

static int record_type_typmod_compare ( const void *  a,
const void *  b,
size_t  size 
)
static

Definition at line 2024 of file typcache.c.

2025 {
2026  RecordCacheEntry *left = (RecordCacheEntry *) a;
2027  RecordCacheEntry *right = (RecordCacheEntry *) b;
2028 
2029  return equalRowTypes(left->tupdesc, right->tupdesc) ? 0 : 1;
2030 }
bool equalRowTypes(TupleDesc tupdesc1, TupleDesc tupdesc2)
Definition: tupdesc.c:586

References a, b, equalRowTypes(), and RecordCacheEntry::tupdesc.

Referenced by assign_record_type_typmod().

◆ record_type_typmod_hash()

static uint32 record_type_typmod_hash ( const void *  data,
size_t  size 
)
static

Definition at line 2013 of file typcache.c.

2014 {
2015  RecordCacheEntry *entry = (RecordCacheEntry *) data;
2016 
2017  return hashRowType(entry->tupdesc);
2018 }
const void * data
uint32 hashRowType(TupleDesc desc)
Definition: tupdesc.c:622

References data, hashRowType(), and RecordCacheEntry::tupdesc.

Referenced by assign_record_type_typmod().

◆ share_tupledesc()

static dsa_pointer share_tupledesc ( dsa_area area,
TupleDesc  tupdesc,
uint32  typmod 
)
static

Definition at line 2908 of file typcache.c.

2909 {
2910  dsa_pointer shared_dp;
2911  TupleDesc shared;
2912 
2913  shared_dp = dsa_allocate(area, TupleDescSize(tupdesc));
2914  shared = (TupleDesc) dsa_get_address(area, shared_dp);
2915  TupleDescCopy(shared, tupdesc);
2916  shared->tdtypmod = typmod;
2917 
2918  return shared_dp;
2919 }
#define dsa_allocate(area, size)
Definition: dsa.h:109
void TupleDescCopy(TupleDesc dst, TupleDesc src)
Definition: tupdesc.c:251
#define TupleDescSize(src)
Definition: tupdesc.h:102

References dsa_allocate, dsa_get_address(), TupleDescData::tdtypmod, TupleDescCopy(), and TupleDescSize.

Referenced by find_or_make_matching_shared_tupledesc(), and SharedRecordTypmodRegistryInit().

◆ shared_record_table_compare()

static int shared_record_table_compare ( const void *  a,
const void *  b,
size_t  size,
void *  arg 
)
static

Definition at line 234 of file typcache.c.

236 {
237  dsa_area *area = (dsa_area *) arg;
240  TupleDesc t1;
241  TupleDesc t2;
242 
243  if (k1->shared)
244  t1 = (TupleDesc) dsa_get_address(area, k1->u.shared_tupdesc);
245  else
246  t1 = k1->u.local_tupdesc;
247 
248  if (k2->shared)
249  t2 = (TupleDesc) dsa_get_address(area, k2->u.shared_tupdesc);
250  else
251  t2 = k2->u.local_tupdesc;
252 
253  return equalRowTypes(t1, t2) ? 0 : 1;
254 }
TupleDesc local_tupdesc
Definition: typcache.c:201
Definition: dsa.c:348

References a, arg, b, dsa_get_address(), equalRowTypes(), SharedRecordTableKey::local_tupdesc, SharedRecordTableKey::shared, SharedRecordTableKey::shared_tupdesc, and SharedRecordTableKey::u.

◆ shared_record_table_hash()

static uint32 shared_record_table_hash ( const void *  a,
size_t  size,
void *  arg 
)
static

Definition at line 260 of file typcache.c.

261 {
262  dsa_area *area = (dsa_area *) arg;
264  TupleDesc t;
265 
266  if (k->shared)
267  t = (TupleDesc) dsa_get_address(area, k->u.shared_tupdesc);
268  else
269  t = k->u.local_tupdesc;
270 
271  return hashRowType(t);
272 }

References a, arg, dsa_get_address(), hashRowType(), SharedRecordTableKey::local_tupdesc, SharedRecordTableKey::shared, SharedRecordTableKey::shared_tupdesc, and SharedRecordTableKey::u.

◆ shared_record_typmod_registry_detach()

static void shared_record_typmod_registry_detach ( dsm_segment segment,
Datum  datum 
)
static

Definition at line 3041 of file typcache.c.

3042 {
3043  /* Be cautious here: maybe we didn't finish initializing. */
3044  if (CurrentSession->shared_record_table != NULL)
3045  {
3048  }
3049  if (CurrentSession->shared_typmod_table != NULL)
3050  {
3053  }
3055 }
void dshash_detach(dshash_table *hash_table)
Definition: dshash.c:307

References CurrentSession, dshash_detach(), Session::shared_record_table, Session::shared_typmod_registry, and Session::shared_typmod_table.

Referenced by SharedRecordTypmodRegistryAttach(), and SharedRecordTypmodRegistryInit().

◆ SharedRecordTypmodRegistryAttach()

void SharedRecordTypmodRegistryAttach ( SharedRecordTypmodRegistry registry)

Definition at line 2294 of file typcache.c.

2295 {
2296  MemoryContext old_context;
2297  dshash_table *record_table;
2298  dshash_table *typmod_table;
2299 
2301 
2302  /* We can't already be attached to a shared registry. */
2303  Assert(CurrentSession != NULL);
2304  Assert(CurrentSession->segment != NULL);
2305  Assert(CurrentSession->area != NULL);
2309 
2310  /*
2311  * We can't already have typmods in our local cache, because they'd clash
2312  * with those imported by SharedRecordTypmodRegistryInit. This should be
2313  * a freshly started parallel worker. If we ever support worker
2314  * recycling, a worker would need to zap its local cache in between
2315  * servicing different queries, in order to be able to call this and
2316  * synchronize typmods with a new leader; but that's problematic because
2317  * we can't be very sure that record-typmod-related state hasn't escaped
2318  * to anywhere else in the process.
2319  */
2320  Assert(NextRecordTypmod == 0);
2321 
2322  old_context = MemoryContextSwitchTo(TopMemoryContext);
2323 
2324  /* Attach to the two hash tables. */
2325  record_table = dshash_attach(CurrentSession->area,
2327  registry->record_table_handle,
2328  CurrentSession->area);
2329  typmod_table = dshash_attach(CurrentSession->area,
2331  registry->typmod_table_handle,
2332  NULL);
2333 
2334  MemoryContextSwitchTo(old_context);
2335 
2336  /*
2337  * Set up detach hook to run at worker exit. Currently this is the same
2338  * as the leader's detach hook, but in future they might need to be
2339  * different.
2340  */
2343  PointerGetDatum(registry));
2344 
2345  /*
2346  * Set up the session state that will tell assign_record_type_typmod and
2347  * lookup_rowtype_tupdesc_internal about the shared registry.
2348  */
2350  CurrentSession->shared_record_table = record_table;
2351  CurrentSession->shared_typmod_table = typmod_table;
2352 }
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
dsm_segment * segment
Definition: session.h:27
dshash_table_handle typmod_table_handle
Definition: typcache.c:186
dshash_table_handle record_table_handle
Definition: typcache.c:184
static const dshash_parameters srtr_typmod_table_params
Definition: typcache.c:285
static void shared_record_typmod_registry_detach(dsm_segment *segment, Datum datum)
Definition: typcache.c:3041
static const dshash_parameters srtr_record_table_params
Definition: typcache.c:275

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 2173 of file typcache.c.

2174 {
2175  return sizeof(SharedRecordTypmodRegistry);
2176 }
struct SharedRecordTypmodRegistry SharedRecordTypmodRegistry
Definition: typcache.h:176

Referenced by GetSessionDsmHandle().

◆ SharedRecordTypmodRegistryInit()

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

Definition at line 2195 of file typcache.c.

2198 {
2199  MemoryContext old_context;
2200  dshash_table *record_table;
2201  dshash_table *typmod_table;
2202  int32 typmod;
2203 
2205 
2206  /* We can't already be attached to a shared registry. */
2210 
2211  old_context = MemoryContextSwitchTo(TopMemoryContext);
2212 
2213  /* Create the hash table of tuple descriptors indexed by themselves. */
2214  record_table = dshash_create(area, &srtr_record_table_params, area);
2215 
2216  /* Create the hash table of tuple descriptors indexed by typmod. */
2217  typmod_table = dshash_create(area, &srtr_typmod_table_params, NULL);
2218 
2219  MemoryContextSwitchTo(old_context);
2220 
2221  /* Initialize the SharedRecordTypmodRegistry. */
2222  registry->record_table_handle = dshash_get_hash_table_handle(record_table);
2223  registry->typmod_table_handle = dshash_get_hash_table_handle(typmod_table);
2225 
2226  /*
2227  * Copy all entries from this backend's private registry into the shared
2228  * registry.
2229  */
2230  for (typmod = 0; typmod < NextRecordTypmod; ++typmod)
2231  {
2232  SharedTypmodTableEntry *typmod_table_entry;
2233  SharedRecordTableEntry *record_table_entry;
2234  SharedRecordTableKey record_table_key;
2235  dsa_pointer shared_dp;
2236  TupleDesc tupdesc;
2237  bool found;
2238 
2239  tupdesc = RecordCacheArray[typmod].tupdesc;
2240  if (tupdesc == NULL)
2241  continue;
2242 
2243  /* Copy the TupleDesc into shared memory. */
2244  shared_dp = share_tupledesc(area, tupdesc, typmod);
2245 
2246  /* Insert into the typmod table. */
2247  typmod_table_entry = dshash_find_or_insert(typmod_table,
2248  &tupdesc->tdtypmod,
2249  &found);
2250  if (found)
2251  elog(ERROR, "cannot create duplicate shared record typmod");
2252  typmod_table_entry->typmod = tupdesc->tdtypmod;
2253  typmod_table_entry->shared_tupdesc = shared_dp;
2254  dshash_release_lock(typmod_table, typmod_table_entry);
2255 
2256  /* Insert into the record table. */
2257  record_table_key.shared = false;
2258  record_table_key.u.local_tupdesc = tupdesc;
2259  record_table_entry = dshash_find_or_insert(record_table,
2260  &record_table_key,
2261  &found);
2262  if (!found)
2263  {
2264  record_table_entry->key.shared = true;
2265  record_table_entry->key.u.shared_tupdesc = shared_dp;
2266  }
2267  dshash_release_lock(record_table, record_table_entry);
2268  }
2269 
2270  /*
2271  * Set up the global state that will tell assign_record_type_typmod and
2272  * lookup_rowtype_tupdesc_internal about the shared registry.
2273  */
2274  CurrentSession->shared_record_table = record_table;
2275  CurrentSession->shared_typmod_table = typmod_table;
2277 
2278  /*
2279  * We install a detach hook in the leader, but only to handle cleanup on
2280  * failure during GetSessionDsmHandle(). Once GetSessionDsmHandle() pins
2281  * the memory, the leader process will use a shared registry until it
2282  * exits.
2283  */
2285 }
static void pg_atomic_init_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
Definition: atomics.h:221
dshash_table_handle dshash_get_hash_table_handle(dshash_table *hash_table)
Definition: dshash.c:367
dshash_table * dshash_create(dsa_area *area, const dshash_parameters *params, void *arg)
Definition: dshash.c:206

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

◆ type_cache_syshash()

static uint32 type_cache_syshash ( const void *  key,
Size  keysize 
)
static

Definition at line 359 of file typcache.c.

360 {
361  Assert(keysize == sizeof(Oid));
362  return GetSysCacheHashValue1(TYPEOID, ObjectIdGetDatum(*(const Oid *) key));
363 }
#define GetSysCacheHashValue1(cacheId, key1)
Definition: syscache.h:118

References Assert, GetSysCacheHashValue1, sort-test::key, and ObjectIdGetDatum().

Referenced by lookup_type_cache().

◆ TypeCacheConstrCallback()

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

Definition at line 2597 of file typcache.c.

2598 {
2599  TypeCacheEntry *typentry;
2600 
2601  /*
2602  * Because this is called very frequently, and typically very few of the
2603  * typcache entries are for domains, we don't use hash_seq_search here.
2604  * Instead we thread all the domain-type entries together so that we can
2605  * visit them cheaply.
2606  */
2607  for (typentry = firstDomainTypeEntry;
2608  typentry != NULL;
2609  typentry = typentry->nextDomain)
2610  {
2611  /* Reset domain constraint validity information */
2613  }
2614 }

References firstDomainTypeEntry, TypeCacheEntry::flags, TypeCacheEntry::nextDomain, and TCFLAGS_CHECKED_DOMAIN_CONSTRAINTS.

Referenced by lookup_type_cache().

◆ TypeCacheOpcCallback()

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

Definition at line 2568 of file typcache.c.

2569 {
2570  HASH_SEQ_STATUS status;
2571  TypeCacheEntry *typentry;
2572 
2573  /* TypeCacheHash must exist, else this callback wouldn't be registered */
2574  hash_seq_init(&status, TypeCacheHash);
2575  while ((typentry = (TypeCacheEntry *) hash_seq_search(&status)) != NULL)
2576  {
2577  /* Reset equality/comparison/hashing validity information */
2578  typentry->flags &= ~TCFLAGS_OPERATOR_FLAGS;
2579  }
2580 }
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1420
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1385

References TypeCacheEntry::flags, hash_seq_init(), hash_seq_search(), TCFLAGS_OPERATOR_FLAGS, and TypeCacheHash.

Referenced by lookup_type_cache().

◆ TypeCacheRelCallback()

static void TypeCacheRelCallback ( Datum  arg,
Oid  relid 
)
static

Definition at line 2415 of file typcache.c.

2416 {
2417  TypeCacheEntry *typentry;
2418 
2419  /*
2420  * RelIdToTypeIdCacheHash and TypeCacheHash should exist, otherwise this
2421  * callback wouldn't be registered
2422  */
2423  if (OidIsValid(relid))
2424  {
2425  RelIdToTypeIdCacheEntry *relentry;
2426 
2427  /*
2428  * Find an RelIdToTypeIdCacheHash entry, which should exist as soon as
2429  * corresponding typcache entry has something to clean.
2430  */
2432  &relid,
2433  HASH_FIND, NULL);
2434 
2435  if (relentry != NULL)
2436  {
2437  typentry = (TypeCacheEntry *) hash_search(TypeCacheHash,
2438  &relentry->composite_typid,
2439  HASH_FIND, NULL);
2440 
2441  if (typentry != NULL)
2442  {
2443  Assert(typentry->typtype == TYPTYPE_COMPOSITE);
2444  Assert(relid == typentry->typrelid);
2445 
2447  }
2448  }
2449 
2450  /*
2451  * Visit all the domain types sequentially. Typically, this shouldn't
2452  * affect performance since domain types are less tended to bloat.
2453  * Domain types are created manually, unlike composite types which are
2454  * automatically created for every temporary table.
2455  */
2456  for (typentry = firstDomainTypeEntry;
2457  typentry != NULL;
2458  typentry = typentry->nextDomain)
2459  {
2460  /*
2461  * If it's domain over composite, reset flags. (We don't bother
2462  * trying to determine whether the specific base type needs a
2463  * reset.) Note that if we haven't determined whether the base
2464  * type is composite, we don't need to reset anything.
2465  */
2466  if (typentry->flags & TCFLAGS_DOMAIN_BASE_IS_COMPOSITE)
2467  typentry->flags &= ~TCFLAGS_OPERATOR_FLAGS;
2468  }
2469  }
2470  else
2471  {
2472  HASH_SEQ_STATUS status;
2473 
2474  /*
2475  * Relid is invalid. By convention, we need to reset all composite
2476  * types in cache. Also, we should reset flags for domain types, and
2477  * we loop over all entries in hash, so, do it in a single scan.
2478  */
2479  hash_seq_init(&status, TypeCacheHash);
2480  while ((typentry = (TypeCacheEntry *) hash_seq_search(&status)) != NULL)
2481  {
2482  if (typentry->typtype == TYPTYPE_COMPOSITE)
2483  {
2485  }
2486  else if (typentry->typtype == TYPTYPE_DOMAIN)
2487  {
2488  /*
2489  * If it's domain over composite, reset flags. (We don't
2490  * bother trying to determine whether the specific base type
2491  * needs a reset.) Note that if we haven't determined whether
2492  * the base type is composite, we don't need to reset
2493  * anything.
2494  */
2495  if (typentry->flags & TCFLAGS_DOMAIN_BASE_IS_COMPOSITE)
2496  typentry->flags &= ~TCFLAGS_OPERATOR_FLAGS;
2497  }
2498  }
2499  }
2500 }
static void InvalidateCompositeTypeCacheEntry(TypeCacheEntry *typentry)
Definition: typcache.c:2363

References Assert, RelIdToTypeIdCacheEntry::composite_typid, firstDomainTypeEntry, TypeCacheEntry::flags, HASH_FIND, hash_search(), hash_seq_init(), hash_seq_search(), InvalidateCompositeTypeCacheEntry(), TypeCacheEntry::nextDomain, OidIsValid, RelIdToTypeIdCacheHash, TCFLAGS_DOMAIN_BASE_IS_COMPOSITE, TCFLAGS_OPERATOR_FLAGS, TypeCacheHash, TypeCacheEntry::typrelid, and TypeCacheEntry::typtype.

Referenced by lookup_type_cache().

◆ TypeCacheTypCallback()

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

Definition at line 2511 of file typcache.c.

2512 {
2513  HASH_SEQ_STATUS status;
2514  TypeCacheEntry *typentry;
2515 
2516  /* TypeCacheHash must exist, else this callback wouldn't be registered */
2517 
2518  /*
2519  * By convention, zero hash value is passed to the callback as a sign that
2520  * it's time to invalidate the whole cache. See sinval.c, inval.c and
2521  * InvalidateSystemCachesExtended().
2522  */
2523  if (hashvalue == 0)
2524  hash_seq_init(&status, TypeCacheHash);
2525  else
2526  hash_seq_init_with_hash_value(&status, TypeCacheHash, hashvalue);
2527 
2528  while ((typentry = (TypeCacheEntry *) hash_seq_search(&status)) != NULL)
2529  {
2530  bool hadPgTypeData = (typentry->flags & TCFLAGS_HAVE_PG_TYPE_DATA);
2531 
2532  Assert(hashvalue == 0 || typentry->type_id_hash == hashvalue);
2533 
2534  /*
2535  * Mark the data obtained directly from pg_type as invalid. Also, if
2536  * it's a domain, typnotnull might've changed, so we'll need to
2537  * recalculate its constraints.
2538  */
2539  typentry->flags &= ~(TCFLAGS_HAVE_PG_TYPE_DATA |
2541 
2542  /*
2543  * Call delete_rel_type_cache() if we cleaned
2544  * TCFLAGS_HAVE_PG_TYPE_DATA flag previously.
2545  */
2546  if (hadPgTypeData)
2548  }
2549 }
void hash_seq_init_with_hash_value(HASH_SEQ_STATUS *status, HTAB *hashp, uint32 hashvalue)
Definition: dynahash.c:1405

References Assert, delete_rel_type_cache_if_needed(), TypeCacheEntry::flags, hash_seq_init(), hash_seq_init_with_hash_value(), hash_seq_search(), TCFLAGS_CHECKED_DOMAIN_CONSTRAINTS, TCFLAGS_HAVE_PG_TYPE_DATA, TypeCacheEntry::type_id_hash, and TypeCacheHash.

Referenced by lookup_type_cache().

◆ UpdateDomainConstraintRef()

void UpdateDomainConstraintRef ( DomainConstraintRef ref)

Definition at line 1438 of file typcache.c.

1439 {
1440  TypeCacheEntry *typentry = ref->tcache;
1441 
1442  /* Make sure typcache entry's data is up to date */
1443  if ((typentry->flags & TCFLAGS_CHECKED_DOMAIN_CONSTRAINTS) == 0 &&
1444  typentry->typtype == TYPTYPE_DOMAIN)
1445  load_domaintype_info(typentry);
1446 
1447  /* Transfer to ref object if there's new info, adjusting refcounts */
1448  if (ref->dcc != typentry->domainData)
1449  {
1450  /* Paranoia --- be sure link is nulled before trying to release */
1451  DomainConstraintCache *dcc = ref->dcc;
1452 
1453  if (dcc)
1454  {
1455  /*
1456  * Note: we just leak the previous list of executable domain
1457  * constraints. Alternatively, we could keep those in a child
1458  * context of ref->refctx and free that context at this point.
1459  * However, in practice this code path will be taken so seldom
1460  * that the extra bookkeeping for a child context doesn't seem
1461  * worthwhile; we'll just allow a leak for the lifespan of refctx.
1462  */
1463  ref->constraints = NIL;
1464  ref->dcc = NULL;
1465  decr_dcc_refcount(dcc);
1466  }
1467  dcc = typentry->domainData;
1468  if (dcc)
1469  {
1470  ref->dcc = dcc;
1471  dcc->dccRefCount++;
1472  if (ref->need_exprstate)
1474  ref->refctx);
1475  else
1476  ref->constraints = dcc->constraints;
1477  }
1478  }
1479 }

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

Variable Documentation

◆ firstDomainTypeEntry

TypeCacheEntry* firstDomainTypeEntry = NULL
static

Definition at line 96 of file typcache.c.

Referenced by lookup_type_cache(), TypeCacheConstrCallback(), and TypeCacheRelCallback().

◆ in_progress_list

Oid* in_progress_list
static

◆ in_progress_list_len

int in_progress_list_len
static

◆ in_progress_list_maxlen

int in_progress_list_maxlen
static

Definition at line 228 of file typcache.c.

Referenced by lookup_type_cache().

◆ NextRecordTypmod

int32 NextRecordTypmod = 0
static

◆ RecordCacheArray

◆ RecordCacheArrayLen

int32 RecordCacheArrayLen = 0
static

◆ RecordCacheHash

HTAB* RecordCacheHash = NULL
static

Definition at line 295 of file typcache.c.

Referenced by assign_record_type_typmod().

◆ RelIdToTypeIdCacheHash

HTAB* RelIdToTypeIdCacheHash = NULL
static

◆ srtr_record_table_params

const dshash_parameters srtr_record_table_params
static
Initial value:
= {
}
void dshash_memcpy(void *dest, const void *src, size_t size, void *arg)
Definition: dshash.c:590
@ LWTRANCHE_PER_SESSION_RECORD_TYPE
Definition: lwlock.h:197
static int shared_record_table_compare(const void *a, const void *b, size_t size, void *arg)
Definition: typcache.c:234
static uint32 shared_record_table_hash(const void *a, size_t size, void *arg)
Definition: typcache.c:260
struct SharedRecordTableKey SharedRecordTableKey

Definition at line 275 of file typcache.c.

Referenced by SharedRecordTypmodRegistryAttach(), and SharedRecordTypmodRegistryInit().

◆ srtr_typmod_table_params

const dshash_parameters srtr_typmod_table_params
static
Initial value:
= {
sizeof(uint32),
}
dshash_hash dshash_memhash(const void *v, size_t size, void *arg)
Definition: dshash.c:581
int dshash_memcmp(const void *a, const void *b, size_t size, void *arg)
Definition: dshash.c:572
@ LWTRANCHE_PER_SESSION_RECORD_TYPMOD
Definition: lwlock.h:198

Definition at line 285 of file typcache.c.

Referenced by SharedRecordTypmodRegistryAttach(), and SharedRecordTypmodRegistryInit().

◆ tupledesc_id_counter

◆ TypeCacheHash