/*------------------------------------------------------------------------- * * queryenvironment.c * Query environment, to store context-specific values like ephemeral named * relations. Initial use is for named tuplestores for delta information * from "normal" relations. * * The initial implementation uses a list because the number of such relations * in any one context is expected to be very small. If that becomes a * performance problem, the implementation can be changed with no other impact * on callers, since this is an opaque structure. This is the reason to * require a create function. * * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * src/backend/utils/misc/queryenvironment.c * *------------------------------------------------------------------------- */ #include "postgres.h" #include "access/table.h" #include "utils/queryenvironment.h" #include "utils/rel.h" /* * Private state of a query environment. */ struct QueryEnvironment { List *namedRelList; }; QueryEnvironment * create_queryEnv(void) { return (QueryEnvironment *) palloc0(sizeof(QueryEnvironment)); } EphemeralNamedRelationMetadata get_visible_ENR_metadata(QueryEnvironment *queryEnv, const char *refname) { EphemeralNamedRelation enr; Assert(refname != NULL); if (queryEnv == NULL) return NULL; enr = get_ENR(queryEnv, refname); if (enr) return &(enr->md); return NULL; } /* * Register a named relation for use in the given environment. * * If this is intended exclusively for planning purposes, the tstate field can * be left NULL; */ void register_ENR(QueryEnvironment *queryEnv, EphemeralNamedRelation enr) { Assert(enr != NULL); Assert(get_ENR(queryEnv, enr->md.name) == NULL); queryEnv->namedRelList = lappend(queryEnv->namedRelList, enr); } /* * Unregister an ephemeral relation by name. This will probably be a rarely * used function, but seems like it should be provided "just in case". */ void unregister_ENR(QueryEnvironment *queryEnv, const char *name) { EphemeralNamedRelation match; match = get_ENR(queryEnv, name); if (match) queryEnv->namedRelList = list_delete(queryEnv->namedRelList, match); } /* * This returns an ENR if there is a name match in the given collection. It * must quietly return NULL if no match is found. */ EphemeralNamedRelation get_ENR(QueryEnvironment *queryEnv, const char *name) { ListCell *lc; Assert(name != NULL); if (queryEnv == NULL) return NULL; foreach(lc, queryEnv->namedRelList) { EphemeralNamedRelation enr = (EphemeralNamedRelation) lfirst(lc); if (strcmp(enr->md.name, name) == 0) return enr; } return NULL; } /* * Gets the TupleDesc for a Ephemeral Named Relation, based on which field was * filled. * * When the TupleDesc is based on a relation from the catalogs, we count on * that relation being used at the same time, so that appropriate locks will * already be held. Locking here would be too late anyway. */ TupleDesc ENRMetadataGetTupDesc(EphemeralNamedRelationMetadata enrmd) { TupleDesc tupdesc; /* One, and only one, of these fields must be filled. */ Assert((enrmd->reliddesc == InvalidOid) != (enrmd->tupdesc == NULL)); if (enrmd->tupdesc != NULL) tupdesc = enrmd->tupdesc; else { Relation relation; relation = table_open(enrmd->reliddesc, NoLock); tupdesc = relation->rd_att; table_close(relation, NoLock); } return tupdesc; }