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

Go to the source code of this file.

Data Structures

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

Macros

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

Typedefs

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

Functions

static int shared_record_table_compare (const void *a, const void *b, size_t size, void *arg)
 
static uint32 shared_record_table_hash (const void *a, size_t size, void *arg)
 
static void load_typcache_tupdesc (TypeCacheEntry *typentry)
 
static void load_rangetype_info (TypeCacheEntry *typentry)
 
static void load_multirangetype_info (TypeCacheEntry *typentry)
 
static void load_domaintype_info (TypeCacheEntry *typentry)
 
static int dcs_cmp (const void *a, const void *b)
 
static void decr_dcc_refcount (DomainConstraintCache *dcc)
 
static void dccref_deletion_callback (void *arg)
 
static Listprep_domain_constraints (List *constraints, MemoryContext execctx)
 
static bool array_element_has_equality (TypeCacheEntry *typentry)
 
static bool array_element_has_compare (TypeCacheEntry *typentry)
 
static bool array_element_has_hashing (TypeCacheEntry *typentry)
 
static bool array_element_has_extended_hashing (TypeCacheEntry *typentry)
 
static void cache_array_element_properties (TypeCacheEntry *typentry)
 
static bool record_fields_have_equality (TypeCacheEntry *typentry)
 
static bool record_fields_have_compare (TypeCacheEntry *typentry)
 
static bool record_fields_have_hashing (TypeCacheEntry *typentry)
 
static bool record_fields_have_extended_hashing (TypeCacheEntry *typentry)
 
static void cache_record_field_properties (TypeCacheEntry *typentry)
 
static bool range_element_has_hashing (TypeCacheEntry *typentry)
 
static bool range_element_has_extended_hashing (TypeCacheEntry *typentry)
 
static void cache_range_element_properties (TypeCacheEntry *typentry)
 
static bool multirange_element_has_hashing (TypeCacheEntry *typentry)
 
static bool multirange_element_has_extended_hashing (TypeCacheEntry *typentry)
 
static void cache_multirange_element_properties (TypeCacheEntry *typentry)
 
static void TypeCacheRelCallback (Datum arg, Oid relid)
 
static void TypeCacheTypCallback (Datum arg, int cacheid, uint32 hashvalue)
 
static void TypeCacheOpcCallback (Datum arg, int cacheid, uint32 hashvalue)
 
static void TypeCacheConstrCallback (Datum arg, int cacheid, uint32 hashvalue)
 
static void load_enum_cache_data (TypeCacheEntry *tcache)
 
static EnumItemfind_enumitem (TypeCacheEnumData *enumdata, Oid arg)
 
static int enum_oid_cmp (const void *left, const void *right)
 
static void shared_record_typmod_registry_detach (dsm_segment *segment, Datum datum)
 
static TupleDesc find_or_make_matching_shared_tupledesc (TupleDesc tupdesc)
 
static dsa_pointer share_tupledesc (dsa_area *area, TupleDesc tupdesc, uint32 typmod)
 
TypeCacheEntrylookup_type_cache (Oid type_id, int flags)
 
void InitDomainConstraintRef (Oid type_id, DomainConstraintRef *ref, MemoryContext refctx, bool need_exprstate)
 
void UpdateDomainConstraintRef (DomainConstraintRef *ref)
 
bool DomainHasConstraints (Oid type_id)
 
static void ensure_record_cache_typmod_slot_exists (int32 typmod)
 
static TupleDesc lookup_rowtype_tupdesc_internal (Oid type_id, int32 typmod, bool noError)
 
TupleDesc lookup_rowtype_tupdesc (Oid type_id, int32 typmod)
 
TupleDesc lookup_rowtype_tupdesc_noerror (Oid type_id, int32 typmod, bool noError)
 
TupleDesc lookup_rowtype_tupdesc_copy (Oid type_id, int32 typmod)
 
TupleDesc lookup_rowtype_tupdesc_domain (Oid type_id, int32 typmod, bool noError)
 
static uint32 record_type_typmod_hash (const void *data, size_t size)
 
static int record_type_typmod_compare (const void *a, const void *b, size_t size)
 
void assign_record_type_typmod (TupleDesc tupDesc)
 
uint64 assign_record_type_identifier (Oid type_id, int32 typmod)
 
size_t SharedRecordTypmodRegistryEstimate (void)
 
