PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
typcache.c File Reference
#include "postgres.h"
#include <limits.h>
#include "access/hash.h"
#include "access/heapam.h"
#include "access/htup_details.h"
#include "access/nbtree.h"
#include "access/parallel.h"
#include "access/session.h"
#include "catalog/indexing.h"
#include "catalog/pg_am.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_enum.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_range.h"
#include "catalog/pg_type.h"
#include "commands/defrem.h"
#include "executor/executor.h"
#include "lib/dshash.h"
#include "optimizer/planner.h"
#include "storage/lwlock.h"
#include "utils/builtins.h"
#include "utils/catcache.h"
#include "utils/fmgroids.h"
#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
#include "utils/typcache.h"
Include dependency graph for typcache.c:

Go to the source code of this file.

Data Structures

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

Macros

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

Typedefs

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

Functions

static int shared_record_table_compare (const void *a, const void *b, size_t size, void *arg)
 
static uint32 shared_record_table_hash (const void *a, size_t size, void *arg)
 
static void load_typcache_tupdesc (TypeCacheEntry *typentry)
 
static void load_rangetype_info (TypeCacheEntry *typentry)
 
static void load_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 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 void TypeCacheRelCallback (Datum arg, Oid relid)
 
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)
 
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)
 
size_t SharedRecordTypmodRegistryEstimate (void)
 
void SharedRecordTypmodRegistryInit (SharedRecordTypmodRegistry *registry, dsm_segment *segment, dsa_area *area)
 
void SharedRecordTypmodRegistryAttach (SharedRecordTypmodRegistry *registry)
 
static bool enum_known_sorted (TypeCacheEnumData *enumdata, Oid arg)
 
int compare_values_of_enum (TypeCacheEntry *tcache, Oid arg1, Oid arg2)
 

Variables

static HTABTypeCacheHash = NULL
 
static TypeCacheEntryfirstDomainTypeEntry = NULL
 
static const dshash_parameters srtr_record_table_params
 
static const dshash_parameters srtr_typmod_table_params
 
static HTABRecordCacheHash = NULL
 
static TupleDescRecordCacheArray = NULL
 
static int32 RecordCacheArrayLen = 0
 
static int32 NextRecordTypmod = 0
 

Macro Definition Documentation

#define TCFLAGS_CHECKED_BTREE_OPCLASS   0x000001

Definition at line 82 of file typcache.c.

Referenced by lookup_type_cache().

#define TCFLAGS_CHECKED_CMP_PROC   0x000020

Definition at line 87 of file typcache.c.

Referenced by lookup_type_cache().

#define TCFLAGS_CHECKED_DOMAIN_CONSTRAINTS   0x010000
#define TCFLAGS_CHECKED_EQ_OPR   0x000004

Definition at line 84 of file typcache.c.

Referenced by lookup_type_cache().

#define TCFLAGS_CHECKED_FIELD_PROPERTIES   0x002000
#define TCFLAGS_CHECKED_GT_OPR   0x000010

Definition at line 86 of file typcache.c.

Referenced by lookup_type_cache().

#define TCFLAGS_CHECKED_HASH_EXTENDED_PROC   0x000080

Definition at line 89 of file typcache.c.

Referenced by lookup_type_cache().

#define TCFLAGS_CHECKED_HASH_OPCLASS   0x000002

Definition at line 83 of file typcache.c.

Referenced by lookup_type_cache().

#define TCFLAGS_CHECKED_HASH_PROC   0x000040

Definition at line 88 of file typcache.c.

Referenced by lookup_type_cache().

#define TCFLAGS_CHECKED_LT_OPR   0x000008

Definition at line 85 of file typcache.c.

Referenced by lookup_type_cache().

#define TCFLAGS_HAVE_ELEM_COMPARE   0x000400

Definition at line 92 of file typcache.c.

Referenced by array_element_has_compare(), and cache_array_element_properties().

#define TCFLAGS_HAVE_ELEM_EQUALITY   0x000200

Definition at line 91 of file typcache.c.

Referenced by array_element_has_equality(), and cache_array_element_properties().

#define TCFLAGS_HAVE_ELEM_EXTENDED_HASHING   0x001000
#define TCFLAGS_HAVE_ELEM_HASHING   0x000800
#define TCFLAGS_HAVE_FIELD_COMPARE   0x008000

Definition at line 97 of file typcache.c.

Referenced by cache_record_field_properties(), and record_fields_have_compare().

#define TCFLAGS_HAVE_FIELD_EQUALITY   0x004000

Definition at line 96 of file typcache.c.

Referenced by cache_record_field_properties(), and record_fields_have_equality().

Typedef Documentation

Function Documentation

static bool array_element_has_compare ( TypeCacheEntry typentry)
static

Definition at line 1287 of file typcache.c.

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

Referenced by lookup_type_cache().

1288 {
1289  if (!(typentry->flags & TCFLAGS_CHECKED_ELEM_PROPERTIES))
1291  return (typentry->flags & TCFLAGS_HAVE_ELEM_COMPARE) != 0;
1292 }
#define TCFLAGS_HAVE_ELEM_COMPARE
Definition: typcache.c:92
#define TCFLAGS_CHECKED_ELEM_PROPERTIES
Definition: typcache.c:90
static void cache_array_element_properties(TypeCacheEntry *typentry)
Definition: typcache.c:1311
static bool array_element_has_equality ( TypeCacheEntry typentry)
static

Definition at line 1279 of file typcache.c.

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

Referenced by lookup_type_cache().

1280 {
1281  if (!(typentry->flags & TCFLAGS_CHECKED_ELEM_PROPERTIES))
1283  return (typentry->flags & TCFLAGS_HAVE_ELEM_EQUALITY) != 0;
1284 }
#define TCFLAGS_CHECKED_ELEM_PROPERTIES
Definition: typcache.c:90
static void cache_array_element_properties(TypeCacheEntry *typentry)
Definition: typcache.c:1311
#define TCFLAGS_HAVE_ELEM_EQUALITY
Definition: typcache.c:91
static bool array_element_has_extended_hashing ( TypeCacheEntry typentry)
static

Definition at line 1303 of file typcache.c.

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

Referenced by lookup_type_cache().

1304 {
1305  if (!(typentry->flags & TCFLAGS_CHECKED_ELEM_PROPERTIES))
1307  return (typentry->flags & TCFLAGS_HAVE_ELEM_EXTENDED_HASHING) != 0;
1308 }
#define TCFLAGS_HAVE_ELEM_EXTENDED_HASHING
Definition: typcache.c:94
#define TCFLAGS_CHECKED_ELEM_PROPERTIES
Definition: typcache.c:90
static void cache_array_element_properties(TypeCacheEntry *typentry)
Definition: typcache.c:1311
static bool array_element_has_hashing ( TypeCacheEntry typentry)
static

Definition at line 1295 of file typcache.c.

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

Referenced by lookup_type_cache().

1296 {
1297  if (!(typentry->flags & TCFLAGS_CHECKED_ELEM_PROPERTIES))
1299  return (typentry->flags & TCFLAGS_HAVE_ELEM_HASHING) != 0;
1300 }
#define TCFLAGS_CHECKED_ELEM_PROPERTIES
Definition: typcache.c:90
static void cache_array_element_properties(TypeCacheEntry *typentry)
Definition: typcache.c:1311
#define TCFLAGS_HAVE_ELEM_HASHING
Definition: typcache.c:93
void assign_record_type_typmod ( TupleDesc  tupDesc)

Definition at line 1652 of file typcache.c.

References Assert, CacheMemoryContext, CreateCacheMemoryContext(), CreateTupleDescCopy(), ensure_record_cache_typmod_slot_exists(), HASHCTL::entrysize, find_or_make_matching_shared_tupledesc(), HASHCTL::hash, HASH_COMPARE, hash_create(), HASH_ELEM, HASH_ENTER, HASH_FUNCTION, hash_search(), HASHCTL::keysize, HASHCTL::match, MemoryContextSwitchTo(), MemSet, NextRecordTypmod, record_type_typmod_compare(), record_type_typmod_hash(), RECORDOID, tupleDesc::tdrefcount, tupleDesc::tdtypeid, tupleDesc::tdtypmod, and RecordCacheEntry::tupdesc.

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

1653 {
1654  RecordCacheEntry *recentry;
1655  TupleDesc entDesc;
1656  bool found;
1657  MemoryContext oldcxt;
1658 
1659  Assert(tupDesc->tdtypeid == RECORDOID);
1660 
1661  if (RecordCacheHash == NULL)
1662  {
1663  /* First time through: initialize the hash table */
1664  HASHCTL ctl;
1665 
1666  MemSet(&ctl, 0, sizeof(ctl));
1667  ctl.keysize = sizeof(TupleDesc); /* just the pointer */
1668  ctl.entrysize = sizeof(RecordCacheEntry);
1671  RecordCacheHash = hash_create("Record information cache", 64,
1672  &ctl,
1674 
1675  /* Also make sure CacheMemoryContext exists */
1676  if (!CacheMemoryContext)
1678  }
1679 
1680  /* Find or create a hashtable entry for this tuple descriptor */
1682  (void *) &tupDesc,
1683  HASH_ENTER, &found);
1684  if (found && recentry->tupdesc != NULL)
1685  {
1686  tupDesc->tdtypmod = recentry->tupdesc->tdtypmod;
1687  return;
1688  }
1689 
1690  /* Not present, so need to manufacture an entry */
1691  recentry->tupdesc = NULL;
1693 
1694  /* Look in the SharedRecordTypmodRegistry, if attached */
1695  entDesc = find_or_make_matching_shared_tupledesc(tupDesc);
1696  if (entDesc == NULL)
1697  {
1698  /* Reference-counted local cache only. */
1699  entDesc = CreateTupleDescCopy(tupDesc);
1700  entDesc->tdrefcount = 1;
1701  entDesc->tdtypmod = NextRecordTypmod++;
1702  }
1704  RecordCacheArray[entDesc->tdtypmod] = entDesc;
1705  recentry->tupdesc = entDesc;
1706 
1707  /* Update the caller's tuple descriptor. */
1708  tupDesc->tdtypmod = entDesc->tdtypmod;
1709 
1710  MemoryContextSwitchTo(oldcxt);
1711 }
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:102
Oid tdtypeid
Definition: tupdesc.h:74
#define HASH_ELEM
Definition: hsearch.h:87
static TupleDesc find_or_make_matching_shared_tupledesc(TupleDesc tupdesc)
Definition: typcache.c:2341
struct RecordCacheEntry RecordCacheEntry
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Size entrysize
Definition: hsearch.h:73
#define MemSet(start, val, len)
Definition: c.h:863
static HTAB * RecordCacheHash
Definition: typcache.c:261
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:902
int32 tdtypmod
Definition: tupdesc.h:75
static TupleDesc * RecordCacheArray
Definition: typcache.c:263
#define RECORDOID
Definition: pg_type.h:680
static int32 NextRecordTypmod
Definition: typcache.c:265
HTAB * hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)
Definition: dynahash.c:316
static void ensure_record_cache_typmod_slot_exists(int32 typmod)
Definition: typcache.c:1463
Size keysize
Definition: hsearch.h:72
HashCompareFunc match
Definition: hsearch.h:75
struct tupleDesc * TupleDesc
static uint32 record_type_typmod_hash(const void *data, size_t size)
Definition: typcache.c:1625
#define Assert(condition)
Definition: c.h:681
#define HASH_COMPARE
Definition: hsearch.h:90
void CreateCacheMemoryContext(void)
Definition: catcache.c:636
static int record_type_typmod_compare(const void *a, const void *b, size_t size)
Definition: typcache.c:1636
int tdrefcount
Definition: tupdesc.h:77
TupleDesc tupdesc
Definition: typcache.c:147
HashValueFunc hash
Definition: hsearch.h:74
#define HASH_FUNCTION
Definition: hsearch.h:89
MemoryContext CacheMemoryContext
Definition: mcxt.c:46
static void cache_array_element_properties ( TypeCacheEntry typentry)
static

Definition at line 1311 of file typcache.c.

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

