/* * SearchSysCacheExists * * A convenience routine that just probes to see if a tuple can be found. * No lock is retained on the syscache entry. */ bool SearchSysCacheExists(int cacheId, Datum key1, Datum key2, Datum key3, Datum key4) { HeapTuple tuple; tuple = SearchSysCache(cacheId, key1, key2, key3, key4); if (!HeapTupleIsValid(tuple)) return false; ReleaseSysCache(tuple); return true; }
/* --------------------------------------------------------------------- * DROP PROCEDURAL LANGUAGE * --------------------------------------------------------------------- */ void DropProceduralLanguage(DropPLangStmt *stmt) { char *languageName; HeapTuple langTup; ObjectAddress object; /* * Check permission */ if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser to drop procedural language"))); /* * Translate the language name, check that the language exists */ languageName = case_translate_language_name(stmt->plname); langTup = SearchSysCache(LANGNAME, CStringGetDatum(languageName), 0, 0, 0); if (!HeapTupleIsValid(langTup)) { if (!stmt->missing_ok) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("language \"%s\" does not exist", languageName))); else ereport(NOTICE, (errmsg("language \"%s\" does not exist, skipping", languageName))); return; } object.classId = LanguageRelationId; object.objectId = HeapTupleGetOid(langTup); object.objectSubId = 0; ReleaseSysCache(langTup); /* * Do the deletion */ performDeletion(&object, stmt->behavior); }
Oid get_oidnamespace(Oid funcoid) { HeapTuple tuple; Form_pg_proc proc; Oid nspoid; tuple = SearchSysCache(PROCOID, ObjectIdGetDatum(funcoid), 0, 0, 0); if (!HeapTupleIsValid(tuple)) elog(ERROR, "cache lookup failed for proc oid %u", funcoid); proc = (Form_pg_proc) GETSTRUCT(tuple); nspoid = proc->pronamespace; ReleaseSysCache(tuple); return nspoid; }
/* * get_func_nargs * Given procedure id, return the number of arguments. */ int get_func_nargs(Oid funcid) { HeapTuple tp; int result; tp = SearchSysCache(PROCOID, ObjectIdGetDatum(funcid), 0, 0, 0); if (!HeapTupleIsValid(tp)) elog(ERROR, "cache lookup failed for function %u", funcid); result = ((Form_pg_proc) GETSTRUCT(tp))->pronargs; ReleaseSysCache(tp); return result; }
/* * op_input_types * * Returns the left and right input datatypes for an operator * (InvalidOid if not relevant). */ void op_input_types(Oid opno, Oid *lefttype, Oid *righttype) { HeapTuple tp; Form_pg_operator optup; tp = SearchSysCache(OPEROID, ObjectIdGetDatum(opno), 0, 0, 0); if (!HeapTupleIsValid(tp)) /* shouldn't happen */ elog(ERROR, "cache lookup failed for operator %u", opno); optup = (Form_pg_operator) GETSTRUCT(tp); *lefttype = optup->oprleft; *righttype = optup->oprright; ReleaseSysCache(tp); }
/* * get_typlenbyval * * A two-fer: given the type OID, return both typlen and typbyval. * * Since both pieces of info are needed to know how to copy a Datum, * many places need both. Might as well get them with one cache lookup * instead of two. Also, this routine raises an error instead of * returning a bogus value when given a bad type OID. */ void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval) { HeapTuple tp; Form_pg_type typtup; tp = SearchSysCache(TYPEOID, ObjectIdGetDatum(typid), 0, 0, 0); if (!HeapTupleIsValid(tp)) elog(ERROR, "cache lookup failed for type %u", typid); typtup = (Form_pg_type) GETSTRUCT(tp); *typlen = typtup->typlen; *typbyval = typtup->typbyval; ReleaseSysCache(tp); }
/*--------------------------------------------------------------------------- * This cluster code allows for clustering multiple tables at once. Because * of this, we cannot just run everything on a single transaction, or we * would be forced to acquire exclusive locks on all the tables being * clustered, simultaneously --- very likely leading to deadlock. * * To solve this we follow a similar strategy to VACUUM code, * clustering each relation in a separate transaction. For this to work, * we need to: * - provide a separate memory context so that we can pass information in * a way that survives across transactions * - start a new transaction every time a new relation is clustered * - check for validity of the information on to-be-clustered relations, * as someone might have deleted a relation behind our back, or * clustered one on a different index * - end the transaction * * The single-relation case does not have any such overhead. * * We also allow a relation being specified without index. In that case, * the indisclustered bit will be looked up, and an ERROR will be thrown * if there is no index with the bit set. *--------------------------------------------------------------------------- */ void cluster(ClusterStmt *stmt) { if (stmt->relation != NULL) { /* This is the single-relation case. */ Oid tableOid, indexOid = InvalidOid; Relation rel; RelToCluster rvtc; /* Find and lock the table */ rel = heap_openrv(stmt->relation, AccessExclusiveLock); tableOid = RelationGetRelid(rel); /* Check permissions */ if (!pg_class_ownercheck(tableOid, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, RelationGetRelationName(rel)); if (stmt->indexname == NULL) { List *index; /* We need to find the index that has indisclustered set. */ foreach(index, RelationGetIndexList(rel)) { HeapTuple idxtuple; Form_pg_index indexForm; indexOid = lfirsto(index); idxtuple = SearchSysCache(INDEXRELID, ObjectIdGetDatum(indexOid), 0, 0, 0); if (!HeapTupleIsValid(idxtuple)) elog(ERROR, "cache lookup failed for index %u", indexOid); indexForm = (Form_pg_index) GETSTRUCT(idxtuple); if (indexForm->indisclustered) { ReleaseSysCache(idxtuple); break; } ReleaseSysCache(idxtuple); indexOid = InvalidOid; }
/* * Method determines if auto-stats should run as per onnostats auto-stats policy. This policy * enables auto-analyze if : * (1) CTAS * (2) I-S or COPY if there are no statistics present */ static bool autostats_on_no_stats_check(AutoStatsCmdType cmdType, Oid relationOid) { if (cmdType == AUTOSTATS_CMDTYPE_CTAS) return true; if (!(cmdType == AUTOSTATS_CMDTYPE_INSERT || cmdType == AUTOSTATS_CMDTYPE_COPY)) return false; /* * a relation has no stats if the corresponding row in pg_class has * relpages=0, reltuples=0 */ { HeapTuple tuple; Form_pg_class classForm; bool result = false; /* * Must get the relation's tuple from pg_class */ tuple = SearchSysCache(RELOID, ObjectIdGetDatum(relationOid), 0, 0, 0); if (!HeapTupleIsValid(tuple)) { ereport(ERROR, (errcode(ERRCODE_UNDEFINED_TABLE), errmsg("relation with OID %u does not exist", relationOid))); return false; } classForm = (Form_pg_class) GETSTRUCT(tuple); elog(DEBUG5, "Auto-stats ONNOSTATS check on tableoid %d has relpages = %d reltuples = %.0f.", relationOid, classForm->relpages, classForm->reltuples); result = (classForm->relpages == 0 && classForm->reltuples < 1); ReleaseSysCache(tuple); return result; } /* we should not get here at all */ }
/* * SearchSysCacheCopy * * A convenience routine that does SearchSysCache and (if successful) * returns a modifiable copy of the syscache entry. The original * syscache entry is released before returning. The caller should * heap_freetuple() the result when done with it. */ HeapTuple SearchSysCacheCopy(int cacheId, Datum key1, Datum key2, Datum key3, Datum key4) { HeapTuple tuple, newtuple; tuple = SearchSysCache(cacheId, key1, key2, key3, key4); if (!HeapTupleIsValid(tuple)) return tuple; newtuple = heap_copytuple(tuple); ReleaseSysCache(tuple); return newtuple; }
/* * GetSysCacheOid * * A convenience routine that does SearchSysCache and returns the OID * of the found tuple, or InvalidOid if no tuple could be found. * No lock is retained on the syscache entry. */ Oid GetSysCacheOid(int cacheId, Datum key1, Datum key2, Datum key3, Datum key4) { HeapTuple tuple; Oid result; tuple = SearchSysCache(cacheId, key1, key2, key3, key4); if (!HeapTupleIsValid(tuple)) return InvalidOid; result = HeapTupleGetOid(tuple); ReleaseSysCache(tuple); return result; }
/* * regtypeout - converts type OID to "typ_name" */ Datum regtypeout(PG_FUNCTION_ARGS) { Oid typid = PG_GETARG_OID(0); char *result; HeapTuple typetup; if (typid == InvalidOid) { result = pstrdup("-"); PG_RETURN_CSTRING(result); } typetup = SearchSysCache(TYPEOID, ObjectIdGetDatum(typid), 0, 0, 0); if (HeapTupleIsValid(typetup)) { Form_pg_type typeform = (Form_pg_type) GETSTRUCT(typetup); /* * In bootstrap mode, skip the fancy namespace stuff and just return * the type name. (This path is only needed for debugging output * anyway.) */ if (IsBootstrapProcessingMode()) { char *typname = NameStr(typeform->typname); result = pstrdup(typname); } else result = format_type_be(typid); ReleaseSysCache(typetup); } else { /* If OID doesn't match any pg_type entry, return it numerically */ result = (char *) palloc(NAMEDATALEN); snprintf(result, NAMEDATALEN, "%u", typid); } PG_RETURN_CSTRING(result); }
/* * regdictionaryout - converts tsdictionary OID to "tsdictionaryname" */ Datum regdictionaryout(PG_FUNCTION_ARGS) { Oid dictid = PG_GETARG_OID(0); char *result; HeapTuple dicttup; if (dictid == InvalidOid) { result = pstrdup("-"); PG_RETURN_CSTRING(result); } dicttup = SearchSysCache(TSDICTOID, ObjectIdGetDatum(dictid), 0, 0, 0); if (HeapTupleIsValid(dicttup)) { Form_pg_ts_dict dictform = (Form_pg_ts_dict) GETSTRUCT(dicttup); char *dictname = NameStr(dictform->dictname); char *nspname; /* * Would this dictionary be found by regdictionaryin? If not, qualify * it. */ if (TSDictionaryIsVisible(dictid)) nspname = NULL; else nspname = get_namespace_name(dictform->dictnamespace); result = quote_qualified_identifier(nspname, dictname); ReleaseSysCache(dicttup); } else { /* If OID doesn't match any pg_ts_dict row, return it numerically */ result = (char *) palloc(NAMEDATALEN); snprintf(result, NAMEDATALEN, "%u", dictid); } PG_RETURN_CSTRING(result); }
/* * op_hashjoinable * * Returns true if the operator is hashjoinable. */ bool op_hashjoinable(Oid opno) { HeapTuple tp; bool result = false; tp = SearchSysCache(OPEROID, ObjectIdGetDatum(opno), 0, 0, 0); if (HeapTupleIsValid(tp)) { Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp); result = optup->oprcanhash; ReleaseSysCache(tp); } return result; }
/* * get_op_opclass_strategy * * Get the operator's strategy number within the specified opclass, * or 0 if it's not a member of the opclass. */ int get_op_opclass_strategy(Oid opno, Oid opclass) { HeapTuple tp; Form_pg_amop amop_tup; int result; tp = SearchSysCache(AMOPOPID, ObjectIdGetDatum(opno), ObjectIdGetDatum(opclass), 0, 0); if (!HeapTupleIsValid(tp)) return 0; amop_tup = (Form_pg_amop) GETSTRUCT(tp); result = amop_tup->amopstrategy; ReleaseSysCache(tp); return result; }
/* * get_opclass_input_type * * Returns the OID of the datatype the opclass indexes. */ Oid get_opclass_input_type(Oid opclass) { HeapTuple tp; Form_pg_opclass cla_tup; Oid result; tp = SearchSysCache(CLAOID, ObjectIdGetDatum(opclass), 0, 0, 0); if (!HeapTupleIsValid(tp)) elog(ERROR, "cache lookup failed for opclass %u", opclass); cla_tup = (Form_pg_opclass) GETSTRUCT(tp); result = cla_tup->opcintype; ReleaseSysCache(tp); return result; }
/* * opclass_is_hash * * Returns TRUE iff the specified opclass is associated with the * hash index access method. */ bool opclass_is_hash(Oid opclass) { HeapTuple tp; Form_pg_opclass cla_tup; bool result; tp = SearchSysCache(CLAOID, ObjectIdGetDatum(opclass), 0, 0, 0); if (!HeapTupleIsValid(tp)) elog(ERROR, "cache lookup failed for opclass %u", opclass); cla_tup = (Form_pg_opclass) GETSTRUCT(tp); result = (cla_tup->opcamid == HASH_AM_OID); ReleaseSysCache(tp); return result; }
/* * SearchSysCacheAttName * * This routine is equivalent to SearchSysCache on the ATTNAME cache, * except that it will return NULL if the found attribute is marked * attisdropped. This is convenient for callers that want to act as * though dropped attributes don't exist. */ HeapTuple SearchSysCacheAttName(Oid relid, const char *attname) { HeapTuple tuple; tuple = SearchSysCache(ATTNAME, ObjectIdGetDatum(relid), CStringGetDatum(attname), 0, 0); if (!HeapTupleIsValid(tuple)) return NULL; if (((Form_pg_attribute) GETSTRUCT(tuple))->attisdropped) { ReleaseSysCache(tuple); return NULL; } return tuple; }
/* * TypeOidGetTypename * Get the name of the type, given the OID */ char * TypeOidGetTypename(Oid typid) { Assert(OidIsValid(typid)); HeapTuple typtup = SearchSysCache(TYPEOID, ObjectIdGetDatum(typid), 0, 0, 0); if (!HeapTupleIsValid(typtup)) elog(ERROR, "cache lookup failed for type %u", typid); Form_pg_type typform = (Form_pg_type) GETSTRUCT(typtup); char *typname = psprintf("%s", NameStr(typform->typname)); ReleaseSysCache(typtup); return typname; }
/* * regconfigout - converts tsconfig OID to "tsconfigname" */ Datum regconfigout(PG_FUNCTION_ARGS) { Oid cfgid = PG_GETARG_OID(0); char *result; HeapTuple cfgtup; if (cfgid == InvalidOid) { result = pstrdup("-"); PG_RETURN_CSTRING(result); } cfgtup = SearchSysCache(TSCONFIGOID, ObjectIdGetDatum(cfgid), 0, 0, 0); if (HeapTupleIsValid(cfgtup)) { Form_pg_ts_config cfgform = (Form_pg_ts_config) GETSTRUCT(cfgtup); char *cfgname = NameStr(cfgform->cfgname); char *nspname; /* * Would this config be found by regconfigin? If not, qualify it. */ if (TSConfigIsVisible(cfgid)) nspname = NULL; else nspname = get_namespace_name(cfgform->cfgnamespace); result = quote_qualified_identifier(nspname, cfgname); ReleaseSysCache(cfgtup); } else { /* If OID doesn't match any pg_ts_config row, return it numerically */ result = (char *) palloc(NAMEDATALEN); snprintf(result, NAMEDATALEN, "%u", cfgid); } PG_RETURN_CSTRING(result); }
/* * IndexGetRelation: given an index's relation OID, get the OID of the * relation it is an index on. Uses the system cache. */ static Oid IndexGetRelation(Oid indexId) { HeapTuple tuple; Form_pg_index index; Oid result; tuple = SearchSysCache(INDEXRELID, ObjectIdGetDatum(indexId), 0, 0, 0); if (!HeapTupleIsValid(tuple)) elog(ERROR, "cache lookup failed for index %u", indexId); index = (Form_pg_index) GETSTRUCT(tuple); Assert(index->indexrelid == indexId); result = index->indrelid; ReleaseSysCache(tuple); return result; }
/* * get_attavgwidth * * Given the table and attribute number of a column, get the average * width of entries in the column. Return zero if no data available. */ int32 get_attavgwidth(Oid relid, AttrNumber attnum) { HeapTuple tp; tp = SearchSysCache(STATRELATT, ObjectIdGetDatum(relid), Int16GetDatum(attnum), 0, 0); if (HeapTupleIsValid(tp)) { int32 stawidth = ((Form_pg_statistic) GETSTRUCT(tp))->stawidth; ReleaseSysCache(tp); if (stawidth > 0) return stawidth; } return 0; }
/* * get_opclass_proc * Get the OID of the specified support function * for the specified opclass and subtype. * * Returns InvalidOid if there is no pg_amproc entry for the given keys. */ Oid get_opclass_proc(Oid opclass, Oid subtype, int16 procnum) { HeapTuple tp; Form_pg_amproc amproc_tup; RegProcedure result; tp = SearchSysCache(AMPROCNUM, ObjectIdGetDatum(opclass), ObjectIdGetDatum(subtype), Int16GetDatum(procnum), 0); if (!HeapTupleIsValid(tp)) return InvalidOid; amproc_tup = (Form_pg_amproc) GETSTRUCT(tp); result = amproc_tup->amproc; ReleaseSysCache(tp); return result; }
/* * This function is called when a PL/Proxy function is created to * check the syntax. */ Datum plproxy_validator(PG_FUNCTION_ARGS) { Oid oid = PG_GETARG_OID(0); HeapTuple proc_tuple; if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid, oid)) PG_RETURN_VOID(); proc_tuple = SearchSysCache(PROCOID, ObjectIdGetDatum(oid), 0, 0, 0); if (!HeapTupleIsValid(proc_tuple)) elog(ERROR, "cache lookup failed for function %u", oid); plproxy_compile(NULL, proc_tuple, true); ReleaseSysCache(proc_tuple); PG_RETURN_VOID(); }
/* * get_opclass_member * Get the OID of the operator that implements the specified strategy * with the specified subtype for the specified opclass. * * Returns InvalidOid if there is no pg_amop entry for the given keys. */ Oid get_opclass_member(Oid opclass, Oid subtype, int16 strategy) { HeapTuple tp; Form_pg_amop amop_tup; Oid result; tp = SearchSysCache(AMOPSTRATEGY, ObjectIdGetDatum(opclass), ObjectIdGetDatum(subtype), Int16GetDatum(strategy), 0); if (!HeapTupleIsValid(tp)) return InvalidOid; amop_tup = (Form_pg_amop) GETSTRUCT(tp); result = amop_tup->amopopr; ReleaseSysCache(tp); return result; }
/* right_oper() -- search for a unary right operator (postfix operator) * Given operator name and type of arg, return oper struct. * * IMPORTANT: the returned operator (if any) is only promised to be * coercion-compatible with the input datatype. Do not use this if * you need an exact- or binary-compatible match. * * If no matching operator found, return NULL if noError is true, * raise an error if it is false. pstate and location are used only to report * the error position; pass NULL/-1 if not available. * * NOTE: on success, the returned object is a syscache entry. The caller * must ReleaseSysCache() the entry when done with it. */ Operator right_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location) { Oid operOid; FuncDetailCode fdresult = FUNCDETAIL_NOTFOUND; HeapTuple tup = NULL; /* * First try for an "exact" match. */ operOid = OpernameGetOprid(op, arg, InvalidOid); if (!OidIsValid(operOid)) { /* * Otherwise, search for the most suitable candidate. */ FuncCandidateList clist; /* Get postfix operators of given name */ clist = OpernameGetCandidates(op, 'r'); /* No operators found? Then fail... */ if (clist != NULL) { /* * We must run oper_select_candidate even if only one candidate, * otherwise we may falsely return a non-type-compatible operator. */ fdresult = oper_select_candidate(1, &arg, clist, &operOid); } } if (OidIsValid(operOid)) tup = SearchSysCache(OPEROID, ObjectIdGetDatum(operOid), 0, 0, 0); if (!HeapTupleIsValid(tup) && !noError) op_error(pstate, op, 'r', arg, InvalidOid, fdresult, location); return (Operator) tup; }
/* * Validator for C language functions * * Make sure that the library file exists, is loadable, and contains * the specified link symbol. Also check for a valid function * information record. */ Datum fmgr_c_validator(PG_FUNCTION_ARGS) { Oid funcoid = PG_GETARG_OID(0); void *libraryhandle; HeapTuple tuple; Form_pg_proc proc; bool isnull; Datum tmp; char *prosrc; char *probin; /* * It'd be most consistent to skip the check if !check_function_bodies, * but the purpose of that switch is to be helpful for pg_dump loading, * and for pg_dump loading it's much better if we *do* check. */ tuple = SearchSysCache(PROCOID, ObjectIdGetDatum(funcoid), 0, 0, 0); if (!HeapTupleIsValid(tuple)) elog(ERROR, "cache lookup failed for function %u", funcoid); proc = (Form_pg_proc) GETSTRUCT(tuple); tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull); if (isnull) elog(ERROR, "null prosrc"); prosrc = DatumGetCString(DirectFunctionCall1(textout, tmp)); tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_probin, &isnull); if (isnull) elog(ERROR, "null probin"); probin = DatumGetCString(DirectFunctionCall1(textout, tmp)); (void) load_external_function(probin, prosrc, true, &libraryhandle); (void) fetch_finfo_record(libraryhandle, prosrc); ReleaseSysCache(tuple); PG_RETURN_VOID(); }
/* * get_oprjoin * * Returns procedure id for computing selectivity of a join. */ RegProcedure get_oprjoin(Oid opno) { HeapTuple tp; tp = SearchSysCache(OPEROID, ObjectIdGetDatum(opno), 0, 0, 0); if (HeapTupleIsValid(tp)) { Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp); RegProcedure result; result = optup->oprjoin; ReleaseSysCache(tp); return result; } else return (RegProcedure) InvalidOid; }
/* * get_func_name * returns the name of the function with the given funcid * * Note: returns a palloc'd copy of the string, or NULL if no such function. */ char * get_func_name(Oid funcid) { HeapTuple tp; tp = SearchSysCache(PROCOID, ObjectIdGetDatum(funcid), 0, 0, 0); if (HeapTupleIsValid(tp)) { Form_pg_proc functup = (Form_pg_proc) GETSTRUCT(tp); char *result; result = pstrdup(NameStr(functup->proname)); ReleaseSysCache(tp); return result; } else return NULL; }
/* * Guts of language dropping. */ void DropProceduralLanguageById(Oid langOid) { Relation rel; HeapTuple langTup; rel = heap_open(LanguageRelationId, RowExclusiveLock); langTup = SearchSysCache(LANGOID, ObjectIdGetDatum(langOid), 0, 0, 0); if (!HeapTupleIsValid(langTup)) /* should not happen */ elog(ERROR, "cache lookup failed for language %u", langOid); simple_heap_delete(rel, &langTup->t_self); ReleaseSysCache(langTup); heap_close(rel, RowExclusiveLock); }
/* * Change language owner, specified by OID */ void AlterLanguageOwner_oid(Oid oid, Oid newOwnerId) { HeapTuple tup; Relation rel; rel = heap_open(LanguageRelationId, RowExclusiveLock); tup = SearchSysCache(LANGOID, ObjectIdGetDatum(oid), 0, 0, 0); if (!HeapTupleIsValid(tup)) elog(ERROR, "cache lookup failed for language %u", oid); AlterLanguageOwner_internal(tup, rel, newOwnerId); ReleaseSysCache(tup); heap_close(rel, RowExclusiveLock); }