void SharedRecordTypmodRegistryInit (SharedRecordTypmodRegistry *registry, dsm_segment *segment, dsa_area *area)
 
void SharedRecordTypmodRegistryAttach (SharedRecordTypmodRegistry *registry)
 
static bool enum_known_sorted (TypeCacheEnumData *enumdata, Oid arg)
 
int compare_values_of_enum (TypeCacheEntry *tcache, Oid arg1, Oid arg2)
 

Variables

static HTABTypeCacheHash = NULL
 
static TypeCacheEntryfirstDomainTypeEntry = NULL
 
static const dshash_parameters srtr_record_table_params
 
static const dshash_parameters srtr_typmod_table_params
 
static HTABRecordCacheHash = NULL
 
static RecordCacheArrayEntryRecordCacheArray = NULL
 
static int32 RecordCacheArrayLen = 0
 
static int32 NextRecordTypmod = 0
 
static uint64 tupledesc_id_counter = INVALID_TUPLEDESC_IDENTIFIER
 

Macro Definition Documentation

◆ TCFLAGS_CHECKED_BTREE_OPCLASS

#define TCFLAGS_CHECKED_BTREE_OPCLASS   0x000002

Definition at line 85 of file typcache.c.

◆ TCFLAGS_CHECKED_CMP_PROC

#define TCFLAGS_CHECKED_CMP_PROC   0x000040

Definition at line 90 of file typcache.c.

◆ TCFLAGS_CHECKED_DOMAIN_CONSTRAINTS

#define TCFLAGS_CHECKED_DOMAIN_CONSTRAINTS   0x080000

Definition at line 103 of file typcache.c.

◆ TCFLAGS_CHECKED_ELEM_PROPERTIES

#define TCFLAGS_CHECKED_ELEM_PROPERTIES   0x000200

Definition at line 93 of file typcache.c.

◆ TCFLAGS_CHECKED_EQ_OPR

#define TCFLAGS_CHECKED_EQ_OPR   0x000008

Definition at line 87 of file typcache.c.

◆ TCFLAGS_CHECKED_FIELD_PROPERTIES

#define TCFLAGS_CHECKED_FIELD_PROPERTIES   0x004000

Definition at line 98 of file typcache.c.

◆ TCFLAGS_CHECKED_GT_OPR

#define TCFLAGS_CHECKED_GT_OPR   0x000020

Definition at line 89 of file typcache.c.

◆ TCFLAGS_CHECKED_HASH_EXTENDED_PROC

#define TCFLAGS_CHECKED_HASH_EXTENDED_PROC   0x000100

Definition at line 92 of file typcache.c.

◆ TCFLAGS_CHECKED_HASH_OPCLASS

#define TCFLAGS_CHECKED_HASH_OPCLASS   0x000004

Definition at line 86 of file typcache.c.

◆ TCFLAGS_CHECKED_HASH_PROC

#define TCFLAGS_CHECKED_HASH_PROC   0x000080

Definition at line 91 of file typcache.c.

◆ TCFLAGS_CHECKED_LT_OPR

#define TCFLAGS_CHECKED_LT_OPR   0x000010

Definition at line 88 of file typcache.c.

◆ TCFLAGS_DOMAIN_BASE_IS_COMPOSITE

#define TCFLAGS_DOMAIN_BASE_IS_COMPOSITE   0x100000

Definition at line 104 of file typcache.c.

◆ TCFLAGS_HAVE_ELEM_COMPARE

#define TCFLAGS_HAVE_ELEM_COMPARE   0x000800

Definition at line 95 of file typcache.c.

◆ TCFLAGS_HAVE_ELEM_EQUALITY

#define TCFLAGS_HAVE_ELEM_EQUALITY   0x000400

Definition at line 94 of file typcache.c.

◆ TCFLAGS_HAVE_ELEM_EXTENDED_HASHING

#define TCFLAGS_HAVE_ELEM_EXTENDED_HASHING   0x002000

Definition at line 97 of file typcache.c.

◆ TCFLAGS_HAVE_ELEM_HASHING

#define TCFLAGS_HAVE_ELEM_HASHING   0x001000

Definition at line 96 of file typcache.c.

◆ TCFLAGS_HAVE_FIELD_COMPARE

#define TCFLAGS_HAVE_FIELD_COMPARE   0x010000

Definition at line 100 of file typcache.c.

◆ TCFLAGS_HAVE_FIELD_EQUALITY

#define TCFLAGS_HAVE_FIELD_EQUALITY   0x008000

