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
 

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
 

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 TupleDescRecordCacheArray = NULL
 
static uint64 * RecordIdentifierArray = 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

◆ RecordCacheEntry

◆ SharedRecordTableEntry

◆ SharedRecordTableKey

◆ SharedTypmodTableEntry

◆ TypeCacheEnumData

Function Documentation

◆ array_element_has_compare()

static bool array_element_has_compare ( TypeCacheEntry typentry)
static

Definition at line 1427 of file typcache.c.

1428 {
1429  if (!(typentry->flags & TCFLAGS_CHECKED_ELEM_PROPERTIES))
1431  return (typentry->flags & TCFLAGS_HAVE_ELEM_COMPARE) != 0;
1432 }
#define TCFLAGS_HAVE_ELEM_COMPARE
Definition: typcache.c:95
static void cache_array_element_properties(TypeCacheEntry *typentry)
Definition: typcache.c:1451
#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 1419 of file typcache.c.

1420 {
1421  if (!(typentry->flags & TCFLAGS_CHECKED_ELEM_PROPERTIES))
1423  return (typentry->flags & TCFLAGS_HAVE_ELEM_EQUALITY) != 0;
1424 }
#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 1443 of file typcache.c.

1444 {
1445  if (!(typentry->flags & TCFLAGS_CHECKED_ELEM_PROPERTIES))
1447  return (typentry->flags & TCFLAGS_HAVE_ELEM_EXTENDED_HASHING) != 0;
1448 }
#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 1435 of file typcache.c.

1436 {
1437  if (!(typentry->flags & TCFLAGS_CHECKED_ELEM_PROPERTIES))
1439  return (typentry->flags & TCFLAGS_HAVE_ELEM_HASHING) != 0;
1440 }
#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 2036 of file typcache.c.

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

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

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

◆ assign_record_type_typmod()

void assign_record_type_typmod ( TupleDesc  tupDesc)

Definition at line 1944 of file typcache.c.

1945 {
1946  RecordCacheEntry *recentry;
1947  TupleDesc entDesc;
1948  bool found;
1949  MemoryContext oldcxt;
1950 
1951  Assert(tupDesc->tdtypeid == RECORDOID);
1952 
1953  if (RecordCacheHash == NULL)
1954  {
1955  /* First time through: initialize the hash table */
1956  HASHCTL ctl;
1957 
1958  ctl.keysize = sizeof(TupleDesc); /* just the pointer */
1959  ctl.entrysize = sizeof(RecordCacheEntry);
1962  RecordCacheHash = hash_create("Record information cache", 64,
1963  &ctl,
1965 
1966  /* Also make sure CacheMemoryContext exists */
1967  if (!CacheMemoryContext)
1969  }
1970 
1971  /*
1972  * Find a hashtable entry for this tuple descriptor. We don't use
1973  * HASH_ENTER yet, because if it's missing, we need to make sure that all
1974  * the allocations succeed before we create the new entry.
1975  */
1977  &tupDesc,
1978  HASH_FIND, &found);
1979  if (found && recentry->tupdesc != NULL)
1980  {
1981  tupDesc->tdtypmod = recentry->tupdesc->tdtypmod;
1982  return;
1983  }
1984 
1985  /* Not present, so need to manufacture an entry */
1987 
1988  /* Look in the SharedRecordTypmodRegistry, if attached */
1989  entDesc = find_or_make_matching_shared_tupledesc(tupDesc);
1990  if (entDesc == NULL)
1991  {
1992  /*
1993  * Make sure we have room before we CreateTupleDescCopy() or advance
1994  * NextRecordTypmod.
1995  */
1997 
1998  /* Reference-counted local cache only. */
1999  entDesc = CreateTupleDescCopy(tupDesc);
2000  entDesc->tdrefcount = 1;
2001  entDesc->tdtypmod = NextRecordTypmod++;
2002  }
2003  else
2004  {
2006  }
2007 
2008  RecordCacheArray[entDesc->tdtypmod] = entDesc;
2009 
2010  /* Assign a unique tupdesc identifier, too. */
2012 
2013  /* Fully initialized; create the hash table entry */
2015  &tupDesc,
2016  HASH_ENTER, NULL);
2017  recentry->tupdesc = entDesc;
2018 
2019  /* Update the caller's tuple descriptor. */
2020  tupDesc->tdtypmod = entDesc->tdtypmod;
2021 
2022  MemoryContextSwitchTo(oldcxt);
2023 }
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:2752
static int32 NextRecordTypmod
Definition: typcache.c:280
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:1928
static void ensure_record_cache_typmod_slot_exists(int32 typmod)
Definition: typcache.c:1702
static uint32 record_type_typmod_hash(const void *data, size_t size)
Definition: typcache.c:1917

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

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