1312 {
1313  Oid elem_type = get_base_element_type(typentry->type_id);
1314 
1315  if (OidIsValid(elem_type))
1316  {
1317  TypeCacheEntry *elementry;
1318 
1319  elementry = lookup_type_cache(elem_type,
1324  if (OidIsValid(elementry->eq_opr))
1325  typentry->flags |= TCFLAGS_HAVE_ELEM_EQUALITY;
1326  if (OidIsValid(elementry->cmp_proc))
1327  typentry->flags |= TCFLAGS_HAVE_ELEM_COMPARE;
1328  if (OidIsValid(elementry->hash_proc))
1329  typentry->flags |= TCFLAGS_HAVE_ELEM_HASHING;
1330  if (OidIsValid(elementry->hash_extended_proc))
1332  }
1334 }
#define TCFLAGS_HAVE_ELEM_COMPARE
Definition: typcache.c:92
#define TYPECACHE_EQ_OPR
Definition: typcache.h:114
#define TCFLAGS_HAVE_ELEM_EXTENDED_HASHING
Definition: typcache.c:94
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:532
#define TCFLAGS_CHECKED_ELEM_PROPERTIES
Definition: typcache.c:90
Oid hash_extended_proc
Definition: typcache.h:61
#define TYPECACHE_HASH_EXTENDED_PROC
Definition: typcache.h:127
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:310
#define TYPECACHE_CMP_PROC
Definition: typcache.h:117
#define TCFLAGS_HAVE_ELEM_EQUALITY
Definition: typcache.c:91
#define TCFLAGS_HAVE_ELEM_HASHING
Definition: typcache.c:93
Oid get_base_element_type(Oid typid)
Definition: lsyscache.c:2557
#define TYPECACHE_HASH_PROC
Definition: typcache.h:118
static void cache_range_element_properties ( TypeCacheEntry typentry)
static

Definition at line 1436 of file typcache.c.

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, TypeCacheEntry::typtype, and TYPTYPE_RANGE.

Referenced by range_element_has_extended_hashing(), and range_element_has_hashing().

1437 {
1438  /* load up subtype link if we didn't already */
1439  if (typentry->rngelemtype == NULL &&
1440  typentry->typtype == TYPTYPE_RANGE)
1441  load_rangetype_info(typentry);
1442 
1443  if (typentry->rngelemtype != NULL)
1444  {
1445  TypeCacheEntry *elementry;
1446 
1447  /* might need to calculate subtype's hash function properties */
1448  elementry = lookup_type_cache(typentry->rngelemtype->type_id,
1451  if (OidIsValid(elementry->hash_proc))
1452  typentry->flags |= TCFLAGS_HAVE_ELEM_HASHING;
1453  if (OidIsValid(elementry->hash_extended_proc))
1455  }
1457 }
#define TCFLAGS_HAVE_ELEM_EXTENDED_HASHING
Definition: typcache.c:94
#define OidIsValid(objectId)
Definition: c.h:532
#define TCFLAGS_CHECKED_ELEM_PROPERTIES
Definition: typcache.c:90
Oid hash_extended_proc
Definition: typcache.h:61
struct TypeCacheEntry * rngelemtype
Definition: typcache.h:88
#define TYPTYPE_RANGE
Definition: pg_type.h:725
#define TYPECACHE_HASH_EXTENDED_PROC
Definition: typcache.h:127
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:310
static void load_rangetype_info(TypeCacheEntry *typentry)
Definition: typcache.c:792
char typtype
Definition: typcache.h:41
#define TCFLAGS_HAVE_ELEM_HASHING
Definition: typcache.c:93
#define TYPECACHE_HASH_PROC
Definition: typcache.h:118
static void cache_record_field_properties ( TypeCacheEntry typentry)
static

Definition at line 1357 of file typcache.c.

References TypeCacheEntry::cmp_proc, DecrTupleDescRefCount(), TypeCacheEntry::eq_opr, TypeCacheEntry::flags, i, IncrTupleDescRefCount(), load_typcache_tupdesc(), lookup_type_cache(), tupleDesc::natts, OidIsValid, RECORDOID, TCFLAGS_CHECKED_FIELD_PROPERTIES, TCFLAGS_HAVE_FIELD_COMPARE, TCFLAGS_HAVE_FIELD_EQUALITY, TypeCacheEntry::tupDesc, TupleDescAttr, TypeCacheEntry::type_id, TYPECACHE_CMP_PROC, TYPECACHE_EQ_OPR, TypeCacheEntry::typtype, and TYPTYPE_COMPOSITE.

Referenced by record_fields_have_compare(), and record_fields_have_equality().

1358 {
1359  /*
1360  * For type RECORD, we can't really tell what will work, since we don't
1361  * have access here to the specific anonymous type. Just assume that
1362  * everything will (we may get a failure at runtime ...)
1363  */
1364  if (typentry->type_id == RECORDOID)
1365  typentry->flags |= (TCFLAGS_HAVE_FIELD_EQUALITY |
1367  else if (typentry->typtype == TYPTYPE_COMPOSITE)
1368  {
1369  TupleDesc tupdesc;
1370  int newflags;
1371  int i;
1372 
1373  /* Fetch composite type's tupdesc if we don't have it already */
1374  if (typentry->tupDesc == NULL)
1375  load_typcache_tupdesc(typentry);
1376  tupdesc = typentry->tupDesc;
1377 
1378  /* Must bump the refcount while we do additional catalog lookups */
1379  IncrTupleDescRefCount(tupdesc);
1380 
1381  /* Have each property if all non-dropped fields have the property */
1382  newflags = (TCFLAGS_HAVE_FIELD_EQUALITY |
1384  for (i = 0; i < tupdesc->natts; i++)
1385  {
1386  TypeCacheEntry *fieldentry;
1387  Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
1388 
1389  if (attr->attisdropped)
1390  continue;
1391 
1392  fieldentry = lookup_type_cache(attr->atttypid,
1395  if (!OidIsValid(fieldentry->eq_opr))
1396  newflags &= ~TCFLAGS_HAVE_FIELD_EQUALITY;
1397  if (!OidIsValid(fieldentry->cmp_proc))
1398  newflags &= ~TCFLAGS_HAVE_FIELD_COMPARE;
1399 
1400  /* We can drop out of the loop once we disprove all bits */
1401  if (newflags == 0)
1402  break;
1403  }
1404  typentry->flags |= newflags;
1405 
1406  DecrTupleDescRefCount(tupdesc);
1407  }
1409 }
static void load_typcache_tupdesc(TypeCacheEntry *typentry)
Definition: typcache.c:764
void IncrTupleDescRefCount(TupleDesc tupdesc)
Definition: tupdesc.c:301
#define TCFLAGS_CHECKED_FIELD_PROPERTIES
Definition: typcache.c:95
#define TYPTYPE_COMPOSITE
Definition: pg_type.h:721
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:84
#define TYPECACHE_EQ_OPR
Definition: typcache.h:114
#define OidIsValid(objectId)
Definition: c.h:532
int natts
Definition: tupdesc.h:73
#define TCFLAGS_HAVE_FIELD_COMPARE
Definition: typcache.c:97
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:187
#define RECORDOID
Definition: pg_type.h:680
#define TCFLAGS_HAVE_FIELD_EQUALITY
Definition: typcache.c:96
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:310
#define TYPECACHE_CMP_PROC
Definition: typcache.h:117
char typtype
Definition: typcache.h:41
void DecrTupleDescRefCount(TupleDesc tupdesc)
Definition: tupdesc.c:319
int i
TupleDesc tupDesc
Definition: typcache.h:80
int compare_values_of_enum ( TypeCacheEntry tcache,
Oid  arg1,
Oid  arg2 
)

Definition at line 2057 of file typcache.c.

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

2058 {
2059  TypeCacheEnumData *enumdata;
2060  EnumItem *item1;
2061  EnumItem *item2;
2062 
2063  /*
2064  * Equal OIDs are certainly equal --- this case was probably handled by
2065  * our caller, but we may as well check.
2066  */
2067  if (arg1 == arg2)
2068  return 0;
2069 
2070  /* Load up the cache if first time through */
2071  if (tcache->enumData == NULL)
2072  load_enum_cache_data(tcache);
2073  enumdata = tcache->enumData;
2074 
2075  /*
2076  * If both OIDs are known-sorted, we can just compare them directly.
2077  */
2078  if (enum_known_sorted(enumdata, arg1) &&
2079  enum_known_sorted(enumdata, arg2))
2080  {
2081  if (arg1 < arg2)
2082  return -1;
2083  else
2084  return 1;
2085  }
2086 
2087  /*
2088  * Slow path: we have to identify their actual sort-order positions.
2089  */
2090  item1 = find_enumitem(enumdata, arg1);
2091  item2 = find_enumitem(enumdata, arg2);
2092 
2093  if (item1 == NULL || item2 == NULL)
2094  {
2095  /*
2096  * We couldn't find one or both values. That means the enum has
2097  * changed under us, so re-initialize the cache and try again. We
2098  * don't bother retrying the known-sorted case in this path.
2099  */
2100  load_enum_cache_data(tcache);
2101  enumdata = tcache->enumData;
2102 
2103  item1 = find_enumitem(enumdata, arg1);
2104  item2 = find_enumitem(enumdata, arg2);
2105 
2106  /*
2107  * If we still can't find the values, complain: we must have corrupt
2108  * data.
2109  */
2110  if (item1 == NULL)
2111  elog(ERROR, "enum value %u not found in cache for enum %s",
2112  arg1, format_type_be(tcache->type_id));
2113  if (item2 == NULL)
2114  elog(ERROR, "enum value %u not found in cache for enum %s",
2115  arg2, format_type_be(tcache->type_id));
2116  }
2117 
2118  if (item1->sort_order < item2->sort_order)
2119  return -1;
2120  else if (item1->sort_order > item2->sort_order)
2121  return 1;
2122  else
2123  return 0;
2124 }
struct TypeCacheEnumData * enumData
Definition: typcache.h:107
char * format_type_be(Oid type_oid)
Definition: format_type.c:94
#define ERROR
Definition: elog.h:43
static bool enum_known_sorted(TypeCacheEnumData *enumdata, Oid arg)
Definition: typcache.c:2028
static EnumItem * find_enumitem(TypeCacheEnumData *enumdata, Oid arg)
Definition: typcache.c:2285
static void load_enum_cache_data(TypeCacheEntry *tcache)
Definition: typcache.c:2130
float4 sort_order
Definition: typcache.c:123
#define elog
Definition: elog.h:219
static void dccref_deletion_callback ( void *  arg)
static

Definition at line 1106 of file typcache.c.

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

Referenced by InitDomainConstraintRef().

1107 {
1109  DomainConstraintCache *dcc = ref->dcc;
1110 
1111  /* Paranoia --- be sure link is nulled before trying to release */
1112  if (dcc)
1113  {
1114  ref->constraints = NIL;
1115  ref->dcc = NULL;
1116  decr_dcc_refcount(dcc);
1117  }
1118 }
#define NIL
Definition: pg_list.h:69
DomainConstraintCache * dcc
Definition: typcache.h:144
void * arg
static void decr_dcc_refcount(DomainConstraintCache *dcc)
Definition: typcache.c:1095
static int dcs_cmp ( const void *  a,
const void *  b 
)
static

Definition at line 1082 of file typcache.c.

Referenced by load_domaintype_info().

1083 {
1084  const DomainConstraintState *const *ca = (const DomainConstraintState *const *) a;
1085  const DomainConstraintState *const *cb = (const DomainConstraintState *const *) b;
1086 
1087  return strcmp((*ca)->name, (*cb)->name);
1088 }
static void decr_dcc_refcount ( DomainConstraintCache dcc)
static

Definition at line 1095 of file typcache.c.

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

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

1096 {
1097  Assert(dcc->dccRefCount > 0);
1098  if (--(dcc->dccRefCount) <= 0)
1100 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:200
MemoryContext dccContext
Definition: typcache.c:115
#define Assert(condition)
Definition: c.h:681
bool DomainHasConstraints ( Oid  type_id)

Definition at line 1252 of file typcache.c.

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

Referenced by ATColumnChangeRequiresRewrite(), and ATExecAddColumn().

1253 {
1254  TypeCacheEntry *typentry;
1255 
1256  /*
1257  * Note: a side effect is to cause the typcache's domain data to become
1258  * valid. This is fine since we'll likely need it soon if there is any.
1259  */
1260  typentry = lookup_type_cache(type_id, TYPECACHE_DOMAIN_INFO);
1261 
1262  return (typentry->domainData != NULL);
1263 }
DomainConstraintCache * domainData
Definition: typcache.h:98
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:310
#define TYPECACHE_DOMAIN_INFO
Definition: typcache.h:126
static void ensure_record_cache_typmod_slot_exists ( int32  typmod)
static

Definition at line 1463 of file typcache.c.

References CacheMemoryContext, MemoryContextAllocZero(), RecordCacheArrayLen, and repalloc().

Referenced by assign_record_type_typmod(), and lookup_rowtype_tupdesc_internal().

1464 {
1465  if (RecordCacheArray == NULL)
1466  {
1469  RecordCacheArrayLen = 64;
1470  }
1471 
1472  if (typmod >= RecordCacheArrayLen)
1473  {
1474  int32 newlen = RecordCacheArrayLen * 2;
1475 
1476  while (typmod >= newlen)
1477  newlen *= 2;
1478 
1480  newlen * sizeof(TupleDesc));
1482  (newlen - RecordCacheArrayLen) * sizeof(TupleDesc));
1483  RecordCacheArrayLen = newlen;
1484  }
1485 }
signed int int32
Definition: c.h:246
static TupleDesc * RecordCacheArray
Definition: typcache.c:263
static int32 RecordCacheArrayLen
Definition: typcache.c:264
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:741
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:962
MemoryContext CacheMemoryContext
Definition: mcxt.c:46
static bool enum_known_sorted ( TypeCacheEnumData enumdata,
Oid  arg 
)
inlinestatic

Definition at line 2028 of file typcache.c.

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

Referenced by compare_values_of_enum().

2029 {
2030  Oid offset;
2031 
2032  if (arg < enumdata->bitmap_base)
2033  return false;
2034  offset = arg - enumdata->bitmap_base;
2035  if (offset > (Oid) INT_MAX)
2036  return false;
2037  return bms_is_member((int) offset, enumdata->sorted_values);
2038 }
unsigned int Oid
Definition: postgres_ext.h:31
Bitmapset * sorted_values
Definition: typcache.c:129
void * arg
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:420
static int enum_oid_cmp ( const void *  left,
const void *  right 
)
static

Definition at line 2302 of file typcache.c.

References EnumItem::enum_oid.

Referenced by find_enumitem(), and load_enum_cache_data().

2303 {
2304  const EnumItem *l = (const EnumItem *) left;
2305  const EnumItem *r = (const EnumItem *) right;
2306 
2307  if (l->enum_oid < r->enum_oid)
2308  return -1;
2309  else if (l->enum_oid > r->enum_oid)
2310  return 1;
2311  else
2312  return 0;
2313 }
Oid enum_oid
Definition: typcache.c:122
static EnumItem * find_enumitem ( TypeCacheEnumData enumdata,
Oid  arg 
)
static

Definition at line 2285 of file typcache.c.

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

Referenced by compare_values_of_enum().

2286 {
2287  EnumItem srch;
2288 
2289  /* On some versions of Solaris, bsearch of zero items dumps core */
2290  if (enumdata->num_values <= 0)
2291  return NULL;
2292 
2293  srch.enum_oid = arg;
2294  return bsearch(&srch, enumdata->enum_values, enumdata->num_values,
2295  sizeof(EnumItem), enum_oid_cmp);
2296 }
EnumItem enum_values[FLEXIBLE_ARRAY_MEMBER]
Definition: typcache.c:131
Oid enum_oid
Definition: typcache.c:122
static int enum_oid_cmp(const void *left, const void *right)
Definition: typcache.c:2302
void * arg
static TupleDesc find_or_make_matching_shared_tupledesc ( TupleDesc  tupdesc)
static

Definition at line 2341 of file typcache.c.

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, SharedRecordTableKey::local_tupdesc, 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, tupleDesc::tdrefcount, SharedTypmodTableEntry::typmod, and SharedRecordTableKey::u.

Referenced by assign_record_type_typmod().

2342 {
2343  TupleDesc result;
2345  SharedRecordTableEntry *record_table_entry;
2346  SharedTypmodTableEntry *typmod_table_entry;
2347  dsa_pointer shared_dp;
2348  bool found;
2349  uint32 typmod;
2350 
2351  /* If not even attached, nothing to do. */
2353  return NULL;
2354 
2355  /* Try to find a matching tuple descriptor in the record table. */
2356  key.shared = false;
2357  key.u.local_tupdesc = tupdesc;
2358  record_table_entry = (SharedRecordTableEntry *)
2360  if (record_table_entry)
2361  {
2362  Assert(record_table_entry->key.shared);
2364  record_table_entry);
2365  result = (TupleDesc)
2367  record_table_entry->key.u.shared_tupdesc);
2368  Assert(result->tdrefcount == -1);
2369 
2370  return result;
2371  }
2372 
2373  /* Allocate a new typmod number. This will be wasted if we error out. */
2374  typmod = (int)
2376  1);
2377 
2378  /* Copy the TupleDesc into shared memory. */
2379  shared_dp = share_tupledesc(CurrentSession->area, tupdesc, typmod);
2380 
2381  /*
2382  * Create an entry in the typmod table so that others will understand this
2383  * typmod number.
2384  */
2385  PG_TRY();
2386  {
2387  typmod_table_entry = (SharedTypmodTableEntry *)
2389  &typmod, &found);
2390  if (found)
2391  elog(ERROR, "cannot create duplicate shared record typmod");
2392  }
2393  PG_CATCH();
2394  {
2395  dsa_free(CurrentSession->area, shared_dp);
2396  PG_RE_THROW();
2397  }
2398  PG_END_TRY();
2399  typmod_table_entry->typmod = typmod;
2400  typmod_table_entry->shared_tupdesc = shared_dp;
2402  typmod_table_entry);
2403 
2404  /*
2405  * Finally create an entry in the record table so others with matching
2406  * tuple descriptors can reuse the typmod.
2407  */
2408  record_table_entry = (SharedRecordTableEntry *)
2410  &found);
2411  if (found)
2412  {
2413  /*
2414  * Someone concurrently inserted a matching tuple descriptor since the
2415  * first time we checked. Use that one instead.
2416  */
2418  record_table_entry);
2419 
2420  /* Might as well free up the space used by the one we created. */
2422  &typmod);
2423  Assert(found);
2424  dsa_free(CurrentSession->area, shared_dp);
2425 
2426  /* Return the one we found. */
2427  Assert(record_table_entry->key.shared);
2428  result = (TupleDesc)
2430  record_table_entry->key.shared);
2431  Assert(result->tdrefcount == -1);
2432 
2433  return result;
2434  }
2435 
2436  /* Store it and return it. */
2437  record_table_entry->key.shared = true;
2438  record_table_entry->key.u.shared_tupdesc = shared_dp;
2440  record_table_entry);
2441  result = (TupleDesc)
2442  dsa_get_address(CurrentSession->area, shared_dp);
2443  Assert(result->tdrefcount == -1);
2444 
2445  return result;
2446 }
Session * CurrentSession
Definition: session.c:48
dshash_table * shared_record_table
Definition: session.h:32
SharedRecordTableKey key
Definition: typcache.c:186
void dshash_release_lock(dshash_table *hash_table, void *entry)
Definition: dshash.c:561
uint64 dsa_pointer
Definition: dsa.h:62
void * dsa_get_address(dsa_area *area, dsa_pointer dp)
Definition: dsa.c:924
dsa_pointer shared_tupdesc
Definition: typcache.c:196
pg_atomic_uint32 next_typmod
Definition: typcache.c:161
#define ERROR
Definition: elog.h:43
dsa_area * area
Definition: session.h:28
unsigned int uint32
Definition: c.h:258
dsa_pointer shared_tupdesc
Definition: typcache.c:175
struct SharedRecordTypmodRegistry * shared_typmod_registry
Definition: session.h:31
struct tupleDesc * TupleDesc
dshash_table * shared_typmod_table
Definition: session.h:33
union SharedRecordTableKey::@36 u
static uint32 pg_atomic_fetch_add_u32(volatile pg_atomic_uint32 *ptr, int32 add_)
Definition: atomics.h:339
#define PG_CATCH()
Definition: elog.h:293
bool dshash_delete_key(dshash_table *hash_table, const void *key)
Definition: dshash.c:502
#define Assert(condition)
Definition: c.h:681
static dsa_pointer share_tupledesc(dsa_area *area, TupleDesc tupdesc, uint32 typmod)
Definition: typcache.c:2320
#define PG_RE_THROW()
Definition: elog.h:314
void dsa_free(dsa_area *area, dsa_pointer dp)
Definition: dsa.c:812
int tdrefcount
Definition: tupdesc.h:77
void * dshash_find_or_insert(dshash_table *hash_table, const void *key, bool *found)
Definition: dshash.c:430
TupleDesc local_tupdesc
Definition: typcache.c:174
void * dshash_find(dshash_table *hash_table, const void *key, bool exclusive)
Definition: dshash.c:385
#define elog
Definition: elog.h:219
#define PG_TRY()
Definition: elog.h:284
#define PG_END_TRY()
Definition: elog.h:300
void InitDomainConstraintRef ( Oid  type_id,
DomainConstraintRef ref,
MemoryContext  refctx,
bool  need_exprstate 
)