Definition at line 99 of file typcache.c.

◆ TCFLAGS_HAVE_FIELD_EXTENDED_HASHING

#define TCFLAGS_HAVE_FIELD_EXTENDED_HASHING   0x040000

Definition at line 102 of file typcache.c.

◆ TCFLAGS_HAVE_FIELD_HASHING

#define TCFLAGS_HAVE_FIELD_HASHING   0x020000

Definition at line 101 of file typcache.c.

◆ TCFLAGS_HAVE_PG_TYPE_DATA

#define TCFLAGS_HAVE_PG_TYPE_DATA   0x000001

Definition at line 84 of file typcache.c.

◆ TCFLAGS_OPERATOR_FLAGS

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

Definition at line 107 of file typcache.c.

Typedef Documentation

◆ RecordCacheArrayEntry

◆ RecordCacheEntry

◆ SharedRecordTableEntry

◆ SharedRecordTableKey

◆ SharedTypmodTableEntry

◆ TypeCacheEnumData

Function Documentation

◆ array_element_has_compare()

static bool array_element_has_compare ( TypeCacheEntry typentry)
static

Definition at line 1435 of file typcache.c.

1436 {
1437  if (!(typentry->flags & TCFLAGS_CHECKED_ELEM_PROPERTIES))
1439  return (typentry->flags & TCFLAGS_HAVE_ELEM_COMPARE) != 0;
1440 }
#define TCFLAGS_HAVE_ELEM_COMPARE
Definition: typcache.c:95
static void cache_array_element_properties(TypeCacheEntry *typentry)
Definition: typcache.c:1459
#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 1427 of file typcache.c.

1428 {
1429  if (!(typentry->flags & TCFLAGS_CHECKED_ELEM_PROPERTIES))
1431  return (typentry->flags & TCFLAGS_HAVE_ELEM_EQUALITY) != 0;
1432 }
#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 1451 of file typcache.c.

1452 {
1453  if (!(typentry->flags & TCFLAGS_CHECKED_ELEM_PROPERTIES))
1455  return (typentry->flags & TCFLAGS_HAVE_ELEM_EXTENDED_HASHING) != 0;
1456 }
#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 1443 of file typcache.c.

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

2046 {
2047  if (type_id != RECORDOID)
2048  {
2049  /*
2050  * It's a named composite type, so use the regular typcache.
2051  */
2052  TypeCacheEntry *typentry;
2053 
2054  typentry = lookup_type_cache(type_id, TYPECACHE_TUPDESC);
2055  if (typentry->tupDesc == NULL)
2056  ereport(ERROR,
2057  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2058  errmsg("type %s is not composite",
2059  format_type_be(type_id))));
2060  Assert(typentry->tupDesc_identifier != 0);
2061  return typentry->tupDesc_identifier;
2062  }
2063  else
2064  {
2065  /*
2066  * It's a transient record type, so look in our record-type table.
2067  */
2068  if (typmod >= 0 && typmod < RecordCacheArrayLen &&
2069  RecordCacheArray[typmod].tupdesc != NULL)
2070  {
2071  Assert(RecordCacheArray[typmod].id != 0);
2072  return RecordCacheArray[typmod].id;
2073  }
2074 
2075  /* For anonymous or unrecognized record type, generate a new ID */
2076  return ++tupledesc_id_counter;
2077  }
2078 }
#define Assert(condition)
Definition: c.h:858
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
uint64 tupDesc_identifier
Definition: typcache.h:90
TupleDesc tupDesc
Definition: typcache.h:89
static RecordCacheArrayEntry * RecordCacheArray
Definition: typcache.c:285
static int32 RecordCacheArrayLen
Definition: typcache.c:286
static uint64 tupledesc_id_counter
Definition: typcache.c:294
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:346
#define TYPECACHE_TUPDESC
Definition: typcache.h:145

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

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

◆ assign_record_type_typmod()

void assign_record_type_typmod ( TupleDesc  tupDesc)

Definition at line 1953 of file typcache.c.

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

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

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

◆ cache_array_element_properties()

static void cache_array_element_properties ( TypeCacheEntry typentry)
static

Definition at line 1459 of file typcache.c.

