Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * parse_relation.c
4 : : * parser support routines dealing with relations
5 : : *
6 : : * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 : : * Portions Copyright (c) 1994, Regents of the University of California
8 : : *
9 : : *
10 : : * IDENTIFICATION
11 : : * src/backend/parser/parse_relation.c
12 : : *
13 : : *-------------------------------------------------------------------------
14 : : */
15 : : #include "postgres.h"
16 : :
17 : : #include <ctype.h>
18 : :
19 : : #include "access/htup_details.h"
20 : : #include "access/relation.h"
21 : : #include "access/sysattr.h"
22 : : #include "access/table.h"
23 : : #include "catalog/heap.h"
24 : : #include "catalog/namespace.h"
25 : : #include "catalog/pg_type.h"
26 : : #include "funcapi.h"
27 : : #include "nodes/makefuncs.h"
28 : : #include "nodes/nodeFuncs.h"
29 : : #include "parser/parse_enr.h"
30 : : #include "parser/parse_relation.h"
31 : : #include "parser/parse_type.h"
32 : : #include "parser/parsetree.h"
33 : : #include "storage/lmgr.h"
34 : : #include "utils/builtins.h"
35 : : #include "utils/lsyscache.h"
36 : : #include "utils/rel.h"
37 : : #include "utils/syscache.h"
38 : : #include "utils/varlena.h"
39 : :
40 : :
41 : : /*
42 : : * Support for fuzzily matching columns.
43 : : *
44 : : * This is for building diagnostic messages, where multiple or non-exact
45 : : * matching attributes are of interest.
46 : : *
47 : : * "distance" is the current best fuzzy-match distance if rfirst isn't NULL,
48 : : * otherwise it is the maximum acceptable distance plus 1.
49 : : *
50 : : * rfirst/first record the closest non-exact match so far, and distance
51 : : * is its distance from the target name. If we have found a second non-exact
52 : : * match of exactly the same distance, rsecond/second record that. (If
53 : : * we find three of the same distance, we conclude that "distance" is not
54 : : * a tight enough bound for a useful hint and clear rfirst/rsecond again.
55 : : * Only if we later find something closer will we re-populate rfirst.)
56 : : *
57 : : * rexact1/exact1 record the location of the first exactly-matching column,
58 : : * if any. If we find multiple exact matches then rexact2/exact2 record
59 : : * another one (we don't especially care which). Currently, these get
60 : : * populated independently of the fuzzy-match fields.
61 : : */
62 : : typedef struct
63 : : {
64 : : int distance; /* Current or limit distance */
65 : : RangeTblEntry *rfirst; /* RTE of closest non-exact match, or NULL */
66 : : AttrNumber first; /* Col index in rfirst */
67 : : RangeTblEntry *rsecond; /* RTE of another non-exact match w/same dist */
68 : : AttrNumber second; /* Col index in rsecond */
69 : : RangeTblEntry *rexact1; /* RTE of first exact match, or NULL */
70 : : AttrNumber exact1; /* Col index in rexact1 */
71 : : RangeTblEntry *rexact2; /* RTE of second exact match, or NULL */
72 : : AttrNumber exact2; /* Col index in rexact2 */
73 : : } FuzzyAttrMatchState;
74 : :
75 : : #define MAX_FUZZY_DISTANCE 3
76 : :
77 : :
78 : : static ParseNamespaceItem *scanNameSpaceForRefname(ParseState *pstate,
79 : : const char *refname,
80 : : int location);
81 : : static ParseNamespaceItem *scanNameSpaceForRelid(ParseState *pstate, Oid relid,
82 : : int location);
83 : : static void check_lateral_ref_ok(ParseState *pstate, ParseNamespaceItem *nsitem,
84 : : int location);
85 : : static int scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte,
86 : : Alias *eref,
87 : : const char *colname, int location,
88 : : int fuzzy_rte_penalty,
89 : : FuzzyAttrMatchState *fuzzystate);
90 : : static void markRTEForSelectPriv(ParseState *pstate,
91 : : int rtindex, AttrNumber col);
92 : : static void expandRelation(Oid relid, Alias *eref,
93 : : int rtindex, int sublevels_up,
94 : : VarReturningType returning_type,
95 : : int location, bool include_dropped,
96 : : List **colnames, List **colvars);
97 : : static void expandTupleDesc(TupleDesc tupdesc, Alias *eref,
98 : : int count, int offset,
99 : : int rtindex, int sublevels_up,
100 : : VarReturningType returning_type,
101 : : int location, bool include_dropped,
102 : : List **colnames, List **colvars);
103 : : static int specialAttNum(const char *attname);
104 : : static bool rte_visible_if_lateral(ParseState *pstate, RangeTblEntry *rte);
105 : : static bool rte_visible_if_qualified(ParseState *pstate, RangeTblEntry *rte);
106 : : static bool isQueryUsingTempRelation_walker(Node *node, void *context);
107 : :
108 : :
109 : : /*
110 : : * refnameNamespaceItem
111 : : * Given a possibly-qualified refname, look to see if it matches any visible
112 : : * namespace item. If so, return a pointer to the nsitem; else return NULL.
113 : : *
114 : : * Optionally get nsitem's nesting depth (0 = current) into *sublevels_up.
115 : : * If sublevels_up is NULL, only consider items at the current nesting
116 : : * level.
117 : : *
118 : : * An unqualified refname (schemaname == NULL) can match any item with matching
119 : : * alias, or matching unqualified relname in the case of alias-less relation
120 : : * items. It is possible that such a refname matches multiple items in the
121 : : * nearest nesting level that has a match; if so, we report an error via
122 : : * ereport().
123 : : *
124 : : * A qualified refname (schemaname != NULL) can only match a relation item
125 : : * that (a) has no alias and (b) is for the same relation identified by
126 : : * schemaname.refname. In this case we convert schemaname.refname to a
127 : : * relation OID and search by relid, rather than by alias name. This is
128 : : * peculiar, but it's what SQL says to do. While processing a query's
129 : : * RETURNING list, there may be additional namespace items for OLD and NEW,
130 : : * with the same relation OID as the target namespace item. These are
131 : : * ignored in the search, since they don't match by schemaname.refname.
132 : : */
133 : : ParseNamespaceItem *
2081 tgl@sss.pgh.pa.us 134 :CBC 548348 : refnameNamespaceItem(ParseState *pstate,
135 : : const char *schemaname,
136 : : const char *refname,
137 : : int location,
138 : : int *sublevels_up)
139 : : {
8430 140 : 548348 : Oid relId = InvalidOid;
141 : :
9125 142 [ + + ]: 548348 : if (sublevels_up)
143 : 545253 : *sublevels_up = 0;
144 : :
8430 145 [ + + ]: 548348 : if (schemaname != NULL)
146 : : {
147 : : Oid namespaceId;
148 : :
149 : : /*
150 : : * We can use LookupNamespaceNoError() here because we are only
151 : : * interested in finding existing RTEs. Checking USAGE permission on
152 : : * the schema is unnecessary since it would have already been checked
153 : : * when the RTE was made. Furthermore, we want to report "RTE not
154 : : * found", not "no permissions for schema", if the name happens to
155 : : * match a schema name the user hasn't got access to.
156 : : */
5789 157 : 42 : namespaceId = LookupNamespaceNoError(schemaname);
5610 158 [ + + ]: 42 : if (!OidIsValid(namespaceId))
5789 159 : 33 : return NULL;
8430 160 : 9 : relId = get_relname_relid(refname, namespaceId);
161 [ - + ]: 9 : if (!OidIsValid(relId))
8430 tgl@sss.pgh.pa.us 162 :UBC 0 : return NULL;
163 : : }
164 : :
9335 lockhart@fourpalms.o 165 [ + + ]:CBC 591516 : while (pstate != NULL)
166 : : {
167 : : ParseNamespaceItem *result;
168 : :
8430 tgl@sss.pgh.pa.us 169 [ + + ]: 573489 : if (OidIsValid(relId))
6214 170 : 12 : result = scanNameSpaceForRelid(pstate, relId, location);
171 : : else
172 : 573477 : result = scanNameSpaceForRefname(pstate, refname, location);
173 : :
7398 174 [ + + ]: 573477 : if (result)
175 : 527247 : return result;
176 : :
9125 177 [ + + ]: 46230 : if (sublevels_up)
178 : 43201 : (*sublevels_up)++;
179 : : else
180 : 3029 : break;
181 : :
7398 182 : 43201 : pstate = pstate->parentParseState;
183 : : }
9125 184 : 21056 : return NULL;
185 : : }
186 : :
187 : : /*
188 : : * Search the query's table namespace for an item matching the
189 : : * given unqualified refname. Return the nsitem if a unique match, or NULL
190 : : * if no match. Raise error if multiple matches.
191 : : *
192 : : * Note: it might seem that we shouldn't have to worry about the possibility
193 : : * of multiple matches; after all, the SQL standard disallows duplicate table
194 : : * aliases within a given SELECT level. Historically, however, Postgres has
195 : : * been laxer than that. For example, we allow
196 : : * SELECT ... FROM tab1 x CROSS JOIN (tab2 x CROSS JOIN tab3 y) z
197 : : * on the grounds that the aliased join (z) hides the aliases within it,
198 : : * therefore there is no conflict between the two RTEs named "x". However,
199 : : * if tab3 is a LATERAL subquery, then from within the subquery both "x"es
200 : : * are visible. Rather than rejecting queries that used to work, we allow
201 : : * this situation, and complain only if there's actually an ambiguous
202 : : * reference to "x".
203 : : */
204 : : static ParseNamespaceItem *
6214 205 : 573477 : scanNameSpaceForRefname(ParseState *pstate, const char *refname, int location)
206 : : {
2081 207 : 573477 : ParseNamespaceItem *result = NULL;
208 : : ListCell *l;
209 : :
4777 210 [ + + + + : 2480720 : foreach(l, pstate->p_namespace)
+ + ]
211 : : {
4778 212 : 1907255 : ParseNamespaceItem *nsitem = (ParseNamespaceItem *) lfirst(l);
213 : :
214 : : /* Ignore columns-only items */
4777 215 [ + + ]: 1907255 : if (!nsitem->p_rel_visible)
216 : 488322 : continue;
217 : : /* If not inside LATERAL, ignore lateral-only items */
4778 218 [ + + + + ]: 1418933 : if (nsitem->p_lateral_only && !pstate->p_lateral_active)
219 : 30 : continue;
220 : :
1620 peter@eisentraut.org 221 [ + + ]: 1418903 : if (strcmp(nsitem->p_names->aliasname, refname) == 0)
222 : : {
7398 tgl@sss.pgh.pa.us 223 [ + + ]: 527256 : if (result)
8085 224 [ + - ]: 6 : ereport(ERROR,
225 : : (errcode(ERRCODE_AMBIGUOUS_ALIAS),
226 : : errmsg("table reference \"%s\" is ambiguous",
227 : : refname),
228 : : parser_errposition(pstate, location)));
4256 229 : 527250 : check_lateral_ref_ok(pstate, nsitem, location);
2081 230 : 527244 : result = nsitem;
231 : : }
232 : : }
9125 233 : 573465 : return result;
234 : : }
235 : :
236 : : /*
237 : : * Search the query's table namespace for a relation item matching the
238 : : * given relation OID. Return the nsitem if a unique match, or NULL
239 : : * if no match. Raise error if multiple matches.
240 : : *
241 : : * See the comments for refnameNamespaceItem to understand why this
242 : : * acts the way it does.
243 : : */
244 : : static ParseNamespaceItem *
6214 245 : 12 : scanNameSpaceForRelid(ParseState *pstate, Oid relid, int location)
246 : : {
2081 247 : 12 : ParseNamespaceItem *result = NULL;
248 : : ListCell *l;
249 : :
4777 250 [ + - + + : 30 : foreach(l, pstate->p_namespace)
+ + ]
251 : : {
4778 252 : 18 : ParseNamespaceItem *nsitem = (ParseNamespaceItem *) lfirst(l);
253 : 18 : RangeTblEntry *rte = nsitem->p_rte;
254 : :
255 : : /* Ignore columns-only items */
4777 256 [ - + ]: 18 : if (!nsitem->p_rel_visible)
4777 tgl@sss.pgh.pa.us 257 :UBC 0 : continue;
258 : : /* If not inside LATERAL, ignore lateral-only items */
4778 tgl@sss.pgh.pa.us 259 [ - + - - ]:CBC 18 : if (nsitem->p_lateral_only && !pstate->p_lateral_active)
4778 tgl@sss.pgh.pa.us 260 :UBC 0 : continue;
261 : : /* Ignore OLD/NEW namespace items that can appear in RETURNING */
232 dean.a.rasheed@gmail 262 [ + + ]:CBC 18 : if (nsitem->p_returning_type != VAR_RETURNING_DEFAULT)
263 : 6 : continue;
264 : :
265 : : /* yes, the test for alias == NULL should be there... */
8430 tgl@sss.pgh.pa.us 266 [ + - ]: 12 : if (rte->rtekind == RTE_RELATION &&
267 [ + + ]: 12 : rte->relid == relid &&
268 [ + - ]: 9 : rte->alias == NULL)
269 : : {
7398 270 [ - + ]: 9 : if (result)
8085 tgl@sss.pgh.pa.us 271 [ # # ]:UBC 0 : ereport(ERROR,
272 : : (errcode(ERRCODE_AMBIGUOUS_ALIAS),
273 : : errmsg("table reference %u is ambiguous",
274 : : relid),
275 : : parser_errposition(pstate, location)));
4256 tgl@sss.pgh.pa.us 276 :CBC 9 : check_lateral_ref_ok(pstate, nsitem, location);
2081 277 : 9 : result = nsitem;
278 : : }
279 : : }
8430 280 : 12 : return result;
281 : : }
282 : :
283 : : /*
284 : : * Search the query's CTE namespace for a CTE matching the given unqualified
285 : : * refname. Return the CTE (and its levelsup count) if a match, or NULL
286 : : * if no match. We need not worry about multiple matches, since parse_cte.c
287 : : * rejects WITH lists containing duplicate CTE names.
288 : : */
289 : : CommonTableExpr *
6179 290 : 98045 : scanNameSpaceForCTE(ParseState *pstate, const char *refname,
291 : : Index *ctelevelsup)
292 : : {
293 : : Index levelsup;
294 : :
295 : 98045 : for (levelsup = 0;
296 [ + + ]: 223957 : pstate != NULL;
297 : 125912 : pstate = pstate->parentParseState, levelsup++)
298 : : {
299 : : ListCell *lc;
300 : :
301 [ + + + + : 132657 : foreach(lc, pstate->p_ctenamespace)
+ + ]
302 : : {
303 : 6745 : CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
304 : :
305 [ + + ]: 6745 : if (strcmp(cte->ctename, refname) == 0)
306 : : {
307 : 3492 : *ctelevelsup = levelsup;
308 : 3492 : return cte;
309 : : }
310 : : }
311 : : }
312 : 94553 : return NULL;
313 : : }
314 : :
315 : : /*
316 : : * Search for a possible "future CTE", that is one that is not yet in scope
317 : : * according to the WITH scoping rules. This has nothing to do with valid
318 : : * SQL semantics, but it's important for error reporting purposes.
319 : : */
320 : : static bool
6177 321 : 90 : isFutureCTE(ParseState *pstate, const char *refname)
322 : : {
323 [ + + ]: 186 : for (; pstate != NULL; pstate = pstate->parentParseState)
324 : : {
325 : : ListCell *lc;
326 : :
327 [ + + + - : 99 : foreach(lc, pstate->p_future_ctes)
+ + ]
328 : : {
329 : 3 : CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
330 : :
331 [ + - ]: 3 : if (strcmp(cte->ctename, refname) == 0)
332 : 3 : return true;
333 : : }
334 : : }
335 : 87 : return false;
336 : : }
337 : :
338 : : /*
339 : : * Search the query's ephemeral named relation namespace for a relation
340 : : * matching the given unqualified refname.
341 : : */
342 : : bool
3081 kgrittn@postgresql.o 343 : 134834 : scanNameSpaceForENR(ParseState *pstate, const char *refname)
344 : : {
345 : 134834 : return name_matches_visible_ENR(pstate, refname);
346 : : }
347 : :
348 : : /*
349 : : * searchRangeTableForRel
350 : : * See if any RangeTblEntry could possibly match the RangeVar.
351 : : * If so, return a pointer to the RangeTblEntry; else return NULL.
352 : : *
353 : : * This is different from refnameNamespaceItem in that it considers every
354 : : * entry in the ParseState's rangetable(s), not only those that are currently
355 : : * visible in the p_namespace list(s). This behavior is invalid per the SQL
356 : : * spec, and it may give ambiguous results (there might be multiple equally
357 : : * valid matches, but only one will be returned). This must be used ONLY
358 : : * as a heuristic in giving suitable error messages. See errorMissingRTE.
359 : : *
360 : : * Notice that we consider both matches on actual relation (or CTE) name
361 : : * and matches on alias.
362 : : */
363 : : static RangeTblEntry *
4778 tgl@sss.pgh.pa.us 364 : 57 : searchRangeTableForRel(ParseState *pstate, RangeVar *relation)
365 : : {
6179 366 : 57 : const char *refname = relation->relname;
367 : 57 : Oid relId = InvalidOid;
368 : 57 : CommonTableExpr *cte = NULL;
3081 kgrittn@postgresql.o 369 : 57 : bool isenr = false;
6179 tgl@sss.pgh.pa.us 370 : 57 : Index ctelevelsup = 0;
371 : : Index levelsup;
372 : :
373 : : /*
374 : : * If it's an unqualified name, check for possible CTE matches. A CTE
375 : : * hides any real relation matches. If no CTE, look for a matching
376 : : * relation.
377 : : *
378 : : * NB: It's not critical that RangeVarGetRelid return the correct answer
379 : : * here in the face of concurrent DDL. If it doesn't, the worst case
380 : : * scenario is a less-clear error message. Also, the tables involved in
381 : : * the query are already locked, which reduces the number of cases in
382 : : * which surprising behavior can occur. So we do the name lookup
383 : : * unlocked.
384 : : */
385 [ + - ]: 57 : if (!relation->schemaname)
386 : : {
387 : 57 : cte = scanNameSpaceForCTE(pstate, refname, &ctelevelsup);
3081 kgrittn@postgresql.o 388 [ + - ]: 57 : if (!cte)
389 : 57 : isenr = scanNameSpaceForENR(pstate, refname);
390 : : }
391 : :
392 [ + - + - ]: 57 : if (!cte && !isenr)
5029 rhaas@postgresql.org 393 : 57 : relId = RangeVarGetRelid(relation, NoLock, true);
394 : :
395 : : /* Now look for RTEs matching either the relation/CTE/ENR or the alias */
6179 tgl@sss.pgh.pa.us 396 : 57 : for (levelsup = 0;
397 [ + + ]: 81 : pstate != NULL;
398 : 24 : pstate = pstate->parentParseState, levelsup++)
399 : : {
400 : : ListCell *l;
401 : :
7179 402 [ + + + + : 108 : foreach(l, pstate->p_rtable)
+ + ]
403 : : {
404 : 84 : RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
405 : :
6179 406 [ + + + + ]: 84 : if (rte->rtekind == RTE_RELATION &&
407 : 57 : OidIsValid(relId) &&
7179 408 [ + + ]: 57 : rte->relid == relId)
409 : 48 : return rte;
6179 410 [ - + - - ]: 63 : if (rte->rtekind == RTE_CTE &&
6179 tgl@sss.pgh.pa.us 411 :UBC 0 : cte != NULL &&
412 [ # # ]: 0 : rte->ctelevelsup + levelsup == ctelevelsup &&
413 [ # # ]: 0 : strcmp(rte->ctename, refname) == 0)
414 : 0 : return rte;
3081 kgrittn@postgresql.o 415 [ - + - - ]:CBC 63 : if (rte->rtekind == RTE_NAMEDTUPLESTORE &&
3081 kgrittn@postgresql.o 416 :UBC 0 : isenr &&
417 [ # # ]: 0 : strcmp(rte->enrname, refname) == 0)
418 : 0 : return rte;
7179 tgl@sss.pgh.pa.us 419 [ + + ]:CBC 63 : if (strcmp(rte->eref->aliasname, refname) == 0)
420 : 27 : return rte;
421 : : }
422 : : }
423 : 9 : return NULL;
424 : : }
425 : :
426 : : /*
427 : : * Check for relation-name conflicts between two namespace lists.
428 : : * Raise an error if any is found.
429 : : *
430 : : * Note: we assume that each given argument does not contain conflicts
431 : : * itself; we just want to know if the two can be merged together.
432 : : *
433 : : * Per SQL, two alias-less plain relation RTEs do not conflict even if
434 : : * they have the same eref->aliasname (ie, same relation name), if they
435 : : * are for different relation OIDs (implying they are in different schemas).
436 : : *
437 : : * We ignore the lateral-only flags in the namespace items: the lists must
438 : : * not conflict, even when all items are considered visible. However,
439 : : * columns-only items should be ignored.
440 : : */
441 : : void
7398 442 : 230384 : checkNameSpaceConflicts(ParseState *pstate, List *namespace1,
443 : : List *namespace2)
444 : : {
445 : : ListCell *l1;
446 : :
447 [ + + + + : 365931 : foreach(l1, namespace1)
+ + ]
448 : : {
4778 449 : 135553 : ParseNamespaceItem *nsitem1 = (ParseNamespaceItem *) lfirst(l1);
450 : 135553 : RangeTblEntry *rte1 = nsitem1->p_rte;
1620 peter@eisentraut.org 451 : 135553 : const char *aliasname1 = nsitem1->p_names->aliasname;
452 : : ListCell *l2;
453 : :
4777 tgl@sss.pgh.pa.us 454 [ + + ]: 135553 : if (!nsitem1->p_rel_visible)
455 : 25896 : continue;
456 : :
7398 457 [ + - + + : 229605 : foreach(l2, namespace2)
+ + ]
458 : : {
4778 459 : 119954 : ParseNamespaceItem *nsitem2 = (ParseNamespaceItem *) lfirst(l2);
460 : 119954 : RangeTblEntry *rte2 = nsitem2->p_rte;
1620 peter@eisentraut.org 461 : 119954 : const char *aliasname2 = nsitem2->p_names->aliasname;
462 : :
4777 tgl@sss.pgh.pa.us 463 [ + + ]: 119954 : if (!nsitem2->p_rel_visible)
464 : 5156 : continue;
1620 peter@eisentraut.org 465 [ + + ]: 114798 : if (strcmp(aliasname2, aliasname1) != 0)
7398 tgl@sss.pgh.pa.us 466 : 114792 : continue; /* definitely no conflict */
467 [ + + + - ]: 6 : if (rte1->rtekind == RTE_RELATION && rte1->alias == NULL &&
468 [ + - + - ]: 3 : rte2->rtekind == RTE_RELATION && rte2->alias == NULL &&
469 [ - + ]: 3 : rte1->relid != rte2->relid)
4522 peter_e@gmx.net 470 :UBC 0 : continue; /* no conflict per SQL rule */
7398 tgl@sss.pgh.pa.us 471 [ + - ]:CBC 6 : ereport(ERROR,
472 : : (errcode(ERRCODE_DUPLICATE_ALIAS),
473 : : errmsg("table name \"%s\" specified more than once",
474 : : aliasname1)));
475 : : }
476 : : }
8430 477 : 230378 : }
478 : :
479 : : /*
480 : : * Complain if a namespace item is currently disallowed as a LATERAL reference.
481 : : * This enforces both SQL:2008's rather odd idea of what to do with a LATERAL
482 : : * reference to the wrong side of an outer join, and our own prohibition on
483 : : * referencing the target table of an UPDATE or DELETE as a lateral reference
484 : : * in a FROM/USING clause.
485 : : *
486 : : * Note: the pstate should be the same query level the nsitem was found in.
487 : : *
488 : : * Convenience subroutine to avoid multiple copies of a rather ugly ereport.
489 : : */
490 : : static void
4256 491 : 880600 : check_lateral_ref_ok(ParseState *pstate, ParseNamespaceItem *nsitem,
492 : : int location)
493 : : {
494 [ + + + + ]: 880600 : if (nsitem->p_lateral_only && !nsitem->p_lateral_ok)
495 : : {
496 : : /* SQL:2008 demands this be an error, not an invisible item */
497 : 12 : RangeTblEntry *rte = nsitem->p_rte;
1620 peter@eisentraut.org 498 : 12 : char *refname = nsitem->p_names->aliasname;
499 : :
4256 tgl@sss.pgh.pa.us 500 [ + - + + : 12 : ereport(ERROR,
+ - ]
501 : : (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
502 : : errmsg("invalid reference to FROM-clause entry for table \"%s\"",
503 : : refname),
504 : : (pstate->p_target_nsitem != NULL &&
505 : : rte == pstate->p_target_nsitem->p_rte) ?
506 : : errhint("There is an entry for table \"%s\", but it cannot be referenced from this part of the query.",
507 : : refname) :
508 : : errdetail("The combining JOIN type must be INNER or LEFT for a LATERAL reference."),
509 : : parser_errposition(pstate, location)));
510 : : }
511 : 880588 : }
512 : :
513 : : /*
514 : : * Given an RT index and nesting depth, find the corresponding
515 : : * ParseNamespaceItem (there must be one).
516 : : */
517 : : ParseNamespaceItem *
2081 518 : 1104 : GetNSItemByRangeTablePosn(ParseState *pstate,
519 : : int varno,
520 : : int sublevels_up)
521 : : {
522 : : ListCell *lc;
523 : :
524 [ - + ]: 1104 : while (sublevels_up-- > 0)
525 : : {
9125 tgl@sss.pgh.pa.us 526 :UBC 0 : pstate = pstate->parentParseState;
2081 527 [ # # ]: 0 : Assert(pstate != NULL);
528 : : }
2081 tgl@sss.pgh.pa.us 529 [ + - + - :CBC 1209 : foreach(lc, pstate->p_namespace)
+ - ]
530 : : {
531 : 1209 : ParseNamespaceItem *nsitem = (ParseNamespaceItem *) lfirst(lc);
532 : :
533 [ + + ]: 1209 : if (nsitem->p_rtindex == varno)
534 : 1104 : return nsitem;
535 : : }
2081 tgl@sss.pgh.pa.us 536 [ # # ]:UBC 0 : elog(ERROR, "nsitem not found (internal error)");
537 : : return NULL; /* keep compiler quiet */
538 : : }
539 : :
540 : : /*
541 : : * Given an RT index and nesting depth, find the corresponding RTE.
542 : : * (Note that the RTE need not be in the query's namespace.)
543 : : */
544 : : RangeTblEntry *
7827 tgl@sss.pgh.pa.us 545 :CBC 398589 : GetRTEByRangeTablePosn(ParseState *pstate,
546 : : int varno,
547 : : int sublevels_up)
548 : : {
549 [ + + ]: 399269 : while (sublevels_up-- > 0)
550 : : {
551 : 680 : pstate = pstate->parentParseState;
552 [ - + ]: 680 : Assert(pstate != NULL);
553 : : }
7769 neilc@samurai.com 554 [ + - - + ]: 398589 : Assert(varno > 0 && varno <= list_length(pstate->p_rtable));
7827 tgl@sss.pgh.pa.us 555 : 398589 : return rt_fetch(varno, pstate->p_rtable);
556 : : }
557 : :
558 : : /*
559 : : * Fetch the CTE for a CTE-reference RTE.
560 : : *
561 : : * rtelevelsup is the number of query levels above the given pstate that the
562 : : * RTE came from.
563 : : */
564 : : CommonTableExpr *
6179 565 : 4364 : GetCTEForRTE(ParseState *pstate, RangeTblEntry *rte, int rtelevelsup)
566 : : {
567 : : Index levelsup;
568 : : ListCell *lc;
569 : :
6181 570 [ - + ]: 4364 : Assert(rte->rtekind == RTE_CTE);
6179 571 : 4364 : levelsup = rte->ctelevelsup + rtelevelsup;
6181 572 [ + + ]: 9645 : while (levelsup-- > 0)
573 : : {
574 : 5281 : pstate = pstate->parentParseState;
575 [ - + ]: 5281 : if (!pstate) /* shouldn't happen */
6181 tgl@sss.pgh.pa.us 576 [ # # ]:UBC 0 : elog(ERROR, "bad levelsup for CTE \"%s\"", rte->ctename);
577 : : }
6181 tgl@sss.pgh.pa.us 578 [ + - + - :CBC 8047 : foreach(lc, pstate->p_ctenamespace)
+ - ]
579 : : {
580 : 8047 : CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
581 : :
582 [ + + ]: 8047 : if (strcmp(cte->ctename, rte->ctename) == 0)
583 : 4364 : return cte;
584 : : }
585 : : /* shouldn't happen */
6181 tgl@sss.pgh.pa.us 586 [ # # ]:UBC 0 : elog(ERROR, "could not find CTE \"%s\"", rte->ctename);
587 : : return NULL; /* keep compiler quiet */
588 : : }
589 : :
590 : : /*
591 : : * updateFuzzyAttrMatchState
592 : : * Using Levenshtein distance, consider if column is best fuzzy match.
593 : : */
594 : : static void
3832 rhaas@postgresql.org 595 :CBC 1149 : updateFuzzyAttrMatchState(int fuzzy_rte_penalty,
596 : : FuzzyAttrMatchState *fuzzystate, RangeTblEntry *rte,
597 : : const char *actual, const char *match, int attnum)
598 : : {
599 : : int columndistance;
600 : : int matchlen;
601 : :
602 : : /* Bail before computing the Levenshtein distance if there's no hope. */
603 [ + + ]: 1149 : if (fuzzy_rte_penalty > fuzzystate->distance)
604 : 27 : return;
605 : :
606 : : /*
607 : : * Outright reject dropped columns, which can appear here with apparent
608 : : * empty actual names, per remarks within scanRTEForColumn().
609 : : */
610 [ + + ]: 1122 : if (actual[0] == '\0')
611 : 66 : return;
612 : :
613 : : /* Use Levenshtein to compute match distance. */
614 : 1056 : matchlen = strlen(match);
615 : : columndistance =
616 : 1056 : varstr_levenshtein_less_equal(actual, strlen(actual), match, matchlen,
617 : : 1, 1, 1,
618 : 1056 : fuzzystate->distance + 1
3515 tgl@sss.pgh.pa.us 619 : 1056 : - fuzzy_rte_penalty,
620 : : true);
621 : :
622 : : /*
623 : : * If more than half the characters are different, don't treat it as a
624 : : * match, to avoid making ridiculous suggestions.
625 : : */
3832 rhaas@postgresql.org 626 [ + + ]: 1056 : if (columndistance > matchlen / 2)
627 : 618 : return;
628 : :
629 : : /*
630 : : * From this point on, we can ignore the distinction between the RTE-name
631 : : * distance and the column-name distance.
632 : : */
633 : 438 : columndistance += fuzzy_rte_penalty;
634 : :
635 : : /*
636 : : * If the new distance is less than or equal to that of the best match
637 : : * found so far, update fuzzystate.
638 : : */
639 [ + + ]: 438 : if (columndistance < fuzzystate->distance)
640 : : {
641 : : /* Store new lowest observed distance as first/only match */
642 : 57 : fuzzystate->distance = columndistance;
643 : 57 : fuzzystate->rfirst = rte;
644 : 57 : fuzzystate->first = attnum;
645 : 57 : fuzzystate->rsecond = NULL;
646 : : }
647 [ + + ]: 381 : else if (columndistance == fuzzystate->distance)
648 : : {
649 : : /* If we already have a match of this distance, update state */
1019 tgl@sss.pgh.pa.us 650 [ + + ]: 21 : if (fuzzystate->rsecond != NULL)
651 : : {
652 : : /*
653 : : * Too many matches at same distance. Clearly, this value of
654 : : * distance is too low a bar, so drop these entries while keeping
655 : : * the current distance value, so that only smaller distances will
656 : : * be considered interesting. Only if we find something of lower
657 : : * distance will we re-populate rfirst (via the stanza above).
658 : : */
3832 rhaas@postgresql.org 659 : 3 : fuzzystate->rfirst = NULL;
660 : 3 : fuzzystate->rsecond = NULL;
661 : : }
1019 tgl@sss.pgh.pa.us 662 [ + + ]: 18 : else if (fuzzystate->rfirst != NULL)
663 : : {
664 : : /* Record as provisional second match */
3832 rhaas@postgresql.org 665 : 9 : fuzzystate->rsecond = rte;
666 : 9 : fuzzystate->second = attnum;
667 : : }
668 : : else
669 : : {
670 : : /*
671 : : * Do nothing. When rfirst is NULL, distance is more than what we
672 : : * want to consider acceptable, so we should ignore this match.
673 : : */
674 : : }
675 : : }
676 : : }
677 : :
678 : : /*
679 : : * scanNSItemForColumn
680 : : * Search the column names of a single namespace item for the given name.
681 : : * If found, return an appropriate Var node, else return NULL.
682 : : * If the name proves ambiguous within this nsitem, raise error.
683 : : *
684 : : * Side effect: if we find a match, mark the corresponding RTE as requiring
685 : : * read access for the column.
686 : : */
687 : : Node *
2081 tgl@sss.pgh.pa.us 688 : 939989 : scanNSItemForColumn(ParseState *pstate, ParseNamespaceItem *nsitem,
689 : : int sublevels_up, const char *colname, int location)
690 : : {
691 : 939989 : RangeTblEntry *rte = nsitem->p_rte;
692 : : int attnum;
693 : : Var *var;
694 : :
695 : : /*
696 : : * Scan the nsitem's column names (or aliases) for a match. Complain if
697 : : * multiple matches.
698 : : */
1620 peter@eisentraut.org 699 : 939989 : attnum = scanRTEForColumn(pstate, rte, nsitem->p_names,
700 : : colname, location,
701 : : 0, NULL);
702 : :
2081 tgl@sss.pgh.pa.us 703 [ + + ]: 939983 : if (attnum == InvalidAttrNumber)
704 : 65818 : return NULL; /* Return NULL if no match */
705 : :
706 : : /* In constraint check, no system column is allowed except tableOid */
707 [ + + + + ]: 874165 : if (pstate->p_expr_kind == EXPR_KIND_CHECK_CONSTRAINT &&
708 [ + + ]: 6 : attnum < InvalidAttrNumber && attnum != TableOidAttributeNumber)
709 [ + - ]: 3 : ereport(ERROR,
710 : : (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
711 : : errmsg("system column \"%s\" reference in check constraint is invalid",
712 : : colname),
713 : : parser_errposition(pstate, location)));
714 : :
715 : : /*
716 : : * In generated column, no system column is allowed except tableOid.
717 : : * (Required for stored generated, but we also do it for virtual generated
718 : : * for now for consistency.)
719 : : */
720 [ + + + + ]: 874162 : if (pstate->p_expr_kind == EXPR_KIND_GENERATED_COLUMN &&
721 [ + + ]: 25 : attnum < InvalidAttrNumber && attnum != TableOidAttributeNumber)
722 [ + - ]: 6 : ereport(ERROR,
723 : : (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
724 : : errmsg("cannot use system column \"%s\" in column generation expression",
725 : : colname),
726 : : parser_errposition(pstate, location)));
727 : :
728 : : /*
729 : : * In a MERGE WHEN condition, no system column is allowed except tableOid
730 : : */
1258 alvherre@alvh.no-ip. 731 [ + + + + ]: 874156 : if (pstate->p_expr_kind == EXPR_KIND_MERGE_WHEN &&
732 [ + + ]: 6 : attnum < InvalidAttrNumber && attnum != TableOidAttributeNumber)
733 [ + - ]: 3 : ereport(ERROR,
734 : : (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
735 : : errmsg("cannot use system column \"%s\" in MERGE WHEN condition",
736 : : colname),
737 : : parser_errposition(pstate, location)));
738 : :
739 : : /* Found a valid match, so build a Var */
2074 tgl@sss.pgh.pa.us 740 [ + + ]: 874153 : if (attnum > InvalidAttrNumber)
741 : : {
742 : : /* Get attribute data from the ParseNamespaceColumn array */
743 : 857134 : ParseNamespaceColumn *nscol = &nsitem->p_nscolumns[attnum - 1];
744 : :
745 : : /* Complain if dropped column. See notes in scanRTEForColumn. */
746 [ - + ]: 857134 : if (nscol->p_varno == 0)
2074 tgl@sss.pgh.pa.us 747 [ # # ]:UBC 0 : ereport(ERROR,
748 : : (errcode(ERRCODE_UNDEFINED_COLUMN),
749 : : errmsg("column \"%s\" of relation \"%s\" does not exist",
750 : : colname,
751 : : nsitem->p_names->aliasname)));
752 : :
2067 tgl@sss.pgh.pa.us 753 :CBC 857134 : var = makeVar(nscol->p_varno,
754 : 857134 : nscol->p_varattno,
755 : : nscol->p_vartype,
756 : : nscol->p_vartypmod,
757 : : nscol->p_varcollid,
758 : : sublevels_up);
759 : : /* makeVar doesn't offer parameters for these, so set them by hand: */
760 : 857134 : var->varnosyn = nscol->p_varnosyn;
761 : 857134 : var->varattnosyn = nscol->p_varattnosyn;
762 : : }
763 : : else
764 : : {
765 : : /* System column, so use predetermined type data */
766 : : const FormData_pg_attribute *sysatt;
767 : :
2074 768 : 17019 : sysatt = SystemAttributeDefinition(attnum);
769 : 17019 : var = makeVar(nsitem->p_rtindex,
770 : : attnum,
771 : 17019 : sysatt->atttypid,
772 : 17019 : sysatt->atttypmod,
773 : 17019 : sysatt->attcollation,
774 : : sublevels_up);
775 : : }
2081 776 : 874153 : var->location = location;
777 : :
778 : : /* Mark Var for RETURNING OLD/NEW, as necessary */
233 dean.a.rasheed@gmail 779 : 874153 : var->varreturningtype = nsitem->p_returning_type;
780 : :
781 : : /* Mark Var if it's nulled by any outer joins */
950 tgl@sss.pgh.pa.us 782 : 874153 : markNullableIfNeeded(pstate, var);
783 : :
784 : : /* Require read access to the column */
1668 785 : 874153 : markVarForSelectPriv(pstate, var);
786 : :
2081 787 : 874153 : return (Node *) var;
788 : : }
789 : :
790 : : /*
791 : : * scanRTEForColumn
792 : : * Search the column names of a single RTE for the given name.
793 : : * If found, return the attnum (possibly negative, for a system column);
794 : : * else return InvalidAttrNumber.
795 : : * If the name proves ambiguous within this RTE, raise error.
796 : : *
797 : : * Actually, we only search the names listed in "eref". This can be either
798 : : * rte->eref, in which case we are indeed searching all the column names,
799 : : * or for a join it can be rte->join_using_alias, in which case we are only
800 : : * considering the common column names (which are the first N columns of the
801 : : * join, so everything works).
802 : : *
803 : : * pstate and location are passed only for error-reporting purposes.
804 : : *
805 : : * Side effect: if fuzzystate is non-NULL, check non-system columns
806 : : * for an approximate match and update fuzzystate accordingly.
807 : : *
808 : : * Note: this is factored out of scanNSItemForColumn because error message
809 : : * creation may want to check RTEs that are not in the namespace. To support
810 : : * that usage, minimize the number of validity checks performed here. It's
811 : : * okay to complain about ambiguous-name cases, though, since if we are
812 : : * working to complain about an invalid name, we've already eliminated that.
813 : : */
814 : : static int
815 : 940190 : scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte,
816 : : Alias *eref,
817 : : const char *colname, int location,
818 : : int fuzzy_rte_penalty,
819 : : FuzzyAttrMatchState *fuzzystate)
820 : : {
821 : 940190 : int result = InvalidAttrNumber;
9125 822 : 940190 : int attnum = 0;
823 : : ListCell *c;
824 : :
825 : : /*
826 : : * Scan the user column names (or aliases) for a match. Complain if
827 : : * multiple matches.
828 : : *
829 : : * Note: eref->colnames may include entries for dropped columns, but those
830 : : * will be empty strings that cannot match any legal SQL identifier, so we
831 : : * don't bother to test for that case here.
832 : : *
833 : : * Should this somehow go wrong and we try to access a dropped column,
834 : : * we'll still catch it by virtue of the check in scanNSItemForColumn().
835 : : * Callers interested in finding match with shortest distance need to
836 : : * defend against this directly, though.
837 : : */
1620 peter@eisentraut.org 838 [ + + + + : 17140861 : foreach(c, eref->colnames)
+ + ]
839 : : {
3832 rhaas@postgresql.org 840 : 16200677 : const char *attcolname = strVal(lfirst(c));
841 : :
9125 tgl@sss.pgh.pa.us 842 : 16200677 : attnum++;
3832 rhaas@postgresql.org 843 [ + + ]: 16200677 : if (strcmp(attcolname, colname) == 0)
844 : : {
9125 tgl@sss.pgh.pa.us 845 [ + + ]: 857176 : if (result)
8085 846 [ + - ]: 6 : ereport(ERROR,
847 : : (errcode(ERRCODE_AMBIGUOUS_COLUMN),
848 : : errmsg("column reference \"%s\" is ambiguous",
849 : : colname),
850 : : parser_errposition(pstate, location)));
2081 851 : 857170 : result = attnum;
852 : : }
853 : :
854 : : /* Update fuzzy match state, if provided. */
3832 rhaas@postgresql.org 855 [ + + ]: 16200671 : if (fuzzystate != NULL)
856 : 1149 : updateFuzzyAttrMatchState(fuzzy_rte_penalty, fuzzystate,
857 : : rte, attcolname, colname, attnum);
858 : : }
859 : :
860 : : /*
861 : : * If we have a unique match, return it. Note that this allows a user
862 : : * alias to override a system column name (such as OID) without error.
863 : : */
9125 tgl@sss.pgh.pa.us 864 [ + + ]: 940184 : if (result)
865 : 857164 : return result;
866 : :
867 : : /*
868 : : * If the RTE represents a real relation, consider system column names.
869 : : * Composites are only used for pseudo-relations like ON CONFLICT's
870 : : * excluded.
871 : : */
3626 andres@anarazel.de 872 [ + + ]: 83020 : if (rte->rtekind == RTE_RELATION &&
873 [ + + ]: 64200 : rte->relkind != RELKIND_COMPOSITE_TYPE)
874 : : {
875 : : /* quick check to see if name could be a system column */
9125 tgl@sss.pgh.pa.us 876 : 64173 : attnum = specialAttNum(colname);
877 [ + + ]: 64173 : if (attnum != InvalidAttrNumber)
878 : : {
879 : : /* now check to see if column actually is defined */
5683 rhaas@postgresql.org 880 [ + - ]: 17040 : if (SearchSysCacheExists2(ATTNUM,
881 : : ObjectIdGetDatum(rte->relid),
882 : : Int16GetDatum(attnum)))
2081 tgl@sss.pgh.pa.us 883 : 17040 : result = attnum;
884 : : }
885 : : }
886 : :
9125 887 : 83020 : return result;
888 : : }
889 : :
890 : : /*
891 : : * colNameToVar
892 : : * Search for an unqualified column name.
893 : : * If found, return the appropriate Var node (or expression).
894 : : * If not found, return NULL. If the name proves ambiguous, raise error.
895 : : * If localonly is true, only names in the innermost query are considered.
896 : : */
897 : : Node *
2867 peter_e@gmx.net 898 : 372479 : colNameToVar(ParseState *pstate, const char *colname, bool localonly,
899 : : int location)
900 : : {
9125 tgl@sss.pgh.pa.us 901 : 372479 : Node *result = NULL;
2081 902 : 372479 : int sublevels_up = 0;
9125 903 : 372479 : ParseState *orig_pstate = pstate;
904 : :
905 [ + + ]: 397404 : while (pstate != NULL)
906 : : {
907 : : ListCell *l;
908 : :
4777 909 [ + + + + : 1003050 : foreach(l, pstate->p_namespace)
+ + ]
910 : : {
4778 911 : 624747 : ParseNamespaceItem *nsitem = (ParseNamespaceItem *) lfirst(l);
912 : : Node *newresult;
913 : :
914 : : /* Ignore table-only items */
4777 915 [ + + ]: 624747 : if (!nsitem->p_cols_visible)
916 : 205706 : continue;
917 : : /* If not inside LATERAL, ignore lateral-only items */
4778 918 [ + + + + ]: 419041 : if (nsitem->p_lateral_only && !pstate->p_lateral_active)
919 : 23 : continue;
920 : :
921 : : /* use orig_pstate here for consistency with other callers */
2081 922 : 419018 : newresult = scanNSItemForColumn(orig_pstate, nsitem, sublevels_up,
923 : : colname, location);
924 : :
9125 925 [ + + ]: 419003 : if (newresult)
926 : : {
927 [ + + ]: 353353 : if (result)
8085 928 [ + - ]: 12 : ereport(ERROR,
929 : : (errcode(ERRCODE_AMBIGUOUS_COLUMN),
930 : : errmsg("column reference \"%s\" is ambiguous",
931 : : colname),
932 : : parser_errposition(pstate, location)));
4256 933 : 353341 : check_lateral_ref_ok(pstate, nsitem, location);
9125 934 : 353335 : result = newresult;
935 : : }
936 : : }
937 : :
7811 938 [ + + + + ]: 378303 : if (result != NULL || localonly)
939 : : break; /* found, or don't want to look at parent */
940 : :
9298 941 : 24925 : pstate = pstate->parentParseState;
2081 942 : 24925 : sublevels_up++;
943 : : }
944 : :
9125 945 : 372446 : return result;
946 : : }
947 : :
948 : : /*
949 : : * searchRangeTableForCol
950 : : * See if any RangeTblEntry could possibly provide the given column name (or
951 : : * find the best match available). Returns state with relevant details.
952 : : *
953 : : * This is different from colNameToVar in that it considers every entry in
954 : : * the ParseState's rangetable(s), not only those that are currently visible
955 : : * in the p_namespace list(s). This behavior is invalid per the SQL spec,
956 : : * and it may give ambiguous results (since there might be multiple equally
957 : : * valid matches). This must be used ONLY as a heuristic in giving suitable
958 : : * error messages. See errorMissingColumn.
959 : : *
960 : : * This function is also different in that it will consider approximate
961 : : * matches -- if the user entered an alias/column pair that is only slightly
962 : : * different from a valid pair, we may be able to infer what they meant to
963 : : * type and provide a reasonable hint. We return a FuzzyAttrMatchState
964 : : * struct providing information about both exact and approximate matches.
965 : : */
966 : : static FuzzyAttrMatchState *
2867 peter_e@gmx.net 967 : 182 : searchRangeTableForCol(ParseState *pstate, const char *alias, const char *colname,
968 : : int location)
969 : : {
4778 tgl@sss.pgh.pa.us 970 : 182 : ParseState *orig_pstate = pstate;
3832 rhaas@postgresql.org 971 : 182 : FuzzyAttrMatchState *fuzzystate = palloc(sizeof(FuzzyAttrMatchState));
972 : :
973 : 182 : fuzzystate->distance = MAX_FUZZY_DISTANCE + 1;
974 : 182 : fuzzystate->rfirst = NULL;
975 : 182 : fuzzystate->rsecond = NULL;
1019 tgl@sss.pgh.pa.us 976 : 182 : fuzzystate->rexact1 = NULL;
977 : 182 : fuzzystate->rexact2 = NULL;
978 : :
4778 979 [ + + ]: 379 : while (pstate != NULL)
980 : : {
981 : : ListCell *l;
982 : :
983 [ + + + + : 425 : foreach(l, pstate->p_rtable)
+ + ]
984 : : {
3759 bruce@momjian.us 985 : 228 : RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
986 : 228 : int fuzzy_rte_penalty = 0;
987 : : int attnum;
988 : :
989 : : /*
990 : : * Typically, it is not useful to look for matches within join
991 : : * RTEs; they effectively duplicate other RTEs for our purposes,
992 : : * and if a match is chosen from a join RTE, an unhelpful alias is
993 : : * displayed in the final diagnostic message.
994 : : */
3832 rhaas@postgresql.org 995 [ + + ]: 228 : if (rte->rtekind == RTE_JOIN)
996 : 27 : continue;
997 : :
998 : : /*
999 : : * If the user didn't specify an alias, then matches against one
1000 : : * RTE are as good as another. But if the user did specify an
1001 : : * alias, then we want at least a fuzzy - and preferably an exact
1002 : : * - match for the range table entry.
1003 : : */
1004 [ + + ]: 201 : if (alias != NULL)
1005 : : fuzzy_rte_penalty =
3515 tgl@sss.pgh.pa.us 1006 : 57 : varstr_levenshtein_less_equal(alias, strlen(alias),
1007 : 57 : rte->eref->aliasname,
2999 1008 : 57 : strlen(rte->eref->aliasname),
1009 : : 1, 1, 1,
1010 : : MAX_FUZZY_DISTANCE + 1,
1011 : : true);
1012 : :
1013 : : /*
1014 : : * Scan for a matching column, and update fuzzystate. Non-exact
1015 : : * matches are dealt with inside scanRTEForColumn, but exact
1016 : : * matches are handled here. (There won't be more than one exact
1017 : : * match in the same RTE, else we'd have thrown error earlier.)
1018 : : */
1019 1019 : 201 : attnum = scanRTEForColumn(orig_pstate, rte, rte->eref,
1020 : : colname, location,
1021 : : fuzzy_rte_penalty, fuzzystate);
1022 [ + + + + ]: 201 : if (attnum != InvalidAttrNumber && fuzzy_rte_penalty == 0)
1023 : : {
1024 [ + + ]: 30 : if (fuzzystate->rexact1 == NULL)
1025 : : {
1026 : 21 : fuzzystate->rexact1 = rte;
1027 : 21 : fuzzystate->exact1 = attnum;
1028 : : }
1029 : : else
1030 : : {
1031 : : /* Needn't worry about overwriting previous rexact2 */
1032 : 9 : fuzzystate->rexact2 = rte;
1033 : 9 : fuzzystate->exact2 = attnum;
1034 : : }
1035 : : }
1036 : : }
1037 : :
4778 1038 : 197 : pstate = pstate->parentParseState;
1039 : : }
1040 : :
3832 rhaas@postgresql.org 1041 : 182 : return fuzzystate;
1042 : : }
1043 : :
1044 : : /*
1045 : : * markNullableIfNeeded
1046 : : * If the RTE referenced by the Var is nullable by outer join(s)
1047 : : * at this point in the query, set var->varnullingrels to show that.
1048 : : */
1049 : : void
950 tgl@sss.pgh.pa.us 1050 : 2601957 : markNullableIfNeeded(ParseState *pstate, Var *var)
1051 : : {
1052 : 2601957 : int rtindex = var->varno;
1053 : : Bitmapset *relids;
1054 : :
1055 : : /* Find the appropriate pstate */
1056 [ + + ]: 2632320 : for (int lv = 0; lv < var->varlevelsup; lv++)
1057 : 30363 : pstate = pstate->parentParseState;
1058 : :
1059 : : /* Find currently-relevant join relids for the Var's rel */
1060 [ + - + + ]: 2601957 : if (rtindex > 0 && rtindex <= list_length(pstate->p_nullingrels))
1061 : 1133931 : relids = (Bitmapset *) list_nth(pstate->p_nullingrels, rtindex - 1);
1062 : : else
1063 : 1468026 : relids = NULL;
1064 : :
1065 : : /*
1066 : : * Merge with any already-declared nulling rels. (Typically there won't
1067 : : * be any, but let's get it right if there are.)
1068 : : */
1069 [ + + ]: 2601957 : if (relids != NULL)
1070 : 429312 : var->varnullingrels = bms_union(var->varnullingrels, relids);
1071 : 2601957 : }
1072 : :
1073 : : /*
1074 : : * markRTEForSelectPriv
1075 : : * Mark the specified column of the RTE with index rtindex
1076 : : * as requiring SELECT privilege
1077 : : *
1078 : : * col == InvalidAttrNumber means a "whole row" reference
1079 : : */
1080 : : static void
1671 1081 : 986575 : markRTEForSelectPriv(ParseState *pstate, int rtindex, AttrNumber col)
1082 : : {
1083 : 986575 : RangeTblEntry *rte = rt_fetch(rtindex, pstate->p_rtable);
1084 : :
6071 1085 [ + + ]: 986575 : if (rte->rtekind == RTE_RELATION)
1086 : : {
1087 : : RTEPermissionInfo *perminfo;
1088 : :
1089 : : /* Make sure the rel as a whole is marked for SELECT access */
1005 alvherre@alvh.no-ip. 1090 : 872771 : perminfo = getRTEPermissionInfo(pstate->p_rteperminfos, rte);
1091 : 872771 : perminfo->requiredPerms |= ACL_SELECT;
1092 : : /* Must offset the attnum to fit in a bitmapset */
1093 : 872771 : perminfo->selectedCols =
1094 : 872771 : bms_add_member(perminfo->selectedCols,
1095 : : col - FirstLowInvalidHeapAttributeNumber);
1096 : : }
6071 tgl@sss.pgh.pa.us 1097 [ + + ]: 113804 : else if (rte->rtekind == RTE_JOIN)
1098 : : {
1099 [ + + ]: 210 : if (col == InvalidAttrNumber)
1100 : : {
1101 : : /*
1102 : : * A whole-row reference to a join has to be treated as whole-row
1103 : : * references to the two inputs.
1104 : : */
1105 : : JoinExpr *j;
1106 : :
1107 [ + - + - ]: 3 : if (rtindex > 0 && rtindex <= list_length(pstate->p_joinexprs))
3071 1108 : 3 : j = list_nth_node(JoinExpr, pstate->p_joinexprs, rtindex - 1);
1109 : : else
6071 tgl@sss.pgh.pa.us 1110 :UBC 0 : j = NULL;
6071 tgl@sss.pgh.pa.us 1111 [ - + ]:CBC 3 : if (j == NULL)
6071 tgl@sss.pgh.pa.us 1112 [ # # ]:UBC 0 : elog(ERROR, "could not find JoinExpr for whole-row reference");
1113 : :
1114 : : /* Note: we can't see FromExpr here */
6071 tgl@sss.pgh.pa.us 1115 [ + - ]:CBC 3 : if (IsA(j->larg, RangeTblRef))
1116 : : {
5931 bruce@momjian.us 1117 : 3 : int varno = ((RangeTblRef *) j->larg)->rtindex;
1118 : :
1671 tgl@sss.pgh.pa.us 1119 : 3 : markRTEForSelectPriv(pstate, varno, InvalidAttrNumber);
1120 : : }
6071 tgl@sss.pgh.pa.us 1121 [ # # ]:UBC 0 : else if (IsA(j->larg, JoinExpr))
1122 : : {
5931 bruce@momjian.us 1123 : 0 : int varno = ((JoinExpr *) j->larg)->rtindex;
1124 : :
1671 tgl@sss.pgh.pa.us 1125 : 0 : markRTEForSelectPriv(pstate, varno, InvalidAttrNumber);
1126 : : }
1127 : : else
6071 1128 [ # # ]: 0 : elog(ERROR, "unrecognized node type: %d",
1129 : : (int) nodeTag(j->larg));
6071 tgl@sss.pgh.pa.us 1130 [ + - ]:CBC 3 : if (IsA(j->rarg, RangeTblRef))
1131 : : {
5931 bruce@momjian.us 1132 : 3 : int varno = ((RangeTblRef *) j->rarg)->rtindex;
1133 : :
1671 tgl@sss.pgh.pa.us 1134 : 3 : markRTEForSelectPriv(pstate, varno, InvalidAttrNumber);
1135 : : }
6071 tgl@sss.pgh.pa.us 1136 [ # # ]:UBC 0 : else if (IsA(j->rarg, JoinExpr))
1137 : : {
5931 bruce@momjian.us 1138 : 0 : int varno = ((JoinExpr *) j->rarg)->rtindex;
1139 : :
1671 tgl@sss.pgh.pa.us 1140 : 0 : markRTEForSelectPriv(pstate, varno, InvalidAttrNumber);
1141 : : }
1142 : : else
6071 1143 [ # # ]: 0 : elog(ERROR, "unrecognized node type: %d",
1144 : : (int) nodeTag(j->rarg));
1145 : : }
1146 : : else
1147 : : {
1148 : : /*
1149 : : * Join alias Vars for ordinary columns must refer to merged JOIN
1150 : : * USING columns. We don't need to do anything here, because the
1151 : : * join input columns will also be referenced in the join's qual
1152 : : * clause, and will get marked for select privilege there.
1153 : : */
1154 : : }
1155 : : }
1156 : : /* other RTE types don't require privilege marking */
6071 tgl@sss.pgh.pa.us 1157 :CBC 986575 : }
1158 : :
1159 : : /*
1160 : : * markVarForSelectPriv
1161 : : * Mark the RTE referenced by the Var as requiring SELECT privilege
1162 : : * for the Var's column (the Var could be a whole-row Var, too)
1163 : : */
1164 : : void
1668 1165 : 986569 : markVarForSelectPriv(ParseState *pstate, Var *var)
1166 : : {
1167 : : Index lv;
1168 : :
6071 1169 [ - + ]: 986569 : Assert(IsA(var, Var));
1170 : : /* Find the appropriate pstate if it's an uplevel Var */
1171 [ + + ]: 1016932 : for (lv = 0; lv < var->varlevelsup; lv++)
1172 : 30363 : pstate = pstate->parentParseState;
1671 1173 : 986569 : markRTEForSelectPriv(pstate, var->varno, var->varattno);
6071 1174 : 986569 : }
1175 : :
1176 : : /*
1177 : : * buildRelationAliases
1178 : : * Construct the eref column name list for a relation RTE.
1179 : : * This code is also used for function RTEs.
1180 : : *
1181 : : * tupdesc: the physical column information
1182 : : * alias: the user-supplied alias, or NULL if none
1183 : : * eref: the eref Alias to store column names in
1184 : : *
1185 : : * eref->colnames is filled in. Also, alias->colnames is rebuilt to insert
1186 : : * empty strings for any dropped columns, so that it will be one-to-one with
1187 : : * physical column numbers.
1188 : : *
1189 : : * It is an error for there to be more aliases present than required.
1190 : : */
1191 : : static void
4307 1192 : 313035 : buildRelationAliases(TupleDesc tupdesc, Alias *alias, Alias *eref)
1193 : : {
7688 1194 : 313035 : int maxattrs = tupdesc->natts;
1195 : : List *aliaslist;
1196 : : ListCell *aliaslc;
1197 : : int numaliases;
1198 : : int varattno;
1199 : 313035 : int numdropped = 0;
1200 : :
1201 [ - + ]: 313035 : Assert(eref->colnames == NIL);
1202 : :
1203 [ + + ]: 313035 : if (alias)
1204 : : {
2245 1205 : 140816 : aliaslist = alias->colnames;
1206 : 140816 : aliaslc = list_head(aliaslist);
1207 : 140816 : numaliases = list_length(aliaslist);
1208 : : /* We'll rebuild the alias colname list */
7688 1209 : 140816 : alias->colnames = NIL;
1210 : : }
1211 : : else
1212 : : {
2245 1213 : 172219 : aliaslist = NIL;
7688 1214 : 172219 : aliaslc = NULL;
1215 : 172219 : numaliases = 0;
1216 : : }
1217 : :
1218 [ + + ]: 3503841 : for (varattno = 0; varattno < maxattrs; varattno++)
1219 : : {
2939 andres@anarazel.de 1220 : 3190806 : Form_pg_attribute attr = TupleDescAttr(tupdesc, varattno);
1221 : : String *attrname;
1222 : :
7688 tgl@sss.pgh.pa.us 1223 [ + + ]: 3190806 : if (attr->attisdropped)
1224 : : {
1225 : : /* Always insert an empty string for a dropped column */
1226 : 2806 : attrname = makeString(pstrdup(""));
1227 [ + + ]: 2806 : if (aliaslc)
1228 : 3 : alias->colnames = lappend(alias->colnames, attrname);
1229 : 2806 : numdropped++;
1230 : : }
1231 [ + + ]: 3188000 : else if (aliaslc)
1232 : : {
1233 : : /* Use the next user-supplied alias */
1458 peter@eisentraut.org 1234 : 3794 : attrname = lfirst_node(String, aliaslc);
2245 tgl@sss.pgh.pa.us 1235 : 3794 : aliaslc = lnext(aliaslist, aliaslc);
7688 1236 : 3794 : alias->colnames = lappend(alias->colnames, attrname);
1237 : : }
1238 : : else
1239 : : {
1240 : 3184206 : attrname = makeString(pstrdup(NameStr(attr->attname)));
1241 : : /* we're done with the alias if any */
1242 : : }
1243 : :
1244 : 3190806 : eref->colnames = lappend(eref->colnames, attrname);
1245 : : }
1246 : :
1247 : : /* Too many user-supplied aliases? */
1248 [ + + ]: 313035 : if (aliaslc)
1249 [ + - ]: 3 : ereport(ERROR,
1250 : : (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
1251 : : errmsg("table \"%s\" has %d columns available but %d columns specified",
1252 : : eref->aliasname, maxattrs - numdropped, numaliases)));
1253 : 313032 : }
1254 : :
1255 : : /*
1256 : : * chooseScalarFunctionAlias
1257 : : * Select the column alias for a function in a function RTE,
1258 : : * when the function returns a scalar type (not composite or RECORD).
1259 : : *
1260 : : * funcexpr: transformed expression tree for the function call
1261 : : * funcname: function name (as determined by FigureColname)
1262 : : * alias: the user-supplied alias for the RTE, or NULL if none
1263 : : * nfuncs: the number of functions appearing in the function RTE
1264 : : *
1265 : : * Note that the name we choose might be overridden later, if the user-given
1266 : : * alias includes column alias names. That's of no concern here.
1267 : : */
1268 : : static char *
4307 1269 : 11907 : chooseScalarFunctionAlias(Node *funcexpr, char *funcname,
1270 : : Alias *alias, int nfuncs)
1271 : : {
1272 : : char *pname;
1273 : :
1274 : : /*
1275 : : * If the expression is a simple function call, and the function has a
1276 : : * single OUT parameter that is named, use the parameter's name.
1277 : : */
1278 [ + - + + ]: 11907 : if (funcexpr && IsA(funcexpr, FuncExpr))
1279 : : {
1280 : 11850 : pname = get_func_result_name(((FuncExpr *) funcexpr)->funcid);
1281 [ + + ]: 11850 : if (pname)
1282 : 645 : return pname;
1283 : : }
1284 : :
1285 : : /*
1286 : : * If there's just one function in the RTE, and the user gave an RTE alias
1287 : : * name, use that name. (This makes FROM func() AS foo use "foo" as the
1288 : : * column name as well as the table alias.)
1289 : : */
1290 [ + + + + ]: 11262 : if (nfuncs == 1 && alias)
1291 : 7562 : return alias->aliasname;
1292 : :
1293 : : /*
1294 : : * Otherwise use the function name.
1295 : : */
1296 : 3700 : return funcname;
1297 : : }
1298 : :
1299 : : /*
1300 : : * buildNSItemFromTupleDesc
1301 : : * Build a ParseNamespaceItem, given a tupdesc describing the columns.
1302 : : *
1303 : : * rte: the new RangeTblEntry for the rel
1304 : : * rtindex: its index in the rangetable list
1305 : : * perminfo: permission list entry for the rel
1306 : : * tupdesc: the physical column information
1307 : : */
1308 : : static ParseNamespaceItem *
1005 alvherre@alvh.no-ip. 1309 : 313032 : buildNSItemFromTupleDesc(RangeTblEntry *rte, Index rtindex,
1310 : : RTEPermissionInfo *perminfo,
1311 : : TupleDesc tupdesc)
1312 : : {
1313 : : ParseNamespaceItem *nsitem;
1314 : : ParseNamespaceColumn *nscolumns;
2074 tgl@sss.pgh.pa.us 1315 : 313032 : int maxattrs = tupdesc->natts;
1316 : : int varattno;
1317 : :
1318 : : /* colnames must have the same number of entries as the nsitem */
1319 [ - + ]: 313032 : Assert(maxattrs == list_length(rte->eref->colnames));
1320 : :
1321 : : /* extract per-column data from the tupdesc */
1322 : : nscolumns = (ParseNamespaceColumn *)
1323 : 313032 : palloc0(maxattrs * sizeof(ParseNamespaceColumn));
1324 : :
1325 [ + + ]: 3503835 : for (varattno = 0; varattno < maxattrs; varattno++)
1326 : : {
1327 : 3190803 : Form_pg_attribute attr = TupleDescAttr(tupdesc, varattno);
1328 : :
1329 : : /* For a dropped column, just leave the entry as zeroes */
1330 [ + + ]: 3190803 : if (attr->attisdropped)
1331 : 2806 : continue;
1332 : :
1333 : 3187997 : nscolumns[varattno].p_varno = rtindex;
1334 : 3187997 : nscolumns[varattno].p_varattno = varattno + 1;
1335 : 3187997 : nscolumns[varattno].p_vartype = attr->atttypid;
1336 : 3187997 : nscolumns[varattno].p_vartypmod = attr->atttypmod;
1337 : 3187997 : nscolumns[varattno].p_varcollid = attr->attcollation;
1338 : 3187997 : nscolumns[varattno].p_varnosyn = rtindex;
1339 : 3187997 : nscolumns[varattno].p_varattnosyn = varattno + 1;
1340 : : }
1341 : :
1342 : : /* ... and build the nsitem */
1343 : 313032 : nsitem = (ParseNamespaceItem *) palloc(sizeof(ParseNamespaceItem));
1620 peter@eisentraut.org 1344 : 313032 : nsitem->p_names = rte->eref;
2074 tgl@sss.pgh.pa.us 1345 : 313032 : nsitem->p_rte = rte;
1346 : 313032 : nsitem->p_rtindex = rtindex;
1005 alvherre@alvh.no-ip. 1347 : 313032 : nsitem->p_perminfo = perminfo;
2074 tgl@sss.pgh.pa.us 1348 : 313032 : nsitem->p_nscolumns = nscolumns;
1349 : : /* set default visibility flags; might get changed later */
1350 : 313032 : nsitem->p_rel_visible = true;
1351 : 313032 : nsitem->p_cols_visible = true;
1352 : 313032 : nsitem->p_lateral_only = false;
1353 : 313032 : nsitem->p_lateral_ok = true;
233 dean.a.rasheed@gmail 1354 : 313032 : nsitem->p_returning_type = VAR_RETURNING_DEFAULT;
1355 : :
2074 tgl@sss.pgh.pa.us 1356 : 313032 : return nsitem;
1357 : : }
1358 : :
1359 : : /*
1360 : : * buildNSItemFromLists
1361 : : * Build a ParseNamespaceItem, given column type information in lists.
1362 : : *
1363 : : * rte: the new RangeTblEntry for the rel
1364 : : * rtindex: its index in the rangetable list
1365 : : * coltypes: per-column datatype OIDs
1366 : : * coltypmods: per-column type modifiers
1367 : : * colcollation: per-column collation OIDs
1368 : : */
1369 : : static ParseNamespaceItem *
1370 : 42166 : buildNSItemFromLists(RangeTblEntry *rte, Index rtindex,
1371 : : List *coltypes, List *coltypmods, List *colcollations)
1372 : : {
1373 : : ParseNamespaceItem *nsitem;
1374 : : ParseNamespaceColumn *nscolumns;
1375 : 42166 : int maxattrs = list_length(coltypes);
1376 : : int varattno;
1377 : : ListCell *lct;
1378 : : ListCell *lcm;
1379 : : ListCell *lcc;
1380 : :
1381 : : /* colnames must have the same number of entries as the nsitem */
1382 [ - + ]: 42166 : Assert(maxattrs == list_length(rte->eref->colnames));
1383 : :
1384 [ - + ]: 42166 : Assert(maxattrs == list_length(coltypmods));
1385 [ - + ]: 42166 : Assert(maxattrs == list_length(colcollations));
1386 : :
1387 : : /* extract per-column data from the lists */
1388 : : nscolumns = (ParseNamespaceColumn *)
1389 : 42166 : palloc0(maxattrs * sizeof(ParseNamespaceColumn));
1390 : :
1391 : 42166 : varattno = 0;
1392 [ + + + + : 143001 : forthree(lct, coltypes,
+ + + + +
+ + + + +
+ - + - +
+ ]
1393 : : lcm, coltypmods,
1394 : : lcc, colcollations)
1395 : : {
1396 : 100835 : nscolumns[varattno].p_varno = rtindex;
1397 : 100835 : nscolumns[varattno].p_varattno = varattno + 1;
1398 : 100835 : nscolumns[varattno].p_vartype = lfirst_oid(lct);
1399 : 100835 : nscolumns[varattno].p_vartypmod = lfirst_int(lcm);
1400 : 100835 : nscolumns[varattno].p_varcollid = lfirst_oid(lcc);
1401 : 100835 : nscolumns[varattno].p_varnosyn = rtindex;
1402 : 100835 : nscolumns[varattno].p_varattnosyn = varattno + 1;
1403 : 100835 : varattno++;
1404 : : }
1405 : :
1406 : : /* ... and build the nsitem */
1407 : 42166 : nsitem = (ParseNamespaceItem *) palloc(sizeof(ParseNamespaceItem));
1620 peter@eisentraut.org 1408 : 42166 : nsitem->p_names = rte->eref;
2074 tgl@sss.pgh.pa.us 1409 : 42166 : nsitem->p_rte = rte;
1410 : 42166 : nsitem->p_rtindex = rtindex;
785 amitlan@postgresql.o 1411 : 42166 : nsitem->p_perminfo = NULL;
2074 tgl@sss.pgh.pa.us 1412 : 42166 : nsitem->p_nscolumns = nscolumns;
1413 : : /* set default visibility flags; might get changed later */
1414 : 42166 : nsitem->p_rel_visible = true;
1415 : 42166 : nsitem->p_cols_visible = true;
1416 : 42166 : nsitem->p_lateral_only = false;
1417 : 42166 : nsitem->p_lateral_ok = true;
233 dean.a.rasheed@gmail 1418 : 42166 : nsitem->p_returning_type = VAR_RETURNING_DEFAULT;
1419 : :
2074 tgl@sss.pgh.pa.us 1420 : 42166 : return nsitem;
1421 : : }
1422 : :
1423 : : /*
1424 : : * Open a table during parse analysis
1425 : : *
1426 : : * This is essentially just the same as table_openrv(), except that it caters
1427 : : * to some parser-specific error reporting needs, notably that it arranges
1428 : : * to include the RangeVar's parse location in any resulting error.
1429 : : *
1430 : : * Note: properly, lockmode should be declared LOCKMODE not int, but that
1431 : : * would require importing storage/lock.h into parse_relation.h. Since
1432 : : * LOCKMODE is typedef'd as int anyway, that seems like overkill.
1433 : : */
1434 : : Relation
6214 1435 : 239661 : parserOpenTable(ParseState *pstate, const RangeVar *relation, int lockmode)
1436 : : {
1437 : : Relation rel;
1438 : : ParseCallbackState pcbstate;
1439 : :
1440 : 239661 : setup_parser_errposition_callback(&pcbstate, pstate, relation->location);
2420 andres@anarazel.de 1441 : 239661 : rel = table_openrv_extended(relation, lockmode, true);
6177 tgl@sss.pgh.pa.us 1442 [ + + ]: 239660 : if (rel == NULL)
1443 : : {
1444 [ + + ]: 91 : if (relation->schemaname)
1445 [ + - ]: 1 : ereport(ERROR,
1446 : : (errcode(ERRCODE_UNDEFINED_TABLE),
1447 : : errmsg("relation \"%s.%s\" does not exist",
1448 : : relation->schemaname, relation->relname)));
1449 : : else
1450 : : {
1451 : : /*
1452 : : * An unqualified name might have been meant as a reference to
1453 : : * some not-yet-in-scope CTE. The bare "does not exist" message
1454 : : * has proven remarkably unhelpful for figuring out such problems,
1455 : : * so we take pains to offer a specific hint.
1456 : : */
2882 1457 [ + + ]: 90 : if (isFutureCTE(pstate, relation->relname))
6177 1458 [ + - ]: 3 : ereport(ERROR,
1459 : : (errcode(ERRCODE_UNDEFINED_TABLE),
1460 : : errmsg("relation \"%s\" does not exist",
1461 : : relation->relname),
1462 : : errdetail("There is a WITH item named \"%s\", but it cannot be referenced from this part of the query.",
1463 : : relation->relname),
1464 : : errhint("Use WITH RECURSIVE, or re-order the WITH items to remove forward references.")));
1465 : : else
1466 [ + - ]: 87 : ereport(ERROR,
1467 : : (errcode(ERRCODE_UNDEFINED_TABLE),
1468 : : errmsg("relation \"%s\" does not exist",
1469 : : relation->relname)));
1470 : : }
1471 : : }
6214 1472 : 239569 : cancel_parser_errposition_callback(&pcbstate);
1473 : 239569 : return rel;
1474 : : }
1475 : :
1476 : : /*
1477 : : * Add an entry for a relation to the pstate's range table (p_rtable).
1478 : : * Then, construct and return a ParseNamespaceItem for the new RTE.
1479 : : *
1480 : : * We do not link the ParseNamespaceItem into the pstate here; it's the
1481 : : * caller's job to do that in the appropriate way.
1482 : : *
1483 : : * Note: formerly this checked for refname conflicts, but that's wrong.
1484 : : * Caller is responsible for checking for conflicts in the appropriate scope.
1485 : : */
1486 : : ParseNamespaceItem *
10147 bruce@momjian.us 1487 : 194838 : addRangeTableEntry(ParseState *pstate,
1488 : : RangeVar *relation,
1489 : : Alias *alias,
1490 : : bool inh,
1491 : : bool inFromCl)
1492 : : {
8970 tgl@sss.pgh.pa.us 1493 : 194838 : RangeTblEntry *rte = makeNode(RangeTblEntry);
1494 : : RTEPermissionInfo *perminfo;
8569 1495 [ + + ]: 194838 : char *refname = alias ? alias->aliasname : relation->relname;
1496 : : LOCKMODE lockmode;
1497 : : Relation rel;
1498 : : ParseNamespaceItem *nsitem;
1499 : :
3840 rhaas@postgresql.org 1500 [ - + ]: 194838 : Assert(pstate != NULL);
1501 : :
8579 tgl@sss.pgh.pa.us 1502 : 194838 : rte->rtekind = RTE_RELATION;
9125 1503 : 194838 : rte->alias = alias;
1504 : :
1505 : : /*
1506 : : * Identify the type of lock we'll need on this relation. It's not the
1507 : : * query's target table (that case is handled elsewhere), so we need
1508 : : * either RowShareLock if it's locked by FOR UPDATE/SHARE, or plain
1509 : : * AccessShareLock otherwise.
1510 : : */
2533 1511 [ + + ]: 194838 : lockmode = isLockedRefname(pstate, refname) ? RowShareLock : AccessShareLock;
1512 : :
1513 : : /*
1514 : : * Get the rel's OID. This access also ensures that we have an up-to-date
1515 : : * relcache entry for the rel. Since this is typically the first access
1516 : : * to a rel in a statement, we must open the rel with the proper lockmode.
1517 : : */
6214 1518 : 194838 : rel = parserOpenTable(pstate, relation, lockmode);
9335 lockhart@fourpalms.o 1519 : 194756 : rte->relid = RelationGetRelid(rel);
548 peter@eisentraut.org 1520 : 194756 : rte->inh = inh;
5310 tgl@sss.pgh.pa.us 1521 : 194756 : rte->relkind = rel->rd_rel->relkind;
2533 1522 : 194756 : rte->rellockmode = lockmode;
1523 : :
1524 : : /*
1525 : : * Build the list of effective column names using user-supplied aliases
1526 : : * and/or actual column names.
1527 : : */
7688 1528 : 194756 : rte->eref = makeAlias(refname, NIL);
4307 1529 : 194756 : buildRelationAliases(rel->rd_att, alias, rte->eref);
1530 : :
1531 : : /*
1532 : : * Set flags and initialize access permissions.
1533 : : *
1534 : : * The initial default on access checks is always check-for-READ-access,
1535 : : * which is the right thing for all except target tables.
1536 : : */
4778 1537 : 194753 : rte->lateral = false;
8569 1538 : 194753 : rte->inFromCl = inFromCl;
1539 : :
1005 alvherre@alvh.no-ip. 1540 : 194753 : perminfo = addRTEPermissionInfo(&pstate->p_rteperminfos, rte);
1541 : 194753 : perminfo->requiredPerms = ACL_SELECT;
1542 : :
1543 : : /*
1544 : : * Add completed RTE to pstate's range table list, so that we know its
1545 : : * index. But we don't add it to the join list --- caller must do that if
1546 : : * appropriate.
1547 : : */
3840 rhaas@postgresql.org 1548 : 194753 : pstate->p_rtable = lappend(pstate->p_rtable, rte);
1549 : :
1550 : : /*
1551 : : * Build a ParseNamespaceItem, but don't add it to the pstate's namespace
1552 : : * list --- caller must do that if appropriate.
1553 : : */
2074 tgl@sss.pgh.pa.us 1554 : 194753 : nsitem = buildNSItemFromTupleDesc(rte, list_length(pstate->p_rtable),
1555 : : perminfo, rel->rd_att);
1556 : :
1557 : : /*
1558 : : * Drop the rel refcount, but keep the access lock till end of transaction
1559 : : * so that the table can't be deleted or have its schema modified
1560 : : * underneath us.
1561 : : */
1562 : 194753 : table_close(rel, NoLock);
1563 : :
1564 : 194753 : return nsitem;
1565 : : }
1566 : :
1567 : : /*
1568 : : * Add an entry for a relation to the pstate's range table (p_rtable).
1569 : : * Then, construct and return a ParseNamespaceItem for the new RTE.
1570 : : *
1571 : : * This is just like addRangeTableEntry() except that it makes an RTE
1572 : : * given an already-open relation instead of a RangeVar reference.
1573 : : *
1574 : : * lockmode is the lock type required for query execution; it must be one
1575 : : * of AccessShareLock, RowShareLock, or RowExclusiveLock depending on the
1576 : : * RTE's role within the query. The caller must hold that lock mode
1577 : : * or a stronger one.
1578 : : *
1579 : : * Note: properly, lockmode should be declared LOCKMODE not int, but that
1580 : : * would require importing storage/lock.h into parse_relation.h. Since
1581 : : * LOCKMODE is typedef'd as int anyway, that seems like overkill.
1582 : : */
1583 : : ParseNamespaceItem *
8569 1584 : 94380 : addRangeTableEntryForRelation(ParseState *pstate,
1585 : : Relation rel,
1586 : : int lockmode,
1587 : : Alias *alias,
1588 : : bool inh,
1589 : : bool inFromCl)
1590 : : {
1591 : 94380 : RangeTblEntry *rte = makeNode(RangeTblEntry);
1592 : : RTEPermissionInfo *perminfo;
7451 1593 [ + + ]: 94380 : char *refname = alias ? alias->aliasname : RelationGetRelationName(rel);
1594 : :
3832 rhaas@postgresql.org 1595 [ - + ]: 94380 : Assert(pstate != NULL);
1596 : :
2533 tgl@sss.pgh.pa.us 1597 [ + + + - : 94380 : Assert(lockmode == AccessShareLock ||
- + ]
1598 : : lockmode == RowShareLock ||
1599 : : lockmode == RowExclusiveLock);
2532 1600 [ - + ]: 94380 : Assert(CheckRelationLockedByMe(rel, lockmode, true));
1601 : :
8569 1602 : 94380 : rte->rtekind = RTE_RELATION;
1603 : 94380 : rte->alias = alias;
7451 1604 : 94380 : rte->relid = RelationGetRelid(rel);
548 peter@eisentraut.org 1605 : 94380 : rte->inh = inh;
5310 tgl@sss.pgh.pa.us 1606 : 94380 : rte->relkind = rel->rd_rel->relkind;
2533 1607 : 94380 : rte->rellockmode = lockmode;
1608 : :
1609 : : /*
1610 : : * Build the list of effective column names using user-supplied aliases
1611 : : * and/or actual column names.
1612 : : */
7688 1613 : 94380 : rte->eref = makeAlias(refname, NIL);
4307 1614 : 94380 : buildRelationAliases(rel->rd_att, alias, rte->eref);
1615 : :
1616 : : /*
1617 : : * Set flags and initialize access permissions.
1618 : : *
1619 : : * The initial default on access checks is always check-for-READ-access,
1620 : : * which is the right thing for all except target tables.
1621 : : */
4778 1622 : 94380 : rte->lateral = false;
10147 bruce@momjian.us 1623 : 94380 : rte->inFromCl = inFromCl;
1624 : :
1005 alvherre@alvh.no-ip. 1625 : 94380 : perminfo = addRTEPermissionInfo(&pstate->p_rteperminfos, rte);
1626 : 94380 : perminfo->requiredPerms = ACL_SELECT;
1627 : :
1628 : : /*
1629 : : * Add completed RTE to pstate's range table list, so that we know its
1630 : : * index. But we don't add it to the join list --- caller must do that if
1631 : : * appropriate.
1632 : : */
3832 rhaas@postgresql.org 1633 : 94380 : pstate->p_rtable = lappend(pstate->p_rtable, rte);
1634 : :
1635 : : /*
1636 : : * Build a ParseNamespaceItem, but don't add it to the pstate's namespace
1637 : : * list --- caller must do that if appropriate.
1638 : : */
2074 tgl@sss.pgh.pa.us 1639 : 94380 : return buildNSItemFromTupleDesc(rte, list_length(pstate->p_rtable),
1640 : : perminfo, rel->rd_att);
1641 : : }
1642 : :
1643 : : /*
1644 : : * Add an entry for a subquery to the pstate's range table (p_rtable).
1645 : : * Then, construct and return a ParseNamespaceItem for the new RTE.
1646 : : *
1647 : : * This is much like addRangeTableEntry() except that it makes a subquery RTE.
1648 : : *
1649 : : * If the subquery does not have an alias, the auto-generated relation name in
1650 : : * the returned ParseNamespaceItem will be marked as not visible, and so only
1651 : : * unqualified references to the subquery columns will be allowed, and the
1652 : : * relation name will not conflict with others in the pstate's namespace list.
1653 : : */
1654 : : ParseNamespaceItem *
9108 1655 : 29546 : addRangeTableEntryForSubquery(ParseState *pstate,
1656 : : Query *subquery,
1657 : : Alias *alias,
1658 : : bool lateral,
1659 : : bool inFromCl)
1660 : : {
8970 1661 : 29546 : RangeTblEntry *rte = makeNode(RangeTblEntry);
1662 : : Alias *eref;
1663 : : int numaliases;
1664 : : List *coltypes,
1665 : : *coltypmods,
1666 : : *colcollations;
1667 : : int varattno;
1668 : : ListCell *tlistitem;
1669 : : ParseNamespaceItem *nsitem;
1670 : :
3832 rhaas@postgresql.org 1671 [ - + ]: 29546 : Assert(pstate != NULL);
1672 : :
8579 tgl@sss.pgh.pa.us 1673 : 29546 : rte->rtekind = RTE_SUBQUERY;
9108 1674 : 29546 : rte->subquery = subquery;
1675 : 29546 : rte->alias = alias;
1676 : :
1144 dean.a.rasheed@gmail 1677 [ + + ]: 29546 : eref = alias ? copyObject(alias) : makeAlias("unnamed_subquery", NIL);
7769 neilc@samurai.com 1678 : 29546 : numaliases = list_length(eref->colnames);
1679 : :
1680 : : /* fill in any unspecified alias columns, and extract column type info */
2074 tgl@sss.pgh.pa.us 1681 : 29546 : coltypes = coltypmods = colcollations = NIL;
9108 1682 : 29546 : varattno = 0;
1683 [ + + + + : 106983 : foreach(tlistitem, subquery->targetList)
+ + ]
1684 : : {
1685 : 77437 : TargetEntry *te = (TargetEntry *) lfirst(tlistitem);
1686 : :
7458 1687 [ + + ]: 77437 : if (te->resjunk)
9108 1688 : 135 : continue;
1689 : 77302 : varattno++;
7458 1690 [ - + ]: 77302 : Assert(varattno == te->resno);
9108 1691 [ + + ]: 77302 : if (varattno > numaliases)
1692 : : {
1693 : : char *attrname;
1694 : :
7458 1695 : 68755 : attrname = pstrdup(te->resname);
8570 1696 : 68755 : eref->colnames = lappend(eref->colnames, makeString(attrname));
1697 : : }
2074 1698 : 77302 : coltypes = lappend_oid(coltypes,
1699 : 77302 : exprType((Node *) te->expr));
1700 : 77302 : coltypmods = lappend_int(coltypmods,
1701 : 77302 : exprTypmod((Node *) te->expr));
1702 : 77302 : colcollations = lappend_oid(colcollations,
1703 : 77302 : exprCollation((Node *) te->expr));
1704 : : }
9108 1705 [ + + ]: 29546 : if (varattno < numaliases)
8085 1706 [ + - ]: 3 : ereport(ERROR,
1707 : : (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
1708 : : errmsg("table \"%s\" has %d columns available but %d columns specified",
1709 : : eref->aliasname, varattno, numaliases)));
1710 : :
9108 1711 : 29543 : rte->eref = eref;
1712 : :
1713 : : /*
1714 : : * Set flags.
1715 : : *
1716 : : * Subqueries are never checked for access rights, so no need to perform
1717 : : * addRTEPermissionInfo().
1718 : : */
4778 1719 : 29543 : rte->lateral = lateral;
9108 1720 : 29543 : rte->inFromCl = inFromCl;
1721 : :
1722 : : /*
1723 : : * Add completed RTE to pstate's range table list, so that we know its
1724 : : * index. But we don't add it to the join list --- caller must do that if
1725 : : * appropriate.
1726 : : */
3832 rhaas@postgresql.org 1727 : 29543 : pstate->p_rtable = lappend(pstate->p_rtable, rte);
1728 : :
1729 : : /*
1730 : : * Build a ParseNamespaceItem, but don't add it to the pstate's namespace
1731 : : * list --- caller must do that if appropriate.
1732 : : */
1144 dean.a.rasheed@gmail 1733 : 29543 : nsitem = buildNSItemFromLists(rte, list_length(pstate->p_rtable),
1734 : : coltypes, coltypmods, colcollations);
1735 : :
1736 : : /*
1737 : : * Mark it visible as a relation name only if it had a user-written alias.
1738 : : */
1739 : 29543 : nsitem->p_rel_visible = (alias != NULL);
1740 : :
1741 : 29543 : return nsitem;
1742 : : }
1743 : :
1744 : : /*
1745 : : * Add an entry for a function (or functions) to the pstate's range table
1746 : : * (p_rtable). Then, construct and return a ParseNamespaceItem for the new RTE.
1747 : : *
1748 : : * This is much like addRangeTableEntry() except that it makes a function RTE.
1749 : : */
1750 : : ParseNamespaceItem *
8518 tgl@sss.pgh.pa.us 1751 : 23678 : addRangeTableEntryForFunction(ParseState *pstate,
1752 : : List *funcnames,
1753 : : List *funcexprs,
1754 : : List *coldeflists,
1755 : : RangeFunction *rangefunc,
1756 : : bool lateral,
1757 : : bool inFromCl)
1758 : : {
1759 : 23678 : RangeTblEntry *rte = makeNode(RangeTblEntry);
8434 bruce@momjian.us 1760 : 23678 : Alias *alias = rangefunc->alias;
1761 : : Alias *eref;
1762 : : char *aliasname;
4307 tgl@sss.pgh.pa.us 1763 : 23678 : int nfuncs = list_length(funcexprs);
1764 : : TupleDesc *functupdescs;
1765 : : TupleDesc tupdesc;
1766 : : ListCell *lc1,
1767 : : *lc2,
1768 : : *lc3;
1769 : : int i;
1770 : : int j;
1771 : : int funcno;
1772 : : int natts,
1773 : : totalatts;
1774 : :
3832 rhaas@postgresql.org 1775 [ - + ]: 23678 : Assert(pstate != NULL);
1776 : :
8518 tgl@sss.pgh.pa.us 1777 : 23678 : rte->rtekind = RTE_FUNCTION;
1778 : 23678 : rte->relid = InvalidOid;
1779 : 23678 : rte->subquery = NULL;
4307 1780 : 23678 : rte->functions = NIL; /* we'll fill this list below */
1781 : 23678 : rte->funcordinality = rangefunc->ordinality;
8518 1782 : 23678 : rte->alias = alias;
1783 : :
1784 : : /*
1785 : : * Choose the RTE alias name. We default to using the first function's
1786 : : * name even when there's more than one; which is maybe arguable but beats
1787 : : * using something constant like "table".
1788 : : */
4307 1789 [ + + ]: 23678 : if (alias)
1790 : 14524 : aliasname = alias->aliasname;
1791 : : else
1792 : 9154 : aliasname = linitial(funcnames);
1793 : :
1794 : 23678 : eref = makeAlias(aliasname, NIL);
1795 : 23678 : rte->eref = eref;
1796 : :
1797 : : /* Process each function ... */
1798 : 23678 : functupdescs = (TupleDesc *) palloc(nfuncs * sizeof(TupleDesc));
1799 : :
1800 : 23678 : totalatts = 0;
1801 : 23678 : funcno = 0;
1802 [ + - + + : 47536 : forthree(lc1, funcexprs, lc2, funcnames, lc3, coldeflists)
+ - + + +
- + + + +
+ - + - +
+ ]
1803 : : {
1804 : 23885 : Node *funcexpr = (Node *) lfirst(lc1);
1805 : 23885 : char *funcname = (char *) lfirst(lc2);
1806 : 23885 : List *coldeflist = (List *) lfirst(lc3);
1807 : 23885 : RangeTblFunction *rtfunc = makeNode(RangeTblFunction);
1808 : : TypeFuncClass functypclass;
1809 : : Oid funcrettype;
1810 : :
1811 : : /* Initialize RangeTblFunction node */
1812 : 23885 : rtfunc->funcexpr = funcexpr;
1813 : 23885 : rtfunc->funccolnames = NIL;
1814 : 23885 : rtfunc->funccoltypes = NIL;
1815 : 23885 : rtfunc->funccoltypmods = NIL;
1816 : 23885 : rtfunc->funccolcollations = NIL;
2999 1817 : 23885 : rtfunc->funcparams = NULL; /* not set until planning */
1818 : :
1819 : : /*
1820 : : * Now determine if the function returns a simple or composite type.
1821 : : */
4307 1822 : 23885 : functypclass = get_expr_result_type(funcexpr,
1823 : : &funcrettype,
1824 : : &tupdesc);
1825 : :
1826 : : /*
1827 : : * A coldeflist is required if the function returns RECORD and hasn't
1828 : : * got a predetermined record type, and is prohibited otherwise. This
1829 : : * can be a bit confusing, so we expend some effort on delivering a
1830 : : * relevant error message.
1831 : : */
1832 [ + + ]: 23885 : if (coldeflist != NIL)
1833 : : {
1810 1834 [ + + + ]: 411 : switch (functypclass)
1835 : : {
1836 : 402 : case TYPEFUNC_RECORD:
1837 : : /* ok */
1838 : 402 : break;
1839 : 6 : case TYPEFUNC_COMPOSITE:
1840 : : case TYPEFUNC_COMPOSITE_DOMAIN:
1841 : :
1842 : : /*
1843 : : * If the function's raw result type is RECORD, we must
1844 : : * have resolved it using its OUT parameters. Otherwise,
1845 : : * it must have a named composite type.
1846 : : */
1847 [ + + ]: 6 : if (exprType(funcexpr) == RECORDOID)
1848 [ + - ]: 3 : ereport(ERROR,
1849 : : (errcode(ERRCODE_SYNTAX_ERROR),
1850 : : errmsg("a column definition list is redundant for a function with OUT parameters"),
1851 : : parser_errposition(pstate,
1852 : : exprLocation((Node *) coldeflist))));
1853 : : else
1854 [ + - ]: 3 : ereport(ERROR,
1855 : : (errcode(ERRCODE_SYNTAX_ERROR),
1856 : : errmsg("a column definition list is redundant for a function returning a named composite type"),
1857 : : parser_errposition(pstate,
1858 : : exprLocation((Node *) coldeflist))));
1859 : : break;
1860 : 3 : default:
1861 [ + - ]: 3 : ereport(ERROR,
1862 : : (errcode(ERRCODE_SYNTAX_ERROR),
1863 : : errmsg("a column definition list is only allowed for functions returning \"record\""),
1864 : : parser_errposition(pstate,
1865 : : exprLocation((Node *) coldeflist))));
1866 : : break;
1867 : : }
1868 : : }
1869 : : else
1870 : : {
4307 1871 [ + + ]: 23474 : if (functypclass == TYPEFUNC_RECORD)
1872 [ + - ]: 15 : ereport(ERROR,
1873 : : (errcode(ERRCODE_SYNTAX_ERROR),
1874 : : errmsg("a column definition list is required for functions returning \"record\""),
1875 : : parser_errposition(pstate, exprLocation(funcexpr))));
1876 : : }
1877 : :
2872 1878 [ + + + + ]: 23861 : if (functypclass == TYPEFUNC_COMPOSITE ||
1879 : : functypclass == TYPEFUNC_COMPOSITE_DOMAIN)
1880 : : {
1881 : : /* Composite data type, e.g. a table's row type */
4307 1882 [ - + ]: 11549 : Assert(tupdesc);
1883 : : }
1884 [ + + ]: 12312 : else if (functypclass == TYPEFUNC_SCALAR)
1885 : : {
1886 : : /* Base data type, i.e. scalar */
2482 andres@anarazel.de 1887 : 11907 : tupdesc = CreateTemplateTupleDesc(1);
4307 tgl@sss.pgh.pa.us 1888 : 23814 : TupleDescInitEntry(tupdesc,
1889 : : (AttrNumber) 1,
1890 : 11907 : chooseScalarFunctionAlias(funcexpr, funcname,
1891 : : alias, nfuncs),
1892 : : funcrettype,
1893 : : exprTypmod(funcexpr),
1894 : : 0);
2074 1895 : 11907 : TupleDescInitEntryCollation(tupdesc,
1896 : : (AttrNumber) 1,
1897 : : exprCollation(funcexpr));
1898 : : }
4307 1899 [ + + ]: 405 : else if (functypclass == TYPEFUNC_RECORD)
1900 : : {
1901 : : ListCell *col;
1902 : :
1903 : : /*
1904 : : * Use the column definition list to construct a tupdesc and fill
1905 : : * in the RangeTblFunction's lists. Limit number of columns to
1906 : : * MaxHeapAttributeNumber, because CheckAttributeNamesTypes will.
1907 : : */
1132 1908 [ - + ]: 402 : if (list_length(coldeflist) > MaxHeapAttributeNumber)
1132 tgl@sss.pgh.pa.us 1909 [ # # ]:UBC 0 : ereport(ERROR,
1910 : : (errcode(ERRCODE_TOO_MANY_COLUMNS),
1911 : : errmsg("column definition lists can have at most %d entries",
1912 : : MaxHeapAttributeNumber),
1913 : : parser_errposition(pstate,
1914 : : exprLocation((Node *) coldeflist))));
2482 andres@anarazel.de 1915 :CBC 402 : tupdesc = CreateTemplateTupleDesc(list_length(coldeflist));
4307 tgl@sss.pgh.pa.us 1916 : 402 : i = 1;
1917 [ + - + + : 1360 : foreach(col, coldeflist)
+ + ]
1918 : : {
1919 : 958 : ColumnDef *n = (ColumnDef *) lfirst(col);
1920 : : char *attrname;
1921 : : Oid attrtype;
1922 : : int32 attrtypmod;
1923 : : Oid attrcollation;
1924 : :
1925 : 958 : attrname = n->colname;
1926 [ - + ]: 958 : if (n->typeName->setof)
4307 tgl@sss.pgh.pa.us 1927 [ # # ]:UBC 0 : ereport(ERROR,
1928 : : (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
1929 : : errmsg("column \"%s\" cannot be declared SETOF",
1930 : : attrname),
1931 : : parser_errposition(pstate, n->location)));
4307 tgl@sss.pgh.pa.us 1932 :CBC 958 : typenameTypeIdAndMod(pstate, n->typeName,
1933 : : &attrtype, &attrtypmod);
1934 : 958 : attrcollation = GetColumnDefCollation(pstate, n, attrtype);
1935 : 958 : TupleDescInitEntry(tupdesc,
1936 : 958 : (AttrNumber) i,
1937 : : attrname,
1938 : : attrtype,
1939 : : attrtypmod,
1940 : : 0);
1941 : 958 : TupleDescInitEntryCollation(tupdesc,
1942 : 958 : (AttrNumber) i,
1943 : : attrcollation);
1944 : 958 : rtfunc->funccolnames = lappend(rtfunc->funccolnames,
1945 : 958 : makeString(pstrdup(attrname)));
1946 : 958 : rtfunc->funccoltypes = lappend_oid(rtfunc->funccoltypes,
1947 : : attrtype);
1948 : 958 : rtfunc->funccoltypmods = lappend_int(rtfunc->funccoltypmods,
1949 : : attrtypmod);
1950 : 958 : rtfunc->funccolcollations = lappend_oid(rtfunc->funccolcollations,
1951 : : attrcollation);
1952 : :
1953 : 958 : i++;
1954 : : }
1955 : :
1956 : : /*
1957 : : * Ensure that the coldeflist defines a legal set of names (no
1958 : : * duplicates, but we needn't worry about system column names) and
1959 : : * datatypes. Although we mostly can't allow pseudo-types, it
1960 : : * seems safe to allow RECORD and RECORD[], since values within
1961 : : * those type classes are self-identifying at runtime, and the
1962 : : * coldeflist doesn't represent anything that will be visible to
1963 : : * other sessions.
1964 : : */
2411 1965 : 402 : CheckAttributeNamesTypes(tupdesc, RELKIND_COMPOSITE_TYPE,
1966 : : CHKATYPE_ANYRECORD);
1967 : : }
1968 : : else
8085 1969 [ + - ]: 3 : ereport(ERROR,
1970 : : (errcode(ERRCODE_DATATYPE_MISMATCH),
1971 : : errmsg("function \"%s\" in FROM has unsupported return type %s",
1972 : : funcname, format_type_be(funcrettype)),
1973 : : parser_errposition(pstate, exprLocation(funcexpr))));
1974 : :
1975 : : /* Finish off the RangeTblFunction and add it to the RTE's list */
4307 1976 : 23858 : rtfunc->funccolcount = tupdesc->natts;
1977 : 23858 : rte->functions = lappend(rte->functions, rtfunc);
1978 : :
1979 : : /* Save the tupdesc for use below */
1980 : 23858 : functupdescs[funcno] = tupdesc;
1981 : 23858 : totalatts += tupdesc->natts;
1982 : 23858 : funcno++;
1983 : : }
1984 : :
1985 : : /*
1986 : : * If there's more than one function, or we want an ordinality column, we
1987 : : * have to produce a merged tupdesc.
1988 : : */
1989 [ + + + + ]: 23651 : if (nfuncs > 1 || rangefunc->ordinality)
1990 : : {
4422 stark@mit.edu 1991 [ + + ]: 438 : if (rangefunc->ordinality)
4307 tgl@sss.pgh.pa.us 1992 : 402 : totalatts++;
1993 : :
1994 : : /* Disallow more columns than will fit in a tuple */
1132 1995 [ - + ]: 438 : if (totalatts > MaxTupleAttributeNumber)
1132 tgl@sss.pgh.pa.us 1996 [ # # ]:UBC 0 : ereport(ERROR,
1997 : : (errcode(ERRCODE_TOO_MANY_COLUMNS),
1998 : : errmsg("functions in FROM can return at most %d columns",
1999 : : MaxTupleAttributeNumber),
2000 : : parser_errposition(pstate,
2001 : : exprLocation((Node *) funcexprs))));
2002 : :
2003 : : /* Merge the tuple descs of each function into a composite one */
2482 andres@anarazel.de 2004 :CBC 438 : tupdesc = CreateTemplateTupleDesc(totalatts);
4307 tgl@sss.pgh.pa.us 2005 : 438 : natts = 0;
2006 [ + + ]: 1083 : for (i = 0; i < nfuncs; i++)
2007 : : {
2008 [ + + ]: 1565 : for (j = 1; j <= functupdescs[i]->natts; j++)
2009 : 920 : TupleDescCopyEntry(tupdesc, ++natts, functupdescs[i], j);
2010 : : }
2011 : :
2012 : : /* Add the ordinality column if needed */
2013 [ + + ]: 438 : if (rangefunc->ordinality)
2014 : : {
2015 : 402 : TupleDescInitEntry(tupdesc,
2016 : 402 : (AttrNumber) ++natts,
2017 : : "ordinality",
2018 : : INT8OID,
2019 : : -1,
2020 : : 0);
2021 : : /* no need to set collation */
2022 : : }
2023 : :
2024 [ - + ]: 438 : Assert(natts == totalatts);
2025 : : }
2026 : : else
2027 : : {
2028 : : /* We can just use the single function's tupdesc as-is */
2029 : 23213 : tupdesc = functupdescs[0];
2030 : : }
2031 : :
2032 : : /* Use the tupdesc while assigning column aliases for the RTE */
2033 : 23651 : buildRelationAliases(tupdesc, alias, eref);
2034 : :
2035 : : /*
2036 : : * Set flags and access permissions.
2037 : : *
2038 : : * Functions are never checked for access rights (at least, not by
2039 : : * ExecCheckPermissions()), so no need to perform addRTEPermissionInfo().
2040 : : */
4778 2041 : 23651 : rte->lateral = lateral;
8518 2042 : 23651 : rte->inFromCl = inFromCl;
2043 : :
2044 : : /*
2045 : : * Add completed RTE to pstate's range table list, so that we know its
2046 : : * index. But we don't add it to the join list --- caller must do that if
2047 : : * appropriate.
2048 : : */
3832 rhaas@postgresql.org 2049 : 23651 : pstate->p_rtable = lappend(pstate->p_rtable, rte);
2050 : :
2051 : : /*
2052 : : * Build a ParseNamespaceItem, but don't add it to the pstate's namespace
2053 : : * list --- caller must do that if appropriate.
2054 : : */
1005 alvherre@alvh.no-ip. 2055 : 23651 : return buildNSItemFromTupleDesc(rte, list_length(pstate->p_rtable), NULL,
2056 : : tupdesc);
2057 : : }
2058 : :
2059 : : /*
2060 : : * Add an entry for a table function to the pstate's range table (p_rtable).
2061 : : * Then, construct and return a ParseNamespaceItem for the new RTE.
2062 : : *
2063 : : * This is much like addRangeTableEntry() except that it makes a tablefunc RTE.
2064 : : */
2065 : : ParseNamespaceItem *
3104 2066 : 331 : addRangeTableEntryForTableFunc(ParseState *pstate,
2067 : : TableFunc *tf,
2068 : : Alias *alias,
2069 : : bool lateral,
2070 : : bool inFromCl)
2071 : : {
2072 : 331 : RangeTblEntry *rte = makeNode(RangeTblEntry);
2073 : : char *refname;
2074 : : Alias *eref;
2075 : : int numaliases;
2076 : :
1132 tgl@sss.pgh.pa.us 2077 [ - + ]: 331 : Assert(pstate != NULL);
2078 : :
2079 : : /* Disallow more columns than will fit in a tuple */
2080 [ - + ]: 331 : if (list_length(tf->colnames) > MaxTupleAttributeNumber)
1132 tgl@sss.pgh.pa.us 2081 [ # # ]:UBC 0 : ereport(ERROR,
2082 : : (errcode(ERRCODE_TOO_MANY_COLUMNS),
2083 : : errmsg("functions in FROM can return at most %d columns",
2084 : : MaxTupleAttributeNumber),
2085 : : parser_errposition(pstate,
2086 : : exprLocation((Node *) tf))));
1132 tgl@sss.pgh.pa.us 2087 [ - + ]:CBC 331 : Assert(list_length(tf->coltypes) == list_length(tf->colnames));
2088 [ - + ]: 331 : Assert(list_length(tf->coltypmods) == list_length(tf->colnames));
2089 [ - + ]: 331 : Assert(list_length(tf->colcollations) == list_length(tf->colnames));
2090 : :
3104 alvherre@alvh.no-ip. 2091 : 331 : rte->rtekind = RTE_TABLEFUNC;
2092 : 331 : rte->relid = InvalidOid;
2093 : 331 : rte->subquery = NULL;
2094 : 331 : rte->tablefunc = tf;
2095 : 331 : rte->coltypes = tf->coltypes;
2096 : 331 : rte->coltypmods = tf->coltypmods;
2097 : 331 : rte->colcollations = tf->colcollations;
2098 : 331 : rte->alias = alias;
2099 : :
520 amitlan@postgresql.o 2100 [ + + ]: 331 : refname = alias ? alias->aliasname :
2101 [ + + ]: 227 : pstrdup(tf->functype == TFT_XMLTABLE ? "xmltable" : "json_table");
3104 alvherre@alvh.no-ip. 2102 [ + + ]: 331 : eref = alias ? copyObject(alias) : makeAlias(refname, NIL);
2103 : 331 : numaliases = list_length(eref->colnames);
2104 : :
2105 : : /* fill in any unspecified alias columns */
2106 [ + + ]: 331 : if (numaliases < list_length(tf->colnames))
2107 : 323 : eref->colnames = list_concat(eref->colnames,
2999 tgl@sss.pgh.pa.us 2108 : 323 : list_copy_tail(tf->colnames, numaliases));
2109 : :
1207 alvherre@alvh.no-ip. 2110 [ + + ]: 331 : if (numaliases > list_length(tf->colnames))
2111 [ + - + + ]: 6 : ereport(ERROR,
2112 : : (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
2113 : : errmsg("%s function has %d columns available but %d columns specified",
2114 : : tf->functype == TFT_XMLTABLE ? "XMLTABLE" : "JSON_TABLE",
2115 : : list_length(tf->colnames), numaliases)));
2116 : :
3104 2117 : 325 : rte->eref = eref;
2118 : :
2119 : : /*
2120 : : * Set flags and access permissions.
2121 : : *
2122 : : * Tablefuncs are never checked for access rights (at least, not by
2123 : : * ExecCheckPermissions()), so no need to perform addRTEPermissionInfo().
2124 : : */
2125 : 325 : rte->lateral = lateral;
2126 : 325 : rte->inFromCl = inFromCl;
2127 : :
2128 : : /*
2129 : : * Add completed RTE to pstate's range table list, so that we know its
2130 : : * index. But we don't add it to the join list --- caller must do that if
2131 : : * appropriate.
2132 : : */
2133 : 325 : pstate->p_rtable = lappend(pstate->p_rtable, rte);
2134 : :
2135 : : /*
2136 : : * Build a ParseNamespaceItem, but don't add it to the pstate's namespace
2137 : : * list --- caller must do that if appropriate.
2138 : : */
2074 tgl@sss.pgh.pa.us 2139 : 325 : return buildNSItemFromLists(rte, list_length(pstate->p_rtable),
2140 : : rte->coltypes, rte->coltypmods,
2141 : : rte->colcollations);
2142 : : }
2143 : :
2144 : : /*
2145 : : * Add an entry for a VALUES list to the pstate's range table (p_rtable).
2146 : : * Then, construct and return a ParseNamespaceItem for the new RTE.
2147 : : *
2148 : : * This is much like addRangeTableEntry() except that it makes a values RTE.
2149 : : */
2150 : : ParseNamespaceItem *
6975 mail@joeconway.com 2151 : 6575 : addRangeTableEntryForValues(ParseState *pstate,
2152 : : List *exprs,
2153 : : List *coltypes,
2154 : : List *coltypmods,
2155 : : List *colcollations,
2156 : : Alias *alias,
2157 : : bool lateral,
2158 : : bool inFromCl)
2159 : : {
2160 : 6575 : RangeTblEntry *rte = makeNode(RangeTblEntry);
2161 [ - + ]: 6575 : char *refname = alias ? alias->aliasname : pstrdup("*VALUES*");
2162 : : Alias *eref;
2163 : : int numaliases;
2164 : : int numcolumns;
2165 : :
3832 rhaas@postgresql.org 2166 [ - + ]: 6575 : Assert(pstate != NULL);
2167 : :
6975 mail@joeconway.com 2168 : 6575 : rte->rtekind = RTE_VALUES;
2169 : 6575 : rte->relid = InvalidOid;
2170 : 6575 : rte->subquery = NULL;
2171 : 6575 : rte->values_lists = exprs;
3194 tgl@sss.pgh.pa.us 2172 : 6575 : rte->coltypes = coltypes;
2173 : 6575 : rte->coltypmods = coltypmods;
2174 : 6575 : rte->colcollations = colcollations;
6975 mail@joeconway.com 2175 : 6575 : rte->alias = alias;
2176 : :
2177 [ - + ]: 6575 : eref = alias ? copyObject(alias) : makeAlias(refname, NIL);
2178 : :
2179 : : /* fill in any unspecified alias columns */
2180 : 6575 : numcolumns = list_length((List *) linitial(exprs));
2181 : 6575 : numaliases = list_length(eref->colnames);
2182 [ + + ]: 16358 : while (numaliases < numcolumns)
2183 : : {
2184 : : char attrname[64];
2185 : :
2186 : 9783 : numaliases++;
2187 : 9783 : snprintf(attrname, sizeof(attrname), "column%d", numaliases);
2188 : 9783 : eref->colnames = lappend(eref->colnames,
2189 : 9783 : makeString(pstrdup(attrname)));
2190 : : }
2191 [ - + ]: 6575 : if (numcolumns < numaliases)
6975 mail@joeconway.com 2192 [ # # ]:UBC 0 : ereport(ERROR,
2193 : : (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
2194 : : errmsg("VALUES lists \"%s\" have %d columns available but %d columns specified",
2195 : : refname, numcolumns, numaliases)));
2196 : :
6975 mail@joeconway.com 2197 :CBC 6575 : rte->eref = eref;
2198 : :
2199 : : /*
2200 : : * Set flags and access permissions.
2201 : : *
2202 : : * Subqueries are never checked for access rights, so no need to perform
2203 : : * addRTEPermissionInfo().
2204 : : */
4766 tgl@sss.pgh.pa.us 2205 : 6575 : rte->lateral = lateral;
6975 mail@joeconway.com 2206 : 6575 : rte->inFromCl = inFromCl;
2207 : :
2208 : : /*
2209 : : * Add completed RTE to pstate's range table list, so that we know its
2210 : : * index. But we don't add it to the join list --- caller must do that if
2211 : : * appropriate.
2212 : : */
3832 rhaas@postgresql.org 2213 : 6575 : pstate->p_rtable = lappend(pstate->p_rtable, rte);
2214 : :
2215 : : /*
2216 : : * Build a ParseNamespaceItem, but don't add it to the pstate's namespace
2217 : : * list --- caller must do that if appropriate.
2218 : : */
2074 tgl@sss.pgh.pa.us 2219 : 6575 : return buildNSItemFromLists(rte, list_length(pstate->p_rtable),
2220 : : rte->coltypes, rte->coltypmods,
2221 : : rte->colcollations);
2222 : : }
2223 : :
2224 : : /*
2225 : : * Add an entry for a join to the pstate's range table (p_rtable).
2226 : : * Then, construct and return a ParseNamespaceItem for the new RTE.
2227 : : *
2228 : : * This is much like addRangeTableEntry() except that it makes a join RTE.
2229 : : * Also, it's more convenient for the caller to construct the
2230 : : * ParseNamespaceColumn array, so we pass that in.
2231 : : */
2232 : : ParseNamespaceItem *
8579 2233 : 47919 : addRangeTableEntryForJoin(ParseState *pstate,
2234 : : List *colnames,
2235 : : ParseNamespaceColumn *nscolumns,
2236 : : JoinType jointype,
2237 : : int nummergedcols,
2238 : : List *aliasvars,
2239 : : List *leftcols,
2240 : : List *rightcols,
2241 : : Alias *join_using_alias,
2242 : : Alias *alias,
2243 : : bool inFromCl)
2244 : : {
2245 : 47919 : RangeTblEntry *rte = makeNode(RangeTblEntry);
2246 : : Alias *eref;
2247 : : int numaliases;
2248 : : ParseNamespaceItem *nsitem;
2249 : :
3832 rhaas@postgresql.org 2250 [ - + ]: 47919 : Assert(pstate != NULL);
2251 : :
2252 : : /*
2253 : : * Fail if join has too many columns --- we must be able to reference any
2254 : : * of the columns with an AttrNumber.
2255 : : */
6363 tgl@sss.pgh.pa.us 2256 [ - + ]: 47919 : if (list_length(aliasvars) > MaxAttrNumber)
6363 tgl@sss.pgh.pa.us 2257 [ # # ]:UBC 0 : ereport(ERROR,
2258 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
2259 : : errmsg("joins can have at most %d columns",
2260 : : MaxAttrNumber)));
2261 : :
8579 tgl@sss.pgh.pa.us 2262 :CBC 47919 : rte->rtekind = RTE_JOIN;
2263 : 47919 : rte->relid = InvalidOid;
2264 : 47919 : rte->subquery = NULL;
2265 : 47919 : rte->jointype = jointype;
2067 2266 : 47919 : rte->joinmergedcols = nummergedcols;
8532 2267 : 47919 : rte->joinaliasvars = aliasvars;
2067 2268 : 47919 : rte->joinleftcols = leftcols;
2269 : 47919 : rte->joinrightcols = rightcols;
1620 peter@eisentraut.org 2270 : 47919 : rte->join_using_alias = join_using_alias;
8579 tgl@sss.pgh.pa.us 2271 : 47919 : rte->alias = alias;
2272 : :
3103 peter_e@gmx.net 2273 [ + + ]: 47919 : eref = alias ? copyObject(alias) : makeAlias("unnamed_join", NIL);
7769 neilc@samurai.com 2274 : 47919 : numaliases = list_length(eref->colnames);
2275 : :
2276 : : /* fill in any unspecified alias columns */
2277 [ + + ]: 47919 : if (numaliases < list_length(colnames))
2278 : 47847 : eref->colnames = list_concat(eref->colnames,
7266 bruce@momjian.us 2279 : 47847 : list_copy_tail(colnames, numaliases));
2280 : :
1207 alvherre@alvh.no-ip. 2281 [ + + ]: 47919 : if (numaliases > list_length(colnames))
2282 [ + - ]: 3 : ereport(ERROR,
2283 : : (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
2284 : : errmsg("join expression \"%s\" has %d columns available but %d columns specified",
2285 : : eref->aliasname, list_length(colnames), numaliases)));
2286 : :
8579 tgl@sss.pgh.pa.us 2287 : 47916 : rte->eref = eref;
2288 : :
2289 : : /*
2290 : : * Set flags and access permissions.
2291 : : *
2292 : : * Joins are never checked for access rights, so no need to perform
2293 : : * addRTEPermissionInfo().
2294 : : */
4778 2295 : 47916 : rte->lateral = false;
8579 2296 : 47916 : rte->inFromCl = inFromCl;
2297 : :
2298 : : /*
2299 : : * Add completed RTE to pstate's range table list, so that we know its
2300 : : * index. But we don't add it to the join list --- caller must do that if
2301 : : * appropriate.
2302 : : */
3832 rhaas@postgresql.org 2303 : 47916 : pstate->p_rtable = lappend(pstate->p_rtable, rte);
2304 : :
2305 : : /*
2306 : : * Build a ParseNamespaceItem, but don't add it to the pstate's namespace
2307 : : * list --- caller must do that if appropriate.
2308 : : */
2074 tgl@sss.pgh.pa.us 2309 : 47916 : nsitem = (ParseNamespaceItem *) palloc(sizeof(ParseNamespaceItem));
1620 peter@eisentraut.org 2310 : 47916 : nsitem->p_names = rte->eref;
2074 tgl@sss.pgh.pa.us 2311 : 47916 : nsitem->p_rte = rte;
1005 alvherre@alvh.no-ip. 2312 : 47916 : nsitem->p_perminfo = NULL;
2074 tgl@sss.pgh.pa.us 2313 : 47916 : nsitem->p_rtindex = list_length(pstate->p_rtable);
2314 : 47916 : nsitem->p_nscolumns = nscolumns;
2315 : : /* set default visibility flags; might get changed later */
2316 : 47916 : nsitem->p_rel_visible = true;
2317 : 47916 : nsitem->p_cols_visible = true;
2318 : 47916 : nsitem->p_lateral_only = false;
2319 : 47916 : nsitem->p_lateral_ok = true;
233 dean.a.rasheed@gmail 2320 : 47916 : nsitem->p_returning_type = VAR_RETURNING_DEFAULT;
2321 : :
2074 tgl@sss.pgh.pa.us 2322 : 47916 : return nsitem;
2323 : : }
2324 : :
2325 : : /*
2326 : : * Add an entry for a CTE reference to the pstate's range table (p_rtable).
2327 : : * Then, construct and return a ParseNamespaceItem for the new RTE.
2328 : : *
2329 : : * This is much like addRangeTableEntry() except that it makes a CTE RTE.
2330 : : */
2331 : : ParseNamespaceItem *
6181 2332 : 3492 : addRangeTableEntryForCTE(ParseState *pstate,
2333 : : CommonTableExpr *cte,
2334 : : Index levelsup,
2335 : : RangeVar *rv,
2336 : : bool inFromCl)
2337 : : {
2338 : 3492 : RangeTblEntry *rte = makeNode(RangeTblEntry);
5307 2339 : 3492 : Alias *alias = rv->alias;
6181 2340 [ + + ]: 3492 : char *refname = alias ? alias->aliasname : cte->ctename;
2341 : : Alias *eref;
2342 : : int numaliases;
2343 : : int varattno;
2344 : : ListCell *lc;
1678 peter@eisentraut.org 2345 : 3492 : int n_dontexpand_columns = 0;
2346 : : ParseNamespaceItem *psi;
2347 : :
3832 rhaas@postgresql.org 2348 [ - + ]: 3492 : Assert(pstate != NULL);
2349 : :
6181 tgl@sss.pgh.pa.us 2350 : 3492 : rte->rtekind = RTE_CTE;
2351 : 3492 : rte->ctename = cte->ctename;
2352 : 3492 : rte->ctelevelsup = levelsup;
2353 : :
2354 : : /* Self-reference if and only if CTE's parse analysis isn't completed */
2355 : 3492 : rte->self_reference = !IsA(cte->ctequery, Query);
2356 [ + + - + ]: 3492 : Assert(cte->cterecursive || !rte->self_reference);
2357 : : /* Bump the CTE's refcount if this isn't a self-reference */
2358 [ + + ]: 3492 : if (!rte->self_reference)
2359 : 2960 : cte->cterefcount++;
2360 : :
2361 : : /*
2362 : : * We throw error if the CTE is INSERT/UPDATE/DELETE/MERGE without
2363 : : * RETURNING. This won't get checked in case of a self-reference, but
2364 : : * that's OK because data-modifying CTEs aren't allowed to be recursive
2365 : : * anyhow.
2366 : : */
5307 2367 [ + + ]: 3492 : if (IsA(cte->ctequery, Query))
2368 : : {
5263 bruce@momjian.us 2369 : 2960 : Query *ctequery = (Query *) cte->ctequery;
2370 : :
5307 tgl@sss.pgh.pa.us 2371 [ + + ]: 2960 : if (ctequery->commandType != CMD_SELECT &&
2372 [ + + ]: 152 : ctequery->returningList == NIL)
2373 [ + - ]: 6 : ereport(ERROR,
2374 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2375 : : errmsg("WITH query \"%s\" does not have a RETURNING clause",
2376 : : cte->ctename),
2377 : : parser_errposition(pstate, rv->location)));
2378 : : }
2379 : :
1678 peter@eisentraut.org 2380 : 3486 : rte->coltypes = list_copy(cte->ctecoltypes);
2381 : 3486 : rte->coltypmods = list_copy(cte->ctecoltypmods);
2382 : 3486 : rte->colcollations = list_copy(cte->ctecolcollations);
2383 : :
6181 tgl@sss.pgh.pa.us 2384 : 3486 : rte->alias = alias;
2385 [ + + ]: 3486 : if (alias)
2386 : 558 : eref = copyObject(alias);
2387 : : else
2388 : 2928 : eref = makeAlias(refname, NIL);
2389 : 3486 : numaliases = list_length(eref->colnames);
2390 : :
2391 : : /* fill in any unspecified alias columns */
2392 : 3486 : varattno = 0;
2393 [ + - + + : 12233 : foreach(lc, cte->ctecolnames)
+ + ]
2394 : : {
2395 : 8747 : varattno++;
2396 [ + + ]: 8747 : if (varattno > numaliases)
2397 : 8723 : eref->colnames = lappend(eref->colnames, lfirst(lc));
2398 : : }
2399 [ - + ]: 3486 : if (varattno < numaliases)
6181 tgl@sss.pgh.pa.us 2400 [ # # ]:UBC 0 : ereport(ERROR,
2401 : : (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
2402 : : errmsg("table \"%s\" has %d columns available but %d columns specified",
2403 : : refname, varattno, numaliases)));
2404 : :
6181 tgl@sss.pgh.pa.us 2405 :CBC 3486 : rte->eref = eref;
2406 : :
1678 peter@eisentraut.org 2407 [ + + ]: 3486 : if (cte->search_clause)
2408 : : {
2409 : 105 : rte->eref->colnames = lappend(rte->eref->colnames, makeString(cte->search_clause->search_seq_column));
2410 [ + + ]: 105 : if (cte->search_clause->search_breadth_first)
2411 : 36 : rte->coltypes = lappend_oid(rte->coltypes, RECORDOID);
2412 : : else
2413 : 69 : rte->coltypes = lappend_oid(rte->coltypes, RECORDARRAYOID);
2414 : 105 : rte->coltypmods = lappend_int(rte->coltypmods, -1);
2415 : 105 : rte->colcollations = lappend_oid(rte->colcollations, InvalidOid);
2416 : :
2417 : 105 : n_dontexpand_columns += 1;
2418 : : }
2419 : :
2420 [ + + ]: 3486 : if (cte->cycle_clause)
2421 : : {
2422 : 93 : rte->eref->colnames = lappend(rte->eref->colnames, makeString(cte->cycle_clause->cycle_mark_column));
2423 : 93 : rte->coltypes = lappend_oid(rte->coltypes, cte->cycle_clause->cycle_mark_type);
2424 : 93 : rte->coltypmods = lappend_int(rte->coltypmods, cte->cycle_clause->cycle_mark_typmod);
2425 : 93 : rte->colcollations = lappend_oid(rte->colcollations, cte->cycle_clause->cycle_mark_collation);
2426 : :
2427 : 93 : rte->eref->colnames = lappend(rte->eref->colnames, makeString(cte->cycle_clause->cycle_path_column));
2428 : 93 : rte->coltypes = lappend_oid(rte->coltypes, RECORDARRAYOID);
2429 : 93 : rte->coltypmods = lappend_int(rte->coltypmods, -1);
2430 : 93 : rte->colcollations = lappend_oid(rte->colcollations, InvalidOid);
2431 : :
2432 : 93 : n_dontexpand_columns += 2;
2433 : : }
2434 : :
2435 : : /*
2436 : : * Set flags and access permissions.
2437 : : *
2438 : : * Subqueries are never checked for access rights, so no need to perform
2439 : : * addRTEPermissionInfo().
2440 : : */
4778 tgl@sss.pgh.pa.us 2441 : 3486 : rte->lateral = false;
6181 2442 : 3486 : rte->inFromCl = inFromCl;
2443 : :
2444 : : /*
2445 : : * Add completed RTE to pstate's range table list, so that we know its
2446 : : * index. But we don't add it to the join list --- caller must do that if
2447 : : * appropriate.
2448 : : */
3832 rhaas@postgresql.org 2449 : 3486 : pstate->p_rtable = lappend(pstate->p_rtable, rte);
2450 : :
2451 : : /*
2452 : : * Build a ParseNamespaceItem, but don't add it to the pstate's namespace
2453 : : * list --- caller must do that if appropriate.
2454 : : */
1678 peter@eisentraut.org 2455 : 3486 : psi = buildNSItemFromLists(rte, list_length(pstate->p_rtable),
2456 : : rte->coltypes, rte->coltypmods,
2457 : : rte->colcollations);
2458 : :
2459 : : /*
2460 : : * The columns added by search and cycle clauses are not included in star
2461 : : * expansion in queries contained in the CTE.
2462 : : */
2463 [ + + ]: 3486 : if (rte->ctelevelsup > 0)
2464 [ + + ]: 2760 : for (int i = 0; i < n_dontexpand_columns; i++)
1620 2465 : 177 : psi->p_nscolumns[list_length(psi->p_names->colnames) - 1 - i].p_dontexpand = true;
2466 : :
1678 2467 : 3486 : return psi;
2468 : : }
2469 : :
2470 : : /*
2471 : : * Add an entry for an ephemeral named relation reference to the pstate's
2472 : : * range table (p_rtable).
2473 : : * Then, construct and return a ParseNamespaceItem for the new RTE.
2474 : : *
2475 : : * It is expected that the RangeVar, which up until now is only known to be an
2476 : : * ephemeral named relation, will (in conjunction with the QueryEnvironment in
2477 : : * the ParseState), create a RangeTblEntry for a specific *kind* of ephemeral
2478 : : * named relation, based on enrtype.
2479 : : *
2480 : : * This is much like addRangeTableEntry() except that it makes an RTE for an
2481 : : * ephemeral named relation.
2482 : : */
2483 : : ParseNamespaceItem *
3081 kgrittn@postgresql.o 2484 : 248 : addRangeTableEntryForENR(ParseState *pstate,
2485 : : RangeVar *rv,
2486 : : bool inFromCl)
2487 : : {
2488 : 248 : RangeTblEntry *rte = makeNode(RangeTblEntry);
2489 : 248 : Alias *alias = rv->alias;
2490 [ + + ]: 248 : char *refname = alias ? alias->aliasname : rv->relname;
2491 : : EphemeralNamedRelationMetadata enrmd;
2492 : : TupleDesc tupdesc;
2493 : : int attno;
2494 : :
3065 tgl@sss.pgh.pa.us 2495 [ - + ]: 248 : Assert(pstate != NULL);
2496 : 248 : enrmd = get_visible_ENR(pstate, rv->relname);
3081 kgrittn@postgresql.o 2497 [ - + ]: 248 : Assert(enrmd != NULL);
2498 : :
2499 [ + - ]: 248 : switch (enrmd->enrtype)
2500 : : {
2501 : 248 : case ENR_NAMED_TUPLESTORE:
2502 : 248 : rte->rtekind = RTE_NAMEDTUPLESTORE;
2503 : 248 : break;
2504 : :
3081 kgrittn@postgresql.o 2505 :UBC 0 : default:
3065 tgl@sss.pgh.pa.us 2506 [ # # ]: 0 : elog(ERROR, "unexpected enrtype: %d", enrmd->enrtype);
2507 : : return NULL; /* for fussy compilers */
2508 : : }
2509 : :
2510 : : /*
2511 : : * Record dependency on a relation. This allows plans to be invalidated
2512 : : * if they access transition tables linked to a table that is altered.
2513 : : */
3081 kgrittn@postgresql.o 2514 :CBC 248 : rte->relid = enrmd->reliddesc;
2515 : :
2516 : : /*
2517 : : * Build the list of effective column names using user-supplied aliases
2518 : : * and/or actual column names.
2519 : : */
2520 : 248 : tupdesc = ENRMetadataGetTupDesc(enrmd);
2521 : 248 : rte->eref = makeAlias(refname, NIL);
2522 : 248 : buildRelationAliases(tupdesc, alias, rte->eref);
2523 : :
2524 : : /* Record additional data for ENR, including column type info */
2525 : 248 : rte->enrname = enrmd->name;
2526 : 248 : rte->enrtuples = enrmd->enrtuples;
2527 : 248 : rte->coltypes = NIL;
2528 : 248 : rte->coltypmods = NIL;
2529 : 248 : rte->colcollations = NIL;
2530 [ + + ]: 804 : for (attno = 1; attno <= tupdesc->natts; ++attno)
2531 : : {
2939 andres@anarazel.de 2532 : 556 : Form_pg_attribute att = TupleDescAttr(tupdesc, attno - 1);
2533 : :
2922 tgl@sss.pgh.pa.us 2534 [ + + ]: 556 : if (att->attisdropped)
2535 : : {
2536 : : /* Record zeroes for a dropped column */
2537 : 9 : rte->coltypes = lappend_oid(rte->coltypes, InvalidOid);
2538 : 9 : rte->coltypmods = lappend_int(rte->coltypmods, 0);
2539 : 9 : rte->colcollations = lappend_oid(rte->colcollations, InvalidOid);
2540 : : }
2541 : : else
2542 : : {
2543 : : /* Let's just make sure we can tell this isn't dropped */
2544 [ - + ]: 547 : if (att->atttypid == InvalidOid)
2922 tgl@sss.pgh.pa.us 2545 [ # # ]:UBC 0 : elog(ERROR, "atttypid is invalid for non-dropped column in \"%s\"",
2546 : : rv->relname);
2922 tgl@sss.pgh.pa.us 2547 :CBC 547 : rte->coltypes = lappend_oid(rte->coltypes, att->atttypid);
2548 : 547 : rte->coltypmods = lappend_int(rte->coltypmods, att->atttypmod);
2549 : 547 : rte->colcollations = lappend_oid(rte->colcollations,
2550 : : att->attcollation);
2551 : : }
2552 : : }
2553 : :
2554 : : /*
2555 : : * Set flags and access permissions.
2556 : : *
2557 : : * ENRs are never checked for access rights, so no need to perform
2558 : : * addRTEPermissionInfo().
2559 : : */
3081 kgrittn@postgresql.o 2560 : 248 : rte->lateral = false;
2561 : 248 : rte->inFromCl = inFromCl;
2562 : :
2563 : : /*
2564 : : * Add completed RTE to pstate's range table list, so that we know its
2565 : : * index. But we don't add it to the join list --- caller must do that if
2566 : : * appropriate.
2567 : : */
3065 tgl@sss.pgh.pa.us 2568 : 248 : pstate->p_rtable = lappend(pstate->p_rtable, rte);
2569 : :
2570 : : /*
2571 : : * Build a ParseNamespaceItem, but don't add it to the pstate's namespace
2572 : : * list --- caller must do that if appropriate.
2573 : : */
1005 alvherre@alvh.no-ip. 2574 : 248 : return buildNSItemFromTupleDesc(rte, list_length(pstate->p_rtable), NULL,
2575 : : tupdesc);
2576 : : }
2577 : :
2578 : : /*
2579 : : * Add an entry for grouping step to the pstate's range table (p_rtable).
2580 : : * Then, construct and return a ParseNamespaceItem for the new RTE.
2581 : : */
2582 : : ParseNamespaceItem *
361 rguo@postgresql.org 2583 : 2237 : addRangeTableEntryForGroup(ParseState *pstate,
2584 : : List *groupClauses)
2585 : : {
2586 : 2237 : RangeTblEntry *rte = makeNode(RangeTblEntry);
2587 : : Alias *eref;
2588 : : List *groupexprs;
2589 : : List *coltypes,
2590 : : *coltypmods,
2591 : : *colcollations;
2592 : : ListCell *lc;
2593 : : ParseNamespaceItem *nsitem;
2594 : :
2595 [ - + ]: 2237 : Assert(pstate != NULL);
2596 : :
2597 : 2237 : rte->rtekind = RTE_GROUP;
2598 : 2237 : rte->alias = NULL;
2599 : :
2600 : 2237 : eref = makeAlias("*GROUP*", NIL);
2601 : :
2602 : : /* fill in any unspecified alias columns, and extract column type info */
2603 : 2237 : groupexprs = NIL;
2604 : 2237 : coltypes = coltypmods = colcollations = NIL;
2605 [ + - + + : 6116 : foreach(lc, groupClauses)
+ + ]
2606 : : {
2607 : 3879 : TargetEntry *te = (TargetEntry *) lfirst(lc);
2608 [ + + ]: 3879 : char *colname = te->resname ? pstrdup(te->resname) : "?column?";
2609 : :
2610 : 3879 : eref->colnames = lappend(eref->colnames, makeString(colname));
2611 : :
2612 : 3879 : groupexprs = lappend(groupexprs, copyObject(te->expr));
2613 : :
2614 : 3879 : coltypes = lappend_oid(coltypes,
2615 : 3879 : exprType((Node *) te->expr));
2616 : 3879 : coltypmods = lappend_int(coltypmods,
2617 : 3879 : exprTypmod((Node *) te->expr));
2618 : 3879 : colcollations = lappend_oid(colcollations,
2619 : 3879 : exprCollation((Node *) te->expr));
2620 : : }
2621 : :
2622 : 2237 : rte->eref = eref;
2623 : 2237 : rte->groupexprs = groupexprs;
2624 : :
2625 : : /*
2626 : : * Set flags.
2627 : : *
2628 : : * The grouping step is never checked for access rights, so no need to
2629 : : * perform addRTEPermissionInfo().
2630 : : */
2631 : 2237 : rte->lateral = false;
2632 : 2237 : rte->inFromCl = false;
2633 : :
2634 : : /*
2635 : : * Add completed RTE to pstate's range table list, so that we know its
2636 : : * index. But we don't add it to the join list --- caller must do that if
2637 : : * appropriate.
2638 : : */
2639 : 2237 : pstate->p_rtable = lappend(pstate->p_rtable, rte);
2640 : :
2641 : : /*
2642 : : * Build a ParseNamespaceItem, but don't add it to the pstate's namespace
2643 : : * list --- caller must do that if appropriate.
2644 : : */
2645 : 2237 : nsitem = buildNSItemFromLists(rte, list_length(pstate->p_rtable),
2646 : : coltypes, coltypmods, colcollations);
2647 : :
2648 : 2237 : return nsitem;
2649 : : }
2650 : :
2651 : :
2652 : : /*
2653 : : * Has the specified refname been selected FOR UPDATE/FOR SHARE?
2654 : : *
2655 : : * This is used when we have not yet done transformLockingClause, but need
2656 : : * to know the correct lock to take during initial opening of relations.
2657 : : *
2658 : : * Note that refname may be NULL (for a subquery without an alias), in which
2659 : : * case the relation can't be locked by name, but it might still be locked if
2660 : : * a locking clause requests that all tables be locked.
2661 : : *
2662 : : * Note: we pay no attention to whether it's FOR UPDATE vs FOR SHARE,
2663 : : * since the table-level lock is the same either way.
2664 : : */
2665 : : bool
5793 tgl@sss.pgh.pa.us 2666 : 202818 : isLockedRefname(ParseState *pstate, const char *refname)
2667 : : {
2668 : : ListCell *l;
2669 : :
2670 : : /*
2671 : : * If we are in a subquery specified as locked FOR UPDATE/SHARE from
2672 : : * parent level, then act as though there's a generic FOR UPDATE here.
2673 : : */
2674 [ + + ]: 202818 : if (pstate->p_locked_from_parent)
2675 : 2 : return true;
2676 : :
2677 [ + + + + : 203023 : foreach(l, pstate->p_locking_clause)
+ + ]
2678 : : {
2679 : 2833 : LockingClause *lc = (LockingClause *) lfirst(l);
2680 : :
2681 [ + + ]: 2833 : if (lc->lockedRels == NIL)
2682 : : {
2683 : : /* all tables used in query */
2684 : 2626 : return true;
2685 : : }
1144 dean.a.rasheed@gmail 2686 [ + + ]: 1917 : else if (refname != NULL)
2687 : : {
2688 : : /* just the named tables */
2689 : : ListCell *l2;
2690 : :
5793 tgl@sss.pgh.pa.us 2691 [ + - + + : 2130 : foreach(l2, lc->lockedRels)
+ + ]
2692 : : {
2693 : 1926 : RangeVar *thisrel = (RangeVar *) lfirst(l2);
2694 : :
2695 [ + + ]: 1926 : if (strcmp(refname, thisrel->relname) == 0)
2696 : 1710 : return true;
2697 : : }
2698 : : }
2699 : : }
9068 2700 : 200190 : return false;
2701 : : }
2702 : :
2703 : : /*
2704 : : * Add the given nsitem/RTE as a top-level entry in the pstate's join list
2705 : : * and/or namespace list. (We assume caller has checked for any
2706 : : * namespace conflicts.) The nsitem is always marked as unconditionally
2707 : : * visible, that is, not LATERAL-only.
2708 : : */
2709 : : void
2074 2710 : 74410 : addNSItemToQuery(ParseState *pstate, ParseNamespaceItem *nsitem,
2711 : : bool addToJoinList,
2712 : : bool addToRelNameSpace, bool addToVarNameSpace)
2713 : : {
8970 2714 [ + + ]: 74410 : if (addToJoinList)
2715 : : {
7398 2716 : 30085 : RangeTblRef *rtr = makeNode(RangeTblRef);
2717 : :
2074 2718 : 30085 : rtr->rtindex = nsitem->p_rtindex;
8970 2719 : 30085 : pstate->p_joinlist = lappend(pstate->p_joinlist, rtr);
2720 : : }
4778 2721 [ + + + + ]: 74410 : if (addToRelNameSpace || addToVarNameSpace)
2722 : : {
2723 : : /* Set the new nsitem's visibility flags correctly */
4777 2724 : 68447 : nsitem->p_rel_visible = addToRelNameSpace;
2725 : 68447 : nsitem->p_cols_visible = addToVarNameSpace;
4778 2726 : 68447 : nsitem->p_lateral_only = false;
2727 : 68447 : nsitem->p_lateral_ok = true;
4777 2728 : 68447 : pstate->p_namespace = lappend(pstate->p_namespace, nsitem);
2729 : : }
9125 2730 : 74410 : }
2731 : :
2732 : : /*
2733 : : * expandRTE -- expand the columns of a rangetable entry
2734 : : *
2735 : : * This creates lists of an RTE's column names (aliases if provided, else
2736 : : * real names) and Vars for each column. Only user columns are considered.
2737 : : * If include_dropped is false then dropped columns are omitted from the
2738 : : * results. If include_dropped is true then empty strings and NULL constants
2739 : : * (not Vars!) are returned for dropped columns.
2740 : : *
2741 : : * rtindex, sublevels_up, returning_type, and location are the varno,
2742 : : * varlevelsup, varreturningtype, and location values to use in the created
2743 : : * Vars. Ordinarily rtindex should match the actual position of the RTE in
2744 : : * its rangetable.
2745 : : *
2746 : : * The output lists go into *colnames and *colvars.
2747 : : * If only one of the two kinds of output list is needed, pass NULL for the
2748 : : * output pointer for the unwanted one.
2749 : : */
2750 : : void
7399 2751 : 11477 : expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
2752 : : VarReturningType returning_type,
2753 : : int location, bool include_dropped,
2754 : : List **colnames, List **colvars)
2755 : : {
2756 : : int varattno;
2757 : :
9125 2758 [ + + ]: 11477 : if (colnames)
2759 : 803 : *colnames = NIL;
2760 [ + + ]: 11477 : if (colvars)
2761 : 11054 : *colvars = NIL;
2762 : :
8518 2763 [ + + + + : 11477 : switch (rte->rtekind)
+ - - ]
2764 : : {
2765 : 78 : case RTE_RELATION:
2766 : : /* Ordinary relation RTE */
6214 2767 : 78 : expandRelation(rte->relid, rte->eref,
2768 : : rtindex, sublevels_up, returning_type, location,
2769 : : include_dropped, colnames, colvars);
8518 2770 : 78 : break;
2771 : 302 : case RTE_SUBQUERY:
2772 : : {
2773 : : /* Subquery RTE */
7678 bruce@momjian.us 2774 : 302 : ListCell *aliasp_item = list_head(rte->eref->colnames);
2775 : : ListCell *tlistitem;
2776 : :
8518 tgl@sss.pgh.pa.us 2777 : 302 : varattno = 0;
2778 [ + - + + : 1072 : foreach(tlistitem, rte->subquery->targetList)
+ + ]
2779 : : {
2780 : 770 : TargetEntry *te = (TargetEntry *) lfirst(tlistitem);
2781 : :
7458 2782 [ - + ]: 770 : if (te->resjunk)
8518 tgl@sss.pgh.pa.us 2783 :UBC 0 : continue;
8518 tgl@sss.pgh.pa.us 2784 :CBC 770 : varattno++;
7458 2785 [ - + ]: 770 : Assert(varattno == te->resno);
2786 : :
2787 : : /*
2788 : : * Formerly it was possible for the subquery tlist to have
2789 : : * more non-junk entries than the colnames list does (if
2790 : : * this RTE has been expanded from a view that has more
2791 : : * columns than it did when the current query was parsed).
2792 : : * Now that ApplyRetrieveRule cleans up such cases, we
2793 : : * shouldn't see that anymore, but let's just check.
2794 : : */
2871 2795 [ - + ]: 770 : if (!aliasp_item)
914 tgl@sss.pgh.pa.us 2796 [ # # ]:UBC 0 : elog(ERROR, "too few column names for subquery %s",
2797 : : rte->eref->aliasname);
2798 : :
8518 tgl@sss.pgh.pa.us 2799 [ + - ]:CBC 770 : if (colnames)
2800 : : {
7773 neilc@samurai.com 2801 : 770 : char *label = strVal(lfirst(aliasp_item));
2802 : :
8518 tgl@sss.pgh.pa.us 2803 : 770 : *colnames = lappend(*colnames, makeString(pstrdup(label)));
2804 : : }
2805 : :
2806 [ + - ]: 770 : if (colvars)
2807 : : {
2808 : : Var *varnode;
2809 : :
2810 : 770 : varnode = makeVar(rtindex, varattno,
7458 2811 : 770 : exprType((Node *) te->expr),
2812 : 770 : exprTypmod((Node *) te->expr),
5324 peter_e@gmx.net 2813 : 770 : exprCollation((Node *) te->expr),
2814 : : sublevels_up);
233 dean.a.rasheed@gmail 2815 : 770 : varnode->varreturningtype = returning_type;
6214 tgl@sss.pgh.pa.us 2816 : 770 : varnode->location = location;
2817 : :
8518 2818 : 770 : *colvars = lappend(*colvars, varnode);
2819 : : }
2820 : :
2245 2821 : 770 : aliasp_item = lnext(rte->eref->colnames, aliasp_item);
2822 : : }
2823 : : }
8518 2824 : 302 : break;
2825 : 9834 : case RTE_FUNCTION:
2826 : : {
2827 : : /* Function RTE */
4307 2828 : 9834 : int atts_done = 0;
2829 : : ListCell *lc;
2830 : :
2831 [ + - + + : 19809 : foreach(lc, rte->functions)
+ + ]
2832 : : {
2833 : 9975 : RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
2834 : : TypeFuncClass functypclass;
509 2835 : 9975 : Oid funcrettype = InvalidOid;
2836 : 9975 : TupleDesc tupdesc = NULL;
2837 : :
2838 : : /* If it has a coldeflist, it returns RECORD */
2839 [ + + ]: 9975 : if (rtfunc->funccolnames != NIL)
2840 : 18 : functypclass = TYPEFUNC_RECORD;
2841 : : else
2842 : 9957 : functypclass = get_expr_result_type(rtfunc->funcexpr,
2843 : : &funcrettype,
2844 : : &tupdesc);
2845 : :
2872 2846 [ + + - + ]: 9975 : if (functypclass == TYPEFUNC_COMPOSITE ||
2847 : : functypclass == TYPEFUNC_COMPOSITE_DOMAIN)
2848 : : {
2849 : : /* Composite data type, e.g. a table's row type */
4307 2850 [ - + ]: 5841 : Assert(tupdesc);
2851 : 5841 : expandTupleDesc(tupdesc, rte->eref,
2852 : : rtfunc->funccolcount, atts_done,
2853 : : rtindex, sublevels_up,
2854 : : returning_type, location,
2855 : : include_dropped, colnames, colvars);
2856 : : }
2857 [ + + ]: 4134 : else if (functypclass == TYPEFUNC_SCALAR)
2858 : : {
2859 : : /* Base data type, i.e. scalar */
2860 [ + + ]: 4116 : if (colnames)
2861 : 144 : *colnames = lappend(*colnames,
2862 : 144 : list_nth(rte->eref->colnames,
2863 : : atts_done));
2864 : :
2865 [ + + ]: 4116 : if (colvars)
2866 : : {
2867 : : Var *varnode;
2868 : :
2869 : 3972 : varnode = makeVar(rtindex, atts_done + 1,
2870 : : funcrettype,
2074 2871 : 3972 : exprTypmod(rtfunc->funcexpr),
4307 2872 : 3972 : exprCollation(rtfunc->funcexpr),
2873 : : sublevels_up);
233 dean.a.rasheed@gmail 2874 : 3972 : varnode->varreturningtype = returning_type;
6214 tgl@sss.pgh.pa.us 2875 : 3972 : varnode->location = location;
2876 : :
8434 bruce@momjian.us 2877 : 3972 : *colvars = lappend(*colvars, varnode);
2878 : : }
2879 : : }
4307 tgl@sss.pgh.pa.us 2880 [ + - ]: 18 : else if (functypclass == TYPEFUNC_RECORD)
2881 : : {
2882 [ + + ]: 18 : if (colnames)
2883 : : {
2884 : : List *namelist;
2885 : :
2886 : : /* extract appropriate subset of column list */
2887 : 3 : namelist = list_copy_tail(rte->eref->colnames,
2888 : : atts_done);
2889 : 3 : namelist = list_truncate(namelist,
2890 : : rtfunc->funccolcount);
2891 : 3 : *colnames = list_concat(*colnames, namelist);
2892 : : }
2893 : :
2894 [ + + ]: 18 : if (colvars)
2895 : : {
2896 : : ListCell *l1;
2897 : : ListCell *l2;
2898 : : ListCell *l3;
2899 : 15 : int attnum = atts_done;
2900 : :
2901 [ + - + + : 55 : forthree(l1, rtfunc->funccoltypes,
+ - + + +
- + + + +
+ - + - +
+ ]
2902 : : l2, rtfunc->funccoltypmods,
2903 : : l3, rtfunc->funccolcollations)
2904 : : {
2905 : 40 : Oid attrtype = lfirst_oid(l1);
2906 : 40 : int32 attrtypmod = lfirst_int(l2);
2907 : 40 : Oid attrcollation = lfirst_oid(l3);
2908 : : Var *varnode;
2909 : :
2910 : 40 : attnum++;
2911 : 40 : varnode = makeVar(rtindex,
2912 : : attnum,
2913 : : attrtype,
2914 : : attrtypmod,
2915 : : attrcollation,
2916 : : sublevels_up);
233 dean.a.rasheed@gmail 2917 : 40 : varnode->varreturningtype = returning_type;
4307 tgl@sss.pgh.pa.us 2918 : 40 : varnode->location = location;
2919 : 40 : *colvars = lappend(*colvars, varnode);
2920 : : }
2921 : : }
2922 : : }
2923 : : else
2924 : : {
2925 : : /* addRangeTableEntryForFunction should've caught this */
4307 tgl@sss.pgh.pa.us 2926 [ # # ]:UBC 0 : elog(ERROR, "function in FROM has unsupported return type");
2927 : : }
4307 tgl@sss.pgh.pa.us 2928 :CBC 9975 : atts_done += rtfunc->funccolcount;
2929 : : }
2930 : :
2931 : : /* Append the ordinality column if any */
4422 stark@mit.edu 2932 [ + + ]: 9834 : if (rte->funcordinality)
2933 : : {
2934 [ + + ]: 316 : if (colnames)
4307 tgl@sss.pgh.pa.us 2935 : 9 : *colnames = lappend(*colnames,
2936 : 9 : llast(rte->eref->colnames));
2937 : :
4422 stark@mit.edu 2938 [ + + ]: 316 : if (colvars)
2939 : : {
4307 tgl@sss.pgh.pa.us 2940 : 307 : Var *varnode = makeVar(rtindex,
2941 : 307 : atts_done + 1,
2942 : : INT8OID,
2943 : : -1,
2944 : : InvalidOid,
2945 : : sublevels_up);
2946 : :
233 dean.a.rasheed@gmail 2947 : 307 : varnode->varreturningtype = returning_type;
4422 stark@mit.edu 2948 : 307 : *colvars = lappend(*colvars, varnode);
2949 : : }
2950 : : }
2951 : : }
8518 tgl@sss.pgh.pa.us 2952 : 9834 : break;
2953 : 6 : case RTE_JOIN:
2954 : : {
2955 : : /* Join RTE */
2956 : : ListCell *colname;
2957 : : ListCell *aliasvar;
2958 : :
7769 neilc@samurai.com 2959 [ - + ]: 6 : Assert(list_length(rte->eref->colnames) == list_length(rte->joinaliasvars));
2960 : :
8518 tgl@sss.pgh.pa.us 2961 : 6 : varattno = 0;
7678 bruce@momjian.us 2962 [ + - + + : 30 : forboth(colname, rte->eref->colnames, aliasvar, rte->joinaliasvars)
+ - + + +
+ + - +
+ ]
2963 : : {
7400 tgl@sss.pgh.pa.us 2964 : 24 : Node *avar = (Node *) lfirst(aliasvar);
2965 : :
8518 2966 : 24 : varattno++;
2967 : :
2968 : : /*
2969 : : * During ordinary parsing, there will never be any
2970 : : * deleted columns in the join. While this function is
2971 : : * also used by the rewriter and planner, they do not
2972 : : * currently call it on any JOIN RTEs. Therefore, this
2973 : : * next bit is dead code, but it seems prudent to handle
2974 : : * the case correctly anyway.
2975 : : */
4428 2976 [ - + ]: 24 : if (avar == NULL)
2977 : : {
7688 tgl@sss.pgh.pa.us 2978 [ # # ]:UBC 0 : if (include_dropped)
2979 : : {
2980 [ # # ]: 0 : if (colnames)
2981 : 0 : *colnames = lappend(*colnames,
7400 2982 : 0 : makeString(pstrdup("")));
7688 2983 [ # # ]: 0 : if (colvars)
2984 : : {
2985 : : /*
2986 : : * Can't use join's column type here (it might
2987 : : * be dropped!); but it doesn't really matter
2988 : : * what type the Const claims to be.
2989 : : */
2990 : 0 : *colvars = lappend(*colvars,
4428 2991 : 0 : makeNullConst(INT4OID, -1,
2992 : : InvalidOid));
2993 : : }
2994 : : }
7688 2995 : 0 : continue;
2996 : : }
2997 : :
8518 tgl@sss.pgh.pa.us 2998 [ - + ]:CBC 24 : if (colnames)
2999 : : {
7773 neilc@samurai.com 3000 :UBC 0 : char *label = strVal(lfirst(colname));
3001 : :
7688 tgl@sss.pgh.pa.us 3002 : 0 : *colnames = lappend(*colnames,
3003 : 0 : makeString(pstrdup(label)));
3004 : : }
3005 : :
8518 tgl@sss.pgh.pa.us 3006 [ + - ]:CBC 24 : if (colvars)
3007 : : {
3008 : : Var *varnode;
3009 : :
3010 : : /*
3011 : : * If the joinaliasvars entry is a simple Var, just
3012 : : * copy it (with adjustment of varlevelsup and
3013 : : * location); otherwise it is a JOIN USING column and
3014 : : * we must generate a join alias Var. This matches
3015 : : * the results that expansion of "join.*" by
3016 : : * expandNSItemVars would have produced, if we had
3017 : : * access to the ParseNamespaceItem for the join.
3018 : : */
2067 3019 [ + - ]: 24 : if (IsA(avar, Var))
3020 : : {
3021 : 24 : varnode = copyObject((Var *) avar);
3022 : 24 : varnode->varlevelsup = sublevels_up;
3023 : : }
3024 : : else
2067 tgl@sss.pgh.pa.us 3025 :UBC 0 : varnode = makeVar(rtindex, varattno,
3026 : : exprType(avar),
3027 : : exprTypmod(avar),
3028 : : exprCollation(avar),
3029 : : sublevels_up);
233 dean.a.rasheed@gmail 3030 :CBC 24 : varnode->varreturningtype = returning_type;
6214 tgl@sss.pgh.pa.us 3031 : 24 : varnode->location = location;
3032 : :
8518 3033 : 24 : *colvars = lappend(*colvars, varnode);
3034 : : }
3035 : : }
3036 : : }
3037 : 6 : break;
3104 alvherre@alvh.no-ip. 3038 : 1257 : case RTE_TABLEFUNC:
3039 : : case RTE_VALUES:
3040 : : case RTE_CTE:
3041 : : case RTE_NAMEDTUPLESTORE:
3042 : : {
3043 : : /* Tablefunc, Values, CTE, or ENR RTE */
6181 tgl@sss.pgh.pa.us 3044 : 1257 : ListCell *aliasp_item = list_head(rte->eref->colnames);
3045 : : ListCell *lct;
3046 : : ListCell *lcm;
3047 : : ListCell *lcc;
3048 : :
3049 : 1257 : varattno = 0;
3194 3050 [ + - + + : 4009 : forthree(lct, rte->coltypes,
+ - + + +
- + + + +
+ - + - +
+ ]
3051 : : lcm, rte->coltypmods,
3052 : : lcc, rte->colcollations)
3053 : : {
5931 bruce@momjian.us 3054 : 2752 : Oid coltype = lfirst_oid(lct);
3055 : 2752 : int32 coltypmod = lfirst_int(lcm);
5324 peter_e@gmx.net 3056 : 2752 : Oid colcoll = lfirst_oid(lcc);
3057 : :
6181 tgl@sss.pgh.pa.us 3058 : 2752 : varattno++;
3059 : :
3060 [ - + ]: 2752 : if (colnames)
3061 : : {
3062 : : /* Assume there is one alias per output column */
2922 tgl@sss.pgh.pa.us 3063 [ # # ]:UBC 0 : if (OidIsValid(coltype))
3064 : : {
3065 : 0 : char *label = strVal(lfirst(aliasp_item));
3066 : :
3067 : 0 : *colnames = lappend(*colnames,
3068 : 0 : makeString(pstrdup(label)));
3069 : : }
3070 [ # # ]: 0 : else if (include_dropped)
3071 : 0 : *colnames = lappend(*colnames,
3072 : 0 : makeString(pstrdup("")));
3073 : :
2245 3074 : 0 : aliasp_item = lnext(rte->eref->colnames, aliasp_item);
3075 : : }
3076 : :
6181 tgl@sss.pgh.pa.us 3077 [ + - ]:CBC 2752 : if (colvars)
3078 : : {
2922 3079 [ + - ]: 2752 : if (OidIsValid(coltype))
3080 : : {
3081 : : Var *varnode;
3082 : :
3083 : 2752 : varnode = makeVar(rtindex, varattno,
3084 : : coltype, coltypmod, colcoll,
3085 : : sublevels_up);
233 dean.a.rasheed@gmail 3086 : 2752 : varnode->varreturningtype = returning_type;
2922 tgl@sss.pgh.pa.us 3087 : 2752 : varnode->location = location;
3088 : :
3089 : 2752 : *colvars = lappend(*colvars, varnode);
3090 : : }
2922 tgl@sss.pgh.pa.us 3091 [ # # ]:UBC 0 : else if (include_dropped)
3092 : : {
3093 : : /*
3094 : : * It doesn't really matter what type the Const
3095 : : * claims to be.
3096 : : */
3097 : 0 : *colvars = lappend(*colvars,
3098 : 0 : makeNullConst(INT4OID, -1,
3099 : : InvalidOid));
3100 : : }
3101 : : }
3102 : : }
3103 : : }
6181 tgl@sss.pgh.pa.us 3104 :CBC 1257 : break;
2413 tgl@sss.pgh.pa.us 3105 :UBC 0 : case RTE_RESULT:
3106 : : case RTE_GROUP:
3107 : : /* These expose no columns, so nothing to do */
3108 : 0 : break;
8518 3109 : 0 : default:
8085 3110 [ # # ]: 0 : elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
3111 : : }
9125 tgl@sss.pgh.pa.us 3112 :CBC 11477 : }
3113 : :
3114 : : /*
3115 : : * expandRelation -- expandRTE subroutine
3116 : : */
3117 : : static void
7688 3118 : 78 : expandRelation(Oid relid, Alias *eref, int rtindex, int sublevels_up,
3119 : : VarReturningType returning_type,
3120 : : int location, bool include_dropped,
3121 : : List **colnames, List **colvars)
3122 : : {
3123 : : Relation rel;
3124 : :
3125 : : /* Get the tupledesc and turn it over to expandTupleDesc */
3126 : 78 : rel = relation_open(relid, AccessShareLock);
4307 3127 : 78 : expandTupleDesc(rel->rd_att, eref, rel->rd_att->natts, 0,
3128 : : rtindex, sublevels_up, returning_type,
3129 : : location, include_dropped,
3130 : : colnames, colvars);
7464 3131 : 78 : relation_close(rel, AccessShareLock);
3132 : 78 : }
3133 : :
3134 : : /*
3135 : : * expandTupleDesc -- expandRTE subroutine
3136 : : *
3137 : : * Generate names and/or Vars for the first "count" attributes of the tupdesc,
3138 : : * and append them to colnames/colvars. "offset" is added to the varattno
3139 : : * that each Var would otherwise have, and we also skip the first "offset"
3140 : : * entries in eref->colnames. (These provisions allow use of this code for
3141 : : * an individual composite-returning function in an RTE_FUNCTION RTE.)
3142 : : */
3143 : : static void
4307 3144 : 5919 : expandTupleDesc(TupleDesc tupdesc, Alias *eref, int count, int offset,
3145 : : int rtindex, int sublevels_up,
3146 : : VarReturningType returning_type,
3147 : : int location, bool include_dropped,
3148 : : List **colnames, List **colvars)
3149 : : {
3150 : : ListCell *aliascell;
3151 : : int varattno;
3152 : :
2245 3153 : 5919 : aliascell = (offset < list_length(eref->colnames)) ?
3154 [ + + ]: 5919 : list_nth_cell(eref->colnames, offset) : NULL;
3155 : :
4307 3156 [ - + ]: 5919 : Assert(count <= tupdesc->natts);
3157 [ + + ]: 46357 : for (varattno = 0; varattno < count; varattno++)
3158 : : {
2939 andres@anarazel.de 3159 : 40438 : Form_pg_attribute attr = TupleDescAttr(tupdesc, varattno);
3160 : :
7688 tgl@sss.pgh.pa.us 3161 [ + + ]: 40438 : if (attr->attisdropped)
3162 : : {
3163 [ + - ]: 21 : if (include_dropped)
3164 : : {
3165 [ + - ]: 21 : if (colnames)
3166 : 21 : *colnames = lappend(*colnames, makeString(pstrdup("")));
3167 [ - + ]: 21 : if (colvars)
3168 : : {
3169 : : /*
3170 : : * can't use atttypid here, but it doesn't really matter
3171 : : * what type the Const claims to be.
3172 : : */
5279 tgl@sss.pgh.pa.us 3173 :UBC 0 : *colvars = lappend(*colvars,
2999 3174 : 0 : makeNullConst(INT4OID, -1, InvalidOid));
3175 : : }
3176 : : }
4307 tgl@sss.pgh.pa.us 3177 [ + - ]:CBC 21 : if (aliascell)
2245 3178 : 21 : aliascell = lnext(eref->colnames, aliascell);
7688 3179 : 21 : continue;
3180 : : }
3181 : :
3182 [ + + ]: 40417 : if (colnames)
3183 : : {
3184 : : char *label;
3185 : :
4307 3186 [ + + ]: 3627 : if (aliascell)
3187 : : {
3188 : 3609 : label = strVal(lfirst(aliascell));
2245 3189 : 3609 : aliascell = lnext(eref->colnames, aliascell);
3190 : : }
3191 : : else
3192 : : {
3193 : : /* If we run out of aliases, use the underlying name */
7688 3194 : 18 : label = NameStr(attr->attname);
3195 : : }
3196 : 3627 : *colnames = lappend(*colnames, makeString(pstrdup(label)));
3197 : : }
3198 : :
3199 [ + + ]: 40417 : if (colvars)
3200 : : {
3201 : : Var *varnode;
3202 : :
4307 3203 : 37039 : varnode = makeVar(rtindex, varattno + offset + 1,
3204 : : attr->atttypid, attr->atttypmod,
3205 : : attr->attcollation,
3206 : : sublevels_up);
233 dean.a.rasheed@gmail 3207 : 37039 : varnode->varreturningtype = returning_type;
6214 tgl@sss.pgh.pa.us 3208 : 37039 : varnode->location = location;
3209 : :
7688 3210 : 37039 : *colvars = lappend(*colvars, varnode);
3211 : : }
3212 : : }
3213 : 5919 : }
3214 : :
3215 : : /*
3216 : : * expandNSItemVars
3217 : : * Produce a list of Vars, and optionally a list of column names,
3218 : : * for the non-dropped columns of the nsitem.
3219 : : *
3220 : : * The emitted Vars are marked with the given sublevels_up and location.
3221 : : *
3222 : : * If colnames isn't NULL, a list of String items for the columns is stored
3223 : : * there; note that it's just a subset of the RTE's eref list, and hence
3224 : : * the list elements mustn't be modified.
3225 : : */
3226 : : List *
950 3227 : 37088 : expandNSItemVars(ParseState *pstate, ParseNamespaceItem *nsitem,
3228 : : int sublevels_up, int location,
3229 : : List **colnames)
3230 : : {
2074 3231 : 37088 : List *result = NIL;
3232 : : int colindex;
3233 : : ListCell *lc;
3234 : :
3235 [ + + ]: 37088 : if (colnames)
3236 : 34617 : *colnames = NIL;
3237 : 37088 : colindex = 0;
1620 peter@eisentraut.org 3238 [ + + + + : 148132 : foreach(lc, nsitem->p_names->colnames)
+ + ]
3239 : : {
1458 3240 : 111044 : String *colnameval = lfirst(lc);
2074 tgl@sss.pgh.pa.us 3241 : 111044 : const char *colname = strVal(colnameval);
3242 : 111044 : ParseNamespaceColumn *nscol = nsitem->p_nscolumns + colindex;
3243 : :
1678 peter@eisentraut.org 3244 [ + + ]: 111044 : if (nscol->p_dontexpand)
3245 : : {
3246 : : /* skip */
3247 : : }
3248 [ + + ]: 111035 : else if (colname[0])
3249 : : {
3250 : : Var *var;
3251 : :
2074 tgl@sss.pgh.pa.us 3252 [ - + ]: 110470 : Assert(nscol->p_varno > 0);
2067 3253 : 110470 : var = makeVar(nscol->p_varno,
3254 : 110470 : nscol->p_varattno,
3255 : : nscol->p_vartype,
3256 : : nscol->p_vartypmod,
3257 : : nscol->p_varcollid,
3258 : : sublevels_up);
3259 : : /* makeVar doesn't offer parameters for these, so set by hand: */
233 dean.a.rasheed@gmail 3260 : 110470 : var->varreturningtype = nscol->p_varreturningtype;
2067 tgl@sss.pgh.pa.us 3261 : 110470 : var->varnosyn = nscol->p_varnosyn;
3262 : 110470 : var->varattnosyn = nscol->p_varattnosyn;
2074 3263 : 110470 : var->location = location;
3264 : :
3265 : : /* ... and update varnullingrels */
950 3266 : 110470 : markNullableIfNeeded(pstate, var);
3267 : :
2074 3268 : 110470 : result = lappend(result, var);
3269 [ + + ]: 110470 : if (colnames)
3270 : 105866 : *colnames = lappend(*colnames, colnameval);
3271 : : }
3272 : : else
3273 : : {
3274 : : /* dropped column, ignore */
3275 [ - + ]: 565 : Assert(nscol->p_varno == 0);
3276 : : }
3277 : 111044 : colindex++;
3278 : : }
3279 : 37088 : return result;
3280 : : }
3281 : :
3282 : : /*
3283 : : * expandNSItemAttrs -
3284 : : * Workhorse for "*" expansion: produce a list of targetentries
3285 : : * for the attributes of the nsitem
3286 : : *
3287 : : * pstate->p_next_resno determines the resnos assigned to the TLEs.
3288 : : * The referenced columns are marked as requiring SELECT access, if
3289 : : * caller requests that.
3290 : : */
3291 : : List *
2081 3292 : 34617 : expandNSItemAttrs(ParseState *pstate, ParseNamespaceItem *nsitem,
3293 : : int sublevels_up, bool require_col_privs, int location)
3294 : : {
3295 : 34617 : RangeTblEntry *rte = nsitem->p_rte;
1005 alvherre@alvh.no-ip. 3296 : 34617 : RTEPermissionInfo *perminfo = nsitem->p_perminfo;
3297 : : List *names,
3298 : : *vars;
3299 : : ListCell *name,
3300 : : *var;
9125 tgl@sss.pgh.pa.us 3301 : 34617 : List *te_list = NIL;
3302 : :
950 3303 : 34617 : vars = expandNSItemVars(pstate, nsitem, sublevels_up, location, &names);
3304 : :
3305 : : /*
3306 : : * Require read access to the table. This is normally redundant with the
3307 : : * markVarForSelectPriv calls below, but not if the table has zero
3308 : : * columns. We need not do anything if the nsitem is for a join: its
3309 : : * component tables will have been marked ACL_SELECT when they were added
3310 : : * to the rangetable. (This step changes things only for the target
3311 : : * relation of UPDATE/DELETE, which cannot be under a join.)
3312 : : */
1671 3313 [ + + ]: 34617 : if (rte->rtekind == RTE_RELATION)
3314 : : {
1005 alvherre@alvh.no-ip. 3315 [ - + ]: 19175 : Assert(perminfo != NULL);
3316 : 19175 : perminfo->requiredPerms |= ACL_SELECT;
3317 : : }
3318 : :
7688 tgl@sss.pgh.pa.us 3319 [ + + + + : 140483 : forboth(name, names, var, vars)
+ + + + +
+ + - +
+ ]
3320 : : {
7773 neilc@samurai.com 3321 : 105866 : char *label = strVal(lfirst(name));
6071 tgl@sss.pgh.pa.us 3322 : 105866 : Var *varnode = (Var *) lfirst(var);
3323 : : TargetEntry *te;
3324 : :
7458 3325 : 105866 : te = makeTargetEntry((Expr *) varnode,
3326 : 105866 : (AttrNumber) pstate->p_next_resno++,
3327 : : label,
3328 : : false);
9546 3329 : 105866 : te_list = lappend(te_list, te);
3330 : :
1258 alvherre@alvh.no-ip. 3331 [ + - ]: 105866 : if (require_col_privs)
3332 : : {
3333 : : /* Require read access to each column */
3334 : 105866 : markVarForSelectPriv(pstate, varnode);
3335 : : }
3336 : : }
3337 : :
2999 tgl@sss.pgh.pa.us 3338 [ + - - + ]: 34617 : Assert(name == NULL && var == NULL); /* lists not the same length? */
3339 : :
9546 3340 : 34617 : return te_list;
3341 : : }
3342 : :
3343 : : /*
3344 : : * get_rte_attribute_name
3345 : : * Get an attribute name from a RangeTblEntry
3346 : : *
3347 : : * This is unlike get_attname() because we use aliases if available.
3348 : : * In particular, it will work on an RTE for a subselect or join, whereas
3349 : : * get_attname() only works on real relations.
3350 : : *
3351 : : * "*" is returned if the given attnum is InvalidAttrNumber --- this case
3352 : : * occurs when a Var represents a whole tuple of a relation.
3353 : : *
3354 : : * It is caller's responsibility to not call this on a dropped attribute.
3355 : : * (You will get some answer for such cases, but it might not be sensible.)
3356 : : */
3357 : : char *
9112 3358 : 994 : get_rte_attribute_name(RangeTblEntry *rte, AttrNumber attnum)
3359 : : {
8907 3360 [ - + ]: 994 : if (attnum == InvalidAttrNumber)
8907 tgl@sss.pgh.pa.us 3361 :UBC 0 : return "*";
3362 : :
3363 : : /*
3364 : : * If there is a user-written column alias, use it.
3365 : : */
8430 tgl@sss.pgh.pa.us 3366 [ + + + + ]:CBC 994 : if (rte->alias &&
7769 neilc@samurai.com 3367 [ - + ]: 27 : attnum > 0 && attnum <= list_length(rte->alias->colnames))
7769 neilc@samurai.com 3368 :UBC 0 : return strVal(list_nth(rte->alias->colnames, attnum - 1));
3369 : :
3370 : : /*
3371 : : * If the RTE is a relation, go to the system catalogs not the
3372 : : * eref->colnames list. This is a little slower but it will give the
3373 : : * right answer if the column has been renamed since the eref list was
3374 : : * built (which can easily happen for rules).
3375 : : */
8430 tgl@sss.pgh.pa.us 3376 [ + + ]:CBC 994 : if (rte->rtekind == RTE_RELATION)
2763 alvherre@alvh.no-ip. 3377 : 979 : return get_attname(rte->relid, attnum, false);
3378 : :
3379 : : /*
3380 : : * Otherwise use the column name from eref. There should always be one.
3381 : : */
7769 neilc@samurai.com 3382 [ + - + - ]: 15 : if (attnum > 0 && attnum <= list_length(rte->eref->colnames))
3383 : 15 : return strVal(list_nth(rte->eref->colnames, attnum - 1));
3384 : :
3385 : : /* else caller gave us a bogus attnum */
8085 tgl@sss.pgh.pa.us 3386 [ # # ]:UBC 0 : elog(ERROR, "invalid attnum %d for rangetable entry %s",
3387 : : attnum, rte->eref->aliasname);
3388 : : return NULL; /* keep compiler quiet */
3389 : : }
3390 : :
3391 : : /*
3392 : : * get_rte_attribute_is_dropped
3393 : : * Check whether attempted attribute ref is to a dropped column
3394 : : */
3395 : : bool
7400 tgl@sss.pgh.pa.us 3396 :CBC 318048 : get_rte_attribute_is_dropped(RangeTblEntry *rte, AttrNumber attnum)
3397 : : {
3398 : : bool result;
3399 : :
8436 3400 [ + + - - : 318048 : switch (rte->rtekind)
+ - - ]
3401 : : {
3402 : 244786 : case RTE_RELATION:
3403 : : {
3404 : : /*
3405 : : * Plain relation RTE --- get the attribute's catalog entry
3406 : : */
3407 : : HeapTuple tp;
3408 : : Form_pg_attribute att_tup;
3409 : :
5683 rhaas@postgresql.org 3410 : 244786 : tp = SearchSysCache2(ATTNUM,
3411 : : ObjectIdGetDatum(rte->relid),
3412 : : Int16GetDatum(attnum));
2999 tgl@sss.pgh.pa.us 3413 [ - + ]: 244786 : if (!HeapTupleIsValid(tp)) /* shouldn't happen */
8085 tgl@sss.pgh.pa.us 3414 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for attribute %d of relation %u",
3415 : : attnum, rte->relid);
8436 tgl@sss.pgh.pa.us 3416 :CBC 244786 : att_tup = (Form_pg_attribute) GETSTRUCT(tp);
3417 : 244786 : result = att_tup->attisdropped;
3418 : 244786 : ReleaseSysCache(tp);
3419 : : }
3420 : 244786 : break;
3421 : 426 : case RTE_SUBQUERY:
3422 : : case RTE_TABLEFUNC:
3423 : : case RTE_VALUES:
3424 : : case RTE_CTE:
3425 : : case RTE_GROUP:
3426 : :
3427 : : /*
3428 : : * Subselect, Table Functions, Values, CTE, GROUP RTEs never have
3429 : : * dropped columns
3430 : : */
3431 : 426 : result = false;
3432 : 426 : break;
3081 kgrittn@postgresql.o 3433 :UBC 0 : case RTE_NAMEDTUPLESTORE:
3434 : : {
3435 : : /* Check dropped-ness by testing for valid coltype */
2922 tgl@sss.pgh.pa.us 3436 [ # # # # ]: 0 : if (attnum <= 0 ||
3437 : 0 : attnum > list_length(rte->coltypes))
3438 [ # # ]: 0 : elog(ERROR, "invalid varattno %d", attnum);
3439 : 0 : result = !OidIsValid((list_nth_oid(rte->coltypes, attnum - 1)));
3440 : : }
3081 kgrittn@postgresql.o 3441 : 0 : break;
7688 tgl@sss.pgh.pa.us 3442 : 0 : case RTE_JOIN:
3443 : : {
3444 : : /*
3445 : : * A join RTE would not have dropped columns when constructed,
3446 : : * but one in a stored rule might contain columns that were
3447 : : * dropped from the underlying tables, if said columns are
3448 : : * nowhere explicitly referenced in the rule. This will be
3449 : : * signaled to us by a null pointer in the joinaliasvars list.
3450 : : */
3451 : : Var *aliasvar;
3452 : :
3453 [ # # # # ]: 0 : if (attnum <= 0 ||
3454 : 0 : attnum > list_length(rte->joinaliasvars))
3455 [ # # ]: 0 : elog(ERROR, "invalid varattno %d", attnum);
3456 : 0 : aliasvar = (Var *) list_nth(rte->joinaliasvars, attnum - 1);
3457 : :
4428 3458 : 0 : result = (aliasvar == NULL);
3459 : : }
7688 3460 : 0 : break;
8436 tgl@sss.pgh.pa.us 3461 :CBC 72836 : case RTE_FUNCTION:
3462 : : {
3463 : : /* Function RTE */
3464 : : ListCell *lc;
4307 3465 : 72836 : int atts_done = 0;
3466 : :
3467 : : /*
3468 : : * Dropped attributes are only possible with functions that
3469 : : * return named composite types. In such a case we have to
3470 : : * look up the result type to see if it currently has this
3471 : : * column dropped. So first, loop over the funcs until we
3472 : : * find the one that covers the requested column.
3473 : : */
3474 [ + - + + : 72866 : foreach(lc, rte->functions)
+ + ]
3475 : : {
3476 : 72854 : RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
3477 : :
3478 [ + - ]: 72854 : if (attnum > atts_done &&
3479 [ + + ]: 72854 : attnum <= atts_done + rtfunc->funccolcount)
3480 : : {
3481 : : TupleDesc tupdesc;
3482 : :
3483 : : /* If it has a coldeflist, it returns RECORD */
509 3484 [ - + ]: 72824 : if (rtfunc->funccolnames != NIL)
3485 : 72824 : return false; /* can't have any dropped columns */
3486 : :
2872 3487 : 72824 : tupdesc = get_expr_result_tupdesc(rtfunc->funcexpr,
3488 : : true);
3489 [ + + ]: 72824 : if (tupdesc)
3490 : : {
3491 : : /* Composite data type, e.g. a table's row type */
3492 : : Form_pg_attribute att_tup;
3493 : :
4307 3494 [ - + ]: 72800 : Assert(tupdesc);
3495 [ - + ]: 72800 : Assert(attnum - atts_done <= tupdesc->natts);
2939 andres@anarazel.de 3496 : 72800 : att_tup = TupleDescAttr(tupdesc,
3497 : 72800 : attnum - atts_done - 1);
4307 tgl@sss.pgh.pa.us 3498 : 72800 : return att_tup->attisdropped;
3499 : : }
3500 : : /* Otherwise, it can't have any dropped columns */
3501 : 24 : return false;
3502 : : }
3503 : 30 : atts_done += rtfunc->funccolcount;
3504 : : }
3505 : :
3506 : : /* If we get here, must be looking for the ordinality column */
3507 [ + - + - ]: 12 : if (rte->funcordinality && attnum == atts_done + 1)
3508 : 12 : return false;
3509 : :
3510 : : /* this probably can't happen ... */
4307 tgl@sss.pgh.pa.us 3511 [ # # ]:UBC 0 : ereport(ERROR,
3512 : : (errcode(ERRCODE_UNDEFINED_COLUMN),
3513 : : errmsg("column %d of relation \"%s\" does not exist",
3514 : : attnum,
3515 : : rte->eref->aliasname)));
3516 : : result = false; /* keep compiler quiet */
3517 : : }
3518 : : break;
2413 3519 : 0 : case RTE_RESULT:
3520 : : /* this probably can't happen ... */
3521 [ # # ]: 0 : ereport(ERROR,
3522 : : (errcode(ERRCODE_UNDEFINED_COLUMN),
3523 : : errmsg("column %d of relation \"%s\" does not exist",
3524 : : attnum,
3525 : : rte->eref->aliasname)));
3526 : : result = false; /* keep compiler quiet */
3527 : : break;
8436 3528 : 0 : default:
8085 3529 [ # # ]: 0 : elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
3530 : : result = false; /* keep compiler quiet */
3531 : : }
3532 : :
8436 tgl@sss.pgh.pa.us 3533 :CBC 245212 : return result;
3534 : : }
3535 : :
3536 : : /*
3537 : : * Given a targetlist and a resno, return the matching TargetEntry
3538 : : *
3539 : : * Returns NULL if resno is not present in list.
3540 : : *
3541 : : * Note: we need to search, rather than just indexing with list_nth(),
3542 : : * because not all tlists are sorted by resno.
3543 : : */
3544 : : TargetEntry *
8062 3545 : 133759 : get_tle_by_resno(List *tlist, AttrNumber resno)
3546 : : {
3547 : : ListCell *l;
3548 : :
7773 neilc@samurai.com 3549 [ + + + + : 411105 : foreach(l, tlist)
+ + ]
3550 : : {
3551 : 410802 : TargetEntry *tle = (TargetEntry *) lfirst(l);
3552 : :
7458 tgl@sss.pgh.pa.us 3553 [ + + ]: 410802 : if (tle->resno == resno)
8062 3554 : 133456 : return tle;
3555 : : }
3556 : 303 : return NULL;
3557 : : }
3558 : :
3559 : : /*
3560 : : * Given a Query and rangetable index, return relation's RowMarkClause if any
3561 : : *
3562 : : * Returns NULL if relation is not selected FOR UPDATE/SHARE
3563 : : */
3564 : : RowMarkClause *
5794 3565 : 11645 : get_parse_rowmark(Query *qry, Index rtindex)
3566 : : {
3567 : : ListCell *l;
3568 : :
7069 3569 [ + + + + : 11781 : foreach(l, qry->rowMarks)
+ + ]
3570 : : {
3571 : 184 : RowMarkClause *rc = (RowMarkClause *) lfirst(l);
3572 : :
3573 [ + + ]: 184 : if (rc->rti == rtindex)
3574 : 48 : return rc;
3575 : : }
3576 : 11597 : return NULL;
3577 : : }
3578 : :
3579 : : /*
3580 : : * given relation and att name, return attnum of variable
3581 : : *
3582 : : * Returns InvalidAttrNumber if the attr doesn't exist (or is dropped).
3583 : : *
3584 : : * This should only be used if the relation is already
3585 : : * table_open()'ed. Use the cache version get_attnum()
3586 : : * for access to non-opened relations.
3587 : : */
3588 : : int
8436 3589 : 24787 : attnameAttNum(Relation rd, const char *attname, bool sysColOK)
3590 : : {
3591 : : int i;
3592 : :
2709 teodor@sigaev.ru 3593 [ + + ]: 126087 : for (i = 0; i < RelationGetNumberOfAttributes(rd); i++)
3594 : : {
2939 andres@anarazel.de 3595 : 126032 : Form_pg_attribute att = TupleDescAttr(rd->rd_att, i);
3596 : :
8436 tgl@sss.pgh.pa.us 3597 [ + + + + ]: 126032 : if (namestrcmp(&(att->attname), attname) == 0 && !att->attisdropped)
9867 bruce@momjian.us 3598 : 24732 : return i + 1;
3599 : : }
3600 : :
8436 tgl@sss.pgh.pa.us 3601 [ + + ]: 55 : if (sysColOK)
3602 : : {
3603 [ - + ]: 12 : if ((i = specialAttNum(attname)) != InvalidAttrNumber)
2482 andres@anarazel.de 3604 :UBC 0 : return i;
3605 : : }
3606 : :
3607 : : /* on failure */
7107 tgl@sss.pgh.pa.us 3608 :CBC 55 : return InvalidAttrNumber;
3609 : : }
3610 : :
3611 : : /* specialAttNum()
3612 : : *
3613 : : * Check attribute name to see if it is "special", e.g. "xmin".
3614 : : * - thomas 2000-02-07
3615 : : *
3616 : : * Note: this only discovers whether the name could be a system attribute.
3617 : : * Caller needs to ensure that it really is an attribute of the rel.
3618 : : */
3619 : : static int
8436 3620 : 64185 : specialAttNum(const char *attname)
3621 : : {
3622 : : const FormData_pg_attribute *sysatt;
3623 : :
2482 andres@anarazel.de 3624 : 64185 : sysatt = SystemAttributeByName(attname);
8720 tgl@sss.pgh.pa.us 3625 [ + + ]: 64185 : if (sysatt != NULL)
3626 : 17040 : return sysatt->attnum;
9335 lockhart@fourpalms.o 3627 : 47145 : return InvalidAttrNumber;
3628 : : }
3629 : :
3630 : :
3631 : : /*
3632 : : * given attribute id, return name of that attribute
3633 : : *
3634 : : * This should only be used if the relation is already
3635 : : * table_open()'ed. Use the cache version get_atttype()
3636 : : * for access to non-opened relations.
3637 : : */
3638 : : const NameData *
8719 tgl@sss.pgh.pa.us 3639 : 6892 : attnumAttName(Relation rd, int attid)
3640 : : {
3641 [ - + ]: 6892 : if (attid <= 0)
3642 : : {
3643 : : const FormData_pg_attribute *sysatt;
3644 : :
2482 andres@anarazel.de 3645 :UBC 0 : sysatt = SystemAttributeDefinition(attid);
8719 tgl@sss.pgh.pa.us 3646 : 0 : return &sysatt->attname;
3647 : : }
8719 tgl@sss.pgh.pa.us 3648 [ - + ]:CBC 6892 : if (attid > rd->rd_att->natts)
8085 tgl@sss.pgh.pa.us 3649 [ # # ]:UBC 0 : elog(ERROR, "invalid attribute number %d", attid);
2939 andres@anarazel.de 3650 :CBC 6892 : return &TupleDescAttr(rd->rd_att, attid - 1)->attname;
3651 : : }
3652 : :
3653 : : /*
3654 : : * given attribute id, return type of that attribute
3655 : : *
3656 : : * This should only be used if the relation is already
3657 : : * table_open()'ed. Use the cache version get_atttype()
3658 : : * for access to non-opened relations.
3659 : : */
3660 : : Oid
10147 bruce@momjian.us 3661 : 98626 : attnumTypeId(Relation rd, int attid)
3662 : : {
8720 tgl@sss.pgh.pa.us 3663 [ - + ]: 98626 : if (attid <= 0)
3664 : : {
3665 : : const FormData_pg_attribute *sysatt;
3666 : :
2482 andres@anarazel.de 3667 :UBC 0 : sysatt = SystemAttributeDefinition(attid);
8720 tgl@sss.pgh.pa.us 3668 : 0 : return sysatt->atttypid;
3669 : : }
8719 tgl@sss.pgh.pa.us 3670 [ - + ]:CBC 98626 : if (attid > rd->rd_att->natts)
8085 tgl@sss.pgh.pa.us 3671 [ # # ]:UBC 0 : elog(ERROR, "invalid attribute number %d", attid);
2939 andres@anarazel.de 3672 :CBC 98626 : return TupleDescAttr(rd->rd_att, attid - 1)->atttypid;
3673 : : }
3674 : :
3675 : : /*
3676 : : * given attribute id, return collation of that attribute
3677 : : *
3678 : : * This should only be used if the relation is already table_open()'ed.
3679 : : */
3680 : : Oid
5262 tgl@sss.pgh.pa.us 3681 : 2812 : attnumCollationId(Relation rd, int attid)
3682 : : {
3683 [ - + ]: 2812 : if (attid <= 0)
3684 : : {
3685 : : /* All system attributes are of noncollatable types. */
5262 tgl@sss.pgh.pa.us 3686 :UBC 0 : return InvalidOid;
3687 : : }
5262 tgl@sss.pgh.pa.us 3688 [ - + ]:CBC 2812 : if (attid > rd->rd_att->natts)
5262 tgl@sss.pgh.pa.us 3689 [ # # ]:UBC 0 : elog(ERROR, "invalid attribute number %d", attid);
2939 andres@anarazel.de 3690 :CBC 2812 : return TupleDescAttr(rd->rd_att, attid - 1)->attcollation;
3691 : : }
3692 : :
3693 : : /*
3694 : : * Generate a suitable error about a missing RTE.
3695 : : *
3696 : : * Since this is a very common type of error, we work rather hard to
3697 : : * produce a helpful message.
3698 : : */
3699 : : void
5799 tgl@sss.pgh.pa.us 3700 : 57 : errorMissingRTE(ParseState *pstate, RangeVar *relation)
3701 : : {
3702 : : RangeTblEntry *rte;
7179 3703 : 57 : const char *badAlias = NULL;
3704 : :
3705 : : /*
3706 : : * Check to see if there are any potential matches in the query's
3707 : : * rangetable. (Note: cases involving a bad schema name in the RangeVar
3708 : : * will throw error immediately here. That seems OK.)
3709 : : */
4778 3710 : 57 : rte = searchRangeTableForRel(pstate, relation);
3711 : :
3712 : : /*
3713 : : * If we found a match that has an alias and the alias is visible in the
3714 : : * namespace, then the problem is probably use of the relation's real name
3715 : : * instead of its alias, ie "SELECT foo.* FROM foo f". This mistake is
3716 : : * common enough to justify a specific hint.
3717 : : *
3718 : : * If we found a match that doesn't meet those criteria, assume the
3719 : : * problem is illegal use of a relation outside its scope, as in the
3720 : : * MySQL-ism "SELECT ... FROM a, b LEFT JOIN c ON (a.x = c.y)".
3721 : : */
7179 3722 [ + + + + ]: 57 : if (rte && rte->alias &&
2081 3723 [ + + ]: 39 : strcmp(rte->eref->aliasname, relation->relname) != 0)
3724 : : {
3725 : : ParseNamespaceItem *nsitem;
3726 : : int sublevels_up;
3727 : :
3728 : 12 : nsitem = refnameNamespaceItem(pstate, NULL, rte->eref->aliasname,
3729 : : relation->location,
3730 : : &sublevels_up);
3731 [ + - + - ]: 12 : if (nsitem && nsitem->p_rte == rte)
3732 : 12 : badAlias = rte->eref->aliasname;
3733 : : }
3734 : :
3735 : : /* If it looks like the user forgot to use an alias, hint about that */
1019 3736 [ + + ]: 57 : if (badAlias)
5799 3737 [ + - ]: 12 : ereport(ERROR,
3738 : : (errcode(ERRCODE_UNDEFINED_TABLE),
3739 : : errmsg("invalid reference to FROM-clause entry for table \"%s\"",
3740 : : relation->relname),
3741 : : errhint("Perhaps you meant to reference the table alias \"%s\".",
3742 : : badAlias),
3743 : : parser_errposition(pstate, relation->location)));
3744 : : /* Hint about case where we found an (inaccessible) exact match */
1019 3745 [ + + ]: 45 : else if (rte)
3746 [ + - + + ]: 36 : ereport(ERROR,
3747 : : (errcode(ERRCODE_UNDEFINED_TABLE),
3748 : : errmsg("invalid reference to FROM-clause entry for table \"%s\"",
3749 : : relation->relname),
3750 : : errdetail("There is an entry for table \"%s\", but it cannot be referenced from this part of the query.",
3751 : : rte->eref->aliasname),
3752 : : rte_visible_if_lateral(pstate, rte) ?
3753 : : errhint("To reference that table, you must mark this subquery with LATERAL.") : 0,
3754 : : parser_errposition(pstate, relation->location)));
3755 : : /* Else, we have nothing to offer but the bald statement of error */
3756 : : else
5799 3757 [ + - ]: 9 : ereport(ERROR,
3758 : : (errcode(ERRCODE_UNDEFINED_TABLE),
3759 : : errmsg("missing FROM-clause entry for table \"%s\"",
3760 : : relation->relname),
3761 : : parser_errposition(pstate, relation->location)));
3762 : : }
3763 : :
3764 : : /*
3765 : : * Generate a suitable error about a missing column.
3766 : : *
3767 : : * Since this is a very common type of error, we work rather hard to
3768 : : * produce a helpful message.
3769 : : */
3770 : : void
4778 3771 : 182 : errorMissingColumn(ParseState *pstate,
3772 : : const char *relname, const char *colname, int location)
3773 : : {
3774 : : FuzzyAttrMatchState *state;
3775 : :
3776 : : /*
3777 : : * Search the entire rtable looking for possible matches. If we find one,
3778 : : * emit a hint about it.
3779 : : */
3832 rhaas@postgresql.org 3780 : 182 : state = searchRangeTableForCol(pstate, relname, colname, location);
3781 : :
3782 : : /*
3783 : : * If there are exact match(es), they must be inaccessible for some
3784 : : * reason.
3785 : : */
1019 tgl@sss.pgh.pa.us 3786 [ + + ]: 182 : if (state->rexact1)
3787 : : {
3788 : : /*
3789 : : * We don't try too hard when there's multiple inaccessible exact
3790 : : * matches, but at least be sure that we don't misleadingly suggest
3791 : : * that there's only one.
3792 : : */
3793 [ + + ]: 21 : if (state->rexact2)
3794 [ + - - + : 6 : ereport(ERROR,
+ - ]
3795 : : (errcode(ERRCODE_UNDEFINED_COLUMN),
3796 : : relname ?
3797 : : errmsg("column %s.%s does not exist", relname, colname) :
3798 : : errmsg("column \"%s\" does not exist", colname),
3799 : : errdetail("There are columns named \"%s\", but they are in tables that cannot be referenced from this part of the query.",
3800 : : colname),
3801 : : !relname ? errhint("Try using a table-qualified name.") : 0,
3802 : : parser_errposition(pstate, location)));
3803 : : /* Single exact match, so try to determine why it's inaccessible. */
3804 [ + - - + : 15 : ereport(ERROR,
+ + + - -
+ ]
3805 : : (errcode(ERRCODE_UNDEFINED_COLUMN),
3806 : : relname ?
3807 : : errmsg("column %s.%s does not exist", relname, colname) :
3808 : : errmsg("column \"%s\" does not exist", colname),
3809 : : errdetail("There is a column named \"%s\" in table \"%s\", but it cannot be referenced from this part of the query.",
3810 : : colname, state->rexact1->eref->aliasname),
3811 : : rte_visible_if_lateral(pstate, state->rexact1) ?
3812 : : errhint("To reference that column, you must mark this subquery with LATERAL.") :
3813 : : (!relname && rte_visible_if_qualified(pstate, state->rexact1)) ?
3814 : : errhint("To reference that column, you must use a table-qualified name.") : 0,
3815 : : parser_errposition(pstate, location)));
3816 : : }
3817 : :
3818 [ + + ]: 161 : if (!state->rsecond)
3819 : : {
3820 : : /* If we found no match at all, we have little to report */
3821 [ + + ]: 155 : if (!state->rfirst)
3822 [ + - + + ]: 134 : ereport(ERROR,
3823 : : (errcode(ERRCODE_UNDEFINED_COLUMN),
3824 : : relname ?
3825 : : errmsg("column %s.%s does not exist", relname, colname) :
3826 : : errmsg("column \"%s\" does not exist", colname),
3827 : : parser_errposition(pstate, location)));
3828 : : /* Handle case where we have a single alternative spelling to offer */
3832 rhaas@postgresql.org 3829 [ + - + + ]: 21 : ereport(ERROR,
3830 : : (errcode(ERRCODE_UNDEFINED_COLUMN),
3831 : : relname ?
3832 : : errmsg("column %s.%s does not exist", relname, colname) :
3833 : : errmsg("column \"%s\" does not exist", colname),
3834 : : errhint("Perhaps you meant to reference the column \"%s.%s\".",
3835 : : state->rfirst->eref->aliasname,
3836 : : strVal(list_nth(state->rfirst->eref->colnames,
3837 : : state->first - 1))),
3838 : : parser_errposition(pstate, location)));
3839 : : }
3840 : : else
3841 : : {
3842 : : /* Handle case where there are two equally useful column hints */
3843 [ + - - + ]: 6 : ereport(ERROR,
3844 : : (errcode(ERRCODE_UNDEFINED_COLUMN),
3845 : : relname ?
3846 : : errmsg("column %s.%s does not exist", relname, colname) :
3847 : : errmsg("column \"%s\" does not exist", colname),
3848 : : errhint("Perhaps you meant to reference the column \"%s.%s\" or the column \"%s.%s\".",
3849 : : state->rfirst->eref->aliasname,
3850 : : strVal(list_nth(state->rfirst->eref->colnames,
3851 : : state->first - 1)),
3852 : : state->rsecond->eref->aliasname,
3853 : : strVal(list_nth(state->rsecond->eref->colnames,
3854 : : state->second - 1))),
3855 : : parser_errposition(pstate, location)));
3856 : : }
3857 : : }
3858 : :
3859 : : /*
3860 : : * Find ParseNamespaceItem for RTE, if it's visible at all.
3861 : : * We assume an RTE couldn't appear more than once in the namespace lists.
3862 : : */
3863 : : static ParseNamespaceItem *
1019 tgl@sss.pgh.pa.us 3864 : 60 : findNSItemForRTE(ParseState *pstate, RangeTblEntry *rte)
3865 : : {
3866 [ + + ]: 111 : while (pstate != NULL)
3867 : : {
3868 : : ListCell *l;
3869 : :
3870 [ + + + + : 147 : foreach(l, pstate->p_namespace)
+ + ]
3871 : : {
3872 : 96 : ParseNamespaceItem *nsitem = (ParseNamespaceItem *) lfirst(l);
3873 : :
3874 [ + + ]: 96 : if (nsitem->p_rte == rte)
3875 : 42 : return nsitem;
3876 : : }
3877 : 51 : pstate = pstate->parentParseState;
3878 : : }
3879 : 18 : return NULL;
3880 : : }
3881 : :
3882 : : /*
3883 : : * Would this RTE be visible, if only the user had written LATERAL?
3884 : : *
3885 : : * This is a helper for deciding whether to issue a HINT about LATERAL.
3886 : : * As such, it doesn't need to be 100% accurate; the HINT could be useful
3887 : : * even if it's not quite right. Hence, we don't delve into fine points
3888 : : * about whether a found nsitem has the appropriate one of p_rel_visible or
3889 : : * p_cols_visible set.
3890 : : */
3891 : : static bool
3892 : 51 : rte_visible_if_lateral(ParseState *pstate, RangeTblEntry *rte)
3893 : : {
3894 : : ParseNamespaceItem *nsitem;
3895 : :
3896 : : /* If LATERAL *is* active, we're clearly barking up the wrong tree */
3897 [ - + ]: 51 : if (pstate->p_lateral_active)
1019 tgl@sss.pgh.pa.us 3898 :UBC 0 : return false;
1019 tgl@sss.pgh.pa.us 3899 :CBC 51 : nsitem = findNSItemForRTE(pstate, rte);
3900 [ + + ]: 51 : if (nsitem)
3901 : : {
3902 : : /* Found it, report whether it's LATERAL-only */
3903 [ + + + + ]: 36 : return nsitem->p_lateral_only && nsitem->p_lateral_ok;
3904 : : }
3905 : 15 : return false;
3906 : : }
3907 : :
3908 : : /*
3909 : : * Would columns in this RTE be visible if qualified?
3910 : : */
3911 : : static bool
3912 : 9 : rte_visible_if_qualified(ParseState *pstate, RangeTblEntry *rte)
3913 : : {
3914 : 9 : ParseNamespaceItem *nsitem = findNSItemForRTE(pstate, rte);
3915 : :
3916 [ + + ]: 9 : if (nsitem)
3917 : : {
3918 : : /* Found it, report whether it's relation-only */
3919 [ + - - + ]: 6 : return nsitem->p_rel_visible && !nsitem->p_cols_visible;
3920 : : }
3921 : 3 : return false;
3922 : : }
3923 : :
3924 : :
3925 : : /*
3926 : : * Examine a fully-parsed query, and return true iff any relation underlying
3927 : : * the query is a temporary relation (table, view, or materialized view).
3928 : : */
3929 : : bool
4530 3930 : 8609 : isQueryUsingTempRelation(Query *query)
3931 : : {
3932 : 8609 : return isQueryUsingTempRelation_walker((Node *) query, NULL);
3933 : : }
3934 : :
3935 : : static bool
3936 : 788733 : isQueryUsingTempRelation_walker(Node *node, void *context)
3937 : : {
3938 [ + + ]: 788733 : if (node == NULL)
3939 : 220946 : return false;
3940 : :
3941 [ + + ]: 567787 : if (IsA(node, Query))
3942 : : {
3943 : 14646 : Query *query = (Query *) node;
3944 : : ListCell *rtable;
3945 : :
3946 [ + + + + : 52065 : foreach(rtable, query->rtable)
+ + ]
3947 : : {
3948 : 37473 : RangeTblEntry *rte = lfirst(rtable);
3949 : :
3950 [ + + ]: 37473 : if (rte->rtekind == RTE_RELATION)
3951 : : {
2420 andres@anarazel.de 3952 : 22833 : Relation rel = table_open(rte->relid, AccessShareLock);
4530 tgl@sss.pgh.pa.us 3953 : 22833 : char relpersistence = rel->rd_rel->relpersistence;
3954 : :
2420 andres@anarazel.de 3955 : 22833 : table_close(rel, AccessShareLock);
4530 tgl@sss.pgh.pa.us 3956 [ + + ]: 22833 : if (relpersistence == RELPERSISTENCE_TEMP)
3957 : 54 : return true;
3958 : : }
3959 : : }
3960 : :
3961 : 14592 : return query_tree_walker(query,
3962 : : isQueryUsingTempRelation_walker,
3963 : : context,
3964 : : QTW_IGNORE_JOINALIASES);
3965 : : }
3966 : :
3967 : 553141 : return expression_tree_walker(node,
3968 : : isQueryUsingTempRelation_walker,
3969 : : context);
3970 : : }
3971 : :
3972 : : /*
3973 : : * addRTEPermissionInfo
3974 : : * Creates RTEPermissionInfo for a given RTE and adds it into the
3975 : : * provided list.
3976 : : *
3977 : : * Returns the RTEPermissionInfo and sets rte->perminfoindex.
3978 : : */
3979 : : RTEPermissionInfo *
1005 alvherre@alvh.no-ip. 3980 : 693965 : addRTEPermissionInfo(List **rteperminfos, RangeTblEntry *rte)
3981 : : {
3982 : : RTEPermissionInfo *perminfo;
3983 : :
962 tgl@sss.pgh.pa.us 3984 [ - + ]: 693965 : Assert(OidIsValid(rte->relid));
1005 alvherre@alvh.no-ip. 3985 [ - + ]: 693965 : Assert(rte->perminfoindex == 0);
3986 : :
3987 : : /* Nope, so make one and add to the list. */
3988 : 693965 : perminfo = makeNode(RTEPermissionInfo);
3989 : 693965 : perminfo->relid = rte->relid;
3990 : 693965 : perminfo->inh = rte->inh;
3991 : : /* Other information is set by fetching the node as and where needed. */
3992 : :
3993 : 693965 : *rteperminfos = lappend(*rteperminfos, perminfo);
3994 : :
3995 : : /* Note its index (1-based!) */
3996 : 693965 : rte->perminfoindex = list_length(*rteperminfos);
3997 : :
3998 : 693965 : return perminfo;
3999 : : }
4000 : :
4001 : : /*
4002 : : * getRTEPermissionInfo
4003 : : * Find RTEPermissionInfo for a given relation in the provided list.
4004 : : *
4005 : : * This is a simple list_nth() operation, though it's good to have the
4006 : : * function for the various sanity checks.
4007 : : */
4008 : : RTEPermissionInfo *
4009 : 1872762 : getRTEPermissionInfo(List *rteperminfos, RangeTblEntry *rte)
4010 : : {
4011 : : RTEPermissionInfo *perminfo;
4012 : :
4013 [ + - ]: 1872762 : if (rte->perminfoindex == 0 ||
4014 [ - + ]: 1872762 : rte->perminfoindex > list_length(rteperminfos))
939 peter@eisentraut.org 4015 [ # # ]:UBC 0 : elog(ERROR, "invalid perminfoindex %u in RTE with relid %u",
4016 : : rte->perminfoindex, rte->relid);
1005 alvherre@alvh.no-ip. 4017 :CBC 1872762 : perminfo = list_nth_node(RTEPermissionInfo, rteperminfos,
4018 : : rte->perminfoindex - 1);
4019 [ - + ]: 1872762 : if (perminfo->relid != rte->relid)
1005 alvherre@alvh.no-ip. 4020 [ # # ]:UBC 0 : elog(ERROR, "permission info at index %u (with relid=%u) does not match provided RTE (with relid=%u)",
4021 : : rte->perminfoindex, perminfo->relid, rte->relid);
4022 : :
1005 alvherre@alvh.no-ip. 4023 :CBC 1872762 : return perminfo;
4024 : : }
|