Definition at line 1165 of file typcache.c.

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_INFO.

Referenced by domain_state_setup(), and ExecInitCoerceToDomain().

1167 {
1168  /* Look up the typcache entry --- we assume it survives indefinitely */
1170  ref->need_exprstate = need_exprstate;
1171  /* For safety, establish the callback before acquiring a refcount */
1172  ref->refctx = refctx;
1173  ref->dcc = NULL;
1175  ref->callback.arg = (void *) ref;
1177  /* Acquire refcount if there are constraints, and set up exported list */
1178  if (ref->tcache->domainData)
1179  {
1180  ref->dcc = ref->tcache->domainData;
1181  ref->dcc->dccRefCount++;
1182  if (ref->need_exprstate)
1184  ref->refctx);
1185  else
1186  ref->constraints = ref->dcc->constraints;
1187  }
1188  else
1189  ref->constraints = NIL;
1190 }
MemoryContextCallback callback
Definition: typcache.h:145
MemoryContextCallbackFunction func
Definition: palloc.h:49
#define NIL
Definition: pg_list.h:69
DomainConstraintCache * dcc
Definition: typcache.h:144
static void dccref_deletion_callback(void *arg)
Definition: typcache.c:1106
DomainConstraintCache * domainData
Definition: typcache.h:98
MemoryContext refctx
Definition: typcache.h:139
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:310
static List * prep_domain_constraints(List *constraints, MemoryContext execctx)
Definition: typcache.c:1127
TypeCacheEntry * tcache
Definition: typcache.h:140
void MemoryContextRegisterResetCallback(MemoryContext context, MemoryContextCallback *cb)
Definition: mcxt.c:265
#define TYPECACHE_DOMAIN_INFO
Definition: typcache.h:126
static void load_domaintype_info ( TypeCacheEntry typentry)
static

Definition at line 855 of file typcache.c.

References AccessShareLock, ALLOCSET_SMALL_SIZES, AllocSetContextCreate(), Anum_pg_constraint_conbin, Anum_pg_constraint_contypid, BTEqualStrategyNumber, CacheMemoryContext, DomainConstraintState::check_expr, DomainConstraintState::check_exprstate, CONSTRAINT_CHECK, ConstraintRelationId, DomainConstraintCache::constraints, DomainConstraintState::constrainttype, ConstraintTypidIndexId, 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, heap_close, heap_open(), HeapTupleIsValid, 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(), TCFLAGS_CHECKED_DOMAIN_CONSTRAINTS, TextDatumGetCString, TypeCacheEntry::type_id, TYPEOID, TYPTYPE_DOMAIN, and val.

Referenced by lookup_type_cache(), and UpdateDomainConstraintRef().

856 {
857  Oid typeOid = typentry->type_id;
859  bool notNull = false;
860  DomainConstraintState **ccons;
861  int cconslen;
862  Relation conRel;
863  MemoryContext oldcxt;
864 
865  /*
866  * If we're here, any existing constraint info is stale, so release it.
867  * For safety, be sure to null the link before trying to delete the data.
868  */
869  if (typentry->domainData)
870  {
871  dcc = typentry->domainData;
872  typentry->domainData = NULL;
873  decr_dcc_refcount(dcc);
874  }
875 
876  /*
877  * We try to optimize the common case of no domain constraints, so don't
878  * create the dcc object and context until we find a constraint. Likewise
879  * for the temp sorting array.
880  */
881  dcc = NULL;
882  ccons = NULL;
883  cconslen = 0;
884 
885  /*
886  * Scan pg_constraint for relevant constraints. We want to find
887  * constraints for not just this domain, but any ancestor domains, so the
888  * outer loop crawls up the domain stack.
889  */
891 
892  for (;;)
893  {
894  HeapTuple tup;
895  HeapTuple conTup;
896  Form_pg_type typTup;
897  int nccons = 0;
898  ScanKeyData key[1];
899  SysScanDesc scan;
900 
901  tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
902  if (!HeapTupleIsValid(tup))
903  elog(ERROR, "cache lookup failed for type %u", typeOid);
904  typTup = (Form_pg_type) GETSTRUCT(tup);
905 
906  if (typTup->typtype != TYPTYPE_DOMAIN)
907  {
908  /* Not a domain, so done */
909  ReleaseSysCache(tup);
910  break;
911  }
912 
913  /* Test for NOT NULL Constraint */
914  if (typTup->typnotnull)
915  notNull = true;
916 
917  /* Look for CHECK Constraints on this domain */
918  ScanKeyInit(&key[0],
920  BTEqualStrategyNumber, F_OIDEQ,
921  ObjectIdGetDatum(typeOid));
922 
923  scan = systable_beginscan(conRel, ConstraintTypidIndexId, true,
924  NULL, 1, key);
925 
926  while (HeapTupleIsValid(conTup = systable_getnext(scan)))
927  {
929  Datum val;
930  bool isNull;
931  char *constring;
932  Expr *check_expr;
934 
935  /* Ignore non-CHECK constraints (presently, shouldn't be any) */
936  if (c->contype != CONSTRAINT_CHECK)
937  continue;
938 
939  /* Not expecting conbin to be NULL, but we'll test for it anyway */
941  conRel->rd_att, &isNull);
942  if (isNull)
943  elog(ERROR, "domain \"%s\" constraint \"%s\" has NULL conbin",
944  NameStr(typTup->typname), NameStr(c->conname));
945 
946  /* Convert conbin to C string in caller context */
947  constring = TextDatumGetCString(val);
948 
949  /* Create the DomainConstraintCache object and context if needed */
950  if (dcc == NULL)
951  {
952  MemoryContext cxt;
953 
955  "Domain constraints",
957  dcc = (DomainConstraintCache *)
959  dcc->constraints = NIL;
960  dcc->dccContext = cxt;
961  dcc->dccRefCount = 0;
962  }
963 
964  /* Create node trees in DomainConstraintCache's context */
965  oldcxt = MemoryContextSwitchTo(dcc->dccContext);
966 
967  check_expr = (Expr *) stringToNode(constring);
968 
969  /* ExecInitExpr will assume we've planned the expression */
970  check_expr = expression_planner(check_expr);
971 
974  r->name = pstrdup(NameStr(c->conname));
975  r->check_expr = check_expr;
976  r->check_exprstate = NULL;
977 
978  MemoryContextSwitchTo(oldcxt);
979 
980  /* Accumulate constraints in an array, for sorting below */
981  if (ccons == NULL)
982  {
983  cconslen = 8;
984  ccons = (DomainConstraintState **)
985  palloc(cconslen * sizeof(DomainConstraintState *));
986  }
987  else if (nccons >= cconslen)
988  {
989  cconslen *= 2;
990  ccons = (DomainConstraintState **)
991  repalloc(ccons, cconslen * sizeof(DomainConstraintState *));
992  }
993  ccons[nccons++] = r;
994  }
995 
996  systable_endscan(scan);
997 
998  if (nccons > 0)
999  {
1000  /*
1001  * Sort the items for this domain, so that CHECKs are applied in a
1002  * deterministic order.
1003  */
1004  if (nccons > 1)
1005  qsort(ccons, nccons, sizeof(DomainConstraintState *), dcs_cmp);
1006 
1007  /*
1008  * Now attach them to the overall list. Use lcons() here because
1009  * constraints of parent domains should be applied earlier.
1010  */
1011  oldcxt = MemoryContextSwitchTo(dcc->dccContext);
1012  while (nccons > 0)
1013  dcc->constraints = lcons(ccons[--nccons], dcc->constraints);
1014  MemoryContextSwitchTo(oldcxt);
1015  }
1016 
1017  /* loop to next domain in stack */
1018  typeOid = typTup->typbasetype;
1019  ReleaseSysCache(tup);
1020  }
1021 
1022  heap_close(conRel, AccessShareLock);
1023 
1024  /*
1025  * Only need to add one NOT NULL check regardless of how many domains in
1026  * the stack request it.
1027  */
1028  if (notNull)
1029  {
1031 
1032  /* Create the DomainConstraintCache object and context if needed */
1033  if (dcc == NULL)
1034  {
1035  MemoryContext cxt;
1036 
1038  "Domain constraints",
1040  dcc = (DomainConstraintCache *)
1042  dcc->constraints = NIL;
1043  dcc->dccContext = cxt;
1044  dcc->dccRefCount = 0;
1045  }
1046 
1047  /* Create node trees in DomainConstraintCache's context */
1048  oldcxt = MemoryContextSwitchTo(dcc->dccContext);
1049 
1051 
1053  r->name = pstrdup("NOT NULL");
1054  r->check_expr = NULL;
1055  r->check_exprstate = NULL;
1056 
1057  /* lcons to apply the nullness check FIRST */
1058  dcc->constraints = lcons(r, dcc->constraints);
1059 
1060  MemoryContextSwitchTo(oldcxt);
1061  }
1062 
1063  /*
1064  * If we made a constraint object, move it into CacheMemoryContext and
1065  * attach it to the typcache entry.
1066  */
1067  if (dcc)
1068  {
1070  typentry->domainData = dcc;
1071  dcc->dccRefCount++; /* count the typcache's reference */
1072  }
1073 
1074  /* Either way, the typcache entry's domain data is now valid. */
1076 }
#define NIL
Definition: pg_list.h:69
#define TYPTYPE_DOMAIN
Definition: pg_type.h:722
void * stringToNode(char *str)
Definition: read.c:38
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define fastgetattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:719
MemoryContext dccContext
Definition: typcache.c:115
DomainConstraintType constrainttype
Definition: execnodes.h:809
DomainConstraintCache * domainData
Definition: typcache.h:98
void MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
Definition: mcxt.c:317
char * pstrdup(const char *in)
Definition: mcxt.c:1076
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:175
Expr * expression_planner(Expr *expr)
Definition: planner.c:5997
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define AccessShareLock
Definition: lockdefs.h:36
static int dcs_cmp(const void *a, const void *b)
Definition: typcache.c:1082
#define heap_close(r, l)
Definition: heapam.h:97
FormData_pg_type * Form_pg_type
Definition: pg_type.h:233
unsigned int Oid
Definition: postgres_ext.h:31
#define Anum_pg_constraint_conbin
#define ConstraintTypidIndexId
Definition: indexing.h:128
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:328
#define CONSTRAINT_CHECK
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
char * c
ExprState * check_exprstate
Definition: execnodes.h:812
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
#define Anum_pg_constraint_contypid
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
#define TextDatumGetCString(d)
Definition: builtins.h:92
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:322
uintptr_t Datum
Definition: postgres.h:372
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
TupleDesc rd_att
Definition: rel.h:115
List * lcons(void *datum, List *list)
Definition: list.c:259
#define makeNode(_type_)
Definition: nodes.h:558
FormData_pg_constraint * Form_pg_constraint
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define TCFLAGS_CHECKED_DOMAIN_CONSTRAINTS
Definition: typcache.c:98
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:962
void * palloc(Size size)
Definition: mcxt.c:848
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:706
#define NameStr(name)
Definition: c.h:493
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define ConstraintRelationId
Definition: pg_constraint.h:29
#define elog
Definition: elog.h:219
#define qsort(a, b, c, d)
Definition: port.h:447
static void decr_dcc_refcount(DomainConstraintCache *dcc)
Definition: typcache.c:1095
long val
Definition: informix.c:689
#define BTEqualStrategyNumber
Definition: stratnum.h:31
MemoryContext CacheMemoryContext
Definition: mcxt.c:46
static void load_enum_cache_data ( TypeCacheEntry tcache)
static

