2017-04-01 06:17:18 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
2020-01-01 18:21:45 +01:00
|
|
|
* Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
|
2017-04-01 06:17:18 +02:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2018-07-11 16:57:04 +02:00
|
|
|
* src/backend/utils/misc/queryenvironment.c
|
2017-04-01 06:17:18 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
#include "postgres.h"
|
|
|
|
|
2019-01-21 19:18:20 +01:00
|
|
|
#include "access/table.h"
|
2017-04-01 06:17:18 +02:00
|
|
|
#include "utils/queryenvironment.h"
|
|
|
|
#include "utils/rel.h"
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Private state of a query environment.
|
|
|
|
*/
|
|
|
|
struct QueryEnvironment
|
|
|
|
{
|
|
|
|
List *namedRelList;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
QueryEnvironment *
|
2020-05-21 17:31:16 +02:00
|
|
|
create_queryEnv(void)
|
2017-04-01 06:17:18 +02:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
2019-01-21 19:32:19 +01:00
|
|
|
relation = table_open(enrmd->reliddesc, NoLock);
|
2017-04-01 06:17:18 +02:00
|
|
|
tupdesc = relation->rd_att;
|
2019-01-21 19:32:19 +01:00
|
|
|
table_close(relation, NoLock);
|
2017-04-01 06:17:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return tupdesc;
|
|
|
|
}
|