1460 {
1461  Oid elem_type = get_base_element_type(typentry->type_id);
1462 
1463  if (OidIsValid(elem_type))
1464  {
1465  TypeCacheEntry *elementry;
1466 
1467  elementry = lookup_type_cache(elem_type,
1472  if (OidIsValid(elementry->eq_opr))
1473  typentry->flags |= TCFLAGS_HAVE_ELEM_EQUALITY;
1474  if (OidIsValid(elementry->cmp_proc))
1475  typentry->flags |= TCFLAGS_HAVE_ELEM_COMPARE;
1476  if (OidIsValid(elementry->hash_proc))
1477  typentry->flags |= TCFLAGS_HAVE_ELEM_HASHING;
1478  if (OidIsValid(elementry->hash_extended_proc))
1480  }
1482 }
#define OidIsValid(objectId)
Definition: c.h:775
Oid get_base_element_type(Oid typid)
Definition: lsyscache.c:2832
unsigned int Oid
Definition: postgres_ext.h:31
Oid hash_extended_proc
Definition: typcache.h:66
#define TYPECACHE_EQ_OPR
Definition: typcache.h:137
#define TYPECACHE_HASH_EXTENDED_PROC
Definition: typcache.h:151
#define TYPECACHE_CMP_PROC
Definition: typcache.h:140
#define TYPECACHE_HASH_PROC
Definition: typcache.h:141

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

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

◆ cache_multirange_element_properties()

static void cache_multirange_element_properties ( TypeCacheEntry typentry)
static

Definition at line 1682 of file typcache.c.

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

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

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

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

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

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

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

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

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

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

1231 {
1232  const DomainConstraintState *const *ca = (const DomainConstraintState *const *) a;
1233  const DomainConstraintState *const *cb = (const DomainConstraintState *const *) b;
1234 
1235  return strcmp((*ca)->name, (*cb)->name);
1236 }
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 1243 of file typcache.c.

1244 {
1245  Assert(dcc->dccRefCount > 0);
1246  if (--(dcc->dccRefCount) <= 0)
1248 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:454
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 1400 of file typcache.c.

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

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

Referenced by ATColumnChangeRequiresRewrite(), ATExecAddColumn(), 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 1710 of file typcache.c.

1711 {
1712  if (RecordCacheArray == NULL)
1713  {
1716  64 * sizeof(RecordCacheArrayEntry));
1717  RecordCacheArrayLen = 64;
1718  }
1719 
1720  if (typmod >= RecordCacheArrayLen)
1721  {
1722  int32 newlen = pg_nextpower2_32(typmod + 1);
1723 
1727  newlen);
1728  RecordCacheArrayLen = newlen;
1729  }
1730 }
signed int int32
Definition: c.h:494
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1214
#define repalloc0_array(pointer, type, oldcount, count)
Definition: palloc.h:109
static uint32 pg_nextpower2_32(uint32 num)
Definition: pg_bitutils.h:189

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

Referenced by assign_record_type_typmod(), and lookup_rowtype_tupdesc_internal().

◆ enum_known_sorted()

static bool enum_known_sorted ( TypeCacheEnumData enumdata,
Oid  arg 
)
inlinestatic

Definition at line 2448 of file typcache.c.

2449 {
2450  Oid offset;
2451 
2452  if (arg < enumdata->bitmap_base)
2453  return false;
2454  offset = arg - enumdata->bitmap_base;
2455  if (offset > (Oid) INT_MAX)
2456  return false;
2457  return bms_is_member((int) offset, enumdata->sorted_values);
2458 }
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:510
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 2722 of file typcache.c.

2723 {
2724  const EnumItem *l = (const EnumItem *) left;
2725  const EnumItem *r = (const EnumItem *) right;
2726 
2727  return pg_cmp_u32(l->enum_oid, r->enum_oid);
2728 }
static int pg_cmp_u32(uint32 a, uint32 b)
Definition: int.h:489
Oid enum_oid
Definition: typcache.c:134

References EnumItem::enum_oid, and pg_cmp_u32().

Referenced by find_enumitem(), and load_enum_cache_data().

◆ find_enumitem()

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

Definition at line 2705 of file typcache.c.

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

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

