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 "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/inval.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/snapmgr.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  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 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)
 
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 bool enum_known_sorted (TypeCacheEnumData *enumdata, Oid arg)
 
int compare_values_of_enum (TypeCacheEntry *tcache, Oid arg1, Oid arg2)
 

Variables

static HTABTypeCacheHash = NULL
 
static TypeCacheEntryfirstDomainTypeEntry = NULL
 
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 85 of file typcache.c.

◆ TCFLAGS_CHECKED_CMP_PROC

#define TCFLAGS_CHECKED_CMP_PROC   0x000040

Definition at line 90 of file typcache.c.

◆ TCFLAGS_CHECKED_DOMAIN_CONSTRAINTS

#define TCFLAGS_CHECKED_DOMAIN_CONSTRAINTS   0x080000

Definition at line 103 of file typcache.c.

◆ TCFLAGS_CHECKED_ELEM_PROPERTIES

#define TCFLAGS_CHECKED_ELEM_PROPERTIES   0x000200

Definition at line 93 of file typcache.c.

◆ TCFLAGS_CHECKED_EQ_OPR

#define TCFLAGS_CHECKED_EQ_OPR   0x000008

Definition at line 87 of file typcache.c.

◆ TCFLAGS_CHECKED_FIELD_PROPERTIES

#define TCFLAGS_CHECKED_FIELD_PROPERTIES   0x004000

Definition at line 98 of file typcache.c.

◆ TCFLAGS_CHECKED_GT_OPR

#define TCFLAGS_CHECKED_GT_OPR   0x000020

Definition at line 89 of file typcache.c.

◆ TCFLAGS_CHECKED_HASH_EXTENDED_PROC

#define TCFLAGS_CHECKED_HASH_EXTENDED_PROC   0x000100

Definition at line 92 of file typcache.c.

◆ TCFLAGS_CHECKED_HASH_OPCLASS

#define TCFLAGS_CHECKED_HASH_OPCLASS   0x000004

Definition at line 86 of file typcache.c.

◆ TCFLAGS_CHECKED_HASH_PROC

#define TCFLAGS_CHECKED_HASH_PROC   0x000080

Definition at line 91 of file typcache.c.

◆ TCFLAGS_CHECKED_LT_OPR

#define TCFLAGS_CHECKED_LT_OPR   0x000010

Definition at line 88 of file typcache.c.

◆ TCFLAGS_DOMAIN_BASE_IS_COMPOSITE

#define TCFLAGS_DOMAIN_BASE_IS_COMPOSITE   0x100000

Definition at line 104 of file typcache.c.

◆ TCFLAGS_HAVE_ELEM_COMPARE

#define TCFLAGS_HAVE_ELEM_COMPARE   0x000800

Definition at line 95 of file typcache.c.

◆ TCFLAGS_HAVE_ELEM_EQUALITY

#define TCFLAGS_HAVE_ELEM_EQUALITY   0x000400

Definition at line 94 of file typcache.c.

◆ TCFLAGS_HAVE_ELEM_EXTENDED_HASHING

#define TCFLAGS_HAVE_ELEM_EXTENDED_HASHING   0x002000

Definition at line 97 of file typcache.c.

◆ TCFLAGS_HAVE_ELEM_HASHING

#define TCFLAGS_HAVE_ELEM_HASHING   0x001000

Definition at line 96 of file typcache.c.

◆ TCFLAGS_HAVE_FIELD_COMPARE

#define TCFLAGS_HAVE_FIELD_COMPARE   0x010000

Definition at line 100 of file typcache.c.

◆ TCFLAGS_HAVE_FIELD_EQUALITY

#define TCFLAGS_HAVE_FIELD_EQUALITY   0x008000

Definition at line 99 of file typcache.c.

◆ TCFLAGS_HAVE_FIELD_EXTENDED_HASHING

#define TCFLAGS_HAVE_FIELD_EXTENDED_HASHING   0x040000

Definition at line 102 of file typcache.c.

◆ TCFLAGS_HAVE_FIELD_HASHING

#define TCFLAGS_HAVE_FIELD_HASHING   0x020000

Definition at line 101 of file typcache.c.

◆ TCFLAGS_HAVE_PG_TYPE_DATA

#define TCFLAGS_HAVE_PG_TYPE_DATA   0x000001

Definition at line 84 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:84

Definition at line 107 of file typcache.c.

Typedef Documentation

◆ RecordCacheArrayEntry

◆ RecordCacheEntry

◆ SharedRecordTableEntry

◆ SharedRecordTableKey

◆ SharedTypmodTableEntry

◆ TypeCacheEnumData

Function Documentation

◆ array_element_has_compare()

static bool array_element_has_compare ( TypeCacheEntry typentry)
static

Definition at line 1432 of file typcache.c.

1433 {
1434  if (!(typentry->flags & TCFLAGS_CHECKED_ELEM_PROPERTIES))
1436  return (typentry->flags & TCFLAGS_HAVE_ELEM_COMPARE) != 0;
1437 }
#define TCFLAGS_HAVE_ELEM_COMPARE
Definition: typcache.c:95
static void cache_array_element_properties(TypeCacheEntry *typentry)
Definition: typcache.c:1456
#define TCFLAGS_CHECKED_ELEM_PROPERTIES
Definition: typcache.c:93

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

1425 {
1426  if (!(typentry->flags & TCFLAGS_CHECKED_ELEM_PROPERTIES))
1428  return (typentry->flags & TCFLAGS_HAVE_ELEM_EQUALITY) != 0;
1429 }
#define TCFLAGS_HAVE_ELEM_EQUALITY
Definition: typcache.c:94

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

1449 {
1450  if (!(typentry->flags & TCFLAGS_CHECKED_ELEM_PROPERTIES))
1452  return (typentry->flags & TCFLAGS_HAVE_ELEM_EXTENDED_HASHING) != 0;
1453 }
#define TCFLAGS_HAVE_ELEM_EXTENDED_HASHING
Definition: typcache.c:97

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

1441 {
1442  if (!(typentry->flags & TCFLAGS_CHECKED_ELEM_PROPERTIES))
1444  return (typentry->flags & TCFLAGS_HAVE_ELEM_HASHING) != 0;
1445 }
#define TCFLAGS_HAVE_ELEM_HASHING
Definition: typcache.c:96

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

2043 {
2044  if (type_id != RECORDOID)
2045  {
2046  /*
2047  * It's a named composite type, so use the regular typcache.
2048  */
2049  TypeCacheEntry *typentry;
2050 
2051  typentry = lookup_type_cache(type_id, TYPECACHE_TUPDESC);
2052  if (typentry->tupDesc == NULL)
2053  ereport(ERROR,
2054  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2055  errmsg("type %s is not composite",
2056  format_type_be(type_id))));
2057  Assert(typentry->tupDesc_identifier != 0);
2058  return typentry->tupDesc_identifier;
2059  }
2060  else
2061  {
2062  /*
2063  * It's a transient record type, so look in our record-type table.
2064  */
2065  if (typmod >= 0 && typmod < RecordCacheArrayLen &&
2066  RecordCacheArray[typmod].tupdesc != NULL)
2067  {
2068  Assert(RecordCacheArray[typmod].id != 0);
2069  return RecordCacheArray[typmod].id;
2070  }
2071 
2072  /* For anonymous or unrecognized record type, generate a new ID */
2073  return ++tupledesc_id_counter;
2074  }
2075 }
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#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
Assert(fmt[strlen(fmt) - 1] !='\n')
uint64 tupDesc_identifier
Definition: typcache.h:90
TupleDesc tupDesc
Definition: typcache.h:89
static RecordCacheArrayEntry * RecordCacheArray
Definition: typcache.c:283
static int32 RecordCacheArrayLen
Definition: typcache.c:284
static uint64 tupledesc_id_counter
Definition: typcache.c:292
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:344
#define TYPECACHE_TUPDESC
Definition: typcache.h:144

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

1951 {
1952  RecordCacheEntry *recentry;
1953  TupleDesc entDesc;
1954  bool found;
1955  MemoryContext oldcxt;
1956 
1957  Assert(tupDesc->tdtypeid == RECORDOID);
1958 
1959  if (RecordCacheHash == NULL)
1960  {
1961  /* First time through: initialize the hash table */
1962  HASHCTL ctl;
1963 
1964  ctl.keysize = sizeof(TupleDesc); /* just the pointer */
1965  ctl.entrysize = sizeof(RecordCacheEntry);
1968  RecordCacheHash = hash_create("Record information cache", 64,
1969  &ctl,
1971 
1972  /* Also make sure CacheMemoryContext exists */
1973  if (!CacheMemoryContext)
1975  }
1976 
1977  /*
1978  * Find a hashtable entry for this tuple descriptor. We don't use
1979  * HASH_ENTER yet, because if it's missing, we need to make sure that all
1980  * the allocations succeed before we create the new entry.
1981  */
1983  &tupDesc,
1984  HASH_FIND, &found);
1985  if (found && recentry->tupdesc != NULL)
1986  {
1987  tupDesc->tdtypmod = recentry->tupdesc->tdtypmod;
1988  return;
1989  }
1990 
1991  /* Not present, so need to manufacture an entry */
1993 
1994  /* Look in the SharedRecordTypmodRegistry, if attached */
1995  entDesc = find_or_make_matching_shared_tupledesc(tupDesc);
1996  if (entDesc == NULL)
1997  {
1998  /*
1999  * Make sure we have room before we CreateTupleDescCopy() or advance
2000  * NextRecordTypmod.
2001  */
2003 
2004  /* Reference-counted local cache only. */
2005  entDesc = CreateTupleDescCopy(tupDesc);
2006  entDesc->tdrefcount = 1;
2007  entDesc->tdtypmod = NextRecordTypmod++;
2008  }
2009  else
2010  {
2012  }
2013 
2014  RecordCacheArray[entDesc->tdtypmod].tupdesc = entDesc;
2015 
2016  /* Assign a unique tupdesc identifier, too. */
2018 
2019  /* Fully initialized; create the hash table entry */
2021  &tupDesc,
2022  HASH_ENTER, NULL);
2023  recentry->tupdesc = entDesc;
2024 
2025  /* Update the caller's tuple descriptor. */
2026  tupDesc->tdtypmod = entDesc->tdtypmod;
2027 
2028  MemoryContextSwitchTo(oldcxt);
2029 }
void CreateCacheMemoryContext(void)
Definition: catcache.c:614
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:953
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:350
@ 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:144
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:138
Size keysize
Definition: hsearch.h:75
HashValueFunc hash
Definition: hsearch.h:78
Size entrysize
Definition: hsearch.h:76
HashCompareFunc match
Definition: hsearch.h:80
TupleDesc tupdesc
Definition: typcache.c:159
int tdrefcount
Definition: tupdesc.h:84
int32 tdtypmod
Definition: tupdesc.h:83
Oid tdtypeid
Definition: tupdesc.h:82
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:111
struct TupleDescData * TupleDesc
Definition: tupdesc.h:89
static TupleDesc find_or_make_matching_shared_tupledesc(TupleDesc tupdesc)
Definition: typcache.c:2758
static int32 NextRecordTypmod
Definition: typcache.c:285
static HTAB * RecordCacheHash
Definition: typcache.c:274
struct RecordCacheEntry RecordCacheEntry
static int record_type_typmod_compare(const void *a, const void *b, size_t size)
Definition: typcache.c:1934
static void ensure_record_cache_typmod_slot_exists(int32 typmod)
Definition: typcache.c:1707
static uint32 record_type_typmod_hash(const void *data, size_t size)
Definition: typcache.c:1923

References Assert(), CacheMemoryContext, CreateCacheMemoryContext(), CreateTupleDescCopy(), ensure_record_cache_typmod_slot_exists(), HASHCTL::entrysize, find_or_make_matching_shared_tupledesc(), HASHCTL::hash, HASH_COMPARE, hash_create(), HASH_ELEM, HASH_ENTER, HASH_FIND, HASH_FUNCTION, hash_search(), RecordCacheArrayEntry::id, HASHCTL::keysize, HASHCTL::match, 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().

