LCOV - code coverage report
Current view: top level - src/backend/parser - parse_relation.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 91.4 % 1251 1144
Test Date: 2026-07-03 19:57:34 Functions: 100.0 % 60 60
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 74.0 % 1051 778

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

Generated by: LCOV version 2.0-1