2757 {
2758  TupleDesc result;
2760  SharedRecordTableEntry *record_table_entry;
2761  SharedTypmodTableEntry *typmod_table_entry;
2762  dsa_pointer shared_dp;
2763  bool found;
2764  uint32 typmod;
2765 
2766  /* If not even attached, nothing to do. */
2768  return NULL;
2769 
2770  /* Try to find a matching tuple descriptor in the record table. */
2771  key.shared = false;
2772  key.u.local_tupdesc = tupdesc;
2773  record_table_entry = (SharedRecordTableEntry *)
2775  if (record_table_entry)
2776  {
2777  Assert(record_table_entry->key.shared);
2779  record_table_entry);
2780  result = (TupleDesc)
2782  record_table_entry->key.u.shared_tupdesc);
2783  Assert(result->tdrefcount == -1);
2784 
2785  return result;
2786  }
2787 
2788  /* Allocate a new typmod number. This will be wasted if we error out. */
2789  typmod = (int)
2791  1);
2792 
2793  /* Copy the TupleDesc into shared memory. */
2794  shared_dp = share_tupledesc(CurrentSession->area, tupdesc, typmod);
2795 
2796  /*
2797  * Create an entry in the typmod table so that others will understand this
2798  * typmod number.
2799  */
2800  PG_TRY();
2801  {
2802  typmod_table_entry = (SharedTypmodTableEntry *)
2804  &typmod, &found);
2805  if (found)
2806  elog(ERROR, "cannot create duplicate shared record typmod");
2807  }
2808  PG_CATCH();
2809  {
2810  dsa_free(CurrentSession->area, shared_dp);
2811  PG_RE_THROW();
2812  }
2813  PG_END_TRY();
2814  typmod_table_entry->typmod = typmod;
2815  typmod_table_entry->shared_tupdesc = shared_dp;
2817  typmod_table_entry);
2818 
2819  /*
2820  * Finally create an entry in the record table so others with matching
2821  * tuple descriptors can reuse the typmod.
2822  */
2823  record_table_entry = (SharedRecordTableEntry *)
2825  &found);
2826  if (found)
2827  {
2828  /*
2829  * Someone concurrently inserted a matching tuple descriptor since the
2830  * first time we checked. Use that one instead.
2831  */
2833  record_table_entry);
2834 
2835  /* Might as well free up the space used by the one we created. */
2837  &typmod);
2838  Assert(found);
2839  dsa_free(CurrentSession->area, shared_dp);
2840 
2841  /* Return the one we found. */
2842  Assert(record_table_entry->key.shared);
2843  result = (TupleDesc)
2845  record_table_entry->key.u.shared_tupdesc);
2846  Assert(result->tdrefcount == -1);
2847 
2848  return result;
2849  }
2850 
2851  /* Store it and return it. */
2852  record_table_entry->key.shared = true;
2853  record_table_entry->key.u.shared_tupdesc = shared_dp;
2855  record_table_entry);
2856  result = (TupleDesc)
2857  dsa_get_address(CurrentSession->area, shared_dp);
2858  Assert(result->tdrefcount == -1);
2859 
2860  return result;
2861 }
static uint32 pg_atomic_fetch_add_u32(volatile pg_atomic_uint32 *ptr, int32 add_)
Definition: atomics.h:361
unsigned int uint32
Definition: c.h:506
void * dsa_get_address(dsa_area *area, dsa_pointer dp)
Definition: dsa.c:942
void dsa_free(dsa_area *area, dsa_pointer dp)
Definition: dsa.c:826
uint64 dsa_pointer
Definition: dsa.h:62
bool dshash_delete_key(dshash_table *hash_table, const void *key)
Definition: dshash.c:503
void dshash_release_lock(dshash_table *hash_table, void *entry)
Definition: dshash.c:558
void * dshash_find(dshash_table *hash_table, const void *key, bool exclusive)
Definition: dshash.c:390
void * dshash_find_or_insert(dshash_table *hash_table, const void *key, bool *found)
Definition: dshash.c:433
#define PG_RE_THROW()
Definition: elog.h: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::@33 u
dsa_pointer shared_tupdesc
Definition: typcache.c:187
pg_atomic_uint32 next_typmod
Definition: typcache.c:173
dsa_pointer shared_tupdesc
Definition: typcache.c:208
static dsa_pointer share_tupledesc(dsa_area *area, TupleDesc tupdesc, uint32 typmod)
Definition: typcache.c:2735

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