◆ cache_array_element_properties()

static void cache_array_element_properties ( TypeCacheEntry typentry)
static

Definition at line 1456 of file typcache.c.

1457 {
1458  Oid elem_type = get_base_element_type(typentry->type_id);
1459 
1460  if (OidIsValid(elem_type))
1461  {
1462  TypeCacheEntry *elementry;
1463 
1464  elementry = lookup_type_cache(elem_type,
1469  if (OidIsValid(elementry->eq_opr))
1470  typentry->flags |= TCFLAGS_HAVE_ELEM_EQUALITY;
1471  if (OidIsValid(elementry->cmp_proc))
1472  typentry->flags |= TCFLAGS_HAVE_ELEM_COMPARE;
1473  if (OidIsValid(elementry->hash_proc))
1474  typentry->flags |= TCFLAGS_HAVE_ELEM_HASHING;
1475  if (OidIsValid(elementry->hash_extended_proc))
1477  }
1479 }
#define OidIsValid(objectId)
Definition: c.h:764
Oid get_base_element_type(Oid typid)
Definition: lsyscache.c:2814
unsigned int Oid
Definition: postgres_ext.h:31
Oid hash_extended_proc
Definition: typcache.h:66
#define TYPECACHE_EQ_OPR
Definition: typcache.h:136
#define TYPECACHE_HASH_EXTENDED_PROC
Definition: typcache.h:150
#define TYPECACHE_CMP_PROC
Definition: typcache.h:139
#define TYPECACHE_HASH_PROC
Definition: typcache.h:140

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

1680 {
1681  /* load up range link if we didn't already */
1682  if (typentry->rngtype == NULL &&
1683  typentry->typtype == TYPTYPE_MULTIRANGE)
1684  load_multirangetype_info(typentry);
1685 
1686  if (typentry->rngtype != NULL && typentry->rngtype->rngelemtype != NULL)
1687  {
1688  TypeCacheEntry *elementry;
1689 
1690  /* might need to calculate subtype's hash function properties */
1691  elementry = lookup_type_cache(typentry->rngtype->rngelemtype->type_id,
1694  if (OidIsValid(elementry->hash_proc))
1695  typentry->flags |= TCFLAGS_HAVE_ELEM_HASHING;
1696  if (OidIsValid(elementry->hash_extended_proc))
1698  }
1700 }
struct TypeCacheEntry * rngelemtype
Definition: typcache.h:98
char typtype
Definition: typcache.h:43
struct TypeCacheEntry * rngtype
Definition: typcache.h:107
static void load_multirangetype_info(TypeCacheEntry *typentry)
Definition: typcache.c:969

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

1640 {
1641  /* load up subtype link if we didn't already */
1642  if (typentry->rngelemtype == NULL &&
1643  typentry->typtype == TYPTYPE_RANGE)
1644  load_rangetype_info(typentry);
1645 
1646  if (typentry->rngelemtype != NULL)
1647  {
1648  TypeCacheEntry *elementry;
1649 
1650  /* might need to calculate subtype's hash function properties */
1651  elementry = lookup_type_cache(typentry->rngelemtype->type_id,
1654  if (OidIsValid(elementry->hash_proc))
1655  typentry->flags |= TCFLAGS_HAVE_ELEM_HASHING;
1656  if (OidIsValid(elementry->hash_extended_proc))
1658  }
1660 }
static void load_rangetype_info(TypeCacheEntry *typentry)
Definition: typcache.c:912

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

1519 {
1520  /*
1521  * For type RECORD, we can't really tell what will work, since we don't
1522  * have access here to the specific anonymous type. Just assume that
1523  * equality and comparison will (we may get a failure at runtime). We
1524  * could also claim that hashing works, but then if code that has the
1525  * option between a comparison-based (sort-based) and a hash-based plan
1526  * chooses hashing, stuff could fail that would otherwise work if it chose
1527  * a comparison-based plan. In practice more types support comparison
1528  * than hashing.
1529  */
1530  if (typentry->type_id == RECORDOID)
1531  {
1532  typentry->flags |= (TCFLAGS_HAVE_FIELD_EQUALITY |
1534  }
1535  else if (typentry->typtype == TYPTYPE_COMPOSITE)
1536  {
1537  TupleDesc tupdesc;
1538  int newflags;
1539  int i;
1540 
1541  /* Fetch composite type's tupdesc if we don't have it already */
1542  if (typentry->tupDesc == NULL)
1543  load_typcache_tupdesc(typentry);
1544  tupdesc = typentry->tupDesc;
1545 
1546  /* Must bump the refcount while we do additional catalog lookups */
1547  IncrTupleDescRefCount(tupdesc);
1548 
1549  /* Have each property if all non-dropped fields have the property */
1550  newflags = (TCFLAGS_HAVE_FIELD_EQUALITY |
1554  for (i = 0; i < tupdesc->natts; i++)
1555  {
1556  TypeCacheEntry *fieldentry;
1557  Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
1558 
1559  if (attr->attisdropped)
1560  continue;
1561 
1562  fieldentry = lookup_type_cache(attr->atttypid,
1567  if (!OidIsValid(fieldentry->eq_opr))
1568  newflags &= ~TCFLAGS_HAVE_FIELD_EQUALITY;
1569  if (!OidIsValid(fieldentry->cmp_proc))
1570  newflags &= ~TCFLAGS_HAVE_FIELD_COMPARE;
1571  if (!OidIsValid(fieldentry->hash_proc))
1572  newflags &= ~TCFLAGS_HAVE_FIELD_HASHING;
1573  if (!OidIsValid(fieldentry->hash_extended_proc))
1575 
1576  /* We can drop out of the loop once we disprove all bits */
1577  if (newflags == 0)
1578  break;
1579  }
1580  typentry->flags |= newflags;
1581 
1582  DecrTupleDescRefCount(tupdesc);
1583  }
1584  else if (typentry->typtype == TYPTYPE_DOMAIN)
1585  {
1586  /* If it's domain over composite, copy base type's properties */
1587  TypeCacheEntry *baseentry;
1588 
1589  /* load up basetype info if we didn't already */
1590  if (typentry->domainBaseType == InvalidOid)
1591  {
1592  typentry->domainBaseTypmod = -1;
1593  typentry->domainBaseType =
1594  getBaseTypeAndTypmod(typentry->type_id,
1595  &typentry->domainBaseTypmod);
1596  }
1597  baseentry = lookup_type_cache(typentry->domainBaseType,
1602  if (baseentry->typtype == TYPTYPE_COMPOSITE)
1603  {
1605  typentry->flags |= baseentry->flags & (TCFLAGS_HAVE_FIELD_EQUALITY |
1609  }
1610  }
1612 }
int i
Definition: isn.c:73
Oid getBaseTypeAndTypmod(Oid typid, int32 *typmod)
Definition: lsyscache.c:2520
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
#define InvalidOid
Definition: postgres_ext.h:36
int32 domainBaseTypmod
Definition: typcache.h:114
Oid domainBaseType
Definition: typcache.h:113
void DecrTupleDescRefCount(TupleDesc tupdesc)
Definition: tupdesc.c:384
void IncrTupleDescRefCount(TupleDesc tupdesc)
Definition: tupdesc.c:366
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
#define TCFLAGS_CHECKED_FIELD_PROPERTIES
Definition: typcache.c:98
#define TCFLAGS_HAVE_FIELD_COMPARE
Definition: typcache.c:100
#define TCFLAGS_DOMAIN_BASE_IS_COMPOSITE
Definition: typcache.c:104
#define TCFLAGS_HAVE_FIELD_EQUALITY
Definition: typcache.c:99
#define TCFLAGS_HAVE_FIELD_EXTENDED_HASHING
Definition: typcache.c:102
#define TCFLAGS_HAVE_FIELD_HASHING
Definition: typcache.c:101
static void load_typcache_tupdesc(TypeCacheEntry *typentry)
Definition: typcache.c:878

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

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

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

1252 {
1254  DomainConstraintCache *dcc = ref->dcc;
1255 
1256  /* Paranoia --- be sure link is nulled before trying to release */
1257  if (dcc)
1258  {
1259  ref->constraints = NIL;
1260  ref->dcc = NULL;
1261  decr_dcc_refcount(dcc);
1262  }
1263 }
void * arg
#define NIL
Definition: pg_list.h:68
DomainConstraintCache * dcc
Definition: typcache.h:171
static void decr_dcc_refcount(DomainConstraintCache *dcc)
Definition: typcache.c:1240

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

1228 {
1229  const DomainConstraintState *const *ca = (const DomainConstraintState *const *) a;
1230  const DomainConstraintState *const *cb = (const DomainConstraintState *const *) b;
1231 
1232  return strcmp((*ca)->name, (*cb)->name);
1233 }
int b
Definition: isn.c:70
int a
Definition: isn.c:69

References a, and b.

Referenced by load_domaintype_info().

◆ decr_dcc_refcount()

static void decr_dcc_refcount ( DomainConstraintCache dcc)
static

Definition at line 1240 of file typcache.c.

1241 {
1242  Assert(dcc->dccRefCount > 0);
1243  if (--(dcc->dccRefCount) <= 0)
1245 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:403
MemoryContext dccContext
Definition: typcache.c:127

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

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

◆ DomainHasConstraints()

bool DomainHasConstraints ( Oid  type_id)

Definition at line 1397 of file typcache.c.

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

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

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

◆ ensure_record_cache_typmod_slot_exists()

static void ensure_record_cache_typmod_slot_exists ( int32  typmod)
static

Definition at line 1707 of file typcache.c.

1708 {
1709  if (RecordCacheArray == NULL)
1710  {
1713  64 * sizeof(RecordCacheArrayEntry));
1714  RecordCacheArrayLen = 64;
1715  }
1716 
1717  if (typmod >= RecordCacheArrayLen)
1718  {
1719  int32 newlen = pg_nextpower2_32(typmod + 1);
1720 
1724  newlen);
1725  RecordCacheArrayLen = newlen;
1726  }
1727 }
signed int int32
Definition: c.h:483
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1064
#define repalloc0_array(pointer, type, oldcount, count)
Definition: palloc.h:110
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 2445 of file typcache.c.

2446 {
2447  Oid offset;
2448 
2449  if (arg < enumdata->bitmap_base)
2450  return false;
2451  offset = arg - enumdata->bitmap_base;
2452  if (offset > (Oid) INT_MAX)
2453  return false;
2454  return bms_is_member((int) offset, enumdata->sorted_values);
2455 }
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:460
Bitmapset * sorted_values
Definition: typcache.c:141

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

2720 {
2721  const EnumItem *l = (const EnumItem *) left;
2722  const EnumItem *r = (const EnumItem *) right;
2723 
2724  if (l->enum_oid < r->enum_oid)
2725  return -1;
2726  else if (l->enum_oid > r->enum_oid)
2727  return 1;
2728  else
2729  return 0;
2730 }
Oid enum_oid
Definition: typcache.c:134

References EnumItem::enum_oid.

Referenced by find_enumitem(), and load_enum_cache_data().

◆ find_enumitem()

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

Definition at line 2702 of file typcache.c.

2703 {
2704  EnumItem srch;
2705 
2706  /* On some versions of Solaris, bsearch of zero items dumps core */
2707  if (enumdata->num_values <= 0)
2708  return NULL;
2709 
2710  srch.enum_oid = arg;
2711  return bsearch(&srch, enumdata->enum_values, enumdata->num_values,
2712  sizeof(EnumItem), enum_oid_cmp);
2713 }
EnumItem enum_values[FLEXIBLE_ARRAY_MEMBER]
Definition: typcache.c:143
static int enum_oid_cmp(const void *left, const void *right)
Definition: typcache.c:2719

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

2759 {
2760  TupleDesc result;
2762  SharedRecordTableEntry *record_table_entry;
2763  SharedTypmodTableEntry *typmod_table_entry;
2764  dsa_pointer shared_dp;
2765  bool found;
2766  uint32 typmod;
2767 
2768  /* If not even attached, nothing to do. */
2770  return NULL;
2771 
2772  /* Try to find a matching tuple descriptor in the record table. */
2773  key.shared = false;
2774  key.u.local_tupdesc = tupdesc;
2775  record_table_entry = (SharedRecordTableEntry *)
2777  if (record_table_entry)
2778  {
2779  Assert(record_table_entry->key.shared);
2781  record_table_entry);
2782  result = (TupleDesc)
2784  record_table_entry->key.u.shared_tupdesc);
2785  Assert(result->tdrefcount == -1);
2786 
2787  return result;
2788  }
2789 
2790  /* Allocate a new typmod number. This will be wasted if we error out. */
2791  typmod = (int)
2793  1);
2794 
2795  /* Copy the TupleDesc into shared memory. */
2796  shared_dp = share_tupledesc(CurrentSession->area, tupdesc, typmod);
2797 
2798  /*
2799  * Create an entry in the typmod table so that others will understand this
2800  * typmod number.
2801  */
2802  PG_TRY();
2803  {
2804  typmod_table_entry = (SharedTypmodTableEntry *)
2806  &typmod, &found);
2807  if (found)
2808  elog(ERROR, "cannot create duplicate shared record typmod");
2809  }
2810  PG_CATCH();
2811  {
2812  dsa_free(CurrentSession->area, shared_dp);
2813  PG_RE_THROW();
2814  }
2815  PG_END_TRY();
2816  typmod_table_entry->typmod = typmod;
2817  typmod_table_entry->shared_tupdesc = shared_dp;
2819  typmod_table_entry);
2820 
2821  /*
2822  * Finally create an entry in the record table so others with matching
2823  * tuple descriptors can reuse the typmod.
2824  */
2825  record_table_entry = (SharedRecordTableEntry *)
2827  &found);
2828  if (found)
2829  {
2830  /*
2831  * Someone concurrently inserted a matching tuple descriptor since the
2832  * first time we checked. Use that one instead.
2833  */
2835  record_table_entry);
2836 
2837  /* Might as well free up the space used by the one we created. */
2839  &typmod);
2840  Assert(found);
2841  dsa_free(CurrentSession->area, shared_dp);
2842 
2843  /* Return the one we found. */
2844  Assert(record_table_entry->key.shared);
2845  result = (TupleDesc)
2847  record_table_entry->key.u.shared_tupdesc);
2848  Assert(result->tdrefcount == -1);
2849 
2850  return result;
2851  }
2852 
2853  /* Store it and return it. */
2854  record_table_entry->key.shared = true;
2855  record_table_entry->key.u.shared_tupdesc = shared_dp;
2857  record_table_entry);
2858  result = (TupleDesc)
2859  dsa_get_address(CurrentSession->area, shared_dp);
2860  Assert(result->tdrefcount == -1);
2861 
2862  return result;
2863 }
static uint32 pg_atomic_fetch_add_u32(volatile pg_atomic_uint32 *ptr, int32 add_)
Definition: atomics.h:323
unsigned int uint32
Definition: c.h:495
void * dsa_get_address(dsa_area *area, dsa_pointer dp)
Definition: dsa.c:949
void dsa_free(dsa_area *area, dsa_pointer dp)
Definition: dsa.c:833
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:411
#define PG_TRY(...)
Definition: elog.h:370
#define PG_END_TRY(...)
Definition: elog.h:395
#define PG_CATCH(...)
Definition: elog.h:380
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:198
union SharedRecordTableKey::@30 u
dsa_pointer shared_tupdesc
Definition: typcache.c:187
pg_atomic_uint32 next_typmod
Definition: typcache.c:173
dsa_pointer shared_tupdesc
Definition: typcache.c:208
static dsa_pointer share_tupledesc(dsa_area *area, TupleDesc tupdesc, uint32 typmod)
Definition: typcache.c:2737

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

