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