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