1315 {
1316  /* Look up the typcache entry --- we assume it survives indefinitely */
1318  ref->need_exprstate = need_exprstate;
1319  /* For safety, establish the callback before acquiring a refcount */
1320  ref->refctx = refctx;
1321  ref->dcc = NULL;
1323  ref->callback.arg = (void *) ref;
1325  /* Acquire refcount if there are constraints, and set up exported list */
1326  if (ref->tcache->domainData)
1327  {
1328  ref->dcc = ref->tcache->domainData;
1329  ref->dcc->dccRefCount++;
1330  if (ref->need_exprstate)
1332  ref->refctx);
1333  else
1334  ref->constraints = ref->dcc->constraints;
1335  }
1336  else
1337  ref->constraints = NIL;
1338 }
void MemoryContextRegisterResetCallback(MemoryContext context, MemoryContextCallback *cb)
Definition: mcxt.c:568
MemoryContext refctx
Definition: typcache.h:167
MemoryContextCallback callback
Definition: typcache.h:173
TypeCacheEntry * tcache
Definition: typcache.h:168
MemoryContextCallbackFunction func
Definition: palloc.h:49
static List * prep_domain_constraints(List *constraints, MemoryContext execctx)
Definition: typcache.c:1275
static void dccref_deletion_callback(void *arg)
Definition: typcache.c:1254

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

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

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

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

Referenced by compare_values_of_enum().

◆ load_multirangetype_info()

static void load_multirangetype_info ( TypeCacheEntry typentry)
static

Definition at line 972 of file typcache.c.

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

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

Referenced by cache_multirange_element_properties(), and lookup_type_cache().

◆ load_rangetype_info()

static void load_rangetype_info ( TypeCacheEntry typentry)
static

Definition at line 914 of file typcache.c.

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

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

Referenced by cache_range_element_properties(), and lookup_type_cache().

◆ load_typcache_tupdesc()

static void load_typcache_tupdesc ( TypeCacheEntry typentry)
static

Definition at line 880 of file typcache.c.

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

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

Referenced by cache_record_field_properties(), and lookup_type_cache().

◆ lookup_rowtype_tupdesc()

◆ lookup_rowtype_tupdesc_copy()

TupleDesc lookup_rowtype_tupdesc_copy ( Oid  type_id,
int32  typmod 
)

Definition at line 1867 of file typcache.c.

1868 {
1869  TupleDesc tmp;
1870 
1871  tmp = lookup_rowtype_tupdesc_internal(type_id, typmod, false);
1872  return CreateTupleDescCopyConstr(tmp);
1873 }
TupleDesc CreateTupleDescCopyConstr(TupleDesc tupdesc)
Definition: tupdesc.c:173

References CreateTupleDescCopyConstr(), and lookup_rowtype_tupdesc_internal().

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

◆ lookup_rowtype_tupdesc_domain()

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

Definition at line 1889 of file typcache.c.

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

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

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

◆ lookup_rowtype_tupdesc_internal()

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

Definition at line 1739 of file typcache.c.

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

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

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

◆ lookup_rowtype_tupdesc_noerror()

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

Definition at line 1850 of file typcache.c.

1851 {
1852  TupleDesc tupDesc;
1853 
1854  tupDesc = lookup_rowtype_tupdesc_internal(type_id, typmod, noError);
1855  if (tupDesc != NULL)
1856  PinTupleDesc(tupDesc);
1857  return tupDesc;
1858 }

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

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

References array_element_has_compare(), array_element_has_equality(), array_element_has_extended_hashing(), array_element_has_hashing(), Assert, BTEqualStrategyNumber, BTGreaterStrategyNumber, BTLessStrategyNumber, BTORDER_PROC, TypeCacheEntry::btree_opf, TypeCacheEntry::btree_opintype, CacheMemoryContext, CacheRegisterRelcacheCallback(), CacheRegisterSyscacheCallback(), TypeCacheEntry::cmp_proc, TypeCacheEntry::cmp_proc_finfo, CreateCacheMemoryContext(), ctl, TypeCacheEntry::domainBaseType, TypeCacheEntry::domainBaseTypmod, TypeCacheEntry::eq_opr, TypeCacheEntry::eq_opr_finfo, ereport, errcode(), errmsg(), ERROR, firstDomainTypeEntry, TypeCacheEntry::flags, fmgr_info_cxt(), FmgrInfo::fn_oid, get_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, 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, TypeCacheEntry::typlen, TypeCacheEntry::typrelid, TypeCacheEntry::typstorage, TypeCacheEntry::typsubscript, and TypeCacheEntry::typtype.

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

◆ multirange_element_has_extended_hashing()

static bool multirange_element_has_extended_hashing ( TypeCacheEntry typentry)
static

Definition at line 1674 of file typcache.c.

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

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

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

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

