1 /*-------------------------------------------------------------------------
2 *
3 * queryenvironment.c
4 * Query environment, to store context-specific values like ephemeral named
5 * relations. Initial use is for named tuplestores for delta information
6 * from "normal" relations.
7 *
8 * The initial implementation uses a list because the number of such relations
9 * in any one context is expected to be very small. If that becomes a
10 * performance problem, the implementation can be changed with no other impact
11 * on callers, since this is an opaque structure. This is the reason to
12 * require a create function.
13 *
14 * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
15 * Portions Copyright (c) 1994, Regents of the University of California
16 *
17 *
18 * IDENTIFICATION
19 * src/backend/backend/utils/misc/queryenvironment.c
20 *
21 *-------------------------------------------------------------------------
22 */
23 #include "postgres.h"
24
25 #include "access/heapam.h"
26 #include "utils/queryenvironment.h"
27 #include "utils/rel.h"
28
29 /*
30 * Private state of a query environment.
31 */
32 struct QueryEnvironment
33 {
34 List *namedRelList;
35 };
36
37
38 QueryEnvironment *
create_queryEnv()39 create_queryEnv()
40 {
41 return (QueryEnvironment *) palloc0(sizeof(QueryEnvironment));
42 }
43
44 EphemeralNamedRelationMetadata
get_visible_ENR_metadata(QueryEnvironment * queryEnv,const char * refname)45 get_visible_ENR_metadata(QueryEnvironment *queryEnv, const char *refname)
46 {
47 EphemeralNamedRelation enr;
48
49 Assert(refname != NULL);
50
51 if (queryEnv == NULL)
52 return NULL;
53
54 enr = get_ENR(queryEnv, refname);
55
56 if (enr)
57 return &(enr->md);
58
59 return NULL;
60 }
61
62 /*
63 * Register a named relation for use in the given environment.
64 *
65 * If this is intended exclusively for planning purposes, the tstate field can
66 * be left NULL;
67 */
68 void
register_ENR(QueryEnvironment * queryEnv,EphemeralNamedRelation enr)69 register_ENR(QueryEnvironment *queryEnv, EphemeralNamedRelation enr)
70 {
71 Assert(enr != NULL);
72 Assert(get_ENR(queryEnv, enr->md.name) == NULL);
73
74 queryEnv->namedRelList = lappend(queryEnv->namedRelList, enr);
75 }
76
77 /*
78 * Unregister an ephemeral relation by name. This will probably be a rarely
79 * used function, but seems like it should be provided "just in case".
80 */
81 void
unregister_ENR(QueryEnvironment * queryEnv,const char * name)82 unregister_ENR(QueryEnvironment *queryEnv, const char *name)
83 {
84 EphemeralNamedRelation match;
85
86 match = get_ENR(queryEnv, name);
87 if (match)
88 queryEnv->namedRelList = list_delete(queryEnv->namedRelList, match);
89 }
90
91 /*
92 * This returns an ENR if there is a name match in the given collection. It
93 * must quietly return NULL if no match is found.
94 */
95 EphemeralNamedRelation
get_ENR(QueryEnvironment * queryEnv,const char * name)96 get_ENR(QueryEnvironment *queryEnv, const char *name)
97 {
98 ListCell *lc;
99
100 Assert(name != NULL);
101
102 if (queryEnv == NULL)
103 return NULL;
104
105 foreach(lc, queryEnv->namedRelList)
106 {
107 EphemeralNamedRelation enr = (EphemeralNamedRelation) lfirst(lc);
108
109 if (strcmp(enr->md.name, name) == 0)
110 return enr;
111 }
112
113 return NULL;
114 }
115
116 /*
117 * Gets the TupleDesc for a Ephemeral Named Relation, based on which field was
118 * filled.
119 *
120 * When the TupleDesc is based on a relation from the catalogs, we count on
121 * that relation being used at the same time, so that appropriate locks will
122 * already be held. Locking here would be too late anyway.
123 */
124 TupleDesc
ENRMetadataGetTupDesc(EphemeralNamedRelationMetadata enrmd)125 ENRMetadataGetTupDesc(EphemeralNamedRelationMetadata enrmd)
126 {
127 TupleDesc tupdesc;
128
129 /* One, and only one, of these fields must be filled. */
130 Assert((enrmd->reliddesc == InvalidOid) != (enrmd->tupdesc == NULL));
131
132 if (enrmd->tupdesc != NULL)
133 tupdesc = enrmd->tupdesc;
134 else
135 {
136 Relation relation;
137
138 relation = heap_open(enrmd->reliddesc, NoLock);
139 tupdesc = relation->rd_att;
140 heap_close(relation, NoLock);
141 }
142
143 return tupdesc;
144 }
145