#include "access/tupdesc.h"
#include "fmgr.h"
Go to the source code of this file.
Data Structures | |
struct | TypeCacheEntry |
Defines | |
#define | TYPECACHE_EQ_OPR 0x0001 |
#define | TYPECACHE_LT_OPR 0x0002 |
#define | TYPECACHE_GT_OPR 0x0004 |
#define | TYPECACHE_CMP_PROC 0x0008 |
#define | TYPECACHE_HASH_PROC 0x0010 |
#define | TYPECACHE_EQ_OPR_FINFO 0x0020 |
#define | TYPECACHE_CMP_PROC_FINFO 0x0040 |
#define | TYPECACHE_HASH_PROC_FINFO 0x0080 |
#define | TYPECACHE_TUPDESC 0x0100 |
#define | TYPECACHE_BTREE_OPFAMILY 0x0200 |
#define | TYPECACHE_HASH_OPFAMILY 0x0400 |
#define | TYPECACHE_RANGE_INFO 0x0800 |
Typedefs | |
typedef struct TypeCacheEntry | TypeCacheEntry |
Functions | |
TypeCacheEntry * | lookup_type_cache (Oid type_id, int flags) |
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) |
void | assign_record_type_typmod (TupleDesc tupDesc) |
int | compare_values_of_enum (TypeCacheEntry *tcache, Oid arg1, Oid arg2) |
#define TYPECACHE_BTREE_OPFAMILY 0x0200 |
Definition at line 107 of file typcache.h.
Referenced by lookup_type_cache().
#define TYPECACHE_CMP_PROC 0x0008 |
Definition at line 101 of file typcache.h.
Referenced by cache_array_element_properties(), cache_record_field_properties(), ExecInitExpr(), lookup_type_cache(), and op_mergejoinable().
#define TYPECACHE_CMP_PROC_FINFO 0x0040 |
Definition at line 104 of file typcache.h.
Referenced by array_cmp(), array_typanalyze(), calc_arraycontsel(), lookup_type_cache(), record_cmp(), and scalararraysel_containment().
#define TYPECACHE_EQ_OPR 0x0001 |
Definition at line 98 of file typcache.h.
Referenced by array_typanalyze(), cache_array_element_properties(), cache_record_field_properties(), get_sort_group_operators(), lookup_type_cache(), and scalararraysel().
#define TYPECACHE_EQ_OPR_FINFO 0x0020 |
Definition at line 103 of file typcache.h.
Referenced by array_contain_compare(), array_eq(), array_replace_internal(), lookup_type_cache(), and record_eq().
#define TYPECACHE_GT_OPR 0x0004 |
Definition at line 100 of file typcache.h.
Referenced by get_rule_orderby(), get_sort_group_operators(), and lookup_type_cache().
#define TYPECACHE_HASH_OPFAMILY 0x0400 |
Definition at line 108 of file typcache.h.
Referenced by lookup_type_cache().
#define TYPECACHE_HASH_PROC 0x0010 |
Definition at line 102 of file typcache.h.
Referenced by cache_array_element_properties(), lookup_type_cache(), and op_hashjoinable().
#define TYPECACHE_HASH_PROC_FINFO 0x0080 |
Definition at line 105 of file typcache.h.
Referenced by array_typanalyze(), hash_array(), hash_range(), and lookup_type_cache().
#define TYPECACHE_LT_OPR 0x0002 |
Definition at line 99 of file typcache.h.
Referenced by get_rule_orderby(), get_sort_group_operators(), and lookup_type_cache().
#define TYPECACHE_RANGE_INFO 0x0800 |
Definition at line 109 of file typcache.h.
Referenced by get_range_io_data(), lookup_type_cache(), and range_get_typcache().
#define TYPECACHE_TUPDESC 0x0100 |
Definition at line 106 of file typcache.h.
Referenced by lookup_rowtype_tupdesc_internal(), and lookup_type_cache().
typedef struct TypeCacheEntry TypeCacheEntry |
void assign_record_type_typmod | ( | TupleDesc | tupDesc | ) |
Definition at line 782 of file typcache.c.
References Assert, tupleDesc::attrs, CacheMemoryContext, CreateCacheMemoryContext(), CreateTupleDescCopy(), HASHCTL::entrysize, equalTupleDescs(), HASHCTL::hash, hash_create(), HASH_ELEM, HASH_FUNCTION, hash_search(), i, HASHCTL::keysize, lcons(), lfirst, MemoryContextSwitchTo(), MemSet, tupleDesc::natts, NextRecordTypmod, NULL, palloc(), REC_HASH_KEYS, RecordCacheArrayLen, RECORDOID, repalloc(), tupleDesc::tdrefcount, tupleDesc::tdtypeid, tupleDesc::tdtypmod, and RecordCacheEntry::tupdescs.
Referenced by BlessTupleDesc(), ExecEvalWholeRowVar(), internal_get_result_type(), and SPI_returntuple().
{ RecordCacheEntry *recentry; TupleDesc entDesc; Oid hashkey[REC_HASH_KEYS]; bool found; int i; ListCell *l; int32 newtypmod; MemoryContext oldcxt; Assert(tupDesc->tdtypeid == RECORDOID); if (RecordCacheHash == NULL) { /* First time through: initialize the hash table */ HASHCTL ctl; MemSet(&ctl, 0, sizeof(ctl)); ctl.keysize = REC_HASH_KEYS * sizeof(Oid); ctl.entrysize = sizeof(RecordCacheEntry); ctl.hash = tag_hash; RecordCacheHash = hash_create("Record information cache", 64, &ctl, HASH_ELEM | HASH_FUNCTION); /* Also make sure CacheMemoryContext exists */ if (!CacheMemoryContext) CreateCacheMemoryContext(); } /* Find or create a hashtable entry for this hash class */ MemSet(hashkey, 0, sizeof(hashkey)); for (i = 0; i < tupDesc->natts; i++) { if (i >= REC_HASH_KEYS) break; hashkey[i] = tupDesc->attrs[i]->atttypid; } recentry = (RecordCacheEntry *) hash_search(RecordCacheHash, (void *) hashkey, HASH_ENTER, &found); if (!found) { /* New entry ... hash_search initialized only the hash key */ recentry->tupdescs = NIL; } /* Look for existing record cache entry */ foreach(l, recentry->tupdescs) { entDesc = (TupleDesc) lfirst(l); if (equalTupleDescs(tupDesc, entDesc)) { tupDesc->tdtypmod = entDesc->tdtypmod; return; } } /* Not present, so need to manufacture an entry */ oldcxt = MemoryContextSwitchTo(CacheMemoryContext); if (RecordCacheArray == NULL) { RecordCacheArray = (TupleDesc *) palloc(64 * sizeof(TupleDesc)); RecordCacheArrayLen = 64; } else if (NextRecordTypmod >= RecordCacheArrayLen) { int32 newlen = RecordCacheArrayLen * 2; RecordCacheArray = (TupleDesc *) repalloc(RecordCacheArray, newlen * sizeof(TupleDesc)); RecordCacheArrayLen = newlen; } /* if fail in subrs, no damage except possibly some wasted memory... */ entDesc = CreateTupleDescCopy(tupDesc); recentry->tupdescs = lcons(entDesc, recentry->tupdescs); /* mark it as a reference-counted tupdesc */ entDesc->tdrefcount = 1; /* now it's safe to advance NextRecordTypmod */ newtypmod = NextRecordTypmod++; entDesc->tdtypmod = newtypmod; RecordCacheArray[newtypmod] = entDesc; /* report to caller as well */ tupDesc->tdtypmod = newtypmod; MemoryContextSwitchTo(oldcxt); }
int compare_values_of_enum | ( | TypeCacheEntry * | tcache, | |
Oid | arg1, | |||
Oid | arg2 | |||
) |
Definition at line 973 of file typcache.c.
References elog, enum_known_sorted(), TypeCacheEntry::enumData, ERROR, find_enumitem(), format_type_be(), load_enum_cache_data(), NULL, EnumItem::sort_order, and TypeCacheEntry::type_id.
Referenced by enum_cmp_internal().
{ TypeCacheEnumData *enumdata; EnumItem *item1; EnumItem *item2; /* * Equal OIDs are certainly equal --- this case was probably handled by * our caller, but we may as well check. */ if (arg1 == arg2) return 0; /* Load up the cache if first time through */ if (tcache->enumData == NULL) load_enum_cache_data(tcache); enumdata = tcache->enumData; /* * If both OIDs are known-sorted, we can just compare them directly. */ if (enum_known_sorted(enumdata, arg1) && enum_known_sorted(enumdata, arg2)) { if (arg1 < arg2) return -1; else return 1; } /* * Slow path: we have to identify their actual sort-order positions. */ item1 = find_enumitem(enumdata, arg1); item2 = find_enumitem(enumdata, arg2); if (item1 == NULL || item2 == NULL) { /* * We couldn't find one or both values. That means the enum has * changed under us, so re-initialize the cache and try again. We * don't bother retrying the known-sorted case in this path. */ load_enum_cache_data(tcache); enumdata = tcache->enumData; item1 = find_enumitem(enumdata, arg1); item2 = find_enumitem(enumdata, arg2); /* * If we still can't find the values, complain: we must have corrupt * data. */ if (item1 == NULL) elog(ERROR, "enum value %u not found in cache for enum %s", arg1, format_type_be(tcache->type_id)); if (item2 == NULL) elog(ERROR, "enum value %u not found in cache for enum %s", arg2, format_type_be(tcache->type_id)); } if (item1->sort_order < item2->sort_order) return -1; else if (item1->sort_order > item2->sort_order) return 1; else return 0; }
Definition at line 731 of file typcache.c.
References IncrTupleDescRefCount(), and lookup_rowtype_tupdesc_internal().
Referenced by ATExecAddOf(), coerce_record_to_complex(), composite_to_json(), exec_move_row_from_datum(), ExecEvalWholeRowSlow(), ExecEvalWholeRowVar(), get_cached_rowtype(), get_rule_expr(), get_tupdesc_from_datum(), GetAttributeByName(), GetAttributeByNum(), hstore_from_record(), hstore_populate_record(), json_populate_record(), plperl_hash_from_datum(), pltcl_func_handler(), PLy_exec_function(), PLy_function_build_args(), PLyObject_ToComposite(), record_cmp(), record_eq(), record_in(), record_out(), record_recv(), record_send(), rowtype_field_matches(), and transformOfType().
{ TupleDesc tupDesc; tupDesc = lookup_rowtype_tupdesc_internal(type_id, typmod, false); IncrTupleDescRefCount(tupDesc); return tupDesc; }
Definition at line 765 of file typcache.c.
References CreateTupleDescCopyConstr(), and lookup_rowtype_tupdesc_internal().
Referenced by ExecInitExpr(), ExecMakeTableFunctionResult(), expandRecordVariable(), ExpandRowReference(), get_expr_result_type(), get_name_for_var_field(), internal_get_result_type(), and TypeGetTupleDesc().
{ TupleDesc tmp; tmp = lookup_rowtype_tupdesc_internal(type_id, typmod, false); return CreateTupleDescCopyConstr(tmp); }
Definition at line 748 of file typcache.c.
References IncrTupleDescRefCount(), lookup_rowtype_tupdesc_internal(), and NULL.
Referenced by plperl_sv_to_datum(), and toast_flatten_tuple_attribute().
{ TupleDesc tupDesc; tupDesc = lookup_rowtype_tupdesc_internal(type_id, typmod, noError); if (tupDesc != NULL) IncrTupleDescRefCount(tupDesc); return tupDesc; }
TypeCacheEntry* lookup_type_cache | ( | Oid | type_id, | |
int | flags | |||
) |
Definition at line 152 of file typcache.c.
References array_element_has_compare(), array_element_has_equality(), 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(), TypeCacheEntry::cmp_proc, TypeCacheEntry::cmp_proc_finfo, CreateCacheMemoryContext(), elog, HASHCTL::entrysize, TypeCacheEntry::eq_opr, TypeCacheEntry::eq_opr_finfo, ereport, errcode(), errmsg(), ERROR, 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, HASHCTL::hash, HASH_AM_OID, hash_create(), HASH_ELEM, HASH_FUNCTION, TypeCacheEntry::hash_opf, TypeCacheEntry::hash_opintype, TypeCacheEntry::hash_proc, TypeCacheEntry::hash_proc_finfo, hash_search(), HASHPROC, HeapTupleIsValid, HTEqualStrategyNumber, InvalidOid, HASHCTL::keysize, load_rangetype_info(), load_typcache_tupdesc(), TypeCacheEntry::lt_opr, MemSet, NameStr, NULL, ObjectIdGetDatum, OidIsValid, RECORD_EQ_OP, record_fields_have_compare(), record_fields_have_equality(), RECORD_GT_OP, RECORD_LT_OP, ReleaseSysCache(), TypeCacheEntry::rngelemtype, SearchSysCache1, TypeCacheEntry::tupDesc, TypeCacheEntry::typalign, TypeCacheEntry::typbyval, TypeCacheEntry::type_id, TYPECACHE_BTREE_OPFAMILY, TYPECACHE_CMP_PROC, TYPECACHE_CMP_PROC_FINFO, TYPECACHE_EQ_OPR, TYPECACHE_EQ_OPR_FINFO, TYPECACHE_GT_OPR, TYPECACHE_HASH_OPFAMILY, TYPECACHE_HASH_PROC, TYPECACHE_HASH_PROC_FINFO, TYPECACHE_LT_OPR, TYPECACHE_RANGE_INFO, TYPECACHE_TUPDESC, TypeCacheRelCallback(), TYPEOID, TypeCacheEntry::typlen, TypeCacheEntry::typrelid, TypeCacheEntry::typstorage, TypeCacheEntry::typtype, TYPTYPE_COMPOSITE, and TYPTYPE_RANGE.
Referenced by array_cmp(), array_contain_compare(), array_eq(), array_replace_internal(), array_typanalyze(), cache_array_element_properties(), cache_record_field_properties(), calc_arraycontsel(), enum_cmp_internal(), ExecInitExpr(), get_range_io_data(), get_rule_orderby(), get_sort_group_operators(), hash_array(), hash_range(), load_rangetype_info(), lookup_rowtype_tupdesc_internal(), op_hashjoinable(), op_mergejoinable(), range_get_typcache(), record_cmp(), record_eq(), scalararraysel(), and scalararraysel_containment().
{ TypeCacheEntry *typentry; bool found; if (TypeCacheHash == NULL) { /* First time through: initialize the hash table */ HASHCTL ctl; MemSet(&ctl, 0, sizeof(ctl)); ctl.keysize = sizeof(Oid); ctl.entrysize = sizeof(TypeCacheEntry); ctl.hash = oid_hash; TypeCacheHash = hash_create("Type information cache", 64, &ctl, HASH_ELEM | HASH_FUNCTION); /* Also set up a callback for relcache SI invalidations */ CacheRegisterRelcacheCallback(TypeCacheRelCallback, (Datum) 0); /* Also make sure CacheMemoryContext exists */ if (!CacheMemoryContext) CreateCacheMemoryContext(); } /* Try to look up an existing entry */ typentry = (TypeCacheEntry *) hash_search(TypeCacheHash, (void *) &type_id, HASH_FIND, NULL); if (typentry == NULL) { /* * If we didn't find one, we want to make one. But first look up the * pg_type row, just to make sure we don't make a cache entry for an * invalid type OID. */ HeapTuple tp; Form_pg_type typtup; tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_id)); if (!HeapTupleIsValid(tp)) elog(ERROR, "cache lookup failed for type %u", type_id); typtup = (Form_pg_type) GETSTRUCT(tp); if (!typtup->typisdefined) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("type \"%s\" is only a shell", NameStr(typtup->typname)))); /* Now make the typcache entry */ typentry = (TypeCacheEntry *) hash_search(TypeCacheHash, (void *) &type_id, HASH_ENTER, &found); Assert(!found); /* it wasn't there a moment ago */ MemSet(typentry, 0, sizeof(TypeCacheEntry)); typentry->type_id = type_id; typentry->typlen = typtup->typlen; typentry->typbyval = typtup->typbyval; typentry->typalign = typtup->typalign; typentry->typstorage = typtup->typstorage; typentry->typtype = typtup->typtype; typentry->typrelid = typtup->typrelid; ReleaseSysCache(tp); } /* * If we haven't already found the opclasses, try to do so */ if ((flags & (TYPECACHE_EQ_OPR | TYPECACHE_LT_OPR | TYPECACHE_GT_OPR | TYPECACHE_CMP_PROC | TYPECACHE_EQ_OPR_FINFO | TYPECACHE_CMP_PROC_FINFO | TYPECACHE_BTREE_OPFAMILY)) && typentry->btree_opf == InvalidOid) { Oid opclass; opclass = GetDefaultOpClass(type_id, BTREE_AM_OID); if (OidIsValid(opclass)) { typentry->btree_opf = get_opclass_family(opclass); typentry->btree_opintype = get_opclass_input_type(opclass); } /* If no btree opclass, we force lookup of the hash opclass */ if (typentry->btree_opf == InvalidOid) { if (typentry->hash_opf == InvalidOid) { opclass = GetDefaultOpClass(type_id, HASH_AM_OID); if (OidIsValid(opclass)) { typentry->hash_opf = get_opclass_family(opclass); typentry->hash_opintype = get_opclass_input_type(opclass); } } } else { /* * In case we find a btree opclass where previously we only found * a hash opclass, reset eq_opr and derived information so that we * can fetch the btree equality operator instead of the hash * equality operator. (They're probably the same operator, but we * don't assume that here.) */ typentry->eq_opr = InvalidOid; typentry->eq_opr_finfo.fn_oid = InvalidOid; typentry->hash_proc = InvalidOid; typentry->hash_proc_finfo.fn_oid = InvalidOid; } } if ((flags & (TYPECACHE_HASH_PROC | TYPECACHE_HASH_PROC_FINFO | TYPECACHE_HASH_OPFAMILY)) && typentry->hash_opf == InvalidOid) { Oid opclass; opclass = GetDefaultOpClass(type_id, HASH_AM_OID); if (OidIsValid(opclass)) { typentry->hash_opf = get_opclass_family(opclass); typentry->hash_opintype = get_opclass_input_type(opclass); } } /* Look for requested operators and functions */ if ((flags & (TYPECACHE_EQ_OPR | TYPECACHE_EQ_OPR_FINFO)) && typentry->eq_opr == InvalidOid) { Oid eq_opr = InvalidOid; if (typentry->btree_opf != InvalidOid) eq_opr = get_opfamily_member(typentry->btree_opf, typentry->btree_opintype, typentry->btree_opintype, BTEqualStrategyNumber); if (eq_opr == InvalidOid && typentry->hash_opf != InvalidOid) eq_opr = get_opfamily_member(typentry->hash_opf, typentry->hash_opintype, typentry->hash_opintype, HTEqualStrategyNumber); /* * If the proposed equality operator is array_eq or record_eq, check * to see if the element type or column types support equality. If * not, array_eq or record_eq would fail at runtime, so we don't want * to report that the type has equality. */ if (eq_opr == ARRAY_EQ_OP && !array_element_has_equality(typentry)) eq_opr = InvalidOid; else if (eq_opr == RECORD_EQ_OP && !record_fields_have_equality(typentry)) eq_opr = InvalidOid; typentry->eq_opr = eq_opr; /* * Reset info about hash function whenever we pick up new info about * equality operator. This is so we can ensure that the hash function * matches the operator. */ typentry->hash_proc = InvalidOid; typentry->hash_proc_finfo.fn_oid = InvalidOid; } if ((flags & TYPECACHE_LT_OPR) && typentry->lt_opr == InvalidOid) { Oid lt_opr = InvalidOid; if (typentry->btree_opf != InvalidOid) lt_opr = get_opfamily_member(typentry->btree_opf, typentry->btree_opintype, typentry->btree_opintype, BTLessStrategyNumber); /* As above, make sure array_cmp or record_cmp will succeed */ if (lt_opr == ARRAY_LT_OP && !array_element_has_compare(typentry)) lt_opr = InvalidOid; else if (lt_opr == RECORD_LT_OP && !record_fields_have_compare(typentry)) lt_opr = InvalidOid; typentry->lt_opr = lt_opr; } if ((flags & TYPECACHE_GT_OPR) && typentry->gt_opr == InvalidOid) { Oid gt_opr = InvalidOid; if (typentry->btree_opf != InvalidOid) gt_opr = get_opfamily_member(typentry->btree_opf, typentry->btree_opintype, typentry->btree_opintype, BTGreaterStrategyNumber); /* As above, make sure array_cmp or record_cmp will succeed */ if (gt_opr == ARRAY_GT_OP && !array_element_has_compare(typentry)) gt_opr = InvalidOid; else if (gt_opr == RECORD_GT_OP && !record_fields_have_compare(typentry)) gt_opr = InvalidOid; typentry->gt_opr = gt_opr; } if ((flags & (TYPECACHE_CMP_PROC | TYPECACHE_CMP_PROC_FINFO)) && typentry->cmp_proc == InvalidOid) { Oid cmp_proc = InvalidOid; if (typentry->btree_opf != InvalidOid) cmp_proc = get_opfamily_proc(typentry->btree_opf, typentry->btree_opintype, typentry->btree_opintype, BTORDER_PROC); /* As above, make sure array_cmp or record_cmp will succeed */ if (cmp_proc == F_BTARRAYCMP && !array_element_has_compare(typentry)) cmp_proc = InvalidOid; else if (cmp_proc == F_BTRECORDCMP && !record_fields_have_compare(typentry)) cmp_proc = InvalidOid; typentry->cmp_proc = cmp_proc; } if ((flags & (TYPECACHE_HASH_PROC | TYPECACHE_HASH_PROC_FINFO)) && typentry->hash_proc == InvalidOid) { Oid hash_proc = InvalidOid; /* * We insist that the eq_opr, if one has been determined, match the * hash opclass; else report there is no hash function. */ if (typentry->hash_opf != InvalidOid && (!OidIsValid(typentry->eq_opr) || typentry->eq_opr == get_opfamily_member(typentry->hash_opf, typentry->hash_opintype, typentry->hash_opintype, HTEqualStrategyNumber))) hash_proc = get_opfamily_proc(typentry->hash_opf, typentry->hash_opintype, typentry->hash_opintype, HASHPROC); /* * As above, make sure hash_array will succeed. We don't currently * support hashing for composite types, but when we do, we'll need * more logic here to check that case too. */ if (hash_proc == F_HASH_ARRAY && !array_element_has_hashing(typentry)) hash_proc = InvalidOid; typentry->hash_proc = hash_proc; } /* * Set up fmgr lookup info as requested * * Note: we tell fmgr the finfo structures live in CacheMemoryContext, * which is not quite right (they're really in the hash table's private * memory context) but this will do for our purposes. */ if ((flags & TYPECACHE_EQ_OPR_FINFO) && typentry->eq_opr_finfo.fn_oid == InvalidOid && typentry->eq_opr != InvalidOid) { Oid eq_opr_func; eq_opr_func = get_opcode(typentry->eq_opr); if (eq_opr_func != InvalidOid) fmgr_info_cxt(eq_opr_func, &typentry->eq_opr_finfo, CacheMemoryContext); } if ((flags & TYPECACHE_CMP_PROC_FINFO) && typentry->cmp_proc_finfo.fn_oid == InvalidOid && typentry->cmp_proc != InvalidOid) { fmgr_info_cxt(typentry->cmp_proc, &typentry->cmp_proc_finfo, CacheMemoryContext); } if ((flags & TYPECACHE_HASH_PROC_FINFO) && typentry->hash_proc_finfo.fn_oid == InvalidOid && typentry->hash_proc != InvalidOid) { fmgr_info_cxt(typentry->hash_proc, &typentry->hash_proc_finfo, CacheMemoryContext); } /* * If it's a composite type (row type), get tupdesc if requested */ if ((flags & TYPECACHE_TUPDESC) && typentry->tupDesc == NULL && typentry->typtype == TYPTYPE_COMPOSITE) { load_typcache_tupdesc(typentry); } /* * If requested, get information about a range type */ if ((flags & TYPECACHE_RANGE_INFO) && typentry->rngelemtype == NULL && typentry->typtype == TYPTYPE_RANGE) { load_rangetype_info(typentry); } return typentry; }