1276 {
1277  List *result = NIL;
1278  MemoryContext oldcxt;
1279  ListCell *lc;
1280 
1281  oldcxt = MemoryContextSwitchTo(execctx);
1282 
1283  foreach(lc, constraints)
1284  {
1286  DomainConstraintState *newr;
1287 
1289  newr->constrainttype = r->constrainttype;
1290  newr->name = r->name;
1291  newr->check_expr = r->check_expr;
1292  newr->check_exprstate = ExecInitExpr(r->check_expr, NULL);
1293 
1294  result = lappend(result, newr);
1295  }
1296 
1297  MemoryContextSwitchTo(oldcxt);
1298 
1299  return result;
1300 }
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:134
List * lappend(List *list, void *datum)
Definition: list.c:339
#define lfirst(lc)
Definition: pg_list.h:172
Definition: pg_list.h:54

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

Referenced by InitDomainConstraintRef(), and UpdateDomainConstraintRef().

◆ range_element_has_extended_hashing()

static bool range_element_has_extended_hashing ( TypeCacheEntry typentry)
static

Definition at line 1634 of file typcache.c.

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

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

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

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

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

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

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

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

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

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

1938 {
1939  RecordCacheEntry *left = (RecordCacheEntry *) a;
1940  RecordCacheEntry *right = (RecordCacheEntry *) b;
1941 
1942  return equalRowTypes(left->tupdesc, right->tupdesc) ? 0 : 1;
1943 }
bool equalRowTypes(TupleDesc tupdesc1, TupleDesc tupdesc2)
Definition: tupdesc.c:586

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

Referenced by assign_record_type_typmod().

◆ record_type_typmod_hash()

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

Definition at line 1926 of file typcache.c.

1927 {
1928  RecordCacheEntry *entry = (RecordCacheEntry *) data;
1929 
1930  return hashRowType(entry->tupdesc);
1931 }
const void * data
uint32 hashRowType(TupleDesc desc)
Definition: tupdesc.c:622

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

Referenced by assign_record_type_typmod().

◆ share_tupledesc()

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

Definition at line 2735 of file typcache.c.

2736 {
2737  dsa_pointer shared_dp;
2738  TupleDesc shared;
2739 
2740  shared_dp = dsa_allocate(area, TupleDescSize(tupdesc));
2741  shared = (TupleDesc) dsa_get_address(area, shared_dp);
2742  TupleDescCopy(shared, tupdesc);
2743  shared->tdtypmod = typmod;
2744 
2745  return shared_dp;
2746 }
#define dsa_allocate(area, size)
Definition: dsa.h:109
void TupleDescCopy(TupleDesc dst, TupleDesc src)
Definition: tupdesc.c:251
#define TupleDescSize(src)
Definition: tupdesc.h:102

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

Referenced by find_or_make_matching_shared_tupledesc(), and SharedRecordTypmodRegistryInit().

◆ shared_record_table_compare()

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

Definition at line 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 equalRowTypes(t1, t2) ? 0 : 1;
235 }
TupleDesc local_tupdesc
Definition: typcache.c:186
Definition: dsa.c:348

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

◆ shared_record_table_hash()

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

Definition at line 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 hashRowType(t);
253 }

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

◆ shared_record_typmod_registry_detach()

static void shared_record_typmod_registry_detach ( dsm_segment segment,
Datum  datum 
)
static

Definition at line 2868 of file typcache.c.

2869 {
2870  /* Be cautious here: maybe we didn't finish initializing. */
2871  if (CurrentSession->shared_record_table != NULL)
2872  {
2875  }
2876  if (CurrentSession->shared_typmod_table != NULL)
2877  {
2880  }
2882 }
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 2207 of file typcache.c.