Definition at line 2130 of file typcache.c.

References AccessShareLock, Anum_pg_enum_enumtypid, TypeCacheEnumData::bitmap_base, bms_add_member(), bms_copy(), bms_free(), bms_make_singleton(), BTEqualStrategyNumber, CacheMemoryContext, EnumItem::enum_oid, enum_oid_cmp(), TypeCacheEnumData::enum_values, TypeCacheEntry::enumData, EnumRelationId, EnumTypIdLabelIndexId, ereport, errcode(), errmsg(), ERROR, format_type_be(), GETSTRUCT, heap_close, heap_open(), HeapTupleGetOid, HeapTupleIsValid, i, InvalidOid, MemoryContextSwitchTo(), TypeCacheEnumData::num_values, ObjectIdGetDatum, offsetof, palloc(), pfree(), qsort, repalloc(), ScanKeyInit(), EnumItem::sort_order, TypeCacheEnumData::sorted_values, systable_beginscan(), systable_endscan(), systable_getnext(), TypeCacheEntry::type_id, TypeCacheEntry::typtype, and TYPTYPE_ENUM.

Referenced by compare_values_of_enum().

2131 {
2132  TypeCacheEnumData *enumdata;
2133  Relation enum_rel;
2134  SysScanDesc enum_scan;
2135  HeapTuple enum_tuple;
2136  ScanKeyData skey;
2137  EnumItem *items;
2138  int numitems;
2139  int maxitems;
2140  Oid bitmap_base;
2141  Bitmapset *bitmap;
2142  MemoryContext oldcxt;
2143  int bm_size,
2144  start_pos;
2145 
2146  /* Check that this is actually an enum */
2147  if (tcache->typtype != TYPTYPE_ENUM)
2148  ereport(ERROR,
2149  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2150  errmsg("%s is not an enum",
2151  format_type_be(tcache->type_id))));
2152 
2153  /*
2154  * Read all the information for members of the enum type. We collect the
2155  * info in working memory in the caller's context, and then transfer it to
2156  * permanent memory in CacheMemoryContext. This minimizes the risk of
2157  * leaking memory from CacheMemoryContext in the event of an error partway
2158  * through.
2159  */
2160  maxitems = 64;
2161  items = (EnumItem *) palloc(sizeof(EnumItem) * maxitems);
2162  numitems = 0;
2163 
2164  /* Scan pg_enum for the members of the target enum type. */
2165  ScanKeyInit(&skey,
2167  BTEqualStrategyNumber, F_OIDEQ,
2168  ObjectIdGetDatum(tcache->type_id));
2169 
2171  enum_scan = systable_beginscan(enum_rel,
2173  true, NULL,
2174  1, &skey);
2175 
2176  while (HeapTupleIsValid(enum_tuple = systable_getnext(enum_scan)))
2177  {
2178  Form_pg_enum en = (Form_pg_enum) GETSTRUCT(enum_tuple);
2179 
2180  if (numitems >= maxitems)
2181  {
2182  maxitems *= 2;
2183  items = (EnumItem *) repalloc(items, sizeof(EnumItem) * maxitems);
2184  }
2185  items[numitems].enum_oid = HeapTupleGetOid(enum_tuple);
2186  items[numitems].sort_order = en->enumsortorder;
2187  numitems++;
2188  }
2189 
2190  systable_endscan(enum_scan);
2191  heap_close(enum_rel, AccessShareLock);
2192 
2193  /* Sort the items into OID order */
2194  qsort(items, numitems, sizeof(EnumItem), enum_oid_cmp);
2195 
2196  /*
2197  * Here, we create a bitmap listing a subset of the enum's OIDs that are
2198  * known to be in order and can thus be compared with just OID comparison.
2199  *
2200  * The point of this is that the enum's initial OIDs were certainly in
2201  * order, so there is some subset that can be compared via OID comparison;
2202  * and we'd rather not do binary searches unnecessarily.
2203  *
2204  * This is somewhat heuristic, and might identify a subset of OIDs that
2205  * isn't exactly what the type started with. That's okay as long as the
2206  * subset is correctly sorted.
2207  */
2208  bitmap_base = InvalidOid;
2209  bitmap = NULL;
2210  bm_size = 1; /* only save sets of at least 2 OIDs */
2211 
2212  for (start_pos = 0; start_pos < numitems - 1; start_pos++)
2213  {
2214  /*
2215  * Identify longest sorted subsequence starting at start_pos
2216  */
2217  Bitmapset *this_bitmap = bms_make_singleton(0);
2218  int this_bm_size = 1;
2219  Oid start_oid = items[start_pos].enum_oid;
2220  float4 prev_order = items[start_pos].sort_order;
2221  int i;
2222 
2223  for (i = start_pos + 1; i < numitems; i++)
2224  {
2225  Oid offset;
2226 
2227  offset = items[i].enum_oid - start_oid;
2228  /* quit if bitmap would be too large; cutoff is arbitrary */
2229  if (offset >= 8192)
2230  break;
2231  /* include the item if it's in-order */
2232  if (items[i].sort_order > prev_order)
2233  {
2234  prev_order = items[i].sort_order;
2235  this_bitmap = bms_add_member(this_bitmap, (int) offset);
2236  this_bm_size++;
2237  }
2238  }
2239 
2240  /* Remember it if larger than previous best */
2241  if (this_bm_size > bm_size)
2242  {
2243  bms_free(bitmap);
2244  bitmap_base = start_oid;
2245  bitmap = this_bitmap;
2246  bm_size = this_bm_size;
2247  }
2248  else
2249  bms_free(this_bitmap);
2250 
2251  /*
2252  * Done if it's not possible to find a longer sequence in the rest of
2253  * the list. In typical cases this will happen on the first
2254  * iteration, which is why we create the bitmaps on the fly instead of
2255  * doing a second pass over the list.
2256  */
2257  if (bm_size >= (numitems - start_pos - 1))
2258  break;
2259  }
2260 
2261  /* OK, copy the data into CacheMemoryContext */
2263  enumdata = (TypeCacheEnumData *)
2264  palloc(offsetof(TypeCacheEnumData, enum_values) +
2265  numitems * sizeof(EnumItem));
2266  enumdata->bitmap_base = bitmap_base;
2267  enumdata->sorted_values = bms_copy(bitmap);
2268  enumdata->num_values = numitems;
2269  memcpy(enumdata->enum_values, items, numitems * sizeof(EnumItem));
2270  MemoryContextSwitchTo(oldcxt);
2271 
2272  pfree(items);
2273  bms_free(bitmap);
2274 
2275  /* And link the finished cache struct into the typcache */
2276  if (tcache->enumData != NULL)
2277  pfree(tcache->enumData);
2278  tcache->enumData = enumdata;
2279 }
struct TypeCacheEnumData * enumData
Definition: typcache.h:107
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:111
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:575
char * format_type_be(Oid type_oid)
Definition: format_type.c:94
#define heap_close(r, l)
Definition: heapam.h:97
unsigned int Oid
Definition: postgres_ext.h:31
#define EnumTypIdLabelIndexId
Definition: indexing.h:157
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:328
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
Bitmapset * sorted_values
Definition: typcache.c:129
void pfree(void *pointer)
Definition: mcxt.c:949
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
#define EnumRelationId
Definition: pg_enum.h:32
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:179
FormData_pg_enum * Form_pg_enum
Definition: pg_enum.h:46
#define ereport(elevel, rest)
Definition: elog.h:122
EnumItem enum_values[FLEXIBLE_ARRAY_MEMBER]
Definition: typcache.c:131
float float4
Definition: c.h:374
Oid enum_oid
Definition: typcache.c:122
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
#define InvalidOid
Definition: postgres_ext.h:36
char typtype
Definition: typcache.h:41
void bms_free(Bitmapset *a)
Definition: bitmapset.c:201
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:698
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:962
#define Anum_pg_enum_enumtypid
Definition: pg_enum.h:53
float4 sort_order
Definition: typcache.c:123
void * palloc(Size size)
Definition: mcxt.c:848
int errmsg(const char *fmt,...)
Definition: elog.c:797
static int enum_oid_cmp(const void *left, const void *right)
Definition: typcache.c:2302
int i
#define TYPTYPE_ENUM
Definition: pg_type.h:723
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:695
#define qsort(a, b, c, d)
Definition: port.h:447
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define offsetof(type, field)
Definition: c.h:549
MemoryContext CacheMemoryContext
Definition: mcxt.c:46
static void load_rangetype_info ( TypeCacheEntry typentry)
static

Definition at line 792 of file typcache.c.

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

Referenced by cache_range_element_properties(), and lookup_type_cache().

793 {
794  Form_pg_range pg_range;
795  HeapTuple tup;
796  Oid subtypeOid;
797  Oid opclassOid;
798  Oid canonicalOid;
799  Oid subdiffOid;
800  Oid opfamilyOid;
801  Oid opcintype;
802  Oid cmpFnOid;
803 
804  /* get information from pg_range */
806  /* should not fail, since we already checked typtype ... */
807  if (!HeapTupleIsValid(tup))
808  elog(ERROR, "cache lookup failed for range type %u",
809  typentry->type_id);
810  pg_range = (Form_pg_range) GETSTRUCT(tup);
811 
812  subtypeOid = pg_range->rngsubtype;
813  typentry->rng_collation = pg_range->rngcollation;
814  opclassOid = pg_range->rngsubopc;
815  canonicalOid = pg_range->rngcanonical;
816  subdiffOid = pg_range->rngsubdiff;
817 
818  ReleaseSysCache(tup);
819 
820  /* get opclass properties and look up the comparison function */
821  opfamilyOid = get_opclass_family(opclassOid);
822  opcintype = get_opclass_input_type(opclassOid);
823 
824  cmpFnOid = get_opfamily_proc(opfamilyOid, opcintype, opcintype,
825  BTORDER_PROC);
826  if (!RegProcedureIsValid(cmpFnOid))
827  elog(ERROR, "missing support function %d(%u,%u) in opfamily %u",
828  BTORDER_PROC, opcintype, opcintype, opfamilyOid);
829 
830  /* set up cached fmgrinfo structs */
831  fmgr_info_cxt(cmpFnOid, &typentry->rng_cmp_proc_finfo,
833  if (OidIsValid(canonicalOid))
834  fmgr_info_cxt(canonicalOid, &typentry->rng_canonical_finfo,
836  if (OidIsValid(subdiffOid))
837  fmgr_info_cxt(subdiffOid, &typentry->rng_subdiff_finfo,
839 
840  /* Lastly, set up link to the element type --- this marks data valid */
841  typentry->rngelemtype = lookup_type_cache(subtypeOid, 0);
842 }
FormData_pg_range * Form_pg_range
Definition: pg_range.h:49
FmgrInfo rng_cmp_proc_finfo
Definition: typcache.h:90
#define BTORDER_PROC
Definition: nbtree.h:229
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:532
FmgrInfo rng_subdiff_finfo
Definition: typcache.h:92
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
#define RegProcedureIsValid(p)
Definition: c.h:534
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:132
FmgrInfo rng_canonical_finfo
Definition: typcache.h:91
struct TypeCacheEntry * rngelemtype
Definition: typcache.h:88
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:310
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
Oid get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum)
Definition: lsyscache.c:744
Oid rng_collation
Definition: typcache.h:89
Oid get_opclass_family(Oid opclass)
Definition: lsyscache.c:1047
#define elog
Definition: elog.h:219
MemoryContext CacheMemoryContext
Definition: mcxt.c:46
Oid get_opclass_input_type(Oid opclass)
Definition: lsyscache.c:1069
static void load_typcache_tupdesc ( TypeCacheEntry typentry)
static

Definition at line 764 of file typcache.c.

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

Referenced by cache_record_field_properties(), and lookup_type_cache().

765 {
766  Relation rel;
767 
768  if (!OidIsValid(typentry->typrelid)) /* should not happen */
769  elog(ERROR, "invalid typrelid for composite type %u",
770  typentry->type_id);
771  rel = relation_open(typentry->typrelid, AccessShareLock);
772  Assert(rel->rd_rel->reltype == typentry->type_id);
773 
774  /*
775  * Link to the tupdesc and increment its refcount (we assert it's a
776  * refcounted descriptor). We don't use IncrTupleDescRefCount() for this,
777  * because the reference mustn't be entered in the current resource owner;
778  * it can outlive the current query.
779  */
780  typentry->tupDesc = RelationGetDescr(rel);
781 
782  Assert(typentry->tupDesc->tdrefcount > 0);
783  typentry->tupDesc->tdrefcount++;
784 
786 }
#define RelationGetDescr(relation)
Definition: rel.h:428
#define AccessShareLock
Definition: lockdefs.h:36
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: heapam.c:1266
Form_pg_class rd_rel
Definition: rel.h:114
#define OidIsValid(objectId)
Definition: c.h:532
#define ERROR
Definition: elog.h:43
#define Assert(condition)
Definition: c.h:681
int tdrefcount
Definition: tupdesc.h:77
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1120
#define elog
Definition: elog.h:219
TupleDesc tupDesc
Definition: typcache.h:80
TupleDesc lookup_rowtype_tupdesc_copy ( Oid  type_id,
int32  typmod 
)

Definition at line 1613 of file typcache.c.

References CreateTupleDescCopyConstr(), and lookup_rowtype_tupdesc_internal().

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

1614 {
1615  TupleDesc tmp;
1616 
1617  tmp = lookup_rowtype_tupdesc_internal(type_id, typmod, false);
1618  return CreateTupleDescCopyConstr(tmp);
1619 }
TupleDesc CreateTupleDescCopyConstr(TupleDesc tupdesc)
Definition: tupdesc.c:131
static TupleDesc lookup_rowtype_tupdesc_internal(Oid type_id, int32 typmod, bool noError)
Definition: typcache.c:1494
static TupleDesc lookup_rowtype_tupdesc_internal ( Oid  type_id,
int32  typmod,
bool  noError 
)
static

Definition at line 1494 of file typcache.c.

References Session::area, Assert, CurrentSession, dsa_get_address(), dshash_find(), dshash_release_lock(), ensure_record_cache_typmod_slot_exists(), ereport, errcode(), errmsg(), ERROR, format_type_be(), lookup_type_cache(), RecordCacheArrayLen, RECORDOID, SharedTypmodTableEntry::shared_tupdesc, Session::shared_typmod_registry, Session::shared_typmod_table, tupleDesc::tdrefcount, tupleDesc::tdtypmod, TypeCacheEntry::tupDesc, and TYPECACHE_TUPDESC.

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

1495 {
1496  if (type_id != RECORDOID)
1497  {
1498  /*
1499  * It's a named composite type, so use the regular typcache.
1500  */
1501  TypeCacheEntry *typentry;
1502 
1503  typentry = lookup_type_cache(type_id, TYPECACHE_TUPDESC);
1504  if (typentry->tupDesc == NULL && !noError)
1505  ereport(ERROR,
1506  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1507  errmsg("type %s is not composite",
1508  format_type_be(type_id))));
1509  return typentry->tupDesc;
1510  }
1511  else
1512  {
1513  /*
1514  * It's a transient record type, so look in our record-type table.
1515  */
1516  if (typmod >= 0)
1517  {
1518  /* It is already in our local cache? */
1519  if (typmod < RecordCacheArrayLen &&
1520  RecordCacheArray[typmod] != NULL)
1521  return RecordCacheArray[typmod];
1522 
1523  /* Are we attached to a shared record typmod registry? */
1525  {
1526  SharedTypmodTableEntry *entry;
1527 
1528  /* Try to find it in the shared typmod index. */
1530  &typmod, false);
1531  if (entry != NULL)
1532  {
1533  TupleDesc tupdesc;
1534 
1535  tupdesc = (TupleDesc)
1537  entry->shared_tupdesc);
1538  Assert(typmod == tupdesc->tdtypmod);
1539 
1540  /* We may need to extend the local RecordCacheArray. */
1542 
1543  /*
1544  * Our local array can now point directly to the TupleDesc
1545  * in shared memory.
1546  */
1547  RecordCacheArray[typmod] = tupdesc;
1548  Assert(tupdesc->tdrefcount == -1);
1549 
1551  entry);
1552 
1553  return RecordCacheArray[typmod];
1554  }
1555  }
1556  }
1557 
1558  if (!noError)
1559  ereport(ERROR,
1560  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1561  errmsg("record type has not been registered")));
1562  return NULL;
1563  }
1564 }
Session * CurrentSession
Definition: session.c:48
int errcode(int sqlerrcode)
Definition: elog.c:575
char * format_type_be(Oid type_oid)
Definition: format_type.c:94
void dshash_release_lock(dshash_table *hash_table, void *entry)
Definition: dshash.c:561
int32 tdtypmod
Definition: tupdesc.h:75
static TupleDesc * RecordCacheArray
Definition: typcache.c:263
void * dsa_get_address(dsa_area *area, dsa_pointer dp)
Definition: dsa.c:924
dsa_pointer shared_tupdesc
Definition: typcache.c:196
#define ERROR
Definition: elog.h:43
dsa_area * area
Definition: session.h:28
#define RECORDOID
Definition: pg_type.h:680
#define ereport(elevel, rest)
Definition: elog.h:122
static int32 RecordCacheArrayLen
Definition: typcache.c:264
struct SharedRecordTypmodRegistry * shared_typmod_registry
Definition: session.h:31
static void ensure_record_cache_typmod_slot_exists(int32 typmod)
Definition: typcache.c:1463
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:310
struct tupleDesc * TupleDesc
dshash_table * shared_typmod_table
Definition: session.h:33
#define Assert(condition)
Definition: c.h:681
int errmsg(const char *fmt,...)
Definition: elog.c:797
int tdrefcount
Definition: tupdesc.h:77
void * dshash_find(dshash_table *hash_table, const void *key, bool exclusive)
Definition: dshash.c:385
TupleDesc tupDesc
Definition: typcache.h:80
#define TYPECACHE_TUPDESC
Definition: typcache.h:122
TupleDesc lookup_rowtype_tupdesc_noerror ( Oid  type_id,
int32  typmod,
bool  noError 
)

