postgresql/src/backend/utils/misc/queryenvironment.c

145 lines
3.4 KiB
C

/*-------------------------------------------------------------------------
*
* 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;
}