2208 {
2209  MemoryContext old_context;
2210  dshash_table *record_table;
2211  dshash_table *typmod_table;
2212 
2214 
2215  /* We can't already be attached to a shared registry. */
2216  Assert(CurrentSession != NULL);
2217  Assert(CurrentSession->segment != NULL);
2218  Assert(CurrentSession->area != NULL);
2222 
2223  /*
2224  * We can't already have typmods in our local cache, because they'd clash
2225  * with those imported by SharedRecordTypmodRegistryInit. This should be
2226  * a freshly started parallel worker. If we ever support worker
2227  * recycling, a worker would need to zap its local cache in between
2228  * servicing different queries, in order to be able to call this and
2229  * synchronize typmods with a new leader; but that's problematic because
2230  * we can't be very sure that record-typmod-related state hasn't escaped
2231  * to anywhere else in the process.
2232  */
2233  Assert(NextRecordTypmod == 0);
2234 
2235  old_context = MemoryContextSwitchTo(TopMemoryContext);
2236 
2237  /* Attach to the two hash tables. */
2238  record_table = dshash_attach(CurrentSession->area,
2240  registry->record_table_handle,
2241  CurrentSession->area);
2242  typmod_table = dshash_attach(CurrentSession->area,
2244  registry->typmod_table_handle,
2245  NULL);
2246 
2247  MemoryContextSwitchTo(old_context);
2248 
2249  /*
2250  * Set up detach hook to run at worker exit. Currently this is the same
2251  * as the leader's detach hook, but in future they might need to be
2252  * different.
2253  */
2256  PointerGetDatum(registry));
2257 
2258  /*
2259  * Set up the session state that will tell assign_record_type_typmod and
2260  * lookup_rowtype_tupdesc_internal about the shared registry.
2261  */
2263  CurrentSession->shared_record_table = record_table;
2264  CurrentSession->shared_typmod_table = typmod_table;
2265 }
dshash_table * dshash_attach(dsa_area *area, const dshash_parameters *params, dshash_table_handle handle, void *arg)
Definition: dshash.c:270
void on_dsm_detach(dsm_segment *seg, on_dsm_detach_callback function, Datum arg)
Definition: dsm.c:1132
#define IsParallelWorker()
Definition: parallel.h:60
MemoryContext TopMemoryContext
Definition: mcxt.c:149
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
dsm_segment * segment
Definition: session.h:27
dshash_table_handle typmod_table_handle
Definition: typcache.c:171
dshash_table_handle record_table_handle
Definition: typcache.c:169
static const dshash_parameters srtr_typmod_table_params
Definition: typcache.c:266
static void shared_record_typmod_registry_detach(dsm_segment *segment, Datum datum)
Definition: typcache.c:2868
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 2086 of file typcache.c.

2087 {
2088  return sizeof(SharedRecordTypmodRegistry);
2089 }
struct SharedRecordTypmodRegistry SharedRecordTypmodRegistry
Definition: typcache.h:176

Referenced by GetSessionDsmHandle().

◆ SharedRecordTypmodRegistryInit()

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

Definition at line 2108 of file typcache.c.

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

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

Referenced by GetSessionDsmHandle().

◆ TypeCacheConstrCallback()

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

Definition at line 2424 of file typcache.c.

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

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

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

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

Referenced by lookup_type_cache().

◆ TypeCacheRelCallback()

static void TypeCacheRelCallback ( Datum  arg,
Oid  relid 
)
static

Definition at line 2290 of file typcache.c.

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

References Assert, TypeCacheEntry::flags, FreeTupleDesc(), hash_seq_init(), hash_seq_search(), InvalidOid, TCFLAGS_DOMAIN_BASE_IS_COMPOSITE, TCFLAGS_OPERATOR_FLAGS, TupleDescData::tdrefcount, TypeCacheEntry::tupDesc, TypeCacheEntry::tupDesc_identifier, TypeCacheHash, TypeCacheEntry::typrelid, and TypeCacheEntry::typtype.

Referenced by lookup_type_cache().

◆ TypeCacheTypCallback()

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

Definition at line 2355 of file typcache.c.

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

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

Referenced by lookup_type_cache().

◆ UpdateDomainConstraintRef()

void UpdateDomainConstraintRef ( DomainConstraintRef ref)

Definition at line 1351 of file typcache.c.

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

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

Referenced by assign_record_type_typmod().

◆ srtr_record_table_params

const dshash_parameters srtr_record_table_params
static
Initial value:
= {
}
void dshash_memcpy(void *dest, const void *src, size_t size, void *arg)
Definition: dshash.c:590
@ LWTRANCHE_PER_SESSION_RECORD_TYPE
Definition: lwlock.h:197
static int shared_record_table_compare(const void *a, const void *b, size_t size, void *arg)
Definition: typcache.c: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:198

Definition at line 266 of file typcache.c.

Referenced by SharedRecordTypmodRegistryAttach(), and SharedRecordTypmodRegistryInit().

◆ tupledesc_id_counter

◆ TypeCacheHash

HTAB* TypeCacheHash = NULL
static