1312 {
1313  /* Look up the typcache entry --- we assume it survives indefinitely */
1315  ref->need_exprstate = need_exprstate;
1316  /* For safety, establish the callback before acquiring a refcount */
1317  ref->refctx = refctx;
1318  ref->dcc = NULL;
1320  ref->callback.arg = (void *) ref;
1322  /* Acquire refcount if there are constraints, and set up exported list */
1323  if (ref->tcache->domainData)
1324  {
1325  ref->dcc = ref->tcache->domainData;
1326  ref->dcc->dccRefCount++;
1327  if (ref->need_exprstate)
1329  ref->refctx);
1330  else
1331  ref->constraints = ref->dcc->constraints;
1332  }
1333  else
1334  ref->constraints = NIL;
1335 }
void MemoryContextRegisterResetCallback(MemoryContext context, MemoryContextCallback *cb)
Definition: mcxt.c:477
MemoryContext refctx
Definition: typcache.h:166
MemoryContextCallback callback
Definition: typcache.h:172
TypeCacheEntry * tcache
Definition: typcache.h:167
MemoryContextCallbackFunction func
Definition: palloc.h:49
static List * prep_domain_constraints(List *constraints, MemoryContext execctx)
Definition: typcache.c:1272
static void dccref_deletion_callback(void *arg)
Definition: typcache.c:1251

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

◆ load_domaintype_info()

static void load_domaintype_info ( TypeCacheEntry typentry)
static

Definition at line 991 of file typcache.c.

992 {
993  Oid typeOid = typentry->type_id;
995  bool notNull = false;
996  DomainConstraintState **ccons;
997  int cconslen;
998  Relation conRel;
999  MemoryContext oldcxt;
1000 
1001  /*
1002  * If we're here, any existing constraint info is stale, so release it.
1003  * For safety, be sure to null the link before trying to delete the data.
1004  */
1005  if (typentry->domainData)
1006  {
1007  dcc = typentry->domainData;
1008  typentry->domainData = NULL;
1009  decr_dcc_refcount(dcc);
1010  }
1011 
1012  /*
1013  * We try to optimize the common case of no domain constraints, so don't
1014  * create the dcc object and context until we find a constraint. Likewise
1015  * for the temp sorting array.
1016  */
1017  dcc = NULL;
1018  ccons = NULL;
1019  cconslen = 0;
1020 
1021  /*
1022  * Scan pg_constraint for relevant constraints. We want to find
1023  * constraints for not just this domain, but any ancestor domains, so the
1024  * outer loop crawls up the domain stack.
1025  */
1026  conRel = table_open(ConstraintRelationId, AccessShareLock);
1027 
1028  for (;;)
1029  {
1030  HeapTuple tup;
1031  HeapTuple conTup;
1032  Form_pg_type typTup;
1033  int nccons = 0;
1034  ScanKeyData key[1];
1035  SysScanDesc scan;
1036 
1037  tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
1038  if (!HeapTupleIsValid(tup))
1039  elog(ERROR, "cache lookup failed for type %u", typeOid);
1040  typTup = (Form_pg_type) GETSTRUCT(tup);
1041 
1042  if (typTup->typtype != TYPTYPE_DOMAIN)
1043  {
1044  /* Not a domain, so done */
1045  ReleaseSysCache(tup);
1046  break;
1047  }
1048 
1049  /* Test for NOT NULL Constraint */
1050  if (typTup->typnotnull)
1051  notNull = true;
1052 
1053  /* Look for CHECK Constraints on this domain */
1054  ScanKeyInit(&key[0],
1055  Anum_pg_constraint_contypid,
1056  BTEqualStrategyNumber, F_OIDEQ,
1057  ObjectIdGetDatum(typeOid));
1058 
1059  scan = systable_beginscan(conRel, ConstraintTypidIndexId, true,
1060  NULL, 1, key);
1061 
1062  while (HeapTupleIsValid(conTup = systable_getnext(scan)))
1063  {
1065  Datum val;
1066  bool isNull;
1067  char *constring;
1068  Expr *check_expr;
1070 
1071  /* Ignore non-CHECK constraints (presently, shouldn't be any) */
1072  if (c->contype != CONSTRAINT_CHECK)
1073  continue;
1074 
1075  /* Not expecting conbin to be NULL, but we'll test for it anyway */
1076  val = fastgetattr(conTup, Anum_pg_constraint_conbin,
1077  conRel->rd_att, &isNull);
1078  if (isNull)
1079  elog(ERROR, "domain \"%s\" constraint \"%s\" has NULL conbin",
1080  NameStr(typTup->typname), NameStr(c->conname));
1081 
1082  /* Convert conbin to C string in caller context */
1083  constring = TextDatumGetCString(val);
1084 
1085  /* Create the DomainConstraintCache object and context if needed */
1086  if (dcc == NULL)
1087  {
1088  MemoryContext cxt;
1089 
1091  "Domain constraints",
1093  dcc = (DomainConstraintCache *)
1095  dcc->constraints = NIL;
1096  dcc->dccContext = cxt;
1097  dcc->dccRefCount = 0;
1098  }
1099 
1100  /* Create node trees in DomainConstraintCache's context */
1101  oldcxt = MemoryContextSwitchTo(dcc->dccContext);
1102 
1103  check_expr = (Expr *) stringToNode(constring);
1104 
1105  /*
1106  * Plan the expression, since ExecInitExpr will expect that.
1107  *
1108  * Note: caching the result of expression_planner() is not very
1109  * good practice. Ideally we'd use a CachedExpression here so
1110  * that we would react promptly to, eg, changes in inlined
1111  * functions. However, because we don't support mutable domain
1112  * CHECK constraints, it's not really clear that it's worth the
1113  * extra overhead to do that.
1114  */
1115  check_expr = expression_planner(check_expr);
1116 
1119  r->name = pstrdup(NameStr(c->conname));
1120  r->check_expr = check_expr;
1121  r->check_exprstate = NULL;
1122 
1123  MemoryContextSwitchTo(oldcxt);
1124 
1125  /* Accumulate constraints in an array, for sorting below */
1126  if (ccons == NULL)
1127  {
1128  cconslen = 8;
1129  ccons = (DomainConstraintState **)
1130  palloc(cconslen * sizeof(DomainConstraintState *));
1131  }
1132  else if (nccons >= cconslen)
1133  {
1134  cconslen *= 2;
1135  ccons = (DomainConstraintState **)
1136  repalloc(ccons, cconslen * sizeof(DomainConstraintState *));
1137  }
1138  ccons[nccons++] = r;
1139  }
1140 
1141  systable_endscan(scan);
1142 
1143  if (nccons > 0)
1144  {
1145  /*
1146  * Sort the items for this domain, so that CHECKs are applied in a
1147  * deterministic order.
1148  */
1149  if (nccons > 1)
1150  qsort(ccons, nccons, sizeof(DomainConstraintState *), dcs_cmp);
1151 
1152  /*
1153  * Now attach them to the overall list. Use lcons() here because
1154  * constraints of parent domains should be applied earlier.
1155  */
1156  oldcxt = MemoryContextSwitchTo(dcc->dccContext);
1157  while (nccons > 0)
1158  dcc->constraints = lcons(ccons[--nccons], dcc->constraints);
1159  MemoryContextSwitchTo(oldcxt);
1160  }
1161 
1162  /* loop to next domain in stack */
1163  typeOid = typTup->typbasetype;
1164  ReleaseSysCache(tup);
1165  }
1166 
1167  table_close(conRel, AccessShareLock);
1168 
1169  /*
1170  * Only need to add one NOT NULL check regardless of how many domains in
1171  * the stack request it.
1172  */
1173  if (notNull)
1174  {
1176 
1177  /* Create the DomainConstraintCache object and context if needed */
1178  if (dcc == NULL)
1179  {
1180  MemoryContext cxt;
1181 
1183  "Domain constraints",
1185  dcc = (DomainConstraintCache *)
1187  dcc->constraints = NIL;
1188  dcc->dccContext = cxt;
1189  dcc->dccRefCount = 0;
1190  }
1191 
1192  /* Create node trees in DomainConstraintCache's context */
1193  oldcxt = MemoryContextSwitchTo(dcc->dccContext);
1194 
1196 
1198  r->name = pstrdup("NOT NULL");
1199  r->check_expr = NULL;
1200  r->check_exprstate = NULL;
1201 
1202  /* lcons to apply the nullness check FIRST */
1203  dcc->constraints = lcons(r, dcc->constraints);
1204 
1205  MemoryContextSwitchTo(oldcxt);
1206  }
1207 
1208  /*
1209  * If we made a constraint object, move it into CacheMemoryContext and
1210  * attach it to the typcache entry.
1211  */
1212  if (dcc)
1213  {
1215  typentry->domainData = dcc;
1216  dcc->dccRefCount++; /* count the typcache's reference */
1217  }
1218 
1219  /* Either way, the typcache entry's domain data is now valid. */
1221 }
#define TextDatumGetCString(d)
Definition: builtins.h:95
#define NameStr(name)
Definition: c.h:735
@ DOM_CONSTRAINT_CHECK
Definition: execnodes.h:993
@ DOM_CONSTRAINT_NOTNULL
Definition: execnodes.h:992
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:599
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:506
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:664
List * lcons(void *datum, List *list)
Definition: list.c:494
#define AccessShareLock
Definition: lockdefs.h:36
void MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
Definition: mcxt.c:546
char * pstrdup(const char *in)
Definition: mcxt.c:1644
MemoryContext CurrentMemoryContext
Definition: mcxt.c:135
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1476
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1021
void * palloc(Size size)
Definition: mcxt.c:1226
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:163
#define makeNode(_type_)
Definition: nodes.h:176
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:6489
#define qsort(a, b, c, d)
Definition: port.h:445
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:999
ExprState * check_exprstate
Definition: execnodes.h:1002
TupleDesc rd_att
Definition: rel.h:112
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:868
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:820
@ TYPEOID
Definition: syscache.h:114
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:1227
#define TCFLAGS_CHECKED_DOMAIN_CONSTRAINTS
Definition: typcache.c:103

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, TYPEOID, 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 2547 of file typcache.c.