Definition at line 1596 of file typcache.c.

References lookup_rowtype_tupdesc_internal(), and PinTupleDesc.

Referenced by plperl_sv_to_datum().

1597 {
1598  TupleDesc tupDesc;
1599 
1600  tupDesc = lookup_rowtype_tupdesc_internal(type_id, typmod, noError);
1601  if (tupDesc != NULL)
1602  PinTupleDesc(tupDesc);
1603  return tupDesc;
1604 }
#define PinTupleDesc(tupdesc)
Definition: tupdesc.h:109
static TupleDesc lookup_rowtype_tupdesc_internal(Oid type_id, int32 typmod, bool noError)
Definition: typcache.c:1494
TypeCacheEntry* lookup_type_cache ( Oid  type_id,
int  flags 
)

Definition at line 310 of file typcache.c.

References array_element_has_compare(), array_element_has_equality(), array_element_has_extended_hashing(), array_element_has_hashing(), ARRAY_EQ_OP, ARRAY_GT_OP, ARRAY_LT_OP, Assert, BTEqualStrategyNumber, BTGreaterStrategyNumber, BTLessStrategyNumber, BTORDER_PROC, BTREE_AM_OID, TypeCacheEntry::btree_opf, TypeCacheEntry::btree_opintype, CacheMemoryContext, CacheRegisterRelcacheCallback(), CacheRegisterSyscacheCallback(), CLAOID, TypeCacheEntry::cmp_proc, TypeCacheEntry::cmp_proc_finfo, CONSTROID, CreateCacheMemoryContext(), HASHCTL::entrysize, TypeCacheEntry::eq_opr, TypeCacheEntry::eq_opr_finfo, ereport, errcode(), errmsg(), ERROR, firstDomainTypeEntry, TypeCacheEntry::flags, fmgr_info_cxt(), FmgrInfo::fn_oid, get_opclass_family(), get_opclass_input_type(), get_opcode(), get_opfamily_member(), get_opfamily_proc(), GetDefaultOpClass(), GETSTRUCT, TypeCacheEntry::gt_opr, HASH_AM_OID, HASH_BLOBS, hash_create(), HASH_ELEM, HASH_ENTER, TypeCacheEntry::hash_extended_proc, TypeCacheEntry::hash_extended_proc_finfo, HASH_FIND, TypeCacheEntry::hash_opf, TypeCacheEntry::hash_opintype, TypeCacheEntry::hash_proc, TypeCacheEntry::hash_proc_finfo, hash_search(), HASHEXTENDED_PROC, HASHSTANDARD_PROC, HeapTupleIsValid, HTEqualStrategyNumber, InvalidOid, HASHCTL::keysize, load_domaintype_info(), load_rangetype_info(), load_typcache_tupdesc(), TypeCacheEntry::lt_opr, MemSet, NameStr, TypeCacheEntry::nextDomain, ObjectIdGetDatum, OidIsValid, range_element_has_extended_hashing(), range_element_has_hashing(), RECORD_EQ_OP, record_fields_have_compare(), record_fields_have_equality(), RECORD_GT_OP, RECORD_LT_OP, ReleaseSysCache(), TypeCacheEntry::rngelemtype, 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, TypeCacheEntry::tupDesc, TypeCacheEntry::typalign, TypeCacheEntry::typbyval, TypeCacheEntry::type_id, TYPECACHE_BTREE_OPFAMILY, TYPECACHE_CMP_PROC, TYPECACHE_CMP_PROC_FINFO, TYPECACHE_DOMAIN_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_RANGE_INFO, TYPECACHE_TUPDESC, TypeCacheConstrCallback(), TypeCacheOpcCallback(), TypeCacheRelCallback(), TYPEOID, TypeCacheEntry::typlen, TypeCacheEntry::typrelid, TypeCacheEntry::typstorage, TypeCacheEntry::typtype, TYPTYPE_COMPOSITE, TYPTYPE_DOMAIN, and TYPTYPE_RANGE.

Referenced by appendAggOrderBy(), array_cmp(), array_contain_compare(), array_eq(), array_position_common(), array_positions(), array_replace_internal(), array_typanalyze(), brin_inclusion_opcinfo(), brin_minmax_opcinfo(), cache_array_element_properties(), cache_range_element_properties(), cache_record_field_properties(), calc_arraycontsel(), CreateStatistics(), dependency_degree(), domain_state_setup(), DomainHasConstraints(), enum_cmp_internal(), ExecInitExprRec(), foreign_expr_walker(), get_range_io_data(), get_rule_orderby(), get_sort_group_operators(), hash_array(), hash_array_extended(), hash_range(), hash_range_extended(), InitDomainConstraintRef(), initGinState(), load_rangetype_info(), lookup_rowtype_tupdesc_internal(), ndistinct_for_combination(), op_hashjoinable(), op_mergejoinable(), range_get_typcache(), record_cmp(), record_eq(), refresh_by_match_merge(), scalararraysel(), scalararraysel_containment(), show_sortorder_options(), tuple_equals_slot(), and width_bucket_array().