◆ cache_array_element_properties()

static void cache_array_element_properties ( TypeCacheEntry typentry)
static

Definition at line 1451 of file typcache.c.

1452 {
1453  Oid elem_type = get_base_element_type(typentry->type_id);
1454 
1455  if (OidIsValid(elem_type))
1456  {
1457  TypeCacheEntry *elementry;
1458 
1459  elementry = lookup_type_cache(elem_type,
1464  if (OidIsValid(elementry->eq_opr))
1465  typentry->flags |= TCFLAGS_HAVE_ELEM_EQUALITY;
1466  if (OidIsValid(elementry->cmp_proc))
1467  typentry->flags |= TCFLAGS_HAVE_ELEM_COMPARE;
1468  if (OidIsValid(elementry->hash_proc))
1469  typentry->flags |= TCFLAGS_HAVE_ELEM_HASHING;
1470  if (OidIsValid(elementry->hash_extended_proc))
1472  }
1474 }
#define OidIsValid(objectId)
Definition: c.h:759
Oid get_base_element_type(Oid typid)
Definition: lsyscache.c:2790
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 1674 of file typcache.c.

1675 {
1676  /* load up range link if we didn't already */
1677  if (typentry->rngtype == NULL &&
1678  typentry->typtype == TYPTYPE_MULTIRANGE)
1679  load_multirangetype_info(typentry);
1680 
1681  if (typentry->rngtype != NULL && typentry->rngtype->rngelemtype != NULL)
1682  {
1683  TypeCacheEntry *elementry;
1684 
1685  /* might need to calculate subtype's hash function properties */
1686  elementry = lookup_type_cache(typentry->rngtype->rngelemtype->type_id,
1689  if (OidIsValid(elementry->hash_proc))
1690  typentry->flags |= TCFLAGS_HAVE_ELEM_HASHING;
1691  if (OidIsValid(elementry->hash_extended_proc))
1693  }
1695 }
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:964

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

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

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

1514 {
1515  /*
1516  * For type RECORD, we can't really tell what will work, since we don't
1517  * have access here to the specific anonymous type. Just assume that
1518  * equality and comparison will (we may get a failure at runtime). We
1519  * could also claim that hashing works, but then if code that has the
1520  * option between a comparison-based (sort-based) and a hash-based plan
1521  * chooses hashing, stuff could fail that would otherwise work if it chose
1522  * a comparison-based plan. In practice more types support comparison
1523  * than hashing.
1524  */
1525  if (typentry->type_id == RECORDOID)
1526  {
1527  typentry->flags |= (TCFLAGS_HAVE_FIELD_EQUALITY |
1529  }
1530  else if (typentry->typtype == TYPTYPE_COMPOSITE)
1531  {
1532  TupleDesc tupdesc;
1533  int newflags;
1534  int i;
1535 
1536  /* Fetch composite type's tupdesc if we don't have it already */
1537  if (typentry->tupDesc == NULL)
1538  load_typcache_tupdesc(typentry);
1539  tupdesc = typentry->tupDesc;
1540 
1541  /* Must bump the refcount while we do additional catalog lookups */
1542  IncrTupleDescRefCount(tupdesc);
1543 
1544  /* Have each property if all non-dropped fields have the property */
1545  newflags = (TCFLAGS_HAVE_FIELD_EQUALITY |
1549  for (i = 0; i < tupdesc->natts; i++)
1550  {
1551  TypeCacheEntry *fieldentry;
1552  Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
1553 
1554  if (attr->attisdropped)
1555  continue;
1556 
1557  fieldentry = lookup_type_cache(attr->atttypid,
1562  if (!OidIsValid(fieldentry->eq_opr))
1563  newflags &= ~TCFLAGS_HAVE_FIELD_EQUALITY;
1564  if (!OidIsValid(fieldentry->cmp_proc))
1565  newflags &= ~TCFLAGS_HAVE_FIELD_COMPARE;
1566  if (!OidIsValid(fieldentry->hash_proc))
1567  newflags &= ~TCFLAGS_HAVE_FIELD_HASHING;
1568  if (!OidIsValid(fieldentry->hash_extended_proc))
1570 
1571  /* We can drop out of the loop once we disprove all bits */
1572  if (newflags == 0)
1573  break;
1574  }
1575  typentry->flags |= newflags;
1576 
1577  DecrTupleDescRefCount(tupdesc);
1578  }
1579  else if (typentry->typtype == TYPTYPE_DOMAIN)
1580  {
1581  /* If it's domain over composite, copy base type's properties */
1582  TypeCacheEntry *baseentry;
1583 
1584  /* load up basetype info if we didn't already */
1585  if (typentry->domainBaseType == InvalidOid)
1586  {
1587  typentry->domainBaseTypmod = -1;
1588  typentry->domainBaseType =
1589  getBaseTypeAndTypmod(typentry->type_id,
1590  &typentry->domainBaseTypmod);
1591  }
1592  baseentry = lookup_type_cache(typentry->domainBaseType,
1597  if (baseentry->typtype == TYPTYPE_COMPOSITE)
1598  {
1600  typentry->flags |= baseentry->flags & (TCFLAGS_HAVE_FIELD_EQUALITY |
1604  }
1605  }
1607 }
int i
Definition: isn.c:73
Oid getBaseTypeAndTypmod(Oid typid, int32 *typmod)
Definition: lsyscache.c:2496
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:873

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

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

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

1247 {
1249  DomainConstraintCache *dcc = ref->dcc;
1250 
1251  /* Paranoia --- be sure link is nulled before trying to release */
1252  if (dcc)
1253  {
1254  ref->constraints = NIL;
1255  ref->dcc = NULL;
1256  decr_dcc_refcount(dcc);
1257  }
1258 }
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:1235

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

1223 {
1224  const DomainConstraintState *const *ca = (const DomainConstraintState *const *) a;
1225  const DomainConstraintState *const *cb = (const DomainConstraintState *const *) b;
1226 
1227  return strcmp((*ca)->name, (*cb)->name);
1228 }
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 1235 of file typcache.c.

1236 {
1237  Assert(dcc->dccRefCount > 0);
1238  if (--(dcc->dccRefCount) <= 0)
1240 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:387
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 1392 of file typcache.c.

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

1703 {
1704  if (RecordCacheArray == NULL)
1705  {
1708  RecordIdentifierArray = (uint64 *)
1709  MemoryContextAllocZero(CacheMemoryContext, 64 * sizeof(uint64));
1710  RecordCacheArrayLen = 64;
1711  }
1712 
1713  if (typmod >= RecordCacheArrayLen)
1714  {
1715  int32 newlen = pg_nextpower2_32(typmod + 1);
1716 
1719  RecordCacheArrayLen = newlen;
1720  }
1721 }
signed int int32
Definition: c.h:478
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1048
#define repalloc0_array(pointer, type, oldcount, count)
Definition: palloc.h:110
static uint32 pg_nextpower2_32(uint32 num)
Definition: pg_bitutils.h:185

References CacheMemoryContext, MemoryContextAllocZero(), pg_nextpower2_32(), RecordCacheArray, RecordCacheArrayLen, RecordIdentifierArray, 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 2439 of file typcache.c.

2440 {
2441  Oid offset;
2442 
2443  if (arg < enumdata->bitmap_base)
2444  return false;
2445  offset = arg - enumdata->bitmap_base;
2446  if (offset > (Oid) INT_MAX)
2447  return false;
2448  return bms_is_member((int) offset, enumdata->sorted_values);
2449 }
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:444
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 2713 of file typcache.c.

2714 {
2715  const EnumItem *l = (const EnumItem *) left;
2716  const EnumItem *r = (const EnumItem *) right;
2717 
2718  if (l->enum_oid < r->enum_oid)
2719  return -1;
2720  else if (l->enum_oid > r->enum_oid)
2721  return 1;
2722  else
2723  return 0;
2724 }
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 2696 of file typcache.c.

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

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

2753 {
2754  TupleDesc result;
2756  SharedRecordTableEntry *record_table_entry;
2757  SharedTypmodTableEntry *typmod_table_entry;
2758  dsa_pointer shared_dp;
2759  bool found;
2760  uint32 typmod;
2761 
2762  /* If not even attached, nothing to do. */
2764  return NULL;
2765 
2766  /* Try to find a matching tuple descriptor in the record table. */
2767  key.shared = false;
2768  key.u.local_tupdesc = tupdesc;
2769  record_table_entry = (SharedRecordTableEntry *)
2771  if (record_table_entry)
2772  {
2773  Assert(record_table_entry->key.shared);
2775  record_table_entry);
2776  result = (TupleDesc)
2778  record_table_entry->key.u.shared_tupdesc);
2779  Assert(result->tdrefcount == -1);
2780 
2781  return result;
2782  }
2783 
2784  /* Allocate a new typmod number. This will be wasted if we error out. */
2785  typmod = (int)
2787  1);
2788 
2789  /* Copy the TupleDesc into shared memory. */
2790  shared_dp = share_tupledesc(CurrentSession->area, tupdesc, typmod);
2791 
2792  /*
2793  * Create an entry in the typmod table so that others will understand this
2794  * typmod number.
2795  */
2796  PG_TRY();
2797  {
2798  typmod_table_entry = (SharedTypmodTableEntry *)
2800  &typmod, &found);
2801  if (found)
2802  elog(ERROR, "cannot create duplicate shared record typmod");
2803  }
2804  PG_CATCH();
2805  {
2806  dsa_free(CurrentSession->area, shared_dp);
2807  PG_RE_THROW();
2808  }
2809  PG_END_TRY();
2810  typmod_table_entry->typmod = typmod;
2811  typmod_table_entry->shared_tupdesc = shared_dp;
2813  typmod_table_entry);
2814 
2815  /*
2816  * Finally create an entry in the record table so others with matching
2817  * tuple descriptors can reuse the typmod.
2818  */
2819  record_table_entry = (SharedRecordTableEntry *)
2821  &found);
2822  if (found)
2823  {
2824  /*
2825  * Someone concurrently inserted a matching tuple descriptor since the
2826  * first time we checked. Use that one instead.
2827  */
2829  record_table_entry);
2830 
2831  /* Might as well free up the space used by the one we created. */
2833  &typmod);
2834  Assert(found);
2835  dsa_free(CurrentSession->area, shared_dp);
2836 
2837  /* Return the one we found. */
2838  Assert(record_table_entry->key.shared);
2839  result = (TupleDesc)
2841  record_table_entry->key.u.shared_tupdesc);
2842  Assert(result->tdrefcount == -1);
2843 
2844  return result;
2845  }
2846 
2847  /* Store it and return it. */
2848  record_table_entry->key.shared = true;
2849  record_table_entry->key.u.shared_tupdesc = shared_dp;
2851  record_table_entry);
2852  result = (TupleDesc)
2853  dsa_get_address(CurrentSession->area, shared_dp);
2854  Assert(result->tdrefcount == -1);
2855 
2856  return result;
2857 }
static uint32 pg_atomic_fetch_add_u32(volatile pg_atomic_uint32 *ptr, int32 add_)
Definition: atomics.h:323
unsigned int uint32
Definition: c.h:490
void * dsa_get_address(dsa_area *area, dsa_pointer dp)
Definition: dsa.c:944
void dsa_free(dsa_area *area, dsa_pointer dp)
Definition: dsa.c:832
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::@29 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:2731

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