2548 {
2549  TypeCacheEnumData *enumdata;
2550  Relation enum_rel;
2551  SysScanDesc enum_scan;
2552  HeapTuple enum_tuple;
2553  ScanKeyData skey;
2554  EnumItem *items;
2555  int numitems;
2556  int maxitems;
2557  Oid bitmap_base;
2558  Bitmapset *bitmap;
2559  MemoryContext oldcxt;
2560  int bm_size,
2561  start_pos;
2562 
2563  /* Check that this is actually an enum */
2564  if (tcache->typtype != TYPTYPE_ENUM)
2565  ereport(ERROR,
2566  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2567  errmsg("%s is not an enum",
2568  format_type_be(tcache->type_id))));
2569 
2570  /*
2571  * Read all the information for members of the enum type. We collect the
2572  * info in working memory in the caller's context, and then transfer it to
2573  * permanent memory in CacheMemoryContext. This minimizes the risk of
2574  * leaking memory from CacheMemoryContext in the event of an error partway
2575  * through.
2576  */
2577  maxitems = 64;
2578  items = (EnumItem *) palloc(sizeof(EnumItem) * maxitems);
2579  numitems = 0;
2580 
2581  /* Scan pg_enum for the members of the target enum type. */
2582  ScanKeyInit(&skey,
2583  Anum_pg_enum_enumtypid,
2584  BTEqualStrategyNumber, F_OIDEQ,
2585  ObjectIdGetDatum(tcache->type_id));
2586 
2587  enum_rel = table_open(EnumRelationId, AccessShareLock);
2588  enum_scan = systable_beginscan(enum_rel,
2589  EnumTypIdLabelIndexId,
2590  true, NULL,
2591  1, &skey);
2592 
2593  while (HeapTupleIsValid(enum_tuple = systable_getnext(enum_scan)))
2594  {
2595  Form_pg_enum en = (Form_pg_enum) GETSTRUCT(enum_tuple);
2596 
2597  if (numitems >= maxitems)
2598  {
2599  maxitems *= 2;
2600  items = (EnumItem *) repalloc(items, sizeof(EnumItem) * maxitems);
2601  }
2602  items[numitems].enum_oid = en->oid;
2603  items[numitems].sort_order = en->enumsortorder;
2604  numitems++;
2605  }
2606 
2607  systable_endscan(enum_scan);
2608  table_close(enum_rel, AccessShareLock);
2609 
2610  /* Sort the items into OID order */
2611  qsort(items, numitems, sizeof(EnumItem), enum_oid_cmp);
2612 
2613  /*
2614  * Here, we create a bitmap listing a subset of the enum's OIDs that are
2615  * known to be in order and can thus be compared with just OID comparison.
2616  *
2617  * The point of this is that the enum's initial OIDs were certainly in
2618  * order, so there is some subset that can be compared via OID comparison;
2619  * and we'd rather not do binary searches unnecessarily.
2620  *
2621  * This is somewhat heuristic, and might identify a subset of OIDs that
2622  * isn't exactly what the type started with. That's okay as long as the
2623  * subset is correctly sorted.
2624  */
2625  bitmap_base = InvalidOid;
2626  bitmap = NULL;
2627  bm_size = 1; /* only save sets of at least 2 OIDs */
2628 
2629  for (start_pos = 0; start_pos < numitems - 1; start_pos++)
2630  {
2631  /*
2632  * Identify longest sorted subsequence starting at start_pos
2633  */
2634  Bitmapset *this_bitmap = bms_make_singleton(0);
2635  int this_bm_size = 1;
2636  Oid start_oid = items[start_pos].enum_oid;
2637  float4 prev_order = items[start_pos].sort_order;
2638  int i;
2639 
2640  for (i = start_pos + 1; i < numitems; i++)
2641  {
2642  Oid offset;
2643 
2644  offset = items[i].enum_oid - start_oid;
2645  /* quit if bitmap would be too large; cutoff is arbitrary */
2646  if (offset >= 8192)
2647  break;
2648  /* include the item if it's in-order */
2649  if (items[i].sort_order > prev_order)
2650  {
2651  prev_order = items[i].sort_order;
2652  this_bitmap = bms_add_member(this_bitmap, (int) offset);
2653  this_bm_size++;
2654  }
2655  }
2656 
2657  /* Remember it if larger than previous best */
2658  if (this_bm_size > bm_size)
2659  {
2660  bms_free(bitmap);
2661  bitmap_base = start_oid;
2662  bitmap = this_bitmap;
2663  bm_size = this_bm_size;
2664  }
2665  else
2666  bms_free(this_bitmap);
2667 
2668  /*
2669  * Done if it's not possible to find a longer sequence in the rest of
2670  * the list. In typical cases this will happen on the first
2671  * iteration, which is why we create the bitmaps on the fly instead of
2672  * doing a second pass over the list.
2673  */
2674  if (bm_size >= (numitems - start_pos - 1))
2675  break;
2676  }
2677 
2678  /* OK, copy the data into CacheMemoryContext */
2680  enumdata = (TypeCacheEnumData *)
2681  palloc(offsetof(TypeCacheEnumData, enum_values) +
2682  numitems * sizeof(EnumItem));
2683  enumdata->bitmap_base = bitmap_base;
2684  enumdata->sorted_values = bms_copy(bitmap);
2685  enumdata->num_values = numitems;
2686  memcpy(enumdata->enum_values, items, numitems * sizeof(EnumItem));
2687  MemoryContextSwitchTo(oldcxt);
2688 
2689  pfree(items);
2690  bms_free(bitmap);
2691 
2692  /* And link the finished cache struct into the typcache */
2693  if (tcache->enumData != NULL)
2694  pfree(tcache->enumData);
2695  tcache->enumData = enumdata;
2696 }
void bms_free(Bitmapset *a)
Definition: bitmapset.c:194
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:171
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:753
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:80
float float4
Definition: c.h:618
void pfree(void *pointer)
Definition: mcxt.c:1456
FormData_pg_enum * Form_pg_enum
Definition: pg_enum.h:44

References AccessShareLock, TypeCacheEnumData::bitmap_base, bms_add_member(), bms_copy(), bms_free(), bms_make_singleton(), BTEqualStrategyNumber, CacheMemoryContext, EnumItem::enum_oid, enum_oid_cmp(), TypeCacheEnumData::enum_values, TypeCacheEntry::enumData, ereport, errcode(), errmsg(), ERROR, format_type_be(), GETSTRUCT, HeapTupleIsValid, i, InvalidOid, MemoryContextSwitchTo(), TypeCacheEnumData::num_values, ObjectIdGetDatum(), palloc(), pfree(), qsort, repalloc(), ScanKeyInit(), EnumItem::sort_order, 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 969 of file typcache.c.

970 {
971  Oid rangetypeOid;
972 
973  rangetypeOid = get_multirange_range(typentry->type_id);
974  if (!OidIsValid(rangetypeOid))
975  elog(ERROR, "cache lookup failed for multirange type %u",
976  typentry->type_id);
977 
978  typentry->rngtype = lookup_type_cache(rangetypeOid, TYPECACHE_RANGE_INFO);
979 }
Oid get_multirange_range(Oid multirangeOid)
Definition: lsyscache.c:3465
#define TYPECACHE_RANGE_INFO
Definition: typcache.h:147

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

