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