1307 {
1308  /* Look up the typcache entry --- we assume it survives indefinitely */
1310  ref->need_exprstate = need_exprstate;
1311  /* For safety, establish the callback before acquiring a refcount */
1312  ref->refctx = refctx;
1313  ref->dcc = NULL;
1315  ref->callback.arg = (void *) ref;
1317  /* Acquire refcount if there are constraints, and set up exported list */
1318  if (ref->tcache->domainData)
1319  {
1320  ref->dcc = ref->tcache->domainData;
1321  ref->dcc->dccRefCount++;
1322  if (ref->need_exprstate)
1324  ref->refctx);
1325  else
1326  ref->constraints = ref->dcc->constraints;
1327  }
1328  else
1329  ref->constraints = NIL;
1330 }
void MemoryContextRegisterResetCallback(MemoryContext context, MemoryContextCallback *cb)
Definition: mcxt.c:461
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:1267
static void dccref_deletion_callback(void *arg)
Definition: typcache.c:1246

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

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

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

965 {
966  Oid rangetypeOid;
967 
968  rangetypeOid = get_multirange_range(typentry->type_id);
969  if (!OidIsValid(rangetypeOid))
970  elog(ERROR, "cache lookup failed for multirange type %u",
971  typentry->type_id);
972 
973  typentry->rngtype = lookup_type_cache(rangetypeOid, TYPECACHE_RANGE_INFO);
974 }
Oid get_multirange_range(Oid multirangeOid)
Definition: lsyscache.c:3441
#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 907 of file typcache.c.