311 {
312  TypeCacheEntry *typentry;
313  bool found;
314 
315  if (TypeCacheHash == NULL)
316  {
317  /* First time through: initialize the hash table */
318  HASHCTL ctl;
319 
320  MemSet(&ctl, 0, sizeof(ctl));
321  ctl.keysize = sizeof(Oid);
322  ctl.entrysize = sizeof(TypeCacheEntry);
323  TypeCacheHash = hash_create("Type information cache", 64,
324  &ctl, HASH_ELEM | HASH_BLOBS);
325 
326  /* Also set up callbacks for SI invalidations */
331 
332  /* Also make sure CacheMemoryContext exists */
333  if (!CacheMemoryContext)
335  }
336 
337  /* Try to look up an existing entry */
339  (void *) &type_id,
340  HASH_FIND, NULL);
341  if (typentry == NULL)
342  {
343  /*
344  * If we didn't find one, we want to make one. But first look up the
345  * pg_type row, just to make sure we don't make a cache entry for an
346  * invalid type OID. If the type OID is not valid, present a
347  * user-facing error, since some code paths such as domain_in() allow
348  * this function to be reached with a user-supplied OID.
349  */
350  HeapTuple tp;
351  Form_pg_type typtup;
352 
353  tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_id));
354  if (!HeapTupleIsValid(tp))
355  ereport(ERROR,
356  (errcode(ERRCODE_UNDEFINED_OBJECT),
357  errmsg("type with OID %u does not exist", type_id)));
358  typtup = (Form_pg_type) GETSTRUCT(tp);
359  if (!typtup->typisdefined)
360  ereport(ERROR,
361  (errcode(ERRCODE_UNDEFINED_OBJECT),
362  errmsg("type \"%s\" is only a shell",
363  NameStr(typtup->typname))));
364 
365  /* Now make the typcache entry */
367  (void *) &type_id,
368  HASH_ENTER, &found);
369  Assert(!found); /* it wasn't there a moment ago */
370 
371  MemSet(typentry, 0, sizeof(TypeCacheEntry));
372  typentry->type_id = type_id;
373  typentry->typlen = typtup->typlen;
374  typentry->typbyval = typtup->typbyval;
375  typentry->typalign = typtup->typalign;
376  typentry->typstorage = typtup->typstorage;
377  typentry->typtype = typtup->typtype;
378  typentry->typrelid = typtup->typrelid;
379 
380  /* If it's a domain, immediately thread it into the domain cache list */
381  if (typentry->typtype == TYPTYPE_DOMAIN)
382  {
383  typentry->nextDomain = firstDomainTypeEntry;
384  firstDomainTypeEntry = typentry;
385  }
386 
387  ReleaseSysCache(tp);
388  }
389 
390  /*
391  * Look up opclasses if we haven't already and any dependent info is
392  * requested.
393  */
398  !(typentry->flags & TCFLAGS_CHECKED_BTREE_OPCLASS))
399  {
400  Oid opclass;
401 
402  opclass = GetDefaultOpClass(type_id, BTREE_AM_OID);
403  if (OidIsValid(opclass))
404  {
405  typentry->btree_opf = get_opclass_family(opclass);
406  typentry->btree_opintype = get_opclass_input_type(opclass);
407  }
408  else
409  {
410  typentry->btree_opf = typentry->btree_opintype = InvalidOid;
411  }
412 
413  /*
414  * Reset information derived from btree opclass. Note in particular
415  * that we'll redetermine the eq_opr even if we previously found one;
416  * this matters in case a btree opclass has been added to a type that
417  * previously had only a hash opclass.
418  */
419  typentry->flags &= ~(TCFLAGS_CHECKED_EQ_OPR |
424  }
425 
426  /*
427  * If we need to look up equality operator, and there's no btree opclass,
428  * force lookup of hash opclass.
429  */
430  if ((flags & (TYPECACHE_EQ_OPR | TYPECACHE_EQ_OPR_FINFO)) &&
431  !(typentry->flags & TCFLAGS_CHECKED_EQ_OPR) &&
432  typentry->btree_opf == InvalidOid)
433  flags |= TYPECACHE_HASH_OPFAMILY;
434 
439  !(typentry->flags & TCFLAGS_CHECKED_HASH_OPCLASS))
440  {
441  Oid opclass;
442 
443  opclass = GetDefaultOpClass(type_id, HASH_AM_OID);
444  if (OidIsValid(opclass))
445  {
446  typentry->hash_opf = get_opclass_family(opclass);
447  typentry->hash_opintype = get_opclass_input_type(opclass);
448  }
449  else
450  {
451  typentry->hash_opf = typentry->hash_opintype = InvalidOid;
452  }
453 
454  /*
455  * Reset information derived from hash opclass. We do *not* reset the
456  * eq_opr; if we already found one from the btree opclass, that
457  * decision is still good.
458  */
459  typentry->flags &= ~(TCFLAGS_CHECKED_HASH_PROC |
461  typentry->flags |= TCFLAGS_CHECKED_HASH_OPCLASS;
462  }
463 
464  /*
465  * Look for requested operators and functions, if we haven't already.
466  */
467  if ((flags & (TYPECACHE_EQ_OPR | TYPECACHE_EQ_OPR_FINFO)) &&
468  !(typentry->flags & TCFLAGS_CHECKED_EQ_OPR))
469  {
470  Oid eq_opr = InvalidOid;
471 
472  if (typentry->btree_opf != InvalidOid)
473  eq_opr = get_opfamily_member(typentry->btree_opf,
474  typentry->btree_opintype,
475  typentry->btree_opintype,
477  if (eq_opr == InvalidOid &&
478  typentry->hash_opf != InvalidOid)
479  eq_opr = get_opfamily_member(typentry->hash_opf,
480  typentry->hash_opintype,
481  typentry->hash_opintype,
483 
484  /*
485  * If the proposed equality operator is array_eq or record_eq, check
486  * to see if the element type or column types support equality. If
487  * not, array_eq or record_eq would fail at runtime, so we don't want
488  * to report that the type has equality. (We can omit similar
489  * checking for ranges because ranges can't be created in the first
490  * place unless their subtypes support equality.)
491  */
492  if (eq_opr == ARRAY_EQ_OP &&
493  !array_element_has_equality(typentry))
494  eq_opr = InvalidOid;
495  else if (eq_opr == RECORD_EQ_OP &&
496  !record_fields_have_equality(typentry))
497  eq_opr = InvalidOid;
498 
499  /* Force update of eq_opr_finfo only if we're changing state */
500  if (typentry->eq_opr != eq_opr)
501  typentry->eq_opr_finfo.fn_oid = InvalidOid;
502 
503  typentry->eq_opr = eq_opr;
504 
505  /*
506  * Reset info about hash functions whenever we pick up new info about
507  * equality operator. This is so we can ensure that the hash
508  * functions match the operator.
509  */
510  typentry->flags &= ~(TCFLAGS_CHECKED_HASH_PROC |
512  typentry->flags |= TCFLAGS_CHECKED_EQ_OPR;
513  }
514  if ((flags & TYPECACHE_LT_OPR) &&
515  !(typentry->flags & TCFLAGS_CHECKED_LT_OPR))
516  {
517  Oid lt_opr = InvalidOid;
518 
519  if (typentry->btree_opf != InvalidOid)
520  lt_opr = get_opfamily_member(typentry->btree_opf,
521  typentry->btree_opintype,
522  typentry->btree_opintype,
524 
525  /*
526  * As above, make sure array_cmp or record_cmp will succeed; but again
527  * we need no special check for ranges.
528  */
529  if (lt_opr == ARRAY_LT_OP &&
530  !array_element_has_compare(typentry))
531  lt_opr = InvalidOid;
532  else if (lt_opr == RECORD_LT_OP &&
533  !record_fields_have_compare(typentry))
534  lt_opr = InvalidOid;
535 
536  typentry->lt_opr = lt_opr;
537  typentry->flags |= TCFLAGS_CHECKED_LT_OPR;
538  }
539  if ((flags & TYPECACHE_GT_OPR) &&
540  !(typentry->flags & TCFLAGS_CHECKED_GT_OPR))
541  {
542  Oid gt_opr = InvalidOid;
543 
544  if (typentry->btree_opf != InvalidOid)
545  gt_opr = get_opfamily_member(typentry->btree_opf,
546  typentry->btree_opintype,
547  typentry->btree_opintype,
549 
550  /*
551  * As above, make sure array_cmp or record_cmp will succeed; but again
552  * we need no special check for ranges.
553  */
554  if (gt_opr == ARRAY_GT_OP &&
555  !array_element_has_compare(typentry))
556  gt_opr = InvalidOid;
557  else if (gt_opr == RECORD_GT_OP &&
558  !record_fields_have_compare(typentry))
559  gt_opr = InvalidOid;
560 
561  typentry->gt_opr = gt_opr;
562  typentry->flags |= TCFLAGS_CHECKED_GT_OPR;
563  }
564  if ((flags & (TYPECACHE_CMP_PROC | TYPECACHE_CMP_PROC_FINFO)) &&
565  !(typentry->flags & TCFLAGS_CHECKED_CMP_PROC))
566  {
567  Oid cmp_proc = InvalidOid;
568 
569  if (typentry->btree_opf != InvalidOid)
570  cmp_proc = get_opfamily_proc(typentry->btree_opf,
571  typentry->btree_opintype,
572  typentry->btree_opintype,
573  BTORDER_PROC);
574 
575  /*
576  * As above, make sure array_cmp or record_cmp will succeed; but again
577  * we need no special check for ranges.
578  */
579  if (cmp_proc == F_BTARRAYCMP &&
580  !array_element_has_compare(typentry))
581  cmp_proc = InvalidOid;
582  else if (cmp_proc == F_BTRECORDCMP &&
583  !record_fields_have_compare(typentry))
584  cmp_proc = InvalidOid;
585 
586  /* Force update of cmp_proc_finfo only if we're changing state */
587  if (typentry->cmp_proc != cmp_proc)
588  typentry->cmp_proc_finfo.fn_oid = InvalidOid;
589 
590  typentry->cmp_proc = cmp_proc;
591  typentry->flags |= TCFLAGS_CHECKED_CMP_PROC;
592  }
594  !(typentry->flags & TCFLAGS_CHECKED_HASH_PROC))
595  {
596  Oid hash_proc = InvalidOid;
597 
598  /*
599  * We insist that the eq_opr, if one has been determined, match the
600  * hash opclass; else report there is no hash function.
601  */
602  if (typentry->hash_opf != InvalidOid &&
603  (!OidIsValid(typentry->eq_opr) ||
604  typentry->eq_opr == get_opfamily_member(typentry->hash_opf,
605  typentry->hash_opintype,
606  typentry->hash_opintype,
608  hash_proc = get_opfamily_proc(typentry->hash_opf,
609  typentry->hash_opintype,
610  typentry->hash_opintype,
612 
613  /*
614  * As above, make sure hash_array will succeed. We don't currently
615  * support hashing for composite types, but when we do, we'll need
616  * more logic here to check that case too.
617  */
618  if (hash_proc == F_HASH_ARRAY &&
619  !array_element_has_hashing(typentry))
620  hash_proc = InvalidOid;
621 
622  /*
623  * Likewise for hash_range.
624  */
625  if (hash_proc == F_HASH_RANGE &&
626  !range_element_has_hashing(typentry))
627  hash_proc = InvalidOid;
628 
629  /* Force update of hash_proc_finfo only if we're changing state */
630  if (typentry->hash_proc != hash_proc)
631  typentry->hash_proc_finfo.fn_oid = InvalidOid;
632 
633  typentry->hash_proc = hash_proc;
634  typentry->flags |= TCFLAGS_CHECKED_HASH_PROC;
635  }
636  if ((flags & (TYPECACHE_HASH_EXTENDED_PROC |
639  {
640  Oid hash_extended_proc = InvalidOid;
641 
642  /*
643  * We insist that the eq_opr, if one has been determined, match the
644  * hash opclass; else report there is no hash function.
645  */
646  if (typentry->hash_opf != InvalidOid &&
647  (!OidIsValid(typentry->eq_opr) ||
648  typentry->eq_opr == get_opfamily_member(typentry->hash_opf,
649  typentry->hash_opintype,
650  typentry->hash_opintype,
652  hash_extended_proc = get_opfamily_proc(typentry->hash_opf,
653  typentry->hash_opintype,
654  typentry->hash_opintype,
656 
657  /*
658  * As above, make sure hash_array_extended will succeed. We don't
659  * currently support hashing for composite types, but when we do,
660  * we'll need more logic here to check that case too.
661  */
662  if (hash_extended_proc == F_HASH_ARRAY_EXTENDED &&
664  hash_extended_proc = InvalidOid;
665 
666  /*
667  * Likewise for hash_range_extended.
668  */
669  if (hash_extended_proc == F_HASH_RANGE_EXTENDED &&
671  hash_extended_proc = InvalidOid;
672 
673  /* Force update of proc finfo only if we're changing state */
674  if (typentry->hash_extended_proc != hash_extended_proc)
676 
677  typentry->hash_extended_proc = hash_extended_proc;
679  }
680 
681  /*
682  * Set up fmgr lookup info as requested
683  *
684  * Note: we tell fmgr the finfo structures live in CacheMemoryContext,
685  * which is not quite right (they're really in the hash table's private
686  * memory context) but this will do for our purposes.
687  *
688  * Note: the code above avoids invalidating the finfo structs unless the
689  * referenced operator/function OID actually changes. This is to prevent
690  * unnecessary leakage of any subsidiary data attached to an finfo, since
691  * that would cause session-lifespan memory leaks.
692  */
693  if ((flags & TYPECACHE_EQ_OPR_FINFO) &&
694  typentry->eq_opr_finfo.fn_oid == InvalidOid &&
695  typentry->eq_opr != InvalidOid)
696  {
697  Oid eq_opr_func;
698 
699  eq_opr_func = get_opcode(typentry->eq_opr);
700  if (eq_opr_func != InvalidOid)
701  fmgr_info_cxt(eq_opr_func, &typentry->eq_opr_finfo,
703  }
704  if ((flags & TYPECACHE_CMP_PROC_FINFO) &&
705  typentry->cmp_proc_finfo.fn_oid == InvalidOid &&
706  typentry->cmp_proc != InvalidOid)
707  {
708  fmgr_info_cxt(typentry->cmp_proc, &typentry->cmp_proc_finfo,
710  }
711  if ((flags & TYPECACHE_HASH_PROC_FINFO) &&
712  typentry->hash_proc_finfo.fn_oid == InvalidOid &&
713  typentry->hash_proc != InvalidOid)
714  {
715  fmgr_info_cxt(typentry->hash_proc, &typentry->hash_proc_finfo,
717  }
718  if ((flags & TYPECACHE_HASH_EXTENDED_PROC_FINFO) &&
720  typentry->hash_extended_proc != InvalidOid)
721  {
723  &typentry->hash_extended_proc_finfo,
725  }
726 
727  /*
728  * If it's a composite type (row type), get tupdesc if requested
729  */
730  if ((flags & TYPECACHE_TUPDESC) &&
731  typentry->tupDesc == NULL &&
732  typentry->typtype == TYPTYPE_COMPOSITE)
733  {
734  load_typcache_tupdesc(typentry);
735  }
736 
737  /*
738  * If requested, get information about a range type
739  */
740  if ((flags & TYPECACHE_RANGE_INFO) &&
741  typentry->rngelemtype == NULL &&
742  typentry->typtype == TYPTYPE_RANGE)
743  {
744  load_rangetype_info(typentry);
745  }
746 
747  /*
748  * If requested, get information about a domain type
749  */
750  if ((flags & TYPECACHE_DOMAIN_INFO) &&
751  (typentry->flags & TCFLAGS_CHECKED_DOMAIN_CONSTRAINTS) == 0 &&
752  typentry->typtype == TYPTYPE_DOMAIN)
753  {
754  load_domaintype_info(typentry);
755  }
756 
757  return typentry;
758 }
static bool array_element_has_hashing(TypeCacheEntry *typentry)
Definition: typcache.c:1295
#define TYPTYPE_DOMAIN
Definition: pg_type.h:722
static void load_typcache_tupdesc(TypeCacheEntry *typentry)
Definition: typcache.c:764
#define BTORDER_PROC
Definition: nbtree.h:229
#define TYPECACHE_RANGE_INFO
Definition: typcache.h:125
Oid GetDefaultOpClass(Oid type_id, Oid am_id)
Definition: indexcmds.c:1390
#define BTGreaterStrategyNumber
Definition: stratnum.h:33
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
Oid hash_opintype
Definition: typcache.h:55
#define TCFLAGS_CHECKED_EQ_OPR
Definition: typcache.c:84
#define HASH_ELEM
Definition: hsearch.h:87
static TypeCacheEntry * firstDomainTypeEntry
Definition: typcache.c:79
#define TYPECACHE_HASH_EXTENDED_PROC_FINFO
Definition: typcache.h:128
#define TCFLAGS_CHECKED_HASH_EXTENDED_PROC
Definition: typcache.c:89
#define TYPTYPE_COMPOSITE
Definition: pg_type.h:721
struct TypeCacheEntry TypeCacheEntry
#define HTEqualStrategyNumber
Definition: hash.h:336
#define TYPECACHE_EQ_OPR_FINFO
Definition: typcache.h:119
#define BTREE_AM_OID
Definition: pg_am.h:70
#define TYPECACHE_HASH_PROC_FINFO
Definition: typcache.h:121
Size entrysize
Definition: hsearch.h:73
#define TYPECACHE_EQ_OPR
Definition: typcache.h:114
int errcode(int sqlerrcode)
Definition: elog.c:575
#define HASHEXTENDED_PROC
Definition: hash.h:352
#define MemSet(start, val, len)
Definition: c.h:863
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:902
FormData_pg_type * Form_pg_type
Definition: pg_type.h:233
unsigned int Oid
Definition: postgres_ext.h:31
#define RECORD_EQ_OP
Definition: pg_operator.h:1720
int16 typlen
Definition: typcache.h:37
#define OidIsValid(objectId)
Definition: c.h:532
bool typbyval
Definition: typcache.h:38
#define HASH_AM_OID
Definition: pg_am.h:73
void CacheRegisterRelcacheCallback(RelcacheCallbackFunction func, Datum arg)
Definition: inval.c:1431
FmgrInfo cmp_proc_finfo
Definition: typcache.h:71
struct TypeCacheEntry * nextDomain
Definition: typcache.h:110
#define TCFLAGS_CHECKED_GT_OPR
Definition: typcache.c:86
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
#define ARRAY_LT_OP
Definition: pg_operator.h:781
char typstorage
Definition: typcache.h:40
static void TypeCacheRelCallback(Datum arg, Oid relid)
Definition: typcache.c:1923
static bool array_element_has_compare(TypeCacheEntry *typentry)
Definition: typcache.c:1287
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:163
Oid hash_extended_proc
Definition: typcache.h:61
FmgrInfo hash_proc_finfo
Definition: typcache.h:72
#define RECORD_LT_OP
Definition: pg_operator.h:1725
#define TYPECACHE_GT_OPR
Definition: typcache.h:116
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:132
#define HASHSTANDARD_PROC
Definition: hash.h:351
#define ereport(elevel, rest)
Definition: elog.h:122
#define TYPECACHE_BTREE_OPFAMILY
Definition: typcache.h:123
struct TypeCacheEntry * rngelemtype
Definition: typcache.h:88
#define RECORD_GT_OP
Definition: pg_operator.h:1728
#define TYPTYPE_RANGE
Definition: pg_type.h:725
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
static bool range_element_has_hashing(TypeCacheEntry *typentry)
Definition: typcache.c:1420
#define HASH_BLOBS
Definition: hsearch.h:88
FmgrInfo hash_extended_proc_finfo
Definition: typcache.h:73
void CacheRegisterSyscacheCallback(int cacheid, SyscacheCallbackFunction func, Datum arg)
Definition: inval.c:1389
#define TYPECACHE_HASH_EXTENDED_PROC
Definition: typcache.h:127
uintptr_t Datum
Definition: postgres.h:372
HTAB * hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)
Definition: dynahash.c:316
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
Oid btree_opintype
Definition: typcache.h:53
Size keysize
Definition: hsearch.h:72
FmgrInfo eq_opr_finfo
Definition: typcache.h:70
#define InvalidOid
Definition: postgres_ext.h:36
static void load_rangetype_info(TypeCacheEntry *typentry)
Definition: typcache.c:792
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1094
Oid fn_oid
Definition: fmgr.h:59
#define TYPECACHE_CMP_PROC
Definition: typcache.h:117
char typtype
Definition: typcache.h:41
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define Assert(condition)
Definition: c.h:681
Oid get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum)
Definition: lsyscache.c:744
#define ARRAY_GT_OP
Definition: pg_operator.h:784
void CreateCacheMemoryContext(void)
Definition: catcache.c:636
#define TCFLAGS_CHECKED_BTREE_OPCLASS
Definition: typcache.c:82
#define TCFLAGS_CHECKED_DOMAIN_CONSTRAINTS
Definition: typcache.c:98
static bool record_fields_have_compare(TypeCacheEntry *typentry)
Definition: typcache.c:1349
#define ARRAY_EQ_OP
Definition: pg_operator.h:776
Oid get_opclass_family(Oid opclass)
Definition: lsyscache.c:1047
static bool array_element_has_equality(TypeCacheEntry *typentry)
Definition: typcache.c:1279
static void load_domaintype_info(TypeCacheEntry *typentry)
Definition: typcache.c:855
#define TCFLAGS_CHECKED_HASH_PROC
Definition: typcache.c:88
char typalign
Definition: typcache.h:39
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define TYPECACHE_LT_OPR
Definition: typcache.h:115
#define TCFLAGS_CHECKED_LT_OPR
Definition: typcache.c:85
#define NameStr(name)
Definition: c.h:493
#define TYPECACHE_CMP_PROC_FINFO
Definition: typcache.h:120
#define TCFLAGS_CHECKED_HASH_OPCLASS
Definition: typcache.c:83
static bool range_element_has_extended_hashing(TypeCacheEntry *typentry)
Definition: typcache.c:1428
#define TYPECACHE_HASH_OPFAMILY
Definition: typcache.h:124
#define TYPECACHE_DOMAIN_INFO
Definition: typcache.h:126
static bool record_fields_have_equality(TypeCacheEntry *typentry)
Definition: typcache.c:1341
#define TCFLAGS_CHECKED_CMP_PROC
Definition: typcache.c:87
#define BTLessStrategyNumber
Definition: stratnum.h:29
static bool array_element_has_extended_hashing(TypeCacheEntry *typentry)
Definition: typcache.c:1303
TupleDesc tupDesc
Definition: typcache.h:80
static void TypeCacheConstrCallback(Datum arg, int cacheid, uint32 hashvalue)
Definition: typcache.c:2004
static HTAB * TypeCacheHash
Definition: typcache.c:76
#define TYPECACHE_HASH_PROC
Definition: typcache.h:118
#define TYPECACHE_TUPDESC
Definition: typcache.h:122
#define BTEqualStrategyNumber
Definition: stratnum.h:31
static void TypeCacheOpcCallback(Datum arg, int cacheid, uint32 hashvalue)
Definition: typcache.c:1975
MemoryContext CacheMemoryContext
Definition: mcxt.c:46
Oid get_opclass_input_type(Oid opclass)
Definition: lsyscache.c:1069
static List * prep_domain_constraints ( List constraints,
MemoryContext  execctx 
)
static

Definition at line 1127 of file typcache.c.

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

Referenced by InitDomainConstraintRef(), and UpdateDomainConstraintRef().

1128 {
1129  List *result = NIL;
1130  MemoryContext oldcxt;
1131  ListCell *lc;
1132 
1133  oldcxt = MemoryContextSwitchTo(execctx);
1134 
1135  foreach(lc, constraints)
1136  {
1138  DomainConstraintState *newr;
1139 
1141  newr->constrainttype = r->constrainttype;
1142  newr->name = r->name;
1143  newr->check_expr = r->check_expr;
1144  newr->check_exprstate = ExecInitExpr(r->check_expr, NULL);
1145 
1146  result = lappend(result, newr);
1147  }
1148 
1149  MemoryContextSwitchTo(oldcxt);
1150 
1151  return result;
1152 }
#define NIL
Definition: pg_list.h:69
DomainConstraintType constrainttype
Definition: execnodes.h:809
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
ExprState * check_exprstate
Definition: execnodes.h:812
List * lappend(List *list, void *datum)
Definition: list.c:128
#define makeNode(_type_)
Definition: nodes.h:558
#define lfirst(lc)
Definition: pg_list.h:106
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:113
Definition: pg_list.h:45
static bool range_element_has_extended_hashing ( TypeCacheEntry typentry)
static

Definition at line 1428 of file typcache.c.

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

Referenced by lookup_type_cache().

1429 {
1430  if (!(typentry->flags & TCFLAGS_CHECKED_ELEM_PROPERTIES))
1432  return (typentry->flags & TCFLAGS_HAVE_ELEM_EXTENDED_HASHING) != 0;
1433 }
static void cache_range_element_properties(TypeCacheEntry *typentry)
Definition: typcache.c:1436
#define TCFLAGS_HAVE_ELEM_EXTENDED_HASHING
Definition: typcache.c:94
#define TCFLAGS_CHECKED_ELEM_PROPERTIES
Definition: typcache.c:90
static bool range_element_has_hashing ( TypeCacheEntry typentry)
static

Definition at line 1420 of file typcache.c.

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

Referenced by lookup_type_cache().

1421 {
1422  if (!(typentry->flags & TCFLAGS_CHECKED_ELEM_PROPERTIES))
1424  return (typentry->flags & TCFLAGS_HAVE_ELEM_HASHING) != 0;
1425 }
static void cache_range_element_properties(TypeCacheEntry *typentry)
Definition: typcache.c:1436
#define TCFLAGS_CHECKED_ELEM_PROPERTIES
Definition: typcache.c:90
#define TCFLAGS_HAVE_ELEM_HASHING
Definition: typcache.c:93
static bool record_fields_have_compare ( TypeCacheEntry typentry)
static

Definition at line 1349 of file typcache.c.

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

Referenced by lookup_type_cache().

1350 {
1351  if (!(typentry->flags & TCFLAGS_CHECKED_FIELD_PROPERTIES))
1353  return (typentry->flags & TCFLAGS_HAVE_FIELD_COMPARE) != 0;
1354 }
#define TCFLAGS_CHECKED_FIELD_PROPERTIES
Definition: typcache.c:95
static void cache_record_field_properties(TypeCacheEntry *typentry)
Definition: typcache.c:1357
#define TCFLAGS_HAVE_FIELD_COMPARE
Definition: typcache.c:97
static bool record_fields_have_equality ( TypeCacheEntry typentry)
static

Definition at line 1341 of file typcache.c.

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

Referenced by lookup_type_cache().

1342 {
1343  if (!(typentry->flags & TCFLAGS_CHECKED_FIELD_PROPERTIES))
1345  return (typentry->flags & TCFLAGS_HAVE_FIELD_EQUALITY) != 0;
1346 }
#define TCFLAGS_CHECKED_FIELD_PROPERTIES
Definition: typcache.c:95
static void cache_record_field_properties(TypeCacheEntry *typentry)
Definition: typcache.c:1357
#define TCFLAGS_HAVE_FIELD_EQUALITY
Definition: typcache.c:96
static int record_type_typmod_compare ( const void *  a,
const void *  b,
size_t  size 
)
static

Definition at line 1636 of file typcache.c.

References equalTupleDescs(), and RecordCacheEntry::tupdesc.

Referenced by assign_record_type_typmod().

1637 {
1638  RecordCacheEntry *left = (RecordCacheEntry *) a;
1639  RecordCacheEntry *right = (RecordCacheEntry *) b;
1640 
1641  return equalTupleDescs(left->tupdesc, right->tupdesc) ? 0 : 1;
1642 }
bool equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
Definition: tupdesc.c:337
TupleDesc tupdesc
Definition: typcache.c:147
static uint32 record_type_typmod_hash ( const void *  data,
size_t  size 
)
static

Definition at line 1625 of file typcache.c.

References hashTupleDesc(), and RecordCacheEntry::tupdesc.

Referenced by assign_record_type_typmod().

1626 {
1627  RecordCacheEntry *entry = (RecordCacheEntry *) data;
1628 
1629  return hashTupleDesc(entry->tupdesc);
1630 }
uint32 hashTupleDesc(TupleDesc desc)
Definition: tupdesc.c:475
TupleDesc tupdesc
Definition: typcache.c:147
static dsa_pointer share_tupledesc ( dsa_area area,
TupleDesc  tupdesc,
uint32  typmod 
)
static

Definition at line 2320 of file typcache.c.

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

Referenced by find_or_make_matching_shared_tupledesc(), and SharedRecordTypmodRegistryInit().

2321 {
2322  dsa_pointer shared_dp;
2323  TupleDesc shared;
2324 
2325  shared_dp = dsa_allocate(area, TupleDescSize(tupdesc));
2326  shared = (TupleDesc) dsa_get_address(area, shared_dp);
2327  TupleDescCopy(shared, tupdesc);
2328  shared->tdtypmod = typmod;
2329 
2330  return shared_dp;
2331 }
#define TupleDescSize(src)
Definition: tupdesc.h:95
uint64 dsa_pointer
Definition: dsa.h:62
int32 tdtypmod
Definition: tupdesc.h:75
void * dsa_get_address(dsa_area *area, dsa_pointer dp)
Definition: dsa.c:924
struct tupleDesc * TupleDesc
void TupleDescCopy(TupleDesc dst, TupleDesc src)
Definition: tupdesc.c:196
#define dsa_allocate(area, size)
Definition: dsa.h:84
static int shared_record_table_compare ( const void *  a,
const void *  b,
size_t  size,
void *  arg 
)
static

Definition at line 203 of file typcache.c.

References dsa_get_address(), equalTupleDescs(), SharedRecordTableKey::local_tupdesc, SharedRecordTableKey::shared, SharedRecordTableKey::shared_tupdesc, and SharedRecordTableKey::u.

205 {
206  dsa_area *area = (dsa_area *) arg;
209  TupleDesc t1;
210  TupleDesc t2;
211 
212  if (k1->shared)
213  t1 = (TupleDesc) dsa_get_address(area, k1->u.shared_tupdesc);
214  else
215  t1 = k1->u.local_tupdesc;
216 
217  if (k2->shared)
218  t2 = (TupleDesc) dsa_get_address(area, k2->u.shared_tupdesc);
219  else
220  t2 = k2->u.local_tupdesc;
221 
222  return equalTupleDescs(t1, t2) ? 0 : 1;
223 }
void * dsa_get_address(dsa_area *area, dsa_pointer dp)
Definition: dsa.c:924
dsa_pointer shared_tupdesc
Definition: typcache.c:175
struct tupleDesc * TupleDesc
union SharedRecordTableKey::@36 u
Definition: dsa.c:354
bool equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
Definition: tupdesc.c:337
TupleDesc local_tupdesc
Definition: typcache.c:174
void * arg
static uint32 shared_record_table_hash ( const void *  a,
size_t  size,
void *  arg 
)
static

Definition at line 229 of file typcache.c.

References dsa_get_address(), hashTupleDesc(), SharedRecordTableKey::local_tupdesc, SharedRecordTableKey::shared, SharedRecordTableKey::shared_tupdesc, and SharedRecordTableKey::u.

230 {
231  dsa_area *area = (dsa_area *) arg;
233  TupleDesc t;
234 
235  if (k->shared)
236  t = (TupleDesc) dsa_get_address(area, k->u.shared_tupdesc);
237  else
238  t = k->u.local_tupdesc;
239 
240  return hashTupleDesc(t);
241 }
uint32 hashTupleDesc(TupleDesc desc)
Definition: tupdesc.c:475
void * dsa_get_address(dsa_area *area, dsa_pointer dp)
Definition: dsa.c:924
dsa_pointer shared_tupdesc
Definition: typcache.c:175
struct tupleDesc * TupleDesc
union SharedRecordTableKey::@36 u
Definition: dsa.c:354
TupleDesc local_tupdesc
Definition: typcache.c:174
void * arg
static void shared_record_typmod_registry_detach ( dsm_segment segment,
Datum  datum 
)
static

Definition at line 2453 of file typcache.c.

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

Referenced by SharedRecordTypmodRegistryAttach(), and SharedRecordTypmodRegistryInit().

2454 {
2455  /* Be cautious here: maybe we didn't finish initializing. */
2456  if (CurrentSession->shared_record_table != NULL)
2457  {
2460  }
2461  if (CurrentSession->shared_typmod_table != NULL)
2462  {
2465  }
2467 }
Session * CurrentSession
Definition: session.c:48
dshash_table * shared_record_table
Definition: session.h:32
void dshash_detach(dshash_table *hash_table)
Definition: dshash.c:302
struct SharedRecordTypmodRegistry * shared_typmod_registry
Definition: session.h:31
dshash_table * shared_typmod_table
Definition: session.h:33
void SharedRecordTypmodRegistryAttach ( SharedRecordTypmodRegistry registry)

Definition at line 1840 of file typcache.c.

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

Referenced by AttachSession().

1841 {
1842  MemoryContext old_context;
1843  dshash_table *record_table;
1844  dshash_table *typmod_table;
1845 
1847 
1848  /* We can't already be attached to a shared registry. */
1849  Assert(CurrentSession != NULL);
1850  Assert(CurrentSession->segment != NULL);
1851  Assert(CurrentSession->area != NULL);
1855 
1856  /*
1857  * We can't already have typmods in our local cache, because they'd clash
1858  * with those imported by SharedRecordTypmodRegistryInit. This should be
1859  * a freshly started parallel worker. If we ever support worker
1860  * recycling, a worker would need to zap its local cache in between
1861  * servicing different queries, in order to be able to call this and
1862  * synchronize typmods with a new leader; but that's problematic because
1863  * we can't be very sure that record-typmod-related state hasn't escaped
1864  * to anywhere else in the process.
1865  */
1866  Assert(NextRecordTypmod == 0);
1867 
1868  old_context = MemoryContextSwitchTo(TopMemoryContext);
1869 
1870  /* Attach to the two hash tables. */
1871  record_table = dshash_attach(CurrentSession->area,
1873  registry->record_table_handle,
1874  CurrentSession->area);
1875  typmod_table = dshash_attach(CurrentSession->area,
1877  registry->typmod_table_handle,
1878  NULL);
1879 
1880  MemoryContextSwitchTo(old_context);
1881 
1882  /*
1883  * Set up detach hook to run at worker exit. Currently this is the same
1884  * as the leader's detach hook, but in future they might need to be
1885  * different.
1886  */
1889  PointerGetDatum(registry));
1890 
1891  /*
1892  * Set up the session state that will tell assign_record_type_typmod and
1893  * lookup_rowtype_tupdesc_internal about the shared registry.
1894  */
1896  CurrentSession->shared_record_table = record_table;
1897  CurrentSession->shared_typmod_table = typmod_table;
1898 }
dshash_table * dshash_attach(dsa_area *area, const dshash_parameters *params, dshash_table_handle handle, void *arg)
Definition: dshash.c:263
#define PointerGetDatum(X)
Definition: postgres.h:562
Session * CurrentSession
Definition: session.c:48
static const dshash_parameters srtr_record_table_params
Definition: typcache.c:244
dshash_table * shared_record_table
Definition: session.h:32
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void on_dsm_detach(dsm_segment *seg, on_dsm_detach_callback function, Datum arg)
Definition: dsm.c:1037
dsa_area * area
Definition: session.h:28
#define IsParallelWorker()
Definition: parallel.h:52
MemoryContext TopMemoryContext
Definition: mcxt.c:43
static const dshash_parameters srtr_typmod_table_params
Definition: typcache.c:253
static void shared_record_typmod_registry_detach(dsm_segment *segment, Datum datum)
Definition: typcache.c:2453
static int32 NextRecordTypmod
Definition: typcache.c:265
struct SharedRecordTypmodRegistry * shared_typmod_registry
Definition: session.h:31
dshash_table * shared_typmod_table
Definition: session.h:33
#define Assert(condition)
Definition: c.h:681
dshash_table_handle record_table_handle
Definition: typcache.c:157
dshash_table_handle typmod_table_handle
Definition: typcache.c:159
dsm_segment * segment
Definition: session.h:27
size_t SharedRecordTypmodRegistryEstimate ( void  )

Definition at line 1719 of file typcache.c.

Referenced by GetSessionDsmHandle().

1720 {
1721  return sizeof(SharedRecordTypmodRegistry);
1722 }
struct SharedRecordTypmodRegistry SharedRecordTypmodRegistry
Definition: typcache.h:148
void SharedRecordTypmodRegistryInit ( SharedRecordTypmodRegistry registry,
dsm_segment segment,
dsa_area area 
)

Definition at line 1741 of file typcache.c.

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, 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, tupleDesc::tdtypmod, TopMemoryContext, SharedTypmodTableEntry::typmod, SharedRecordTypmodRegistry::typmod_table_handle, and SharedRecordTableKey::u.

Referenced by GetSessionDsmHandle().

1744 {
1745  MemoryContext old_context;
1746  dshash_table *record_table;
1747  dshash_table *typmod_table;
1748  int32 typmod;
1749 
1751 
1752  /* We can't already be attached to a shared registry. */
1756 
1757  old_context = MemoryContextSwitchTo(TopMemoryContext);
1758 
1759  /* Create the hash table of tuple descriptors indexed by themselves. */
1760  record_table = dshash_create(area, &srtr_record_table_params, area);
1761 
1762  /* Create the hash table of tuple descriptors indexed by typmod. */
1763  typmod_table = dshash_create(area, &srtr_typmod_table_params, NULL);
1764 
1765  MemoryContextSwitchTo(old_context);
1766 
1767  /* Initialize the SharedRecordTypmodRegistry. */
1768  registry->record_table_handle = dshash_get_hash_table_handle(record_table);
1769  registry->typmod_table_handle = dshash_get_hash_table_handle(typmod_table);
1771 
1772  /*
1773  * Copy all entries from this backend's private registry into the shared
1774  * registry.
1775  */
1776  for (typmod = 0; typmod < NextRecordTypmod; ++typmod)
1777  {
1778  SharedTypmodTableEntry *typmod_table_entry;
1779  SharedRecordTableEntry *record_table_entry;
1780  SharedRecordTableKey record_table_key;
1781  dsa_pointer shared_dp;
1782  TupleDesc tupdesc;
1783  bool found;
1784 
1785  tupdesc = RecordCacheArray[typmod];
1786  if (tupdesc == NULL)
1787  continue;
1788 
1789  /* Copy the TupleDesc into shared memory. */
1790  shared_dp = share_tupledesc(area, tupdesc, typmod);
1791 
1792  /* Insert into the typmod table. */
1793  typmod_table_entry = dshash_find_or_insert(typmod_table,
1794  &tupdesc->tdtypmod,
1795  &found);
1796  if (found)
1797  elog(ERROR, "cannot create duplicate shared record typmod");
1798  typmod_table_entry->typmod = tupdesc->tdtypmod;
1799  typmod_table_entry->shared_tupdesc = shared_dp;
1800  dshash_release_lock(typmod_table, typmod_table_entry);
1801 
1802  /* Insert into the record table. */
1803  record_table_key.shared = false;
1804  record_table_key.u.local_tupdesc = tupdesc;
1805  record_table_entry = dshash_find_or_insert(record_table,
1806  &record_table_key,
1807  &found);
1808  if (!found)
1809  {
1810  record_table_entry->key.shared = true;
1811  record_table_entry->key.u.shared_tupdesc = shared_dp;
1812  }
1813  dshash_release_lock(record_table, record_table_entry);
1814  }
1815 
1816  /*
1817  * Set up the global state that will tell assign_record_type_typmod and
1818  * lookup_rowtype_tupdesc_internal about the shared registry.
1819  */
1820  CurrentSession->shared_record_table = record_table;
1821  CurrentSession->shared_typmod_table = typmod_table;
1823 
1824  /*
1825  * We install a detach hook in the leader, but only to handle cleanup on
1826  * failure during GetSessionDsmHandle(). Once GetSessionDsmHandle() pins
1827  * the memory, the leader process will use a shared registry until it
1828  * exits.
1829  */
1831 }
Session * CurrentSession
Definition: session.c:48
static const dshash_parameters srtr_record_table_params
Definition: typcache.c:244
dshash_table * shared_record_table
Definition: session.h:32
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
SharedRecordTableKey key
Definition: typcache.c:186
void on_dsm_detach(dsm_segment *seg, on_dsm_detach_callback function, Datum arg)
Definition: dsm.c:1037
void dshash_release_lock(dshash_table *hash_table, void *entry)
Definition: dshash.c:561
uint64 dsa_pointer
Definition: dsa.h:62
int32 tdtypmod
Definition: tupdesc.h:75
signed int int32
Definition: c.h:246
static TupleDesc * RecordCacheArray
Definition: typcache.c:263
dsa_pointer shared_tupdesc
Definition: typcache.c:196
pg_atomic_uint32 next_typmod
Definition: typcache.c:161
#define ERROR
Definition: elog.h:43
dshash_table_handle dshash_get_hash_table_handle(dshash_table *hash_table)
Definition: dshash.c:362
dsa_pointer shared_tupdesc
Definition: typcache.c:175
#define IsParallelWorker()
Definition: parallel.h:52
MemoryContext TopMemoryContext
Definition: mcxt.c:43
static const dshash_parameters srtr_typmod_table_params
Definition: typcache.c:253
static void shared_record_typmod_registry_detach(dsm_segment *segment, Datum datum)
Definition: typcache.c:2453
static int32 NextRecordTypmod
Definition: typcache.c:265
struct SharedRecordTypmodRegistry * shared_typmod_registry
Definition: session.h:31
uintptr_t Datum
Definition: postgres.h:372
dshash_table * dshash_create(dsa_area *area, const dshash_parameters *params, void *arg)
Definition: dshash.c:196
dshash_table * shared_typmod_table
Definition: session.h:33
union SharedRecordTableKey::@36 u
#define Assert(condition)
Definition: c.h:681
static dsa_pointer share_tupledesc(dsa_area *area, TupleDesc tupdesc, uint32 typmod)
Definition: typcache.c:2320
dshash_table_handle record_table_handle
Definition: typcache.c:157
void * dshash_find_or_insert(dshash_table *hash_table, const void *key, bool *found)
Definition: dshash.c:430
TupleDesc local_tupdesc
Definition: typcache.c:174
static void pg_atomic_init_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
Definition: atomics.h:234
#define elog
Definition: elog.h:219
dshash_table_handle typmod_table_handle
Definition: typcache.c:159
static void TypeCacheConstrCallback ( Datum  arg,
int  cacheid,
uint32  hashvalue 
)
static

Definition at line 2004 of file typcache.c.

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

Referenced by lookup_type_cache().

2005 {
2006  TypeCacheEntry *typentry;
2007 
2008  /*
2009  * Because this is called very frequently, and typically very few of the
2010  * typcache entries are for domains, we don't use hash_seq_search here.
2011  * Instead we thread all the domain-type entries together so that we can
2012  * visit them cheaply.
2013  */
2014  for (typentry = firstDomainTypeEntry;
2015  typentry != NULL;
2016  typentry = typentry->nextDomain)
2017  {
2018  /* Reset domain constraint validity information */
2020  }
2021 }
static TypeCacheEntry * firstDomainTypeEntry
Definition: typcache.c:79
struct TypeCacheEntry * nextDomain
Definition: typcache.h:110
#define TCFLAGS_CHECKED_DOMAIN_CONSTRAINTS
Definition: typcache.c:98
static void TypeCacheOpcCallback ( Datum  arg,
int  cacheid,
uint32  hashvalue 
)
static

Definition at line 1975 of file typcache.c.

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

Referenced by lookup_type_cache().

1976 {
1978  TypeCacheEntry *typentry;
1979 
1980  /* TypeCacheHash must exist, else this callback wouldn't be registered */
1981  hash_seq_init(&status, TypeCacheHash);
1982  while ((typentry = (TypeCacheEntry *) hash_seq_search(&status)) != NULL)
1983  {
1984  /* Reset equality/comparison/hashing validity information */
1985  typentry->flags = 0;
1986  }
1987 }
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1385
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1375
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:225
static HTAB * TypeCacheHash
Definition: typcache.c:76
static void TypeCacheRelCallback ( Datum  arg,
Oid  relid 
)
static

Definition at line 1923 of file typcache.c.

References Assert, TypeCacheEntry::flags, FreeTupleDesc(), hash_seq_init(), hash_seq_search(), InvalidOid, status(), tupleDesc::tdrefcount, TypeCacheEntry::tupDesc, TypeCacheEntry::typrelid, TypeCacheEntry::typtype, and TYPTYPE_COMPOSITE.

Referenced by lookup_type_cache().

1924 {
1926  TypeCacheEntry *typentry;
1927 
1928  /* TypeCacheHash must exist, else this callback wouldn't be registered */
1929  hash_seq_init(&status, TypeCacheHash);
1930  while ((typentry = (TypeCacheEntry *) hash_seq_search(&status)) != NULL)
1931  {
1932  if (typentry->typtype != TYPTYPE_COMPOSITE)
1933  continue; /* skip non-composites */
1934 
1935  /* Skip if no match, unless we're zapping all composite types */
1936  if (relid != typentry->typrelid && relid != InvalidOid)
1937  continue;
1938 
1939  /* Delete tupdesc if we have it */
1940  if (typentry->tupDesc != NULL)
1941  {
1942  /*
1943  * Release our refcount, and free the tupdesc if none remain.
1944  * (Can't use DecrTupleDescRefCount because this reference is not
1945  * logged in current resource owner.)
1946  */
1947  Assert(typentry->tupDesc->tdrefcount > 0);
1948  if (--typentry->tupDesc->tdrefcount == 0)
1949  FreeTupleDesc(typentry->tupDesc);
1950  typentry->tupDesc = NULL;
1951  }
1952 
1953  /* Reset equality/comparison/hashing validity information */
1954  typentry->flags = 0;
1955  }
1956 }
#define TYPTYPE_COMPOSITE
Definition: pg_type.h:721
#define InvalidOid
Definition: postgres_ext.h:36
char typtype
Definition: typcache.h:41
#define Assert(condition)
Definition: c.h:681
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1385
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1375
void FreeTupleDesc(TupleDesc tupdesc)
Definition: tupdesc.c:251
int tdrefcount
Definition: tupdesc.h:77
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:225
TupleDesc tupDesc
Definition: typcache.h:80
static HTAB * TypeCacheHash
Definition: typcache.c:76
void UpdateDomainConstraintRef ( DomainConstraintRef ref)

Definition at line 1203 of file typcache.c.

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, TypeCacheEntry::typtype, and TYPTYPE_DOMAIN.

Referenced by domain_check_input().

1204 {
1205  TypeCacheEntry *typentry = ref->tcache;
1206 
1207  /* Make sure typcache entry's data is up to date */
1208  if ((typentry->flags & TCFLAGS_CHECKED_DOMAIN_CONSTRAINTS) == 0 &&
1209  typentry->typtype == TYPTYPE_DOMAIN)
1210  load_domaintype_info(typentry);
1211 
1212  /* Transfer to ref object if there's new info, adjusting refcounts */
1213  if (ref->dcc != typentry->domainData)
1214  {
1215  /* Paranoia --- be sure link is nulled before trying to release */
1216  DomainConstraintCache *dcc = ref->dcc;
1217 
1218  if (dcc)
1219  {
1220  /*
1221  * Note: we just leak the previous list of executable domain
1222  * constraints. Alternatively, we could keep those in a child
1223  * context of ref->refctx and free that context at this point.
1224  * However, in practice this code path will be taken so seldom
1225  * that the extra bookkeeping for a child context doesn't seem
1226  * worthwhile; we'll just allow a leak for the lifespan of refctx.
1227  */
1228  ref->constraints = NIL;
1229  ref->dcc = NULL;
1230  decr_dcc_refcount(dcc);
1231  }
1232  dcc = typentry->domainData;
1233  if (dcc)
1234  {
1235  ref->dcc = dcc;
1236  dcc->dccRefCount++;
1237  if (ref->need_exprstate)
1239  ref->refctx);
1240  else
1241  ref->constraints = dcc->constraints;
1242  }
1243  }
1244 }
#define NIL
Definition: pg_list.h:69
#define TYPTYPE_DOMAIN
Definition: pg_type.h:722
DomainConstraintCache * dcc
Definition: typcache.h:144
DomainConstraintCache * domainData
Definition: typcache.h:98
MemoryContext refctx
Definition: typcache.h:139
char typtype
Definition: typcache.h:41
static List * prep_domain_constraints(List *constraints, MemoryContext execctx)
Definition: typcache.c:1127
TypeCacheEntry * tcache
Definition: typcache.h:140
#define TCFLAGS_CHECKED_DOMAIN_CONSTRAINTS
Definition: typcache.c:98
static void load_domaintype_info(TypeCacheEntry *typentry)
Definition: typcache.c:855
static void decr_dcc_refcount(DomainConstraintCache *dcc)
Definition: typcache.c:1095

Variable Documentation

TypeCacheEntry* firstDomainTypeEntry = NULL
static

Definition at line 79 of file typcache.c.

Referenced by lookup_type_cache().

int32 NextRecordTypmod = 0
static
TupleDesc* RecordCacheArray = NULL
static

Definition at line 263 of file typcache.c.

int32 RecordCacheArrayLen = 0
static
HTAB* RecordCacheHash = NULL
static

Definition at line 261 of file typcache.c.

const dshash_parameters srtr_record_table_params
static
Initial value:
= {
}
static int shared_record_table_compare(const void *a, const void *b, size_t size, void *arg)
Definition: typcache.c:203
static uint32 shared_record_table_hash(const void *a, size_t size, void *arg)
Definition: typcache.c:229
struct SharedRecordTableKey SharedRecordTableKey

Definition at line 244 of file typcache.c.

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

Definition at line 253 of file typcache.c.

HTAB* TypeCacheHash = NULL
static

Definition at line 76 of file typcache.c.