913 {
914  Form_pg_range pg_range;
915  HeapTuple tup;
916  Oid subtypeOid;
917  Oid opclassOid;
918  Oid canonicalOid;
919  Oid subdiffOid;
920  Oid opfamilyOid;
921  Oid opcintype;
922  Oid cmpFnOid;
923 
924  /* get information from pg_range */
926  /* should not fail, since we already checked typtype ... */
927  if (!HeapTupleIsValid(tup))
928  elog(ERROR, "cache lookup failed for range type %u",
929  typentry->type_id);
930  pg_range = (Form_pg_range) GETSTRUCT(tup);
931 
932  subtypeOid = pg_range->rngsubtype;
933  typentry->rng_collation = pg_range->rngcollation;
934  opclassOid = pg_range->rngsubopc;
935  canonicalOid = pg_range->rngcanonical;
936  subdiffOid = pg_range->rngsubdiff;
937 
938  ReleaseSysCache(tup);
939 
940  /* get opclass properties and look up the comparison function */
941  opfamilyOid = get_opclass_family(opclassOid);
942  opcintype = get_opclass_input_type(opclassOid);
943 
944  cmpFnOid = get_opfamily_proc(opfamilyOid, opcintype, opcintype,
945  BTORDER_PROC);
946  if (!RegProcedureIsValid(cmpFnOid))
947  elog(ERROR, "missing support function %d(%u,%u) in opfamily %u",
948  BTORDER_PROC, opcintype, opcintype, opfamilyOid);
949 
950  /* set up cached fmgrinfo structs */
951  fmgr_info_cxt(cmpFnOid, &typentry->rng_cmp_proc_finfo,
953  if (OidIsValid(canonicalOid))
954  fmgr_info_cxt(canonicalOid, &typentry->rng_canonical_finfo,
956  if (OidIsValid(subdiffOid))
957  fmgr_info_cxt(subdiffOid, &typentry->rng_subdiff_finfo,
959 
960  /* Lastly, set up link to the element type --- this marks data valid */
961  typentry->rngelemtype = lookup_type_cache(subtypeOid, 0);
962 }
#define RegProcedureIsValid(p)
Definition: c.h:766
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:137
Oid get_opclass_input_type(Oid opclass)
Definition: lsyscache.c:1216
Oid get_opclass_family(Oid opclass)
Definition: lsyscache.c:1194
Oid get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum)
Definition: lsyscache.c:795
#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:100
Oid rng_collation
Definition: typcache.h:99
FmgrInfo rng_subdiff_finfo
Definition: typcache.h:102
FmgrInfo rng_canonical_finfo
Definition: typcache.h:101
@ RANGETYPE
Definition: syscache.h:87

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, RANGETYPE, RegProcedureIsValid, ReleaseSysCache(), TypeCacheEntry::rng_canonical_finfo, TypeCacheEntry::rng_cmp_proc_finfo, TypeCacheEntry::rng_collation, 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 878 of file typcache.c.

879 {
880  Relation rel;
881 
882  if (!OidIsValid(typentry->typrelid)) /* should not happen */
883  elog(ERROR, "invalid typrelid for composite type %u",
884  typentry->type_id);
885  rel = relation_open(typentry->typrelid, AccessShareLock);
886  Assert(rel->rd_rel->reltype == typentry->type_id);
887 
888  /*
889  * Link to the tupdesc and increment its refcount (we assert it's a
890  * refcounted descriptor). We don't use IncrTupleDescRefCount() for this,
891  * because the reference mustn't be entered in the current resource owner;
892  * it can outlive the current query.
893  */
894  typentry->tupDesc = RelationGetDescr(rel);
895 
896  Assert(typentry->tupDesc->tdrefcount > 0);
897  typentry->tupDesc->tdrefcount++;
898 
899  /*
900  * In future, we could take some pains to not change tupDesc_identifier if
901  * the tupdesc didn't really change; but for now it's not worth it.
902  */
904 
906 }
#define RelationGetDescr(relation)
Definition: rel.h:530
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
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 1864 of file typcache.c.

1865 {
1866  TupleDesc tmp;
1867 
1868  tmp = lookup_rowtype_tupdesc_internal(type_id, typmod, false);
1869  return CreateTupleDescCopyConstr(tmp);
1870 }
TupleDesc CreateTupleDescCopyConstr(TupleDesc tupdesc)
Definition: tupdesc.c:151

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

1887 {
1888  TupleDesc tupDesc;
1889 
1890  if (type_id != RECORDOID)
1891  {
1892  /*
1893  * Check for domain or named composite type. We might as well load
1894  * whichever data is needed.
1895  */
1896  TypeCacheEntry *typentry;
1897 
1898  typentry = lookup_type_cache(type_id,
1901  if (typentry->typtype == TYPTYPE_DOMAIN)
1903  typentry->domainBaseTypmod,
1904  noError);
1905  if (typentry->tupDesc == NULL && !noError)
1906  ereport(ERROR,
1907  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1908  errmsg("type %s is not composite",
1909  format_type_be(type_id))));
1910  tupDesc = typentry->tupDesc;
1911  }
1912  else
1913  tupDesc = lookup_rowtype_tupdesc_internal(type_id, typmod, noError);
1914  if (tupDesc != NULL)
1915  PinTupleDesc(tupDesc);
1916  return tupDesc;
1917 }
TupleDesc lookup_rowtype_tupdesc_noerror(Oid type_id, int32 typmod, bool noError)
Definition: typcache.c:1847
#define TYPECACHE_DOMAIN_BASE_INFO
Definition: typcache.h:148

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

1737 {
1738  if (type_id != RECORDOID)
1739  {
1740  /*
1741  * It's a named composite type, so use the regular typcache.
1742  */
1743  TypeCacheEntry *typentry;
1744 
1745  typentry = lookup_type_cache(type_id, TYPECACHE_TUPDESC);
1746  if (typentry->tupDesc == NULL && !noError)
1747  ereport(ERROR,
1748  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1749  errmsg("type %s is not composite",
1750  format_type_be(type_id))));
1751  return typentry->tupDesc;
1752  }
1753  else
1754  {
1755  /*
1756  * It's a transient record type, so look in our record-type table.
1757  */
1758  if (typmod >= 0)
1759  {
1760  /* It is already in our local cache? */
1761  if (typmod < RecordCacheArrayLen &&
1762  RecordCacheArray[typmod].tupdesc != NULL)
1763  return RecordCacheArray[typmod].tupdesc;
1764 
1765  /* Are we attached to a shared record typmod registry? */
1767  {
1768  SharedTypmodTableEntry *entry;
1769 
1770  /* Try to find it in the shared typmod index. */
1772  &typmod, false);
1773  if (entry != NULL)
1774  {
1775  TupleDesc tupdesc;
1776 
1777  tupdesc = (TupleDesc)
1779  entry->shared_tupdesc);
1780  Assert(typmod == tupdesc->tdtypmod);
1781 
1782  /* We may need to extend the local RecordCacheArray. */
1784 
1785  /*
1786  * Our local array can now point directly to the TupleDesc
1787  * in shared memory, which is non-reference-counted.
1788  */
1789  RecordCacheArray[typmod].tupdesc = tupdesc;
1790  Assert(tupdesc->tdrefcount == -1);
1791 
1792  /*
1793  * We don't share tupdesc identifiers across processes, so
1794  * assign one locally.
1795  */
1797 
1799  entry);
1800 
1801  return RecordCacheArray[typmod].tupdesc;
1802  }
1803  }
1804  }
1805 
1806  if (!noError)
1807  ereport(ERROR,
1808  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1809  errmsg("record type has not been registered")));
1810  return NULL;
1811  }
1812 }

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

1848 {
1849  TupleDesc tupDesc;
1850 
1851  tupDesc = lookup_rowtype_tupdesc_internal(type_id, typmod, noError);
1852  if (tupDesc != NULL)
1853  PinTupleDesc(tupDesc);
1854  return tupDesc;
1855 }

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