908 {
909  Form_pg_range pg_range;
910  HeapTuple tup;
911  Oid subtypeOid;
912  Oid opclassOid;
913  Oid canonicalOid;
914  Oid subdiffOid;
915  Oid opfamilyOid;
916  Oid opcintype;
917  Oid cmpFnOid;
918 
919  /* get information from pg_range */
921  /* should not fail, since we already checked typtype ... */
922  if (!HeapTupleIsValid(tup))
923  elog(ERROR, "cache lookup failed for range type %u",
924  typentry->type_id);
925  pg_range = (Form_pg_range) GETSTRUCT(tup);
926 
927  subtypeOid = pg_range->rngsubtype;
928  typentry->rng_collation = pg_range->rngcollation;
929  opclassOid = pg_range->rngsubopc;
930  canonicalOid = pg_range->rngcanonical;
931  subdiffOid = pg_range->rngsubdiff;
932 
933  ReleaseSysCache(tup);
934 
935  /* get opclass properties and look up the comparison function */
936  opfamilyOid = get_opclass_family(opclassOid);
937  opcintype = get_opclass_input_type(opclassOid);
938 
939  cmpFnOid = get_opfamily_proc(opfamilyOid, opcintype, opcintype,
940  BTORDER_PROC);
941  if (!RegProcedureIsValid(cmpFnOid))
942  elog(ERROR, "missing support function %d(%u,%u) in opfamily %u",
943  BTORDER_PROC, opcintype, opcintype, opfamilyOid);
944 
945  /* set up cached fmgrinfo structs */
946  fmgr_info_cxt(cmpFnOid, &typentry->rng_cmp_proc_finfo,
948  if (OidIsValid(canonicalOid))
949  fmgr_info_cxt(canonicalOid, &typentry->rng_canonical_finfo,
951  if (OidIsValid(subdiffOid))
952  fmgr_info_cxt(subdiffOid, &typentry->rng_subdiff_finfo,
954 
955  /* Lastly, set up link to the element type --- this marks data valid */
956  typentry->rngelemtype = lookup_type_cache(subtypeOid, 0);
957 }
#define RegProcedureIsValid(p)
Definition: c.h:761
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:708
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 873 of file typcache.c.

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

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

1859 {
1860  TupleDesc tmp;
1861 
1862  tmp = lookup_rowtype_tupdesc_internal(type_id, typmod, false);
1863  return CreateTupleDescCopyConstr(tmp);
1864 }
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 1880 of file typcache.c.

1881 {
1882  TupleDesc tupDesc;
1883 
1884  if (type_id != RECORDOID)
1885  {
1886  /*
1887  * Check for domain or named composite type. We might as well load
1888  * whichever data is needed.
1889  */
1890  TypeCacheEntry *typentry;
1891 
1892  typentry = lookup_type_cache(type_id,
1895  if (typentry->typtype == TYPTYPE_DOMAIN)
1897  typentry->domainBaseTypmod,
1898  noError);
1899  if (typentry->tupDesc == NULL && !noError)
1900  ereport(ERROR,
1901  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1902  errmsg("type %s is not composite",
1903  format_type_be(type_id))));
1904  tupDesc = typentry->tupDesc;
1905  }
1906  else
1907  tupDesc = lookup_rowtype_tupdesc_internal(type_id, typmod, noError);
1908  if (tupDesc != NULL)
1909  PinTupleDesc(tupDesc);
1910  return tupDesc;
1911 }
TupleDesc lookup_rowtype_tupdesc_noerror(Oid type_id, int32 typmod, bool noError)
Definition: typcache.c:1841
#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 1730 of file typcache.c.

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

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(), lookup_type_cache(), RecordCacheArray, RecordCacheArrayLen, RecordIdentifierArray, SharedTypmodTableEntry::shared_tupdesc, Session::shared_typmod_registry, Session::shared_typmod_table, TupleDescData::tdrefcount, TupleDescData::tdtypmod, 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 1841 of file typcache.c.

1842 {
1843  TupleDesc tupDesc;
1844 
1845  tupDesc = lookup_rowtype_tupdesc_internal(type_id, typmod, noError);
1846  if (tupDesc != NULL)
1847  PinTupleDesc(tupDesc);
1848  return tupDesc;
1849 }

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

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

1667 {
1668  if (!(typentry->flags & TCFLAGS_CHECKED_ELEM_PROPERTIES))
1670  return (typentry->flags & TCFLAGS_HAVE_ELEM_EXTENDED_HASHING) != 0;
1671 }
static void cache_multirange_element_properties(TypeCacheEntry *typentry)
Definition: typcache.c:1674

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

1659 {
1660  if (!(typentry->flags & TCFLAGS_CHECKED_ELEM_PROPERTIES))
1662  return (typentry->flags & TCFLAGS_HAVE_ELEM_HASHING) != 0;
1663 }

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

1268 {
1269  List *result = NIL;
1270  MemoryContext oldcxt;
1271  ListCell *lc;
1272 
1273  oldcxt = MemoryContextSwitchTo(execctx);
1274 
1275  foreach(lc, constraints)
1276  {
1278  DomainConstraintState *newr;
1279 
1281  newr->constrainttype = r->constrainttype;
1282  newr->name = r->name;
1283  newr->check_expr = r->check_expr;
1284  newr->check_exprstate = ExecInitExpr(r->check_expr, NULL);
1285 
1286  result = lappend(result, newr);
1287  }
1288 
1289  MemoryContextSwitchTo(oldcxt);
1290 
1291  return result;
1292 }
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:127
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 1626 of file typcache.c.

1627 {
1628  if (!(typentry->flags & TCFLAGS_CHECKED_ELEM_PROPERTIES))
1630  return (typentry->flags & TCFLAGS_HAVE_ELEM_EXTENDED_HASHING) != 0;
1631 }
static void cache_range_element_properties(TypeCacheEntry *typentry)
Definition: typcache.c:1634

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

1619 {
1620  if (!(typentry->flags & TCFLAGS_CHECKED_ELEM_PROPERTIES))
1622  return (typentry->flags & TCFLAGS_HAVE_ELEM_HASHING) != 0;
1623 }

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

1490 {
1491  if (!(typentry->flags & TCFLAGS_CHECKED_FIELD_PROPERTIES))
1493  return (typentry->flags & TCFLAGS_HAVE_FIELD_COMPARE) != 0;
1494 }
static void cache_record_field_properties(TypeCacheEntry *typentry)
Definition: typcache.c:1513

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

1482 {
1483  if (!(typentry->flags & TCFLAGS_CHECKED_FIELD_PROPERTIES))
1485  return (typentry->flags & TCFLAGS_HAVE_FIELD_EQUALITY) != 0;
1486 }

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

1498 {
1499  if (!(typentry->flags & TCFLAGS_CHECKED_FIELD_PROPERTIES))
1501  return (typentry->flags & TCFLAGS_HAVE_FIELD_HASHING) != 0;
1502 }

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

1929 {
1930  RecordCacheEntry *left = (RecordCacheEntry *) a;
1931  RecordCacheEntry *right = (RecordCacheEntry *) b;
1932 
1933  return equalTupleDescs(left->tupdesc, right->tupdesc) ? 0 : 1;
1934 }
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 1917 of file typcache.c.

1918 {
1919  RecordCacheEntry *entry = (RecordCacheEntry *) data;
1920 
1921  return hashTupleDesc(entry->tupdesc);
1922 }
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 2731 of file typcache.c.

2732 {
2733  dsa_pointer shared_dp;
2734  TupleDesc shared;
2735 
2736  shared_dp = dsa_allocate(area, TupleDescSize(tupdesc));
2737  shared = (TupleDesc) dsa_get_address(area, shared_dp);
2738  TupleDescCopy(shared, tupdesc);
2739  shared->tdtypmod = typmod;
2740 
2741  return shared_dp;
2742 }
#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 2864 of file typcache.c.

2865 {
2866  /* Be cautious here: maybe we didn't finish initializing. */
2867  if (CurrentSession->shared_record_table != NULL)
2868  {
2871  }
2872  if (CurrentSession->shared_typmod_table != NULL)
2873  {
2876  }
2878 }
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 2198 of file typcache.c.

2199 {
2200  MemoryContext old_context;
2201  dshash_table *record_table;
2202  dshash_table *typmod_table;
2203 
2205 
2206  /* We can't already be attached to a shared registry. */
2207  Assert(CurrentSession != NULL);
2208  Assert(CurrentSession->segment != NULL);
2209  Assert(CurrentSession->area != NULL);
2213 
2214  /*
2215  * We can't already have typmods in our local cache, because they'd clash
2216  * with those imported by SharedRecordTypmodRegistryInit. This should be
2217  * a freshly started parallel worker. If we ever support worker
2218  * recycling, a worker would need to zap its local cache in between
2219  * servicing different queries, in order to be able to call this and
2220  * synchronize typmods with a new leader; but that's problematic because
2221  * we can't be very sure that record-typmod-related state hasn't escaped
2222  * to anywhere else in the process.
2223  */
2224  Assert(NextRecordTypmod == 0);
2225 
2226  old_context = MemoryContextSwitchTo(TopMemoryContext);
2227 
2228  /* Attach to the two hash tables. */
2229  record_table = dshash_attach(CurrentSession->area,
2231  registry->record_table_handle,
2232  CurrentSession->area);
2233  typmod_table = dshash_attach(CurrentSession->area,
2235  registry->typmod_table_handle,
2236  NULL);
2237 
2238  MemoryContextSwitchTo(old_context);
2239 
2240  /*
2241  * Set up detach hook to run at worker exit. Currently this is the same
2242  * as the leader's detach hook, but in future they might need to be
2243  * different.
2244  */
2247  PointerGetDatum(registry));
2248 
2249  /*
2250  * Set up the session state that will tell assign_record_type_typmod and
2251  * lookup_rowtype_tupdesc_internal about the shared registry.
2252  */
2254  CurrentSession->shared_record_table = record_table;
2255  CurrentSession->shared_typmod_table = typmod_table;
2256 }
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:2864
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 2077 of file typcache.c.

2078 {
2079  return sizeof(SharedRecordTypmodRegistry);
2080 }
struct SharedRecordTypmodRegistry SharedRecordTypmodRegistry
Definition: typcache.h:175

Referenced by GetSessionDsmHandle().

◆ SharedRecordTypmodRegistryInit()

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

Definition at line 2099 of file typcache.c.

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

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

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

2387 {
2389  TypeCacheEntry *typentry;
2390 
2391  /* TypeCacheHash must exist, else this callback wouldn't be registered */
2393  while ((typentry = (TypeCacheEntry *) hash_seq_search(&status)) != NULL)
2394  {
2395  /* Reset equality/comparison/hashing validity information */
2396  typentry->flags &= ~TCFLAGS_OPERATOR_FLAGS;
2397  }
2398 }
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
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:224
#define TCFLAGS_OPERATOR_FLAGS
Definition: typcache.c:107

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

Referenced by lookup_type_cache().

◆ TypeCacheRelCallback()

static void TypeCacheRelCallback ( Datum  arg,
Oid  relid 
)
static

Definition at line 2281 of file typcache.c.

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

References Assert(), TypeCacheEntry::flags, FreeTupleDesc(), hash_seq_init(), hash_seq_search(), InvalidOid, status(), 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 2346 of file typcache.c.

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

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

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

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

◆ RecordIdentifierArray

uint64* RecordIdentifierArray = NULL
static

◆ srtr_record_table_params

const dshash_parameters srtr_record_table_params
static
Initial value:
= {
}
@ LWTRANCHE_PER_SESSION_RECORD_TYPE
Definition: lwlock.h:198
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:199

Definition at line 265 of file typcache.c.

Referenced by SharedRecordTypmodRegistryAttach(), and SharedRecordTypmodRegistryInit().

◆ tupledesc_id_counter

◆ TypeCacheHash

HTAB* TypeCacheHash = NULL
static