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-2019, PostgreSQL Global Development Group |
15 | * Portions Copyright (c) 1994, Regents of the University of California |
16 | * |
17 | * |
18 | * IDENTIFICATION |
19 | * src/backend/utils/misc/queryenvironment.c |
20 | * |
21 | *------------------------------------------------------------------------- |
22 | */ |
23 | #include "postgres.h" |
24 | |
25 | #include "access/table.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 * |
39 | create_queryEnv() |
40 | { |
41 | return (QueryEnvironment *) palloc0(sizeof(QueryEnvironment)); |
42 | } |
43 | |
44 | EphemeralNamedRelationMetadata |
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 |
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 |
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 |
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 |
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 = table_open(enrmd->reliddesc, NoLock); |
139 | tupdesc = relation->rd_att; |
140 | table_close(relation, NoLock); |
141 | } |
142 | |
143 | return tupdesc; |
144 | } |
145 | |