345 {
346  TypeCacheEntry *typentry;
347  bool found;
348 
349  if (TypeCacheHash == NULL)
350  {
351  /* First time through: initialize the hash table */
352  HASHCTL ctl;
353 
354  ctl.keysize = sizeof(Oid);
355  ctl.entrysize = sizeof(TypeCacheEntry);
356  TypeCacheHash = hash_create("Type information cache", 64,
357  &ctl, HASH_ELEM | HASH_BLOBS);
358 
359  /* Also set up callbacks for SI invalidations */
364 
365  /* Also make sure CacheMemoryContext exists */
366  if (!CacheMemoryContext)
368  }
369 
370  /* Try to look up an existing entry */
372  &type_id,
373  HASH_FIND, NULL);
374  if (typentry == NULL)
375  {
376  /*
377  * If we didn't find one, we want to make one. But first look up the
378  * pg_type row, just to make sure we don't make a cache entry for an
379  * invalid type OID. If the type OID is not valid, present a
380  * user-facing error, since some code paths such as domain_in() allow
381  * this function to be reached with a user-supplied OID.
382  */
383  HeapTuple tp;
384  Form_pg_type typtup;
385 
386  tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_id));
387  if (!HeapTupleIsValid(tp))
388  ereport(ERROR,
389  (errcode(ERRCODE_UNDEFINED_OBJECT),
390  errmsg("type with OID %u does not exist", type_id)));
391  typtup = (Form_pg_type) GETSTRUCT(tp);
392  if (!typtup->typisdefined)
393  ereport(ERROR,
394  (errcode(ERRCODE_UNDEFINED_OBJECT),
395  errmsg("type \"%s\" is only a shell",
396  NameStr(typtup->typname))));
397 
398  /* Now make the typcache entry */
400  &type_id,
401  HASH_ENTER, &found);
402  Assert(!found); /* it wasn't there a moment ago */
403 
404  MemSet(typentry, 0, sizeof(TypeCacheEntry));
405 
406  /* These fields can never change, by definition */
407  typentry->type_id = type_id;
409  ObjectIdGetDatum(type_id));
410 
411  /* Keep this part in sync with the code below */
412  typentry->typlen = typtup->typlen;
413  typentry->typbyval = typtup->typbyval;
414  typentry->typalign = typtup->typalign;
415  typentry->typstorage = typtup->typstorage;
416  typentry->typtype = typtup->typtype;
417  typentry->typrelid = typtup->typrelid;
418  typentry->typsubscript = typtup->typsubscript;
419  typentry->typelem = typtup->typelem;
420  typentry->typcollation = typtup->typcollation;
421  typentry->flags |= TCFLAGS_HAVE_PG_TYPE_DATA;
422 
423  /* If it's a domain, immediately thread it into the domain cache list */
424  if (typentry->typtype == TYPTYPE_DOMAIN)
425  {
426  typentry->nextDomain = firstDomainTypeEntry;
427  firstDomainTypeEntry = typentry;
428  }
429 
430  ReleaseSysCache(tp);
431  }
432  else if (!(typentry->flags & TCFLAGS_HAVE_PG_TYPE_DATA))
433  {
434  /*
435  * We have an entry, but its pg_type row got changed, so reload the
436  * data obtained directly from pg_type.
437  */
438  HeapTuple tp;
439  Form_pg_type typtup;
440 
441  tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_id));
442  if (!HeapTupleIsValid(tp))
443  ereport(ERROR,
444  (errcode(ERRCODE_UNDEFINED_OBJECT),
445  errmsg("type with OID %u does not exist", type_id)));
446  typtup = (Form_pg_type) GETSTRUCT(tp);
447  if (!typtup->typisdefined)
448  ereport(ERROR,
449  (errcode(ERRCODE_UNDEFINED_OBJECT),
450  errmsg("type \"%s\" is only a shell",
451  NameStr(typtup->typname))));
452 
453  /*
454  * Keep this part in sync with the code above. Many of these fields
455  * shouldn't ever change, particularly typtype, but copy 'em anyway.
456  */
457  typentry->typlen = typtup->typlen;
458  typentry->typbyval = typtup->typbyval;
459  typentry->typalign = typtup->typalign;
460  typentry->typstorage = typtup->typstorage;
461  typentry->typtype = typtup->typtype;
462  typentry->typrelid = typtup->typrelid;
463  typentry->typsubscript = typtup->typsubscript;
464  typentry->typelem = typtup->typelem;
465  typentry->typcollation = typtup->typcollation;
466  typentry->flags |= TCFLAGS_HAVE_PG_TYPE_DATA;
467 
468  ReleaseSysCache(tp);
469  }
470 
471  /*
472  * Look up opclasses if we haven't already and any dependent info is
473  * requested.
474  */
479  !(typentry->flags & TCFLAGS_CHECKED_BTREE_OPCLASS))
480  {
481  Oid opclass;
482 
483  opclass = GetDefaultOpClass(type_id, BTREE_AM_OID);
484  if (OidIsValid(opclass))
485  {
486  typentry->btree_opf = get_opclass_family(opclass);
487  typentry->btree_opintype = get_opclass_input_type(opclass);
488  }
489  else
490  {
491  typentry->btree_opf = typentry->btree_opintype = InvalidOid;
492  }
493 
494  /*
495  * Reset information derived from btree opclass. Note in particular
496  * that we'll redetermine the eq_opr even if we previously found one;
497  * this matters in case a btree opclass has been added to a type that
498  * previously had only a hash opclass.
499  */
500  typentry->flags &= ~(TCFLAGS_CHECKED_EQ_OPR |
505  }
506 
507  /*
508  * If we need to look up equality operator, and there's no btree opclass,
509  * force lookup of hash opclass.
510  */
511  if ((flags & (TYPECACHE_EQ_OPR | TYPECACHE_EQ_OPR_FINFO)) &&
512  !(typentry->flags & TCFLAGS_CHECKED_EQ_OPR) &&
513  typentry->btree_opf == InvalidOid)
514  flags |= TYPECACHE_HASH_OPFAMILY;
515 
520  !(typentry->flags & TCFLAGS_CHECKED_HASH_OPCLASS))
521  {
522  Oid opclass;
523 
524  opclass = GetDefaultOpClass(type_id, HASH_AM_OID);
525  if (OidIsValid(opclass))
526  {
527  typentry->hash_opf = get_opclass_family(opclass);
528  typentry->hash_opintype = get_opclass_input_type(opclass);
529  }
530  else
531  {
532  typentry->hash_opf = typentry->hash_opintype = InvalidOid;
533  }
534 
535  /*
536  * Reset information derived from hash opclass. We do *not* reset the
537  * eq_opr; if we already found one from the btree opclass, that
538  * decision is still good.
539  */
540  typentry->flags &= ~(TCFLAGS_CHECKED_HASH_PROC |
542  typentry->flags |= TCFLAGS_CHECKED_HASH_OPCLASS;
543  }
544 
545  /*
546  * Look for requested operators and functions, if we haven't already.
547  */
548  if ((flags & (TYPECACHE_EQ_OPR | TYPECACHE_EQ_OPR_FINFO)) &&
549  !(typentry->flags & TCFLAGS_CHECKED_EQ_OPR))
550  {
551  Oid eq_opr = InvalidOid;
552 
553  if (typentry->btree_opf != InvalidOid)
554  eq_opr = get_opfamily_member(typentry->btree_opf,
555  typentry->btree_opintype,
556  typentry->btree_opintype,
558  if (eq_opr == InvalidOid &&
559  typentry->hash_opf != InvalidOid)
560  eq_opr = get_opfamily_member(typentry->hash_opf,
561  typentry->hash_opintype,
562  typentry->hash_opintype,
564 
565  /*
566  * If the proposed equality operator is array_eq or record_eq, check
567  * to see if the element type or column types support equality. If
568  * not, array_eq or record_eq would fail at runtime, so we don't want
569  * to report that the type has equality. (We can omit similar
570  * checking for ranges and multiranges because ranges can't be created
571  * in the first place unless their subtypes support equality.)
572  */
573  if (eq_opr == ARRAY_EQ_OP &&
574  !array_element_has_equality(typentry))
575  eq_opr = InvalidOid;
576  else if (eq_opr == RECORD_EQ_OP &&
577  !record_fields_have_equality(typentry))
578  eq_opr = InvalidOid;
579 
580  /* Force update of eq_opr_finfo only if we're changing state */
581  if (typentry->eq_opr != eq_opr)
582  typentry->eq_opr_finfo.fn_oid = InvalidOid;
583 
584  typentry->eq_opr = eq_opr;
585 
586  /*
587  * Reset info about hash functions whenever we pick up new info about
588  * equality operator. This is so we can ensure that the hash
589  * functions match the operator.
590  */
591  typentry->flags &= ~(TCFLAGS_CHECKED_HASH_PROC |
593  typentry->flags |= TCFLAGS_CHECKED_EQ_OPR;
594  }
595  if ((flags & TYPECACHE_LT_OPR) &&
596  !(typentry->flags & TCFLAGS_CHECKED_LT_OPR))
597  {
598  Oid lt_opr = InvalidOid;
599 
600  if (typentry->btree_opf != InvalidOid)
601  lt_opr = get_opfamily_member(typentry->btree_opf,
602  typentry->btree_opintype,
603  typentry->btree_opintype,
605 
606  /*
607  * As above, make sure array_cmp or record_cmp will succeed; but again
608  * we need no special check for ranges or multiranges.
609  */
610  if (lt_opr == ARRAY_LT_OP &&
611  !array_element_has_compare(typentry))
612  lt_opr = InvalidOid;
613  else if (lt_opr == RECORD_LT_OP &&
614  !record_fields_have_compare(typentry))
615  lt_opr = InvalidOid;
616 
617  typentry->lt_opr = lt_opr;
618  typentry->flags |= TCFLAGS_CHECKED_LT_OPR;
619  }
620  if ((flags & TYPECACHE_GT_OPR) &&
621  !(typentry->flags & TCFLAGS_CHECKED_GT_OPR))
622  {
623  Oid gt_opr = InvalidOid;
624 
625  if (typentry->btree_opf != InvalidOid)
626  gt_opr = get_opfamily_member(typentry->btree_opf,
627  typentry->btree_opintype,
628  typentry->btree_opintype,
630 
631  /*
632  * As above, make sure array_cmp or record_cmp will succeed; but again
633  * we need no special check for ranges or multiranges.
634  */
635  if (gt_opr == ARRAY_GT_OP &&
636  !array_element_has_compare(typentry))
637  gt_opr = InvalidOid;
638  else if (gt_opr == RECORD_GT_OP &&
639  !record_fields_have_compare(typentry))
640  gt_opr = InvalidOid;
641 
642  typentry->gt_opr = gt_opr;
643  typentry->flags |= TCFLAGS_CHECKED_GT_OPR;
644  }
645  if ((flags & (TYPECACHE_CMP_PROC | TYPECACHE_CMP_PROC_FINFO)) &&
646  !(typentry->flags & TCFLAGS_CHECKED_CMP_PROC))
647  {
648  Oid cmp_proc = InvalidOid;
649 
650  if (typentry->btree_opf != InvalidOid)
651  cmp_proc = get_opfamily_proc(typentry->btree_opf,
652  typentry->btree_opintype,
653  typentry->btree_opintype,
654  BTORDER_PROC);
655 
656  /*
657  * As above, make sure array_cmp or record_cmp will succeed; but again
658  * we need no special check for ranges or multiranges.
659  */
660  if (cmp_proc == F_BTARRAYCMP &&
661  !array_element_has_compare(typentry))
662  cmp_proc = InvalidOid;
663  else if (cmp_proc == F_BTRECORDCMP &&
664  !record_fields_have_compare(typentry))
665  cmp_proc = InvalidOid;
666 
667  /* Force update of cmp_proc_finfo only if we're changing state */
668  if (typentry->cmp_proc != cmp_proc)
669  typentry->cmp_proc_finfo.fn_oid = InvalidOid;
670 
671  typentry->cmp_proc = cmp_proc;
672  typentry->flags |= TCFLAGS_CHECKED_CMP_PROC;
673  }
675  !(typentry->flags & TCFLAGS_CHECKED_HASH_PROC))
676  {
677  Oid hash_proc = InvalidOid;
678 
679  /*
680  * We insist that the eq_opr, if one has been determined, match the
681  * hash opclass; else report there is no hash function.
682  */
683  if (typentry->hash_opf != InvalidOid &&
684  (!OidIsValid(typentry->eq_opr) ||
685  typentry->eq_opr == get_opfamily_member(typentry->hash_opf,
686  typentry->hash_opintype,
687  typentry->hash_opintype,
689  hash_proc = get_opfamily_proc(typentry->hash_opf,
690  typentry->hash_opintype,
691  typentry->hash_opintype,
693 
694  /*
695  * As above, make sure hash_array, hash_record, or hash_range will
696  * succeed.
697  */
698  if (hash_proc == F_HASH_ARRAY &&
699  !array_element_has_hashing(typentry))
700  hash_proc = InvalidOid;
701  else if (hash_proc == F_HASH_RECORD &&
702  !record_fields_have_hashing(typentry))
703  hash_proc = InvalidOid;
704  else if (hash_proc == F_HASH_RANGE &&
705  !range_element_has_hashing(typentry))
706  hash_proc = InvalidOid;
707 
708  /*
709  * Likewise for hash_multirange.
710  */
711  if (hash_proc == F_HASH_MULTIRANGE &&
713  hash_proc = InvalidOid;
714 
715  /* Force update of hash_proc_finfo only if we're changing state */
716  if (typentry->hash_proc != hash_proc)
717  typentry->hash_proc_finfo.fn_oid = InvalidOid;
718 
719  typentry->hash_proc = hash_proc;
720  typentry->flags |= TCFLAGS_CHECKED_HASH_PROC;
721  }
722  if ((flags & (TYPECACHE_HASH_EXTENDED_PROC |
725  {
726  Oid hash_extended_proc = InvalidOid;
727 
728  /*
729  * We insist that the eq_opr, if one has been determined, match the
730  * hash opclass; else report there is no hash function.
731  */
732  if (typentry->hash_opf != InvalidOid &&
733  (!OidIsValid(typentry->eq_opr) ||
734  typentry->eq_opr == get_opfamily_member(typentry->hash_opf,
735  typentry->hash_opintype,
736  typentry->hash_opintype,
738  hash_extended_proc = get_opfamily_proc(typentry->hash_opf,
739  typentry->hash_opintype,
740  typentry->hash_opintype,
742 
743  /*
744  * As above, make sure hash_array_extended, hash_record_extended, or
745  * hash_range_extended will succeed.
746  */
747  if (hash_extended_proc == F_HASH_ARRAY_EXTENDED &&
749  hash_extended_proc = InvalidOid;
750  else if (hash_extended_proc == F_HASH_RECORD_EXTENDED &&
752  hash_extended_proc = InvalidOid;
753  else if (hash_extended_proc == F_HASH_RANGE_EXTENDED &&
755  hash_extended_proc = InvalidOid;
756 
757  /*
758  * Likewise for hash_multirange_extended.
759  */
760  if (hash_extended_proc == F_HASH_MULTIRANGE_EXTENDED &&
762  hash_extended_proc = InvalidOid;
763 
764  /* Force update of proc finfo only if we're changing state */
765  if (typentry->hash_extended_proc != hash_extended_proc)
767 
768  typentry->hash_extended_proc = hash_extended_proc;
770  }
771 
772  /*
773  * Set up fmgr lookup info as requested
774  *
775  * Note: we tell fmgr the finfo structures live in CacheMemoryContext,
776  * which is not quite right (they're really in the hash table's private
777  * memory context) but this will do for our purposes.
778  *
779  * Note: the code above avoids invalidating the finfo structs unless the
780  * referenced operator/function OID actually changes. This is to prevent
781  * unnecessary leakage of any subsidiary data attached to an finfo, since
782  * that would cause session-lifespan memory leaks.
783  */
784  if ((flags & TYPECACHE_EQ_OPR_FINFO) &&
785  typentry->eq_opr_finfo.fn_oid == InvalidOid &&
786  typentry->eq_opr != InvalidOid)
787  {
788  Oid eq_opr_func;
789 
790  eq_opr_func = get_opcode(typentry->eq_opr);
791  if (eq_opr_func != InvalidOid)
792  fmgr_info_cxt(eq_opr_func, &typentry->eq_opr_finfo,
794  }
795  if ((flags & TYPECACHE_CMP_PROC_FINFO) &&
796  typentry->cmp_proc_finfo.fn_oid == InvalidOid &&
797  typentry->cmp_proc != InvalidOid)
798  {
799  fmgr_info_cxt(typentry->cmp_proc, &typentry->cmp_proc_finfo,
801  }
802  if ((flags & TYPECACHE_HASH_PROC_FINFO) &&
803  typentry->hash_proc_finfo.fn_oid == InvalidOid &&
804  typentry->hash_proc != InvalidOid)
805  {
806  fmgr_info_cxt(typentry->hash_proc, &typentry->hash_proc_finfo,
808  }
809  if ((flags & TYPECACHE_HASH_EXTENDED_PROC_FINFO) &&
811  typentry->hash_extended_proc != InvalidOid)
812  {
814  &typentry->hash_extended_proc_finfo,
816  }
817 
818  /*
819  * If it's a composite type (row type), get tupdesc if requested
820  */
821  if ((flags & TYPECACHE_TUPDESC) &&
822  typentry->tupDesc == NULL &&
823  typentry->typtype == TYPTYPE_COMPOSITE)
824  {
825  load_typcache_tupdesc(typentry);
826  }
827 
828  /*
829  * If requested, get information about a range type
830  *
831  * This includes making sure that the basic info about the range element
832  * type is up-to-date.
833  */
834  if ((flags & TYPECACHE_RANGE_INFO) &&
835  typentry->typtype == TYPTYPE_RANGE)
836  {
837  if (typentry->rngelemtype == NULL)
838  load_rangetype_info(typentry);
839  else if (!(typentry->rngelemtype->flags & TCFLAGS_HAVE_PG_TYPE_DATA))
840  (void) lookup_type_cache(typentry->rngelemtype->type_id, 0);
841  }
842 
843  /*
844  * If requested, get information about a multirange type
845  */
846  if ((flags & TYPECACHE_MULTIRANGE_INFO) &&
847  typentry->rngtype == NULL &&
848  typentry->typtype == TYPTYPE_MULTIRANGE)
849  {
850  load_multirangetype_info(typentry);
851  }
852 
853  /*
854  * If requested, get information about a domain type
855  */
856  if ((flags & TYPECACHE_DOMAIN_BASE_INFO) &&
857  typentry->domainBaseType == InvalidOid &&
858  typentry->typtype == TYPTYPE_DOMAIN)
859  {
860  typentry->domainBaseTypmod = -1;
861  typentry->domainBaseType =
862  getBaseTypeAndTypmod(type_id, &typentry->domainBaseTypmod);
863  }
864  if ((flags & TYPECACHE_DOMAIN_CONSTR_INFO) &&
865  (typentry->flags & TCFLAGS_CHECKED_DOMAIN_CONSTRAINTS) == 0 &&
866  typentry->typtype == TYPTYPE_DOMAIN)
867  {
868  load_domaintype_info(typentry);
869  }
870 
871  return typentry;
872 }
#define MemSet(start, val, len)
Definition: c.h:1009
#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:2310
void CacheRegisterRelcacheCallback(RelcacheCallbackFunction func, Datum arg)
Definition: inval.c:1561
void CacheRegisterSyscacheCallback(int cacheid, SyscacheCallbackFunction func, Datum arg)
Definition: inval.c:1519
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1289
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:165
#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:132
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
@ CLAOID
Definition: syscache.h:48
@ CONSTROID
Definition: syscache.h:53
#define GetSysCacheHashValue1(cacheId, key1)
Definition: syscache.h:209
#define TCFLAGS_CHECKED_BTREE_OPCLASS
Definition: typcache.c:85
#define TCFLAGS_CHECKED_HASH_OPCLASS
Definition: typcache.c:86
static bool range_element_has_hashing(TypeCacheEntry *typentry)
Definition: typcache.c:1623
static bool record_fields_have_hashing(TypeCacheEntry *typentry)
Definition: typcache.c:1502
static bool record_fields_have_extended_hashing(TypeCacheEntry *typentry)
Definition: typcache.c:1510
#define TCFLAGS_CHECKED_GT_OPR
Definition: typcache.c:89
static bool multirange_element_has_hashing(TypeCacheEntry *typentry)
Definition: typcache.c:1663
static bool record_fields_have_equality(TypeCacheEntry *typentry)
Definition: typcache.c:1486
#define TCFLAGS_CHECKED_LT_OPR
Definition: typcache.c:88
#define TCFLAGS_CHECKED_HASH_PROC
Definition: typcache.c:91
static bool array_element_has_extended_hashing(TypeCacheEntry *typentry)
Definition: typcache.c:1448
static bool array_element_has_hashing(TypeCacheEntry *typentry)
Definition: typcache.c:1440
#define TCFLAGS_CHECKED_CMP_PROC
Definition: typcache.c:90
static bool multirange_element_has_extended_hashing(TypeCacheEntry *typentry)
Definition: typcache.c:1671
static bool array_element_has_equality(TypeCacheEntry *typentry)
Definition: typcache.c:1424
static bool range_element_has_extended_hashing(TypeCacheEntry *typentry)
Definition: typcache.c:1631
static TypeCacheEntry * firstDomainTypeEntry
Definition: typcache.c:81
#define TCFLAGS_CHECKED_HASH_EXTENDED_PROC
Definition: typcache.c:92
static void TypeCacheTypCallback(Datum arg, int cacheid, uint32 hashvalue)
Definition: typcache.c:2352
static void TypeCacheConstrCallback(Datum arg, int cacheid, uint32 hashvalue)
Definition: typcache.c:2421
static void TypeCacheOpcCallback(Datum arg, int cacheid, uint32 hashvalue)
Definition: typcache.c:2392
static void load_domaintype_info(TypeCacheEntry *typentry)
Definition: typcache.c:991
static void TypeCacheRelCallback(Datum arg, Oid relid)
Definition: typcache.c:2287
static bool array_element_has_compare(TypeCacheEntry *typentry)
Definition: typcache.c:1432
static HTAB * TypeCacheHash
Definition: typcache.c:78
static bool record_fields_have_compare(TypeCacheEntry *typentry)
Definition: typcache.c:1494
#define TCFLAGS_CHECKED_EQ_OPR
Definition: typcache.c:87
#define TYPECACHE_HASH_PROC_FINFO
Definition: typcache.h:143
#define TYPECACHE_HASH_OPFAMILY
Definition: typcache.h:146
#define TYPECACHE_MULTIRANGE_INFO
Definition: typcache.h:152
#define TYPECACHE_EQ_OPR_FINFO
Definition: typcache.h:141
#define TYPECACHE_BTREE_OPFAMILY
Definition: typcache.h:145
#define TYPECACHE_GT_OPR
Definition: typcache.h:138
struct TypeCacheEntry TypeCacheEntry
#define TYPECACHE_LT_OPR
Definition: typcache.h:137
#define TYPECACHE_HASH_EXTENDED_PROC_FINFO
Definition: typcache.h:151
#define TYPECACHE_CMP_PROC_FINFO
Definition: typcache.h:142

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

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

◆ multirange_element_has_extended_hashing()

static bool multirange_element_has_extended_hashing ( TypeCacheEntry typentry)
static

Definition at line 1671 of file typcache.c.

1672 {
1673  if (!(typentry->flags & TCFLAGS_CHECKED_ELEM_PROPERTIES))
1675  return (typentry->flags & TCFLAGS_HAVE_ELEM_EXTENDED_HASHING) != 0;
1676 }
static void cache_multirange_element_properties(TypeCacheEntry *typentry)
Definition: typcache.c:1679

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

1664 {
1665  if (!(typentry->flags & TCFLAGS_CHECKED_ELEM_PROPERTIES))
1667  return (typentry->flags & TCFLAGS_HAVE_ELEM_HASHING) != 0;
1668 }

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

1273 {
1274  List *result = NIL;
1275  MemoryContext oldcxt;
1276  ListCell *lc;
1277 
1278  oldcxt = MemoryContextSwitchTo(execctx);
1279 
1280  foreach(lc, constraints)
1281  {
1283  DomainConstraintState *newr;
1284 
1286  newr->constrainttype = r->constrainttype;
1287  newr->name = r->name;
1288  newr->check_expr = r->check_expr;
1289  newr->check_exprstate = ExecInitExpr(r->check_expr, NULL);
1290 
1291  result = lappend(result, newr);
1292  }
1293 
1294  MemoryContextSwitchTo(oldcxt);
1295 
1296  return result;
1297 }
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:128
List * lappend(List *list, void *datum)
Definition: list.c:338
#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 1631 of file typcache.c.

1632 {
1633  if (!(typentry->flags & TCFLAGS_CHECKED_ELEM_PROPERTIES))
1635  return (typentry->flags & TCFLAGS_HAVE_ELEM_EXTENDED_HASHING) != 0;
1636 }
static void cache_range_element_properties(TypeCacheEntry *typentry)
Definition: typcache.c:1639

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

1624 {
1625  if (!(typentry->flags & TCFLAGS_CHECKED_ELEM_PROPERTIES))
1627  return (typentry->flags & TCFLAGS_HAVE_ELEM_HASHING) != 0;
1628 }

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

1495 {
1496  if (!(typentry->flags & TCFLAGS_CHECKED_FIELD_PROPERTIES))
1498  return (typentry->flags & TCFLAGS_HAVE_FIELD_COMPARE) != 0;
1499 }
static void cache_record_field_properties(TypeCacheEntry *typentry)
Definition: typcache.c:1518

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

1487 {
1488  if (!(typentry->flags & TCFLAGS_CHECKED_FIELD_PROPERTIES))
1490  return (typentry->flags & TCFLAGS_HAVE_FIELD_EQUALITY) != 0;
1491 }

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

1503 {
1504  if (!(typentry->flags & TCFLAGS_CHECKED_FIELD_PROPERTIES))
1506  return (typentry->flags & TCFLAGS_HAVE_FIELD_HASHING) != 0;
1507 }

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

1935 {
1936  RecordCacheEntry *left = (RecordCacheEntry *) a;
1937  RecordCacheEntry *right = (RecordCacheEntry *) b;
1938 
1939  return equalTupleDescs(left->tupdesc, right->tupdesc) ? 0 : 1;
1940 }
bool equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
Definition: tupdesc.c:402

References a, b, equalTupleDescs(), 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 1923 of file typcache.c.

1924 {
1925  RecordCacheEntry *entry = (RecordCacheEntry *) data;
1926 
1927  return hashTupleDesc(entry->tupdesc);
1928 }
const void * data
uint32 hashTupleDesc(TupleDesc desc)
Definition: tupdesc.c:554

References data, hashTupleDesc(), 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 2737 of file typcache.c.

2738 {
2739  dsa_pointer shared_dp;
2740  TupleDesc shared;
2741 
2742  shared_dp = dsa_allocate(area, TupleDescSize(tupdesc));
2743  shared = (TupleDesc) dsa_get_address(area, shared_dp);
2744  TupleDescCopy(shared, tupdesc);
2745  shared->tdtypmod = typmod;
2746 
2747  return shared_dp;
2748 }
#define dsa_allocate(area, size)
Definition: dsa.h:84
void TupleDescCopy(TupleDesc dst, TupleDesc src)
Definition: tupdesc.c:229
#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 215 of file typcache.c.

217 {
218  dsa_area *area = (dsa_area *) arg;
221  TupleDesc t1;
222  TupleDesc t2;
223 
224  if (k1->shared)
225  t1 = (TupleDesc) dsa_get_address(area, k1->u.shared_tupdesc);
226  else
227  t1 = k1->u.local_tupdesc;
228 
229  if (k2->shared)
230  t2 = (TupleDesc) dsa_get_address(area, k2->u.shared_tupdesc);
231  else
232  t2 = k2->u.local_tupdesc;
233 
234  return equalTupleDescs(t1, t2) ? 0 : 1;
235 }
TupleDesc local_tupdesc
Definition: typcache.c:186
Definition: dsa.c:367

References a, arg, b, dsa_get_address(), equalTupleDescs(), 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 241 of file typcache.c.

242 {
243  dsa_area *area = (dsa_area *) arg;
245  TupleDesc t;
246 
247  if (k->shared)
248  t = (TupleDesc) dsa_get_address(area, k->u.shared_tupdesc);
249  else
250  t = k->u.local_tupdesc;
251 
252  return hashTupleDesc(t);
253 }

References a, arg, dsa_get_address(), hashTupleDesc(), 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 2870 of file typcache.c.

2871 {
2872  /* Be cautious here: maybe we didn't finish initializing. */
2873  if (CurrentSession->shared_record_table != NULL)
2874  {
2877  }
2878  if (CurrentSession->shared_typmod_table != NULL)
2879  {
2882  }
2884 }
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 2204 of file typcache.c.

2205 {
2206  MemoryContext old_context;
2207  dshash_table *record_table;
2208  dshash_table *typmod_table;
2209 
2211 
2212  /* We can't already be attached to a shared registry. */
2213  Assert(CurrentSession != NULL);
2214  Assert(CurrentSession->segment != NULL);
2215  Assert(CurrentSession->area != NULL);
2219 
2220  /*
2221  * We can't already have typmods in our local cache, because they'd clash
2222  * with those imported by SharedRecordTypmodRegistryInit. This should be
2223  * a freshly started parallel worker. If we ever support worker
2224  * recycling, a worker would need to zap its local cache in between
2225  * servicing different queries, in order to be able to call this and
2226  * synchronize typmods with a new leader; but that's problematic because
2227  * we can't be very sure that record-typmod-related state hasn't escaped
2228  * to anywhere else in the process.
2229  */
2230  Assert(NextRecordTypmod == 0);
2231 
2232  old_context = MemoryContextSwitchTo(TopMemoryContext);
2233 
2234  /* Attach to the two hash tables. */
2235  record_table = dshash_attach(CurrentSession->area,
2237  registry->record_table_handle,
2238  CurrentSession->area);
2239  typmod_table = dshash_attach(CurrentSession->area,
2241  registry->typmod_table_handle,
2242  NULL);
2243 
2244  MemoryContextSwitchTo(old_context);
2245 
2246  /*
2247  * Set up detach hook to run at worker exit. Currently this is the same
2248  * as the leader's detach hook, but in future they might need to be
2249  * different.
2250  */
2253  PointerGetDatum(registry));
2254 
2255  /*
2256  * Set up the session state that will tell assign_record_type_typmod and
2257  * lookup_rowtype_tupdesc_internal about the shared registry.
2258  */
2260  CurrentSession->shared_record_table = record_table;
2261  CurrentSession->shared_typmod_table = typmod_table;
2262 }
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:1103
#define IsParallelWorker()
Definition: parallel.h:61
MemoryContext TopMemoryContext
Definition: mcxt.c:141
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:171
dshash_table_handle record_table_handle
Definition: typcache.c:169
static const dshash_parameters srtr_typmod_table_params
Definition: typcache.c:265
static void shared_record_typmod_registry_detach(dsm_segment *segment, Datum datum)
Definition: typcache.c:2870
static const dshash_parameters srtr_record_table_params
Definition: typcache.c:256

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

Referenced by AttachSession().

◆ SharedRecordTypmodRegistryEstimate()

size_t SharedRecordTypmodRegistryEstimate ( void  )

Definition at line 2083 of file typcache.c.

2084 {
2085  return sizeof(SharedRecordTypmodRegistry);
2086 }
struct SharedRecordTypmodRegistry SharedRecordTypmodRegistry
Definition: typcache.h:175

Referenced by GetSessionDsmHandle().

◆ SharedRecordTypmodRegistryInit()

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

Definition at line 2105 of file typcache.c.

2108 {
2109  MemoryContext old_context;
2110  dshash_table *record_table;
2111  dshash_table *typmod_table;
2112  int32 typmod;
2113 
2115 
2116  /* We can't already be attached to a shared registry. */
2120 
2121  old_context = MemoryContextSwitchTo(TopMemoryContext);
2122 
2123  /* Create the hash table of tuple descriptors indexed by themselves. */
2124  record_table = dshash_create(area, &srtr_record_table_params, area);
2125 
2126  /* Create the hash table of tuple descriptors indexed by typmod. */
2127  typmod_table = dshash_create(area, &srtr_typmod_table_params, NULL);
2128 
2129  MemoryContextSwitchTo(old_context);
2130 
2131  /* Initialize the SharedRecordTypmodRegistry. */
2132  registry->record_table_handle = dshash_get_hash_table_handle(record_table);
2133  registry->typmod_table_handle = dshash_get_hash_table_handle(typmod_table);
2135 
2136  /*
2137  * Copy all entries from this backend's private registry into the shared
2138  * registry.
2139  */
2140  for (typmod = 0; typmod < NextRecordTypmod; ++typmod)
2141  {
2142  SharedTypmodTableEntry *typmod_table_entry;
2143  SharedRecordTableEntry *record_table_entry;
2144  SharedRecordTableKey record_table_key;
2145  dsa_pointer shared_dp;
2146  TupleDesc tupdesc;
2147  bool found;
2148 
2149  tupdesc = RecordCacheArray[typmod].tupdesc;
2150  if (tupdesc == NULL)
2151  continue;
2152 
2153  /* Copy the TupleDesc into shared memory. */
2154  shared_dp = share_tupledesc(area, tupdesc, typmod);
2155 
2156  /* Insert into the typmod table. */
2157  typmod_table_entry = dshash_find_or_insert(typmod_table,
2158  &tupdesc->tdtypmod,
2159  &found);
2160  if (found)
2161  elog(ERROR, "cannot create duplicate shared record typmod");
2162  typmod_table_entry->typmod = tupdesc->tdtypmod;
2163  typmod_table_entry->shared_tupdesc = shared_dp;
2164  dshash_release_lock(typmod_table, typmod_table_entry);
2165 
2166  /* Insert into the record table. */
2167  record_table_key.shared = false;
2168  record_table_key.u.local_tupdesc = tupdesc;
2169  record_table_entry = dshash_find_or_insert(record_table,
2170  &record_table_key,
2171  &found);
2172  if (!found)
2173  {
2174  record_table_entry->key.shared = true;
2175  record_table_entry->key.u.shared_tupdesc = shared_dp;
2176  }
2177  dshash_release_lock(record_table, record_table_entry);
2178  }
2179 
2180  /*
2181  * Set up the global state that will tell assign_record_type_typmod and
2182  * lookup_rowtype_tupdesc_internal about the shared registry.
2183  */
2184  CurrentSession->shared_record_table = record_table;
2185  CurrentSession->shared_typmod_table = typmod_table;
2187 
2188  /*
2189  * We install a detach hook in the leader, but only to handle cleanup on
2190  * failure during GetSessionDsmHandle(). Once GetSessionDsmHandle() pins
2191  * the memory, the leader process will use a shared registry until it
2192  * exits.
2193  */
2195 }
static void pg_atomic_init_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
Definition: atomics.h:218
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().

◆ TypeCacheConstrCallback()

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

Definition at line 2421 of file typcache.c.

2422 {
2423  TypeCacheEntry *typentry;
2424 
2425  /*
2426  * Because this is called very frequently, and typically very few of the
2427  * typcache entries are for domains, we don't use hash_seq_search here.
2428  * Instead we thread all the domain-type entries together so that we can
2429  * visit them cheaply.
2430  */
2431  for (typentry = firstDomainTypeEntry;
2432  typentry != NULL;
2433  typentry = typentry->nextDomain)
2434  {
2435  /* Reset domain constraint validity information */
2437  }
2438 }

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

2393 {
2394  HASH_SEQ_STATUS status;
2395  TypeCacheEntry *typentry;
2396 
2397  /* TypeCacheHash must exist, else this callback wouldn't be registered */
2398  hash_seq_init(&status, TypeCacheHash);
2399  while ((typentry = (TypeCacheEntry *) hash_seq_search(&status)) != NULL)
2400  {
2401  /* Reset equality/comparison/hashing validity information */
2402  typentry->flags &= ~TCFLAGS_OPERATOR_FLAGS;
2403  }
2404 }
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1431
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1421
#define TCFLAGS_OPERATOR_FLAGS
Definition: typcache.c:107

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

2288 {
2289  HASH_SEQ_STATUS status;
2290  TypeCacheEntry *typentry;
2291 
2292  /* TypeCacheHash must exist, else this callback wouldn't be registered */
2293  hash_seq_init(&status, TypeCacheHash);
2294  while ((typentry = (TypeCacheEntry *) hash_seq_search(&status)) != NULL)
2295  {
2296  if (typentry->typtype == TYPTYPE_COMPOSITE)
2297  {
2298  /* Skip if no match, unless we're zapping all composite types */
2299  if (relid != typentry->typrelid && relid != InvalidOid)
2300  continue;
2301 
2302  /* Delete tupdesc if we have it */
2303  if (typentry->tupDesc != NULL)
2304  {
2305  /*
2306  * Release our refcount, and free the tupdesc if none remain.
2307  * (Can't use DecrTupleDescRefCount because this reference is
2308  * not logged in current resource owner.)
2309  */
2310  Assert(typentry->tupDesc->tdrefcount > 0);
2311  if (--typentry->tupDesc->tdrefcount == 0)
2312  FreeTupleDesc(typentry->tupDesc);
2313  typentry->tupDesc = NULL;
2314 
2315  /*
2316  * Also clear tupDesc_identifier, so that anything watching
2317  * that will realize that the tupdesc has possibly changed.
2318  * (Alternatively, we could specify that to detect possible
2319  * tupdesc change, one must check for tupDesc != NULL as well
2320  * as tupDesc_identifier being the same as what was previously
2321  * seen. That seems error-prone.)
2322  */
2323  typentry->tupDesc_identifier = 0;
2324  }
2325 
2326  /* Reset equality/comparison/hashing validity information */
2327  typentry->flags &= ~TCFLAGS_OPERATOR_FLAGS;
2328  }
2329  else if (typentry->typtype == TYPTYPE_DOMAIN)
2330  {
2331  /*
2332  * If it's domain over composite, reset flags. (We don't bother
2333  * trying to determine whether the specific base type needs a
2334  * reset.) Note that if we haven't determined whether the base
2335  * type is composite, we don't need to reset anything.
2336  */
2337  if (typentry->flags & TCFLAGS_DOMAIN_BASE_IS_COMPOSITE)
2338  typentry->flags &= ~TCFLAGS_OPERATOR_FLAGS;
2339  }
2340  }
2341 }
void FreeTupleDesc(TupleDesc tupdesc)
Definition: tupdesc.c:309

References Assert(), TypeCacheEntry::flags, FreeTupleDesc(), hash_seq_init(), hash_seq_search(), InvalidOid, TCFLAGS_DOMAIN_BASE_IS_COMPOSITE, TCFLAGS_OPERATOR_FLAGS, TupleDescData::tdrefcount, TypeCacheEntry::tupDesc, TypeCacheEntry::tupDesc_identifier, 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 2352 of file typcache.c.

2353 {
2354  HASH_SEQ_STATUS status;
2355  TypeCacheEntry *typentry;
2356 
2357  /* TypeCacheHash must exist, else this callback wouldn't be registered */
2358  hash_seq_init(&status, TypeCacheHash);
2359  while ((typentry = (TypeCacheEntry *) hash_seq_search(&status)) != NULL)
2360  {
2361  /* Is this the targeted type row (or it's a total cache flush)? */
2362  if (hashvalue == 0 || typentry->type_id_hash == hashvalue)
2363  {
2364  /*
2365  * Mark the data obtained directly from pg_type as invalid. Also,
2366  * if it's a domain, typnotnull might've changed, so we'll need to
2367  * recalculate its constraints.
2368  */
2369  typentry->flags &= ~(TCFLAGS_HAVE_PG_TYPE_DATA |
2371  }
2372  }
2373 }

References TypeCacheEntry::flags, hash_seq_init(), 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 1348 of file typcache.c.

1349 {
1350  TypeCacheEntry *typentry = ref->tcache;
1351 
1352  /* Make sure typcache entry's data is up to date */
1353  if ((typentry->flags & TCFLAGS_CHECKED_DOMAIN_CONSTRAINTS) == 0 &&
1354  typentry->typtype == TYPTYPE_DOMAIN)
1355  load_domaintype_info(typentry);
1356 
1357  /* Transfer to ref object if there's new info, adjusting refcounts */
1358  if (ref->dcc != typentry->domainData)
1359  {
1360  /* Paranoia --- be sure link is nulled before trying to release */
1361  DomainConstraintCache *dcc = ref->dcc;
1362 
1363  if (dcc)
1364  {
1365  /*
1366  * Note: we just leak the previous list of executable domain
1367  * constraints. Alternatively, we could keep those in a child
1368  * context of ref->refctx and free that context at this point.
1369  * However, in practice this code path will be taken so seldom
1370  * that the extra bookkeeping for a child context doesn't seem
1371  * worthwhile; we'll just allow a leak for the lifespan of refctx.
1372  */
1373  ref->constraints = NIL;
1374  ref->dcc = NULL;
1375  decr_dcc_refcount(dcc);
1376  }
1377  dcc = typentry->domainData;
1378  if (dcc)
1379  {
1380  ref->dcc = dcc;
1381  dcc->dccRefCount++;
1382  if (ref->need_exprstate)
1384  ref->refctx);
1385  else
1386  ref->constraints = dcc->constraints;
1387  }
1388  }
1389 }

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

Referenced by lookup_type_cache(), and TypeCacheConstrCallback().

◆ NextRecordTypmod

int32 NextRecordTypmod = 0
static

◆ RecordCacheArray

◆ RecordCacheArrayLen

int32 RecordCacheArrayLen = 0
static

◆ RecordCacheHash

HTAB* RecordCacheHash = NULL
static

Definition at line 274 of file typcache.c.

Referenced by assign_record_type_typmod().

◆ srtr_record_table_params

const dshash_parameters srtr_record_table_params
static
Initial value:
= {
}
@ LWTRANCHE_PER_SESSION_RECORD_TYPE
Definition: lwlock.h:199
static int shared_record_table_compare(const void *a, const void *b, size_t size, void *arg)
Definition: typcache.c:215
static uint32 shared_record_table_hash(const void *a, size_t size, void *arg)
Definition: typcache.c:241
struct SharedRecordTableKey SharedRecordTableKey

Definition at line 256 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:200

Definition at line 265 of file typcache.c.

Referenced by SharedRecordTypmodRegistryAttach(), and SharedRecordTypmodRegistryInit().

◆ tupledesc_id_counter

◆ TypeCacheHash

HTAB* TypeCacheHash = NULL
static