Make parser rely more heavily on the ParseNamespaceItem data structure.
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 2 Jan 2020 16:29:01 +0000 (11:29 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 2 Jan 2020 16:29:01 +0000 (11:29 -0500)
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs.  In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.

Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem.  These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure.  Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.

The ParseNamespaceColumn structs also include Var identity information
(varno/varattno).  That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.

Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us

20 files changed:
src/backend/catalog/heap.c
src/backend/commands/copy.c
src/backend/commands/policy.c
src/backend/commands/tablecmds.c
src/backend/commands/trigger.c
src/backend/commands/view.c
src/backend/optimizer/plan/subselect.c
src/backend/parser/analyze.c
src/backend/parser/parse_clause.c
src/backend/parser/parse_coerce.c
src/backend/parser/parse_expr.c
src/backend/parser/parse_relation.c
src/backend/parser/parse_target.c
src/backend/parser/parse_utilcmd.c
src/backend/replication/logical/tablesync.c
src/backend/rewrite/rewriteHandler.c
src/include/parser/parse_node.h
src/include/parser/parse_relation.h
src/include/parser/parsetree.h
src/test/modules/test_rls_hooks/test_rls_hooks.c

index 01ecd9f9809008320593a268c7397dc57eb679c0..0fdff2918f7914bceb75301e8b6d3801c6325086 100644 (file)
@@ -2531,7 +2531,7 @@ AddRelationNewConstraints(Relation rel,
    TupleConstr *oldconstr;
    int         numoldchecks;
    ParseState *pstate;
-   RangeTblEntry *rte;
+   ParseNamespaceItem *nsitem;
    int         numchecks;
    List       *checknames;
    ListCell   *cell;
@@ -2554,13 +2554,13 @@ AddRelationNewConstraints(Relation rel,
     */
    pstate = make_parsestate(NULL);
    pstate->p_sourcetext = queryString;
-   rte = addRangeTableEntryForRelation(pstate,
-                                       rel,
-                                       AccessShareLock,
-                                       NULL,
-                                       false,
-                                       true);
-   addRTEtoQuery(pstate, rte, true, true, true);
+   nsitem = addRangeTableEntryForRelation(pstate,
+                                          rel,
+                                          AccessShareLock,
+                                          NULL,
+                                          false,
+                                          true);
+   addNSItemToQuery(pstate, nsitem, true, true, true);
 
    /*
     * Process column default expressions.
index c442e202b51575ef25e063e27626c855cfedc9a5..c93a788798d73852e70dd0bb99b38cd31963897e 100644 (file)
@@ -882,6 +882,7 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
    if (stmt->relation)
    {
        LOCKMODE    lockmode = is_from ? RowExclusiveLock : AccessShareLock;
+       ParseNamespaceItem *nsitem;
        RangeTblEntry *rte;
        TupleDesc   tupDesc;
        List       *attnums;
@@ -894,14 +895,15 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 
        relid = RelationGetRelid(rel);
 
-       rte = addRangeTableEntryForRelation(pstate, rel, lockmode,
-                                           NULL, false, false);
+       nsitem = addRangeTableEntryForRelation(pstate, rel, lockmode,
+                                              NULL, false, false);
+       rte = nsitem->p_rte;
        rte->requiredPerms = (is_from ? ACL_INSERT : ACL_SELECT);
 
        if (stmt->whereClause)
        {
-           /* add rte to column namespace  */
-           addRTEtoQuery(pstate, rte, false, true, true);
+           /* add nsitem to query namespace */
+           addNSItemToQuery(pstate, nsitem, false, true, true);
 
            /* Transform the raw expression tree */
            whereClause = transformExpr(pstate, stmt->whereClause, EXPR_KIND_COPY_WHERE);
index 818010b7c3189bb1e842fd32b2354137494debc4..6e990a38182dc7f111f791b9d364cc42f5527314 100644 (file)
@@ -568,9 +568,9 @@ RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid policy_id)
            qual_expr = stringToNode(qual_value);
 
            /* Add this rel to the parsestate's rangetable, for dependencies */
-           addRangeTableEntryForRelation(qual_pstate, rel,
-                                         AccessShareLock,
-                                         NULL, false, false);
+           (void) addRangeTableEntryForRelation(qual_pstate, rel,
+                                                AccessShareLock,
+                                                NULL, false, false);
 
            qual_parse_rtable = qual_pstate->p_rtable;
            free_parsestate(qual_pstate);
@@ -592,9 +592,9 @@ RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid policy_id)
            with_check_qual = stringToNode(with_check_value);
 
            /* Add this rel to the parsestate's rangetable, for dependencies */
-           addRangeTableEntryForRelation(with_check_pstate, rel,
-                                         AccessShareLock,
-                                         NULL, false, false);
+           (void) addRangeTableEntryForRelation(with_check_pstate, rel,
+                                                AccessShareLock,
+                                                NULL, false, false);
 
            with_check_parse_rtable = with_check_pstate->p_rtable;
            free_parsestate(with_check_pstate);
@@ -699,7 +699,7 @@ CreatePolicy(CreatePolicyStmt *stmt)
    ArrayType  *role_ids;
    ParseState *qual_pstate;
    ParseState *with_check_pstate;
-   RangeTblEntry *rte;
+   ParseNamespaceItem *nsitem;
    Node       *qual;
    Node       *with_check_qual;
    ScanKeyData skey[2];
@@ -755,16 +755,16 @@ CreatePolicy(CreatePolicyStmt *stmt)
    target_table = relation_open(table_id, NoLock);
 
    /* Add for the regular security quals */
-   rte = addRangeTableEntryForRelation(qual_pstate, target_table,
-                                       AccessShareLock,
-                                       NULL, false, false);
-   addRTEtoQuery(qual_pstate, rte, false, true, true);
+   nsitem = addRangeTableEntryForRelation(qual_pstate, target_table,
+                                          AccessShareLock,
+                                          NULL, false, false);
+   addNSItemToQuery(qual_pstate, nsitem, false, true, true);
 
    /* Add for the with-check quals */
-   rte = addRangeTableEntryForRelation(with_check_pstate, target_table,
-                                       AccessShareLock,
-                                       NULL, false, false);
-   addRTEtoQuery(with_check_pstate, rte, false, true, true);
+   nsitem = addRangeTableEntryForRelation(with_check_pstate, target_table,
+                                          AccessShareLock,
+                                          NULL, false, false);
+   addNSItemToQuery(with_check_pstate, nsitem, false, true, true);
 
    qual = transformWhereClause(qual_pstate,
                                copyObject(stmt->qual),
@@ -933,14 +933,14 @@ AlterPolicy(AlterPolicyStmt *stmt)
    /* Parse the using policy clause */
    if (stmt->qual)
    {
-       RangeTblEntry *rte;
+       ParseNamespaceItem *nsitem;
        ParseState *qual_pstate = make_parsestate(NULL);
 
-       rte = addRangeTableEntryForRelation(qual_pstate, target_table,
-                                           AccessShareLock,
-                                           NULL, false, false);
+       nsitem = addRangeTableEntryForRelation(qual_pstate, target_table,
+                                              AccessShareLock,
+                                              NULL, false, false);
 
-       addRTEtoQuery(qual_pstate, rte, false, true, true);
+       addNSItemToQuery(qual_pstate, nsitem, false, true, true);
 
        qual = transformWhereClause(qual_pstate, copyObject(stmt->qual),
                                    EXPR_KIND_POLICY,
@@ -956,14 +956,14 @@ AlterPolicy(AlterPolicyStmt *stmt)
    /* Parse the with-check policy clause */
    if (stmt->with_check)
    {
-       RangeTblEntry *rte;
+       ParseNamespaceItem *nsitem;
        ParseState *with_check_pstate = make_parsestate(NULL);
 
-       rte = addRangeTableEntryForRelation(with_check_pstate, target_table,
-                                           AccessShareLock,
-                                           NULL, false, false);
+       nsitem = addRangeTableEntryForRelation(with_check_pstate, target_table,
+                                              AccessShareLock,
+                                              NULL, false, false);
 
-       addRTEtoQuery(with_check_pstate, rte, false, true, true);
+       addNSItemToQuery(with_check_pstate, nsitem, false, true, true);
 
        with_check_qual = transformWhereClause(with_check_pstate,
                                               copyObject(stmt->with_check),
@@ -1107,9 +1107,9 @@ AlterPolicy(AlterPolicyStmt *stmt)
            qual = stringToNode(qual_value);
 
            /* Add this rel to the parsestate's rangetable, for dependencies */
-           addRangeTableEntryForRelation(qual_pstate, target_table,
-                                         AccessShareLock,
-                                         NULL, false, false);
+           (void) addRangeTableEntryForRelation(qual_pstate, target_table,
+                                                AccessShareLock,
+                                                NULL, false, false);
 
            qual_parse_rtable = qual_pstate->p_rtable;
            free_parsestate(qual_pstate);
@@ -1149,9 +1149,10 @@ AlterPolicy(AlterPolicyStmt *stmt)
            with_check_qual = stringToNode(with_check_value);
 
            /* Add this rel to the parsestate's rangetable, for dependencies */
-           addRangeTableEntryForRelation(with_check_pstate, target_table,
-                                         AccessShareLock,
-                                         NULL, false, false);
+           (void) addRangeTableEntryForRelation(with_check_pstate,
+                                                target_table,
+                                                AccessShareLock,
+                                                NULL, false, false);
 
            with_check_parse_rtable = with_check_pstate->p_rtable;
            free_parsestate(with_check_pstate);
index 57781a522e04d8d714aa3317830e2d950de7453d..01bc292ada0bcb8c53ea1203ae01d892b355a98d 100644 (file)
@@ -918,7 +918,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
                    defaultPartOid;
        Relation    parent,
                    defaultRel = NULL;
-       RangeTblEntry *rte;
+       ParseNamespaceItem *nsitem;
 
        /* Already have strong enough lock on the parent */
        parent = table_open(parentId, NoLock);
@@ -962,13 +962,14 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
        pstate->p_sourcetext = queryString;
 
        /*
-        * Add an RTE containing this relation, so that transformExpr called
-        * on partition bound expressions is able to report errors using a
-        * proper context.
+        * Add an nsitem containing this relation, so that transformExpr
+        * called on partition bound expressions is able to report errors
+        * using a proper context.
         */
-       rte = addRangeTableEntryForRelation(pstate, rel, AccessShareLock,
-                                           NULL, false, false);
-       addRTEtoQuery(pstate, rte, false, true, true);
+       nsitem = addRangeTableEntryForRelation(pstate, rel, AccessShareLock,
+                                              NULL, false, false);
+       addNSItemToQuery(pstate, nsitem, false, true, true);
+
        bound = transformPartitionBound(pstate, parent, stmt->partbound);
 
        /*
@@ -14970,7 +14971,7 @@ transformPartitionSpec(Relation rel, PartitionSpec *partspec, char *strategy)
 {
    PartitionSpec *newspec;
    ParseState *pstate;
-   RangeTblEntry *rte;
+   ParseNamespaceItem *nsitem;
    ListCell   *l;
 
    newspec = makeNode(PartitionSpec);
@@ -15004,9 +15005,9 @@ transformPartitionSpec(Relation rel, PartitionSpec *partspec, char *strategy)
     * rangetable entry.  We need a ParseState for transformExpr.
     */
    pstate = make_parsestate(NULL);
-   rte = addRangeTableEntryForRelation(pstate, rel, AccessShareLock,
-                                       NULL, false, true);
-   addRTEtoQuery(pstate, rte, true, true, true);
+   nsitem = addRangeTableEntryForRelation(pstate, rel, AccessShareLock,
+                                          NULL, false, true);
+   addNSItemToQuery(pstate, nsitem, true, true, true);
 
    /* take care of any partition expressions */
    foreach(l, partspec->partParams)
index c5c7b2101c3f40705ca9df54c36309fcf61f178a..b9b1262e300279a6d9f664d4a76b3930a7676d54 100644 (file)
@@ -565,7 +565,7 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
    if (!whenClause && stmt->whenClause)
    {
        ParseState *pstate;
-       RangeTblEntry *rte;
+       ParseNamespaceItem *nsitem;
        List       *varList;
        ListCell   *lc;
 
@@ -574,20 +574,20 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
        pstate->p_sourcetext = queryString;
 
        /*
-        * Set up RTEs for OLD and NEW references.
+        * Set up nsitems for OLD and NEW references.
         *
         * 'OLD' must always have varno equal to 1 and 'NEW' equal to 2.
         */
-       rte = addRangeTableEntryForRelation(pstate, rel,
-                                           AccessShareLock,
-                                           makeAlias("old", NIL),
-                                           false, false);
-       addRTEtoQuery(pstate, rte, false, true, true);
-       rte = addRangeTableEntryForRelation(pstate, rel,
-                                           AccessShareLock,
-                                           makeAlias("new", NIL),
-                                           false, false);
-       addRTEtoQuery(pstate, rte, false, true, true);
+       nsitem = addRangeTableEntryForRelation(pstate, rel,
+                                              AccessShareLock,
+                                              makeAlias("old", NIL),
+                                              false, false);
+       addNSItemToQuery(pstate, nsitem, false, true, true);
+       nsitem = addRangeTableEntryForRelation(pstate, rel,
+                                              AccessShareLock,
+                                              makeAlias("new", NIL),
+                                              false, false);
+       addNSItemToQuery(pstate, nsitem, false, true, true);
 
        /* Transform expression.  Copy to be sure we don't modify original */
        whenClause = transformWhereClause(pstate,
index f18fb29c165f36c820be4c53298ba72c4b5abc8d..06bc2b76ed78c431f7938c81e40f336dd9ef1ef0 100644 (file)
@@ -341,6 +341,7 @@ UpdateRangeTableOfViewParse(Oid viewOid, Query *viewParse)
 {
    Relation    viewRel;
    List       *new_rt;
+   ParseNamespaceItem *nsitem;
    RangeTblEntry *rt_entry1,
               *rt_entry2;
    ParseState *pstate;
@@ -365,14 +366,17 @@ UpdateRangeTableOfViewParse(Oid viewOid, Query *viewParse)
     * Create the 2 new range table entries and form the new range table...
     * OLD first, then NEW....
     */
-   rt_entry1 = addRangeTableEntryForRelation(pstate, viewRel,
-                                             AccessShareLock,
-                                             makeAlias("old", NIL),
-                                             false, false);
-   rt_entry2 = addRangeTableEntryForRelation(pstate, viewRel,
-                                             AccessShareLock,
-                                             makeAlias("new", NIL),
-                                             false, false);
+   nsitem = addRangeTableEntryForRelation(pstate, viewRel,
+                                          AccessShareLock,
+                                          makeAlias("old", NIL),
+                                          false, false);
+   rt_entry1 = nsitem->p_rte;
+   nsitem = addRangeTableEntryForRelation(pstate, viewRel,
+                                          AccessShareLock,
+                                          makeAlias("new", NIL),
+                                          false, false);
+   rt_entry2 = nsitem->p_rte;
+
    /* Must override addRangeTableEntry's default access-check flags */
    rt_entry1->requiredPerms = 0;
    rt_entry2->requiredPerms = 0;
index fd8f24aeea9df53e9de081e0c699c9d2dd1985b7..3650e8329d5890544c2f64522dc1dad5820cf411 100644 (file)
@@ -1217,6 +1217,7 @@ convert_ANY_sublink_to_join(PlannerInfo *root, SubLink *sublink,
    Query      *subselect = (Query *) sublink->subselect;
    Relids      upper_varnos;
    int         rtindex;
+   ParseNamespaceItem *nsitem;
    RangeTblEntry *rte;
    RangeTblRef *rtr;
    List       *subquery_vars;
@@ -1264,11 +1265,12 @@ convert_ANY_sublink_to_join(PlannerInfo *root, SubLink *sublink,
     * below). Therefore this is a lot easier than what pull_up_subqueries has
     * to go through.
     */
-   rte = addRangeTableEntryForSubquery(pstate,
-                                       subselect,
-                                       makeAlias("ANY_subquery", NIL),
-                                       false,
-                                       false);
+   nsitem = addRangeTableEntryForSubquery(pstate,
+                                          subselect,
+                                          makeAlias("ANY_subquery", NIL),
+                                          false,
+                                          false);
+   rte = nsitem->p_rte;
    parse->rtable = lappend(parse->rtable, rte);
    rtindex = list_length(parse->rtable);
 
index 01125ad8cf97cfaf3ceb5be535cd098c24690109..447a61ef8c39172f0525bd85b21a916034f80698 100644 (file)
@@ -415,9 +415,7 @@ transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt)
                                         stmt->relation->inh,
                                         true,
                                         ACL_DELETE);
-
-   /* grab the namespace item made by setTargetTable */
-   nsitem = (ParseNamespaceItem *) llast(pstate->p_namespace);
+   nsitem = pstate->p_target_nsitem;
 
    /* there's no DISTINCT in DELETE */
    qry->distinctClause = NIL;
@@ -476,8 +474,8 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
    List       *sub_namespace;
    List       *icolumns;
    List       *attrnos;
+   ParseNamespaceItem *nsitem;
    RangeTblEntry *rte;
-   RangeTblRef *rtr;
    ListCell   *icols;
    ListCell   *attnos;
    ListCell   *lc;
@@ -611,18 +609,14 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
 
        /*
         * Make the source be a subquery in the INSERT's rangetable, and add
-        * it to the INSERT's joinlist.
+        * it to the INSERT's joinlist (but not the namespace).
         */
-       rte = addRangeTableEntryForSubquery(pstate,
-                                           selectQuery,
-                                           makeAlias("*SELECT*", NIL),
-                                           false,
-                                           false);
-       rtr = makeNode(RangeTblRef);
-       /* assume new rte is at end */
-       rtr->rtindex = list_length(pstate->p_rtable);
-       Assert(rte == rt_fetch(rtr->rtindex, pstate->p_rtable));
-       pstate->p_joinlist = lappend(pstate->p_joinlist, rtr);
+       nsitem = addRangeTableEntryForSubquery(pstate,
+                                              selectQuery,
+                                              makeAlias("*SELECT*", NIL),
+                                              false,
+                                              false);
+       addNSItemToQuery(pstate, nsitem, true, false, false);
 
        /*----------
         * Generate an expression list for the INSERT that selects all the
@@ -652,7 +646,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
                expr = tle->expr;
            else
            {
-               Var        *var = makeVarFromTargetEntry(rtr->rtindex, tle);
+               Var        *var = makeVarFromTargetEntry(nsitem->p_rtindex, tle);
 
                var->location = exprLocation((Node *) tle->expr);
                expr = (Expr *) var;
@@ -774,19 +768,15 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
        /*
         * Generate the VALUES RTE
         */
-       rte = addRangeTableEntryForValues(pstate, exprsLists,
-                                         coltypes, coltypmods, colcollations,
-                                         NULL, lateral, true);
-       rtr = makeNode(RangeTblRef);
-       /* assume new rte is at end */
-       rtr->rtindex = list_length(pstate->p_rtable);
-       Assert(rte == rt_fetch(rtr->rtindex, pstate->p_rtable));
-       pstate->p_joinlist = lappend(pstate->p_joinlist, rtr);
+       nsitem = addRangeTableEntryForValues(pstate, exprsLists,
+                                            coltypes, coltypmods, colcollations,
+                                            NULL, lateral, true);
+       addNSItemToQuery(pstate, nsitem, true, false, false);
 
        /*
         * Generate list of Vars referencing the RTE
         */
-       expandRTE(rte, rtr->rtindex, 0, -1, false, NULL, &exprList);
+       exprList = expandNSItemVars(nsitem, 0, -1, NULL);
 
        /*
         * Re-apply any indirection on the target column specs to the Vars
@@ -829,7 +819,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
     * Generate query's target list using the computed list of expressions.
     * Also, mark all the target columns as needing insert permissions.
     */
-   rte = pstate->p_target_rangetblentry;
+   rte = pstate->p_target_nsitem->p_rte;
    qry->targetList = NIL;
    Assert(list_length(exprList) <= list_length(icolumns));
    forthree(lc, exprList, icols, icolumns, attnos, attrnos)
@@ -863,8 +853,8 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
    if (stmt->returningList)
    {
        pstate->p_namespace = NIL;
-       addRTEtoQuery(pstate, pstate->p_target_rangetblentry,
-                     false, true, true);
+       addNSItemToQuery(pstate, pstate->p_target_nsitem,
+                        false, true, true);
        qry->returningList = transformReturningList(pstate,
                                                    stmt->returningList);
    }
@@ -999,7 +989,6 @@ transformOnConflictClause(ParseState *pstate,
    Oid         arbiterConstraint;
    List       *onConflictSet = NIL;
    Node       *onConflictWhere = NULL;
-   RangeTblEntry *exclRte = NULL;
    int         exclRelIndex = 0;
    List       *exclRelTlist = NIL;
    OnConflictExpr *result;
@@ -1012,6 +1001,8 @@ transformOnConflictClause(ParseState *pstate,
    if (onConflictClause->action == ONCONFLICT_UPDATE)
    {
        Relation    targetrel = pstate->p_target_relation;
+       ParseNamespaceItem *exclNSItem;
+       RangeTblEntry *exclRte;
 
        /*
         * All INSERT expressions have been parsed, get ready for potentially
@@ -1025,17 +1016,18 @@ transformOnConflictClause(ParseState *pstate,
         * relation, and no permission checks are required on it.  (We'll
         * check the actual target relation, instead.)
         */
-       exclRte = addRangeTableEntryForRelation(pstate,
-                                               targetrel,
-                                               RowExclusiveLock,
-                                               makeAlias("excluded", NIL),
-                                               false, false);
+       exclNSItem = addRangeTableEntryForRelation(pstate,
+                                                  targetrel,
+                                                  RowExclusiveLock,
+                                                  makeAlias("excluded", NIL),
+                                                  false, false);
+       exclRte = exclNSItem->p_rte;
+       exclRelIndex = exclNSItem->p_rtindex;
+
        exclRte->relkind = RELKIND_COMPOSITE_TYPE;
        exclRte->requiredPerms = 0;
        /* other permissions fields in exclRte are already empty */
 
-       exclRelIndex = list_length(pstate->p_rtable);
-
        /* Create EXCLUDED rel's targetlist for use by EXPLAIN */
        exclRelTlist = BuildOnConflictExcludedTargetlist(targetrel,
                                                         exclRelIndex);
@@ -1044,9 +1036,9 @@ transformOnConflictClause(ParseState *pstate,
         * Add EXCLUDED and the target RTE to the namespace, so that they can
         * be used in the UPDATE subexpressions.
         */
-       addRTEtoQuery(pstate, exclRte, false, true, true);
-       addRTEtoQuery(pstate, pstate->p_target_rangetblentry,
-                     false, true, true);
+       addNSItemToQuery(pstate, exclNSItem, false, true, true);
+       addNSItemToQuery(pstate, pstate->p_target_nsitem,
+                        false, true, true);
 
        /*
         * Now transform the UPDATE subexpressions.
@@ -1343,7 +1335,6 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
    List      **colexprs = NULL;
    int         sublist_length = -1;
    bool        lateral = false;
-   RangeTblEntry *rte;
    ParseNamespaceItem *nsitem;
    ListCell   *lc;
    ListCell   *lc2;
@@ -1511,14 +1502,10 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
    /*
     * Generate the VALUES RTE
     */
-   rte = addRangeTableEntryForValues(pstate, exprsLists,
-                                     coltypes, coltypmods, colcollations,
-                                     NULL, lateral, true);
-   addRTEtoQuery(pstate, rte, true, true, true);
-
-   /* grab the namespace item made by addRTEtoQuery */
-   nsitem = (ParseNamespaceItem *) llast(pstate->p_namespace);
-   Assert(rte == nsitem->p_rte);
+   nsitem = addRangeTableEntryForValues(pstate, exprsLists,
+                                        coltypes, coltypmods, colcollations,
+                                        NULL, lateral, true);
+   addNSItemToQuery(pstate, nsitem, true, true, true);
 
    /*
     * Generate a targetlist as though expanding "*"
@@ -1593,7 +1580,9 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
               *targetnames,
               *sv_namespace;
    int         sv_rtable_length;
-   RangeTblEntry *jrte;
+   ParseNamespaceItem *jnsitem;
+   ParseNamespaceColumn *sortnscolumns;
+   int         sortcolindex;
    int         tllen;
 
    qry->commandType = CMD_SELECT;
@@ -1686,6 +1675,9 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
    qry->targetList = NIL;
    targetvars = NIL;
    targetnames = NIL;
+   sortnscolumns = (ParseNamespaceColumn *)
+       palloc0(list_length(sostmt->colTypes) * sizeof(ParseNamespaceColumn));
+   sortcolindex = 0;
 
    forfour(lct, sostmt->colTypes,
            lcm, sostmt->colTypmods,
@@ -1716,6 +1708,14 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
        qry->targetList = lappend(qry->targetList, tle);
        targetvars = lappend(targetvars, var);
        targetnames = lappend(targetnames, makeString(colName));
+       sortnscolumns[sortcolindex].p_varno = leftmostRTI;
+       sortnscolumns[sortcolindex].p_varattno = lefttle->resno;
+       sortnscolumns[sortcolindex].p_vartype = colType;
+       sortnscolumns[sortcolindex].p_vartypmod = colTypmod;
+       sortnscolumns[sortcolindex].p_varcollid = colCollation;
+       sortnscolumns[sortcolindex].p_varnosyn = leftmostRTI;
+       sortnscolumns[sortcolindex].p_varattnosyn = lefttle->resno;
+       sortcolindex++;
    }
 
    /*
@@ -1730,18 +1730,19 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
     */
    sv_rtable_length = list_length(pstate->p_rtable);
 
-   jrte = addRangeTableEntryForJoin(pstate,
-                                    targetnames,
-                                    JOIN_INNER,
-                                    targetvars,
-                                    NULL,
-                                    false);
+   jnsitem = addRangeTableEntryForJoin(pstate,
+                                       targetnames,
+                                       sortnscolumns,
+                                       JOIN_INNER,
+                                       targetvars,
+                                       NULL,
+                                       false);
 
    sv_namespace = pstate->p_namespace;
    pstate->p_namespace = NIL;
 
-   /* add jrte to column namespace only */
-   addRTEtoQuery(pstate, jrte, false, false, true);
+   /* add jnsitem to column namespace only */
+   addNSItemToQuery(pstate, jnsitem, false, false, true);
 
    /*
     * For now, we don't support resjunk sort clauses on the output of a
@@ -1757,7 +1758,7 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
                                          EXPR_KIND_ORDER_BY,
                                          false /* allow SQL92 rules */ );
 
-   /* restore namespace, remove jrte from rtable */
+   /* restore namespace, remove join RTE from rtable */
    pstate->p_namespace = sv_namespace;
    pstate->p_rtable = list_truncate(pstate->p_rtable, sv_rtable_length);
 
@@ -1869,7 +1870,7 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt,
        /* Process leaf SELECT */
        Query      *selectQuery;
        char        selectName[32];
-       RangeTblEntry *rte PG_USED_FOR_ASSERTS_ONLY;
+       ParseNamespaceItem *nsitem;
        RangeTblRef *rtr;
        ListCell   *tl;
 
@@ -1926,19 +1927,17 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt,
         */
        snprintf(selectName, sizeof(selectName), "*SELECT* %d",
                 list_length(pstate->p_rtable) + 1);
-       rte = addRangeTableEntryForSubquery(pstate,
-                                           selectQuery,
-                                           makeAlias(selectName, NIL),
-                                           false,
-                                           false);
+       nsitem = addRangeTableEntryForSubquery(pstate,
+                                              selectQuery,
+                                              makeAlias(selectName, NIL),
+                                              false,
+                                              false);
 
        /*
         * Return a RangeTblRef to replace the SelectStmt in the set-op tree.
         */
        rtr = makeNode(RangeTblRef);
-       /* assume new rte is at end */
-       rtr->rtindex = list_length(pstate->p_rtable);
-       Assert(rte == rt_fetch(rtr->rtindex, pstate->p_rtable));
+       rtr->rtindex = nsitem->p_rtindex;
        return (Node *) rtr;
    }
    else
@@ -2236,9 +2235,7 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
                                         stmt->relation->inh,
                                         true,
                                         ACL_UPDATE);
-
-   /* grab the namespace item made by setTargetTable */
-   nsitem = (ParseNamespaceItem *) llast(pstate->p_namespace);
+   nsitem = pstate->p_target_nsitem;
 
    /* subqueries in FROM cannot access the result relation */
    nsitem->p_lateral_only = true;
@@ -2297,7 +2294,7 @@ transformUpdateTargetList(ParseState *pstate, List *origTlist)
        pstate->p_next_resno = RelationGetNumberOfAttributes(pstate->p_target_relation) + 1;
 
    /* Prepare non-junk columns for assignment to target table */
-   target_rte = pstate->p_target_rangetblentry;
+   target_rte = pstate->p_target_nsitem->p_rte;
    orig_tl = list_head(origTlist);
 
    foreach(tl, tlist)
index 04ebd877ab7fe58f4d805e07ce1d03f42420b699..5fa42d307ac987dde63c61f598f0c67054bf00f6 100644 (file)
 #include "utils/rel.h"
 #include "utils/syscache.h"
 
-/* Convenience macro for the most common makeNamespaceItem() case */
-#define makeDefaultNSItem(rte, rti) \
-   makeNamespaceItem(rte, rti, true, true, false, true)
 
 static void extractRemainingColumns(List *common_colnames,
                                    List *src_colnames, List *src_colvars,
-                                   List **res_colnames, List **res_colvars);
+                                   ParseNamespaceColumn *src_nscolumns,
+                                   List **res_colnames, List **res_colvars,
+                                   ParseNamespaceColumn *res_nscolumns);
 static Node *transformJoinUsingClause(ParseState *pstate,
                                      RangeTblEntry *leftRTE, RangeTblEntry *rightRTE,
                                      List *leftVars, List *rightVars);
 static Node *transformJoinOnClause(ParseState *pstate, JoinExpr *j,
                                   List *namespace);
-static RangeTblEntry *getRTEForSpecialRelationTypes(ParseState *pstate,
-                                                   RangeVar *rv);
-static RangeTblEntry *transformTableEntry(ParseState *pstate, RangeVar *r);
-static RangeTblEntry *transformRangeSubselect(ParseState *pstate,
-                                             RangeSubselect *r);
-static RangeTblEntry *transformRangeFunction(ParseState *pstate,
-                                            RangeFunction *r);
-static RangeTblEntry *transformRangeTableFunc(ParseState *pstate,
-                                             RangeTableFunc *t);
+static ParseNamespaceItem *transformTableEntry(ParseState *pstate, RangeVar *r);
+static ParseNamespaceItem *transformRangeSubselect(ParseState *pstate,
+                                                  RangeSubselect *r);
+static ParseNamespaceItem *transformRangeFunction(ParseState *pstate,
+                                                 RangeFunction *r);
+static ParseNamespaceItem *transformRangeTableFunc(ParseState *pstate,
+                                                  RangeTableFunc *t);
 static TableSampleClause *transformRangeTableSample(ParseState *pstate,
                                                    RangeTableSample *rts);
+static ParseNamespaceItem *getNSItemForSpecialRelationTypes(ParseState *pstate,
+                                                           RangeVar *rv);
 static Node *transformFromClauseItem(ParseState *pstate, Node *n,
-                                    RangeTblEntry **top_rte, int *top_rti,
+                                    ParseNamespaceItem **top_nsitem,
                                     List **namespace);
 static Node *buildMergedJoinVar(ParseState *pstate, JoinType jointype,
                                Var *l_colvar, Var *r_colvar);
-static ParseNamespaceItem *makeNamespaceItem(RangeTblEntry *rte, int rtindex,
-                                            bool rel_visible, bool cols_visible,
-                                            bool lateral_only, bool lateral_ok);
 static void setNamespaceColumnVisibility(List *namespace, bool cols_visible);
 static void setNamespaceLateralState(List *namespace,
                                     bool lateral_only, bool lateral_ok);
@@ -130,13 +126,11 @@ transformFromClause(ParseState *pstate, List *frmList)
    foreach(fl, frmList)
    {
        Node       *n = lfirst(fl);
-       RangeTblEntry *rte;
-       int         rtindex;
+       ParseNamespaceItem *nsitem;
        List       *namespace;
 
        n = transformFromClauseItem(pstate, n,
-                                   &rte,
-                                   &rtindex,
+                                   &nsitem,
                                    &namespace);
 
        checkNameSpaceConflicts(pstate, pstate->p_namespace, namespace);
@@ -183,8 +177,7 @@ int
 setTargetTable(ParseState *pstate, RangeVar *relation,
               bool inh, bool alsoSource, AclMode requiredPerms)
 {
-   RangeTblEntry *rte;
-   int         rtindex;
+   ParseNamespaceItem *nsitem;
 
    /*
     * ENRs hide tables of the same name, so we need to check for them first.
@@ -212,19 +205,14 @@ setTargetTable(ParseState *pstate, RangeVar *relation,
                                                RowExclusiveLock);
 
    /*
-    * Now build an RTE.
+    * Now build an RTE and a ParseNamespaceItem.
     */
-   rte = addRangeTableEntryForRelation(pstate, pstate->p_target_relation,
-                                       RowExclusiveLock,
-                                       relation->alias, inh, false);
+   nsitem = addRangeTableEntryForRelation(pstate, pstate->p_target_relation,
+                                          RowExclusiveLock,
+                                          relation->alias, inh, false);
 
-   /* assume new rte is at end */
-   rtindex = list_length(pstate->p_rtable);
-   Assert(rte == rt_fetch(rtindex, pstate->p_rtable));
-
-   /* remember the RTE as being the query target */
-   pstate->p_target_rangetblentry = rte;
-   pstate->p_target_rtindex = rtindex;
+   /* remember the RTE/nsitem as being the query target */
+   pstate->p_target_nsitem = nsitem;
 
    /*
     * Override addRangeTableEntry's default ACL_SELECT permissions check, and
@@ -235,28 +223,30 @@ setTargetTable(ParseState *pstate, RangeVar *relation,
     * analysis, we will add the ACL_SELECT bit back again; see
     * markVarForSelectPriv and its callers.
     */
-   rte->requiredPerms = requiredPerms;
+   nsitem->p_rte->requiredPerms = requiredPerms;
 
    /*
     * If UPDATE/DELETE, add table to joinlist and namespace.
-    *
-    * Note: some callers know that they can find the new ParseNamespaceItem
-    * at the end of the pstate->p_namespace list.  This is a bit ugly but not
-    * worth complicating this function's signature for.
     */
    if (alsoSource)
-       addRTEtoQuery(pstate, rte, true, true, true);
+       addNSItemToQuery(pstate, nsitem, true, true, true);
 
-   return rtindex;
+   return nsitem->p_rtindex;
 }
 
 /*
  * Extract all not-in-common columns from column lists of a source table
+ *
+ * We hand back new lists in *res_colnames and *res_colvars.  But
+ * res_nscolumns points to a caller-allocated array that we fill in
+ * the next few entries in.
  */
 static void
 extractRemainingColumns(List *common_colnames,
                        List *src_colnames, List *src_colvars,
-                       List **res_colnames, List **res_colvars)
+                       ParseNamespaceColumn *src_nscolumns,
+                       List **res_colnames, List **res_colvars,
+                       ParseNamespaceColumn *res_nscolumns)
 {
    List       *new_colnames = NIL;
    List       *new_colvars = NIL;
@@ -271,6 +261,14 @@ extractRemainingColumns(List *common_colnames,
        bool        match = false;
        ListCell   *cnames;
 
+       /*
+        * Ignore any dropped columns in the src_nscolumns input.  (The list
+        * inputs won't contain entries for dropped columns.)
+        */
+       while (src_nscolumns->p_varno == 0)
+           src_nscolumns++;
+
+       /* is current src column already accounted for in common_colnames? */
        foreach(cnames, common_colnames)
        {
            char       *ccolname = strVal(lfirst(cnames));
@@ -284,9 +282,15 @@ extractRemainingColumns(List *common_colnames,
 
        if (!match)
        {
+           /* Nope, so emit it as next output column */
            new_colnames = lappend(new_colnames, lfirst(lnames));
            new_colvars = lappend(new_colvars, lfirst(lvars));
+           /* Copy the input relation's nscolumn data for this column */
+           *res_nscolumns = *src_nscolumns;
+           res_nscolumns++;
        }
+
+       src_nscolumns++;
    }
 
    *res_colnames = new_colnames;
@@ -388,25 +392,20 @@ transformJoinOnClause(ParseState *pstate, JoinExpr *j, List *namespace)
 /*
  * transformTableEntry --- transform a RangeVar (simple relation reference)
  */
-static RangeTblEntry *
+static ParseNamespaceItem *
 transformTableEntry(ParseState *pstate, RangeVar *r)
 {
-   RangeTblEntry *rte;
-
-   /* We need only build a range table entry */
-   rte = addRangeTableEntry(pstate, r, r->alias, r->inh, true);
-
-   return rte;
+   /* addRangeTableEntry does all the work */
+   return addRangeTableEntry(pstate, r, r->alias, r->inh, true);
 }
 
 /*
  * transformRangeSubselect --- transform a sub-SELECT appearing in FROM
  */
-static RangeTblEntry *
+static ParseNamespaceItem *
 transformRangeSubselect(ParseState *pstate, RangeSubselect *r)
 {
    Query      *query;
-   RangeTblEntry *rte;
 
    /*
     * We require user to supply an alias for a subselect, per SQL92. To relax
@@ -454,29 +453,26 @@ transformRangeSubselect(ParseState *pstate, RangeSubselect *r)
        elog(ERROR, "unexpected non-SELECT command in subquery in FROM");
 
    /*
-    * OK, build an RTE for the subquery.
+    * OK, build an RTE and nsitem for the subquery.
     */
-   rte = addRangeTableEntryForSubquery(pstate,
-                                       query,
-                                       r->alias,
-                                       r->lateral,
-                                       true);
-
-   return rte;
+   return addRangeTableEntryForSubquery(pstate,
+                                        query,
+                                        r->alias,
+                                        r->lateral,
+                                        true);
 }
 
 
 /*
  * transformRangeFunction --- transform a function call appearing in FROM
  */
-static RangeTblEntry *
+static ParseNamespaceItem *
 transformRangeFunction(ParseState *pstate, RangeFunction *r)
 {
    List       *funcexprs = NIL;
    List       *funcnames = NIL;
    List       *coldeflists = NIL;
    bool        is_lateral;
-   RangeTblEntry *rte;
    ListCell   *lc;
 
    /*
@@ -677,13 +673,11 @@ transformRangeFunction(ParseState *pstate, RangeFunction *r)
    is_lateral = r->lateral || contain_vars_of_level((Node *) funcexprs, 0);
 
    /*
-    * OK, build an RTE for the function.
+    * OK, build an RTE and nsitem for the function.
     */
-   rte = addRangeTableEntryForFunction(pstate,
-                                       funcnames, funcexprs, coldeflists,
-                                       r, is_lateral, true);
-
-   return rte;
+   return addRangeTableEntryForFunction(pstate,
+                                        funcnames, funcexprs, coldeflists,
+                                        r, is_lateral, true);
 }
 
 /*
@@ -694,13 +688,12 @@ transformRangeFunction(ParseState *pstate, RangeFunction *r)
  * row-generating expression, the column-generating expressions, and the
  * default value expressions.
  */
-static RangeTblEntry *
+static ParseNamespaceItem *
 transformRangeTableFunc(ParseState *pstate, RangeTableFunc *rtf)
 {
    TableFunc  *tf = makeNode(TableFunc);
    const char *constructName;
    Oid         docType;
-   RangeTblEntry *rte;
    bool        is_lateral;
    ListCell   *col;
    char      **names;
@@ -903,10 +896,8 @@ transformRangeTableFunc(ParseState *pstate, RangeTableFunc *rtf)
     */
    is_lateral = rtf->lateral || contain_vars_of_level((Node *) tf, 0);
 
-   rte = addRangeTableEntryForTableFunc(pstate,
-                                        tf, rtf->alias, is_lateral, true);
-
-   return rte;
+   return addRangeTableEntryForTableFunc(pstate,
+                                         tf, rtf->alias, is_lateral, true);
 }
 
 /*
@@ -1013,17 +1004,17 @@ transformRangeTableSample(ParseState *pstate, RangeTableSample *rts)
 }
 
 /*
- * getRTEForSpecialRelationTypes
+ * getNSItemForSpecialRelationTypes
  *
  * If given RangeVar refers to a CTE or an EphemeralNamedRelation,
- * build and return an appropriate RTE, otherwise return NULL
+ * build and return an appropriate ParseNamespaceItem, otherwise return NULL
  */
-static RangeTblEntry *
-getRTEForSpecialRelationTypes(ParseState *pstate, RangeVar *rv)
+static ParseNamespaceItem *
+getNSItemForSpecialRelationTypes(ParseState *pstate, RangeVar *rv)
 {
+   ParseNamespaceItem *nsitem;
    CommonTableExpr *cte;
    Index       levelsup;
-   RangeTblEntry *rte;
 
    /*
     * if it is a qualified name, it can't be a CTE or tuplestore reference
@@ -1033,13 +1024,13 @@ getRTEForSpecialRelationTypes(ParseState *pstate, RangeVar *rv)
 
    cte = scanNameSpaceForCTE(pstate, rv->relname, &levelsup);
    if (cte)
-       rte = addRangeTableEntryForCTE(pstate, cte, levelsup, rv, true);
+       nsitem = addRangeTableEntryForCTE(pstate, cte, levelsup, rv, true);
    else if (scanNameSpaceForENR(pstate, rv->relname))
-       rte = addRangeTableEntryForENR(pstate, rv, true);
+       nsitem = addRangeTableEntryForENR(pstate, rv, true);
    else
-       rte = NULL;
+       nsitem = NULL;
 
-   return rte;
+   return nsitem;
 }
 
 /*
@@ -1053,11 +1044,9 @@ getRTEForSpecialRelationTypes(ParseState *pstate, RangeVar *rv)
  * The function return value is the node to add to the jointree (a
  * RangeTblRef or JoinExpr).  Additional output parameters are:
  *
- * *top_rte: receives the RTE corresponding to the jointree item.
- * (We could extract this from the function return node, but it saves cycles
- * to pass it back separately.)
- *
- * *top_rti: receives the rangetable index of top_rte.  (Ditto.)
+ * *top_nsitem: receives the ParseNamespaceItem directly corresponding to the
+ * jointree item.  (This is only used during internal recursion, not by
+ * outside callers.)
  *
  * *namespace: receives a List of ParseNamespaceItems for the RTEs exposed
  * as table/column names by this item.  (The lateral_only flags in these items
@@ -1065,7 +1054,7 @@ getRTEForSpecialRelationTypes(ParseState *pstate, RangeVar *rv)
  */
 static Node *
 transformFromClauseItem(ParseState *pstate, Node *n,
-                       RangeTblEntry **top_rte, int *top_rti,
+                       ParseNamespaceItem **top_nsitem,
                        List **namespace)
 {
    if (IsA(n, RangeVar))
@@ -1073,78 +1062,58 @@ transformFromClauseItem(ParseState *pstate, Node *n,
        /* Plain relation reference, or perhaps a CTE reference */
        RangeVar   *rv = (RangeVar *) n;
        RangeTblRef *rtr;
-       RangeTblEntry *rte;
-       int         rtindex;
+       ParseNamespaceItem *nsitem;
 
        /* Check if it's a CTE or tuplestore reference */
-       rte = getRTEForSpecialRelationTypes(pstate, rv);
+       nsitem = getNSItemForSpecialRelationTypes(pstate, rv);
 
        /* if not found above, must be a table reference */
-       if (!rte)
-           rte = transformTableEntry(pstate, rv);
-
-       /* assume new rte is at end */
-       rtindex = list_length(pstate->p_rtable);
-       Assert(rte == rt_fetch(rtindex, pstate->p_rtable));
-       *top_rte = rte;
-       *top_rti = rtindex;
-       *namespace = list_make1(makeDefaultNSItem(rte, rtindex));
+       if (!nsitem)
+           nsitem = transformTableEntry(pstate, rv);
+
+       *top_nsitem = nsitem;
+       *namespace = list_make1(nsitem);
        rtr = makeNode(RangeTblRef);
-       rtr->rtindex = rtindex;
+       rtr->rtindex = nsitem->p_rtindex;
        return (Node *) rtr;
    }
    else if (IsA(n, RangeSubselect))
    {
        /* sub-SELECT is like a plain relation */
        RangeTblRef *rtr;
-       RangeTblEntry *rte;
-       int         rtindex;
-
-       rte = transformRangeSubselect(pstate, (RangeSubselect *) n);
-       /* assume new rte is at end */
-       rtindex = list_length(pstate->p_rtable);
-       Assert(rte == rt_fetch(rtindex, pstate->p_rtable));
-       *top_rte = rte;
-       *top_rti = rtindex;
-       *namespace = list_make1(makeDefaultNSItem(rte, rtindex));
+       ParseNamespaceItem *nsitem;
+
+       nsitem = transformRangeSubselect(pstate, (RangeSubselect *) n);
+       *top_nsitem = nsitem;
+       *namespace = list_make1(nsitem);
        rtr = makeNode(RangeTblRef);
-       rtr->rtindex = rtindex;
+       rtr->rtindex = nsitem->p_rtindex;
        return (Node *) rtr;
    }
    else if (IsA(n, RangeFunction))
    {
        /* function is like a plain relation */
        RangeTblRef *rtr;
-       RangeTblEntry *rte;
-       int         rtindex;
-
-       rte = transformRangeFunction(pstate, (RangeFunction *) n);
-       /* assume new rte is at end */
-       rtindex = list_length(pstate->p_rtable);
-       Assert(rte == rt_fetch(rtindex, pstate->p_rtable));
-       *top_rte = rte;
-       *top_rti = rtindex;
-       *namespace = list_make1(makeDefaultNSItem(rte, rtindex));
+       ParseNamespaceItem *nsitem;
+
+       nsitem = transformRangeFunction(pstate, (RangeFunction *) n);
+       *top_nsitem = nsitem;
+       *namespace = list_make1(nsitem);
        rtr = makeNode(RangeTblRef);
-       rtr->rtindex = rtindex;
+       rtr->rtindex = nsitem->p_rtindex;
        return (Node *) rtr;
    }
    else if (IsA(n, RangeTableFunc))
    {
        /* table function is like a plain relation */
        RangeTblRef *rtr;
-       RangeTblEntry *rte;
-       int         rtindex;
-
-       rte = transformRangeTableFunc(pstate, (RangeTableFunc *) n);
-       /* assume new rte is at end */
-       rtindex = list_length(pstate->p_rtable);
-       Assert(rte == rt_fetch(rtindex, pstate->p_rtable));
-       *top_rte = rte;
-       *top_rti = rtindex;
-       *namespace = list_make1(makeDefaultNSItem(rte, rtindex));
+       ParseNamespaceItem *nsitem;
+
+       nsitem = transformRangeTableFunc(pstate, (RangeTableFunc *) n);
+       *top_nsitem = nsitem;
+       *namespace = list_make1(nsitem);
        rtr = makeNode(RangeTblRef);
-       rtr->rtindex = rtindex;
+       rtr->rtindex = nsitem->p_rtindex;
        return (Node *) rtr;
    }
    else if (IsA(n, RangeTableSample))
@@ -1152,19 +1121,17 @@ transformFromClauseItem(ParseState *pstate, Node *n,
        /* TABLESAMPLE clause (wrapping some other valid FROM node) */
        RangeTableSample *rts = (RangeTableSample *) n;
        Node       *rel;
-       RangeTblRef *rtr;
        RangeTblEntry *rte;
 
        /* Recursively transform the contained relation */
        rel = transformFromClauseItem(pstate, rts->relation,
-                                     top_rte, top_rti, namespace);
-       /* Currently, grammar could only return a RangeVar as contained rel */
-       rtr = castNode(RangeTblRef, rel);
-       rte = rt_fetch(rtr->rtindex, pstate->p_rtable);
+                                     top_nsitem, namespace);
+       rte = (*top_nsitem)->p_rte;
        /* We only support this on plain relations and matviews */
-       if (rte->relkind != RELKIND_RELATION &&
-           rte->relkind != RELKIND_MATVIEW &&
-           rte->relkind != RELKIND_PARTITIONED_TABLE)
+       if (rte->rtekind != RTE_RELATION ||
+           (rte->relkind != RELKIND_RELATION &&
+            rte->relkind != RELKIND_MATVIEW &&
+            rte->relkind != RELKIND_PARTITIONED_TABLE))
            ereport(ERROR,
                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                     errmsg("TABLESAMPLE clause can only be applied to tables and materialized views"),
@@ -1172,16 +1139,15 @@ transformFromClauseItem(ParseState *pstate, Node *n,
 
        /* Transform TABLESAMPLE details and attach to the RTE */
        rte->tablesample = transformRangeTableSample(pstate, rts);
-       return (Node *) rtr;
+       return rel;
    }
    else if (IsA(n, JoinExpr))
    {
        /* A newfangled join expression */
        JoinExpr   *j = (JoinExpr *) n;
-       RangeTblEntry *l_rte;
-       RangeTblEntry *r_rte;
-       int         l_rtindex;
-       int         r_rtindex;
+       ParseNamespaceItem *nsitem;
+       ParseNamespaceItem *l_nsitem;
+       ParseNamespaceItem *r_nsitem;
        List       *l_namespace,
                   *r_namespace,
                   *my_namespace,
@@ -1191,9 +1157,10 @@ transformFromClauseItem(ParseState *pstate, Node *n,
                   *l_colvars,
                   *r_colvars,
                   *res_colvars;
+       ParseNamespaceColumn *res_nscolumns;
+       int         res_colindex;
        bool        lateral_ok;
        int         sv_namespace_length;
-       RangeTblEntry *rte;
        int         k;
 
        /*
@@ -1201,8 +1168,7 @@ transformFromClauseItem(ParseState *pstate, Node *n,
         * it in this order for correct visibility of LATERAL references.
         */
        j->larg = transformFromClauseItem(pstate, j->larg,
-                                         &l_rte,
-                                         &l_rtindex,
+                                         &l_nsitem,
                                          &l_namespace);
 
        /*
@@ -1225,8 +1191,7 @@ transformFromClauseItem(ParseState *pstate, Node *n,
 
        /* And now we can process the RHS */
        j->rarg = transformFromClauseItem(pstate, j->rarg,
-                                         &r_rte,
-                                         &r_rtindex,
+                                         &r_nsitem,
                                          &r_namespace);
 
        /* Remove the left-side RTEs from the namespace list again */
@@ -1248,12 +1213,10 @@ transformFromClauseItem(ParseState *pstate, Node *n,
        /*
         * Extract column name and var lists from both subtrees
         *
-        * Note: expandRTE returns new lists, safe for me to modify
+        * Note: expandNSItemVars returns new lists, safe for me to modify
         */
-       expandRTE(l_rte, l_rtindex, 0, -1, false,
-                 &l_colnames, &l_colvars);
-       expandRTE(r_rte, r_rtindex, 0, -1, false,
-                 &r_colnames, &r_colvars);
+       l_colvars = expandNSItemVars(l_nsitem, 0, -1, &l_colnames);
+       r_colvars = expandNSItemVars(r_nsitem, 0, -1, &r_colnames);
 
        /*
         * Natural join does not explicitly specify columns; must generate
@@ -1302,6 +1265,12 @@ transformFromClauseItem(ParseState *pstate, Node *n,
        res_colnames = NIL;
        res_colvars = NIL;
 
+       /* this may be larger than needed, but it's not worth being exact */
+       res_nscolumns = (ParseNamespaceColumn *)
+           palloc0((list_length(l_colnames) + list_length(r_colnames)) *
+                   sizeof(ParseNamespaceColumn));
+       res_colindex = 0;
+
        if (j->usingClause)
        {
            /*
@@ -1325,6 +1294,8 @@ transformFromClauseItem(ParseState *pstate, Node *n,
                int         r_index = -1;
                Var        *l_colvar,
                           *r_colvar;
+               Node       *u_colvar;
+               ParseNamespaceColumn *res_nscolumn;
 
                /* Check for USING(foo,foo) */
                foreach(col, res_colnames)
@@ -1390,16 +1361,58 @@ transformFromClauseItem(ParseState *pstate, Node *n,
                r_usingvars = lappend(r_usingvars, r_colvar);
 
                res_colnames = lappend(res_colnames, lfirst(ucol));
-               res_colvars = lappend(res_colvars,
-                                     buildMergedJoinVar(pstate,
-                                                        j->jointype,
-                                                        l_colvar,
-                                                        r_colvar));
+               u_colvar = buildMergedJoinVar(pstate,
+                                             j->jointype,
+                                             l_colvar,
+                                             r_colvar);
+               res_colvars = lappend(res_colvars, u_colvar);
+               res_nscolumn = res_nscolumns + res_colindex;
+               res_colindex++;
+               if (u_colvar == (Node *) l_colvar)
+               {
+                   /* Merged column is equivalent to left input */
+                   res_nscolumn->p_varno = l_colvar->varno;
+                   res_nscolumn->p_varattno = l_colvar->varattno;
+                   res_nscolumn->p_vartype = l_colvar->vartype;
+                   res_nscolumn->p_vartypmod = l_colvar->vartypmod;
+                   res_nscolumn->p_varcollid = l_colvar->varcollid;
+                   /* XXX these are not quite right, but doesn't matter yet */
+                   res_nscolumn->p_varnosyn = l_colvar->varno;
+                   res_nscolumn->p_varattnosyn = l_colvar->varattno;
+               }
+               else if (u_colvar == (Node *) r_colvar)
+               {
+                   /* Merged column is equivalent to right input */
+                   res_nscolumn->p_varno = r_colvar->varno;
+                   res_nscolumn->p_varattno = r_colvar->varattno;
+                   res_nscolumn->p_vartype = r_colvar->vartype;
+                   res_nscolumn->p_vartypmod = r_colvar->vartypmod;
+                   res_nscolumn->p_varcollid = r_colvar->varcollid;
+                   /* XXX these are not quite right, but doesn't matter yet */
+                   res_nscolumn->p_varnosyn = r_colvar->varno;
+                   res_nscolumn->p_varattnosyn = r_colvar->varattno;
+               }
+               else
+               {
+                   /*
+                    * Merged column is not semantically equivalent to either
+                    * input, so it needs to be referenced as the join output
+                    * column.  We don't know the join's varno yet, so we'll
+                    * replace these zeroes below.
+                    */
+                   res_nscolumn->p_varno = 0;
+                   res_nscolumn->p_varattno = res_colindex;
+                   res_nscolumn->p_vartype = exprType(u_colvar);
+                   res_nscolumn->p_vartypmod = exprTypmod(u_colvar);
+                   res_nscolumn->p_varcollid = exprCollation(u_colvar);
+                   res_nscolumn->p_varnosyn = 0;
+                   res_nscolumn->p_varattnosyn = res_colindex;
+               }
            }
 
            j->quals = transformJoinUsingClause(pstate,
-                                               l_rte,
-                                               r_rte,
+                                               l_nsitem->p_rte,
+                                               r_nsitem->p_rte,
                                                l_usingvars,
                                                r_usingvars);
        }
@@ -1416,10 +1429,16 @@ transformFromClauseItem(ParseState *pstate, Node *n,
        /* Add remaining columns from each side to the output columns */
        extractRemainingColumns(res_colnames,
                                l_colnames, l_colvars,
-                               &l_colnames, &l_colvars);
+                               l_nsitem->p_nscolumns,
+                               &l_colnames, &l_colvars,
+                               res_nscolumns + res_colindex);
+       res_colindex += list_length(l_colvars);
        extractRemainingColumns(res_colnames,
                                r_colnames, r_colvars,
-                               &r_colnames, &r_colvars);
+                               r_nsitem->p_nscolumns,
+                               &r_colnames, &r_colvars,
+                               res_nscolumns + res_colindex);
+       res_colindex += list_length(r_colvars);
        res_colnames = list_concat(res_colnames, l_colnames);
        res_colvars = list_concat(res_colvars, l_colvars);
        res_colnames = list_concat(res_colnames, r_colnames);
@@ -1441,21 +1460,41 @@ transformFromClauseItem(ParseState *pstate, Node *n,
        }
 
        /*
-        * Now build an RTE for the result of the join
+        * Now build an RTE and nsitem for the result of the join.
+        * res_nscolumns isn't totally done yet, but that's OK because
+        * addRangeTableEntryForJoin doesn't examine it, only store a pointer.
         */
-       rte = addRangeTableEntryForJoin(pstate,
-                                       res_colnames,
-                                       j->jointype,
-                                       res_colvars,
-                                       j->alias,
-                                       true);
+       nsitem = addRangeTableEntryForJoin(pstate,
+                                          res_colnames,
+                                          res_nscolumns,
+                                          j->jointype,
+                                          res_colvars,
+                                          j->alias,
+                                          true);
 
-       /* assume new rte is at end */
-       j->rtindex = list_length(pstate->p_rtable);
-       Assert(rte == rt_fetch(j->rtindex, pstate->p_rtable));
+       j->rtindex = nsitem->p_rtindex;
 
-       *top_rte = rte;
-       *top_rti = j->rtindex;
+       /*
+        * Now that we know the join RTE's rangetable index, we can fix up the
+        * res_nscolumns data in places where it should contain that.
+        */
+       Assert(res_colindex == list_length(nsitem->p_rte->eref->colnames));
+       for (k = 0; k < res_colindex; k++)
+       {
+           ParseNamespaceColumn *nscol = res_nscolumns + k;
+
+           /* fill in join RTI for merged columns */
+           if (nscol->p_varno == 0)
+               nscol->p_varno = j->rtindex;
+           if (nscol->p_varnosyn == 0)
+               nscol->p_varnosyn = j->rtindex;
+           /* if join has an alias, it syntactically hides all inputs */
+           if (j->alias)
+           {
+               nscol->p_varnosyn = j->rtindex;
+               nscol->p_varattnosyn = k + 1;
+           }
+       }
 
        /* make a matching link to the JoinExpr for later use */
        for (k = list_length(pstate->p_joinexprs) + 1; k < j->rtindex; k++)
@@ -1483,13 +1522,13 @@ transformFromClauseItem(ParseState *pstate, Node *n,
         * The join RTE itself is always made visible for unqualified column
         * names.  It's visible as a relation name only if it has an alias.
         */
-       *namespace = lappend(my_namespace,
-                            makeNamespaceItem(rte,
-                                              j->rtindex,
-                                              (j->alias != NULL),
-                                              true,
-                                              false,
-                                              true));
+       nsitem->p_rel_visible = (j->alias != NULL);
+       nsitem->p_cols_visible = true;
+       nsitem->p_lateral_only = false;
+       nsitem->p_lateral_ok = true;
+
+       *top_nsitem = nsitem;
+       *namespace = lappend(my_namespace, nsitem);
 
        return (Node *) j;
    }
@@ -1617,27 +1656,6 @@ buildMergedJoinVar(ParseState *pstate, JoinType jointype,
    return res_node;
 }
 
-/*
- * makeNamespaceItem -
- *   Convenience subroutine to construct a ParseNamespaceItem.
- */
-static ParseNamespaceItem *
-makeNamespaceItem(RangeTblEntry *rte, int rtindex,
-                 bool rel_visible, bool cols_visible,
-                 bool lateral_only, bool lateral_ok)
-{
-   ParseNamespaceItem *nsitem;
-
-   nsitem = (ParseNamespaceItem *) palloc(sizeof(ParseNamespaceItem));
-   nsitem->p_rte = rte;
-   nsitem->p_rtindex = rtindex;
-   nsitem->p_rel_visible = rel_visible;
-   nsitem->p_cols_visible = cols_visible;
-   nsitem->p_lateral_only = lateral_only;
-   nsitem->p_lateral_ok = lateral_ok;
-   return nsitem;
-}
-
 /*
  * setNamespaceColumnVisibility -
  *   Convenience subroutine to update cols_visible flags in a namespace list.
@@ -3163,8 +3181,8 @@ transformOnConflictArbiter(ParseState *pstate,
         */
        save_namespace = pstate->p_namespace;
        pstate->p_namespace = NIL;
-       addRTEtoQuery(pstate, pstate->p_target_rangetblentry,
-                     false, false, true);
+       addNSItemToQuery(pstate, pstate->p_target_nsitem,
+                        false, false, true);
 
        if (infer->indexElems)
            *arbiterExpr = resolve_unique_index_expr(pstate, infer,
@@ -3189,7 +3207,7 @@ transformOnConflictArbiter(ParseState *pstate,
        if (infer->conname)
        {
            Oid         relid = RelationGetRelid(pstate->p_target_relation);
-           RangeTblEntry *rte = pstate->p_target_rangetblentry;
+           RangeTblEntry *rte = pstate->p_target_nsitem->p_rte;
            Bitmapset  *conattnos;
 
            conattnos = get_relation_constraint_attnos(relid, infer->conname,
index 8e9cde7bd0cc371a4d02e5360711314612ee18fa..929f758ef45441bd026fc412f123a0ae4d816464 100644 (file)
@@ -1010,11 +1010,10 @@ coerce_record_to_complex(ParseState *pstate, Node *node,
        int         rtindex = ((Var *) node)->varno;
        int         sublevels_up = ((Var *) node)->varlevelsup;
        int         vlocation = ((Var *) node)->location;
-       RangeTblEntry *rte;
+       ParseNamespaceItem *nsitem;
 
-       rte = GetRTEByRangeTablePosn(pstate, rtindex, sublevels_up);
-       expandRTE(rte, rtindex, sublevels_up, vlocation, false,
-                 NULL, &args);
+       nsitem = GetNSItemByRangeTablePosn(pstate, rtindex, sublevels_up);
+       args = expandNSItemVars(nsitem, sublevels_up, vlocation, NULL);
    }
    else
        ereport(ERROR,
index 02b8d0aca349265f476db907d527c722d6130ab5..831db4af9559c18589ef81211cee09fe495b1dc0 100644 (file)
@@ -2656,8 +2656,8 @@ static Node *
 transformCurrentOfExpr(ParseState *pstate, CurrentOfExpr *cexpr)
 {
    /* CURRENT OF can only appear at top level of UPDATE/DELETE */
-   Assert(pstate->p_target_rtindex > 0);
-   cexpr->cvarno = pstate->p_target_rtindex;
+   Assert(pstate->p_target_nsitem != NULL);
+   cexpr->cvarno = pstate->p_target_nsitem->p_rtindex;
 
    /*
     * Check to see if the cursor name matches a parameter of type REFCURSOR.
index 6dc33e2411c0127d4be76e356070f4f4547e635f..d7c4bae8ccfee8bbc5241de8b5bd689f7714535c 100644 (file)
@@ -472,7 +472,8 @@ check_lateral_ref_ok(ParseState *pstate, ParseNamespaceItem *nsitem,
                (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
                 errmsg("invalid reference to FROM-clause entry for table \"%s\"",
                        refname),
-                (rte == pstate->p_target_rangetblentry) ?
+                (pstate->p_target_nsitem != NULL &&
+                 rte == pstate->p_target_nsitem->p_rte) ?
                 errhint("There is an entry for table \"%s\", but it cannot be referenced from this part of the query.",
                         refname) :
                 errdetail("The combining JOIN type must be INNER or LEFT for a LATERAL reference."),
@@ -669,9 +670,6 @@ scanNSItemForColumn(ParseState *pstate, ParseNamespaceItem *nsitem,
    RangeTblEntry *rte = nsitem->p_rte;
    int         attnum;
    Var        *var;
-   Oid         vartypeid;
-   int32       vartypmod;
-   Oid         varcollid;
 
    /*
     * Scan the RTE's column names (or aliases) for a match.  Complain if
@@ -703,11 +701,39 @@ scanNSItemForColumn(ParseState *pstate, ParseNamespaceItem *nsitem,
                 parser_errposition(pstate, location)));
 
    /* Found a valid match, so build a Var */
-   get_rte_attribute_type(rte, attnum,
-                          &vartypeid, &vartypmod, &varcollid);
-   var = makeVar(nsitem->p_rtindex, attnum,
-                 vartypeid, vartypmod, varcollid,
-                 sublevels_up);
+   if (attnum > InvalidAttrNumber)
+   {
+       /* Get attribute data from the ParseNamespaceColumn array */
+       ParseNamespaceColumn *nscol = &nsitem->p_nscolumns[attnum - 1];
+
+       /* Complain if dropped column.  See notes in scanRTEForColumn. */
+       if (nscol->p_varno == 0)
+           ereport(ERROR,
+                   (errcode(ERRCODE_UNDEFINED_COLUMN),
+                    errmsg("column \"%s\" of relation \"%s\" does not exist",
+                           colname,
+                           rte->eref->aliasname)));
+
+       var = makeVar(nsitem->p_rtindex,
+                     attnum,
+                     nscol->p_vartype,
+                     nscol->p_vartypmod,
+                     nscol->p_varcollid,
+                     sublevels_up);
+   }
+   else
+   {
+       /* System column, so use predetermined type data */
+       const FormData_pg_attribute *sysatt;
+
+       sysatt = SystemAttributeDefinition(attnum);
+       var = makeVar(nsitem->p_rtindex,
+                     attnum,
+                     sysatt->atttypid,
+                     sysatt->atttypmod,
+                     sysatt->attcollation,
+                     sublevels_up);
+   }
    var->location = location;
 
    /* Require read access to the column */
@@ -753,11 +779,9 @@ scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte,
     * don't bother to test for that case here.
     *
     * Should this somehow go wrong and we try to access a dropped column,
-    * we'll still catch it by virtue of the checks in
-    * get_rte_attribute_type(), which is called by scanNSItemForColumn().
-    * That routine has to do a cache lookup anyway, so the check there is
-    * cheap.  Callers interested in finding match with shortest distance need
-    * to defend against this directly, though.
+    * we'll still catch it by virtue of the check in scanNSItemForColumn().
+    * Callers interested in finding match with shortest distance need to
+    * defend against this directly, though.
     */
    foreach(c, rte->eref->colnames)
    {
@@ -1200,6 +1224,121 @@ chooseScalarFunctionAlias(Node *funcexpr, char *funcname,
    return funcname;
 }
 
+/*
+ * buildNSItemFromTupleDesc
+ *     Build a ParseNamespaceItem, given a tupdesc describing the columns.
+ *
+ * rte: the new RangeTblEntry for the rel
+ * rtindex: its index in the rangetable list
+ * tupdesc: the physical column information
+ */
+static ParseNamespaceItem *
+buildNSItemFromTupleDesc(RangeTblEntry *rte, Index rtindex, TupleDesc tupdesc)
+{
+   ParseNamespaceItem *nsitem;
+   ParseNamespaceColumn *nscolumns;
+   int         maxattrs = tupdesc->natts;
+   int         varattno;
+
+   /* colnames must have the same number of entries as the nsitem */
+   Assert(maxattrs == list_length(rte->eref->colnames));
+
+   /* extract per-column data from the tupdesc */
+   nscolumns = (ParseNamespaceColumn *)
+       palloc0(maxattrs * sizeof(ParseNamespaceColumn));
+
+   for (varattno = 0; varattno < maxattrs; varattno++)
+   {
+       Form_pg_attribute attr = TupleDescAttr(tupdesc, varattno);
+
+       /* For a dropped column, just leave the entry as zeroes */
+       if (attr->attisdropped)
+           continue;
+
+       nscolumns[varattno].p_varno = rtindex;
+       nscolumns[varattno].p_varattno = varattno + 1;
+       nscolumns[varattno].p_vartype = attr->atttypid;
+       nscolumns[varattno].p_vartypmod = attr->atttypmod;
+       nscolumns[varattno].p_varcollid = attr->attcollation;
+       nscolumns[varattno].p_varnosyn = rtindex;
+       nscolumns[varattno].p_varattnosyn = varattno + 1;
+   }
+
+   /* ... and build the nsitem */
+   nsitem = (ParseNamespaceItem *) palloc(sizeof(ParseNamespaceItem));
+   nsitem->p_rte = rte;
+   nsitem->p_rtindex = rtindex;
+   nsitem->p_nscolumns = nscolumns;
+   /* set default visibility flags; might get changed later */
+   nsitem->p_rel_visible = true;
+   nsitem->p_cols_visible = true;
+   nsitem->p_lateral_only = false;
+   nsitem->p_lateral_ok = true;
+
+   return nsitem;
+}
+
+/*
+ * buildNSItemFromLists
+ *     Build a ParseNamespaceItem, given column type information in lists.
+ *
+ * rte: the new RangeTblEntry for the rel
+ * rtindex: its index in the rangetable list
+ * coltypes: per-column datatype OIDs
+ * coltypmods: per-column type modifiers
+ * colcollation: per-column collation OIDs
+ */
+static ParseNamespaceItem *
+buildNSItemFromLists(RangeTblEntry *rte, Index rtindex,
+                    List *coltypes, List *coltypmods, List *colcollations)
+{
+   ParseNamespaceItem *nsitem;
+   ParseNamespaceColumn *nscolumns;
+   int         maxattrs = list_length(coltypes);
+   int         varattno;
+   ListCell   *lct;
+   ListCell   *lcm;
+   ListCell   *lcc;
+
+   /* colnames must have the same number of entries as the nsitem */
+   Assert(maxattrs == list_length(rte->eref->colnames));
+
+   Assert(maxattrs == list_length(coltypmods));
+   Assert(maxattrs == list_length(colcollations));
+
+   /* extract per-column data from the lists */
+   nscolumns = (ParseNamespaceColumn *)
+       palloc0(maxattrs * sizeof(ParseNamespaceColumn));
+
+   varattno = 0;
+   forthree(lct, coltypes,
+            lcm, coltypmods,
+            lcc, colcollations)
+   {
+       nscolumns[varattno].p_varno = rtindex;
+       nscolumns[varattno].p_varattno = varattno + 1;
+       nscolumns[varattno].p_vartype = lfirst_oid(lct);
+       nscolumns[varattno].p_vartypmod = lfirst_int(lcm);
+       nscolumns[varattno].p_varcollid = lfirst_oid(lcc);
+       nscolumns[varattno].p_varnosyn = rtindex;
+       nscolumns[varattno].p_varattnosyn = varattno + 1;
+       varattno++;
+   }
+
+   /* ... and build the nsitem */
+   nsitem = (ParseNamespaceItem *) palloc(sizeof(ParseNamespaceItem));
+   nsitem->p_rte = rte;
+   nsitem->p_rtindex = rtindex;
+   nsitem->p_nscolumns = nscolumns;
+   /* set default visibility flags; might get changed later */
+   nsitem->p_rel_visible = true;
+   nsitem->p_cols_visible = true;
+   nsitem->p_lateral_only = false;
+   nsitem->p_lateral_ok = true;
+
+   return nsitem;
+}
+
 /*
  * Open a table during parse analysis
  *
@@ -1255,11 +1394,15 @@ parserOpenTable(ParseState *pstate, const RangeVar *relation, int lockmode)
 
 /*
  * Add an entry for a relation to the pstate's range table (p_rtable).
+ * Then, construct and return a ParseNamespaceItem for the new RTE.
+ *
+ * We do not link the ParseNamespaceItem into the pstate here; it's the
+ * caller's job to do that in the appropriate way.
  *
  * Note: formerly this checked for refname conflicts, but that's wrong.
  * Caller is responsible for checking for conflicts in the appropriate scope.
  */
-RangeTblEntry *
+ParseNamespaceItem *
 addRangeTableEntry(ParseState *pstate,
                   RangeVar *relation,
                   Alias *alias,
@@ -1270,6 +1413,7 @@ addRangeTableEntry(ParseState *pstate,
    char       *refname = alias ? alias->aliasname : relation->relname;
    LOCKMODE    lockmode;
    Relation    rel;
+   ParseNamespaceItem *nsitem;
 
    Assert(pstate != NULL);
 
@@ -1301,13 +1445,6 @@ addRangeTableEntry(ParseState *pstate,
    rte->eref = makeAlias(refname, NIL);
    buildRelationAliases(rel->rd_att, alias, rte->eref);
 
-   /*
-    * Drop the rel refcount, but keep the access lock till end of transaction
-    * so that the table can't be deleted or have its schema modified
-    * underneath us.
-    */
-   table_close(rel, NoLock);
-
    /*
     * Set flags and access permissions.
     *
@@ -1326,16 +1463,32 @@ addRangeTableEntry(ParseState *pstate,
    rte->extraUpdatedCols = NULL;
 
    /*
-    * Add completed RTE to pstate's range table list, but not to join list
-    * nor namespace --- caller must do that if appropriate.
+    * Add completed RTE to pstate's range table list, so that we know its
+    * index.  But we don't add it to the join list --- caller must do that if
+    * appropriate.
     */
    pstate->p_rtable = lappend(pstate->p_rtable, rte);
 
-   return rte;
+   /*
+    * Build a ParseNamespaceItem, but don't add it to the pstate's namespace
+    * list --- caller must do that if appropriate.
+    */
+   nsitem = buildNSItemFromTupleDesc(rte, list_length(pstate->p_rtable),
+                                     rel->rd_att);
+
+   /*
+    * Drop the rel refcount, but keep the access lock till end of transaction
+    * so that the table can't be deleted or have its schema modified
+    * underneath us.
+    */
+   table_close(rel, NoLock);
+
+   return nsitem;
 }
 
 /*
  * Add an entry for a relation to the pstate's range table (p_rtable).
+ * Then, construct and return a ParseNamespaceItem for the new RTE.
  *
  * This is just like addRangeTableEntry() except that it makes an RTE
  * given an already-open relation instead of a RangeVar reference.
@@ -1349,7 +1502,7 @@ addRangeTableEntry(ParseState *pstate,
  * would require importing storage/lock.h into parse_relation.h.  Since
  * LOCKMODE is typedef'd as int anyway, that seems like overkill.
  */
-RangeTblEntry *
+ParseNamespaceItem *
 addRangeTableEntryForRelation(ParseState *pstate,
                              Relation rel,
                              int lockmode,
@@ -1398,21 +1551,28 @@ addRangeTableEntryForRelation(ParseState *pstate,
    rte->extraUpdatedCols = NULL;
 
    /*
-    * Add completed RTE to pstate's range table list, but not to join list
-    * nor namespace --- caller must do that if appropriate.
+    * Add completed RTE to pstate's range table list, so that we know its
+    * index.  But we don't add it to the join list --- caller must do that if
+    * appropriate.
     */
    pstate->p_rtable = lappend(pstate->p_rtable, rte);
 
-   return rte;
+   /*
+    * Build a ParseNamespaceItem, but don't add it to the pstate's namespace
+    * list --- caller must do that if appropriate.
+    */
+   return buildNSItemFromTupleDesc(rte, list_length(pstate->p_rtable),
+                                   rel->rd_att);
 }
 
 /*
  * Add an entry for a subquery to the pstate's range table (p_rtable).
+ * Then, construct and return a ParseNamespaceItem for the new RTE.
  *
- * This is just like addRangeTableEntry() except that it makes a subquery RTE.
+ * This is much like addRangeTableEntry() except that it makes a subquery RTE.
  * Note that an alias clause *must* be supplied.
  */
-RangeTblEntry *
+ParseNamespaceItem *
 addRangeTableEntryForSubquery(ParseState *pstate,
                              Query *subquery,
                              Alias *alias,
@@ -1423,6 +1583,9 @@ addRangeTableEntryForSubquery(ParseState *pstate,
    char       *refname = alias->aliasname;
    Alias      *eref;
    int         numaliases;
+   List       *coltypes,
+              *coltypmods,
+              *colcollations;
    int         varattno;
    ListCell   *tlistitem;
 
@@ -1435,7 +1598,8 @@ addRangeTableEntryForSubquery(ParseState *pstate,
    eref = copyObject(alias);
    numaliases = list_length(eref->colnames);
 
-   /* fill in any unspecified alias columns */
+   /* fill in any unspecified alias columns, and extract column type info */
+   coltypes = coltypmods = colcollations = NIL;
    varattno = 0;
    foreach(tlistitem, subquery->targetList)
    {
@@ -1452,6 +1616,12 @@ addRangeTableEntryForSubquery(ParseState *pstate,
            attrname = pstrdup(te->resname);
            eref->colnames = lappend(eref->colnames, makeString(attrname));
        }
+       coltypes = lappend_oid(coltypes,
+                              exprType((Node *) te->expr));
+       coltypmods = lappend_int(coltypmods,
+                                exprTypmod((Node *) te->expr));
+       colcollations = lappend_oid(colcollations,
+                                   exprCollation((Node *) te->expr));
    }
    if (varattno < numaliases)
        ereport(ERROR,
@@ -1478,21 +1648,27 @@ addRangeTableEntryForSubquery(ParseState *pstate,
    rte->extraUpdatedCols = NULL;
 
    /*
-    * Add completed RTE to pstate's range table list, but not to join list
-    * nor namespace --- caller must do that if appropriate.
+    * Add completed RTE to pstate's range table list, so that we know its
+    * index.  But we don't add it to the join list --- caller must do that if
+    * appropriate.
     */
    pstate->p_rtable = lappend(pstate->p_rtable, rte);
 
-   return rte;
+   /*
+    * Build a ParseNamespaceItem, but don't add it to the pstate's namespace
+    * list --- caller must do that if appropriate.
+    */
+   return buildNSItemFromLists(rte, list_length(pstate->p_rtable),
+                               coltypes, coltypmods, colcollations);
 }
 
 /*
  * Add an entry for a function (or functions) to the pstate's range table
- * (p_rtable).
+ * (p_rtable).  Then, construct and return a ParseNamespaceItem for the new RTE.
  *
- * This is just like addRangeTableEntry() except that it makes a function RTE.
+ * This is much like addRangeTableEntry() except that it makes a function RTE.
  */
-RangeTblEntry *
+ParseNamespaceItem *
 addRangeTableEntryForFunction(ParseState *pstate,
                              List *funcnames,
                              List *funcexprs,
@@ -1742,20 +1918,27 @@ addRangeTableEntryForFunction(ParseState *pstate,
    rte->extraUpdatedCols = NULL;
 
    /*
-    * Add completed RTE to pstate's range table list, but not to join list
-    * nor namespace --- caller must do that if appropriate.
+    * Add completed RTE to pstate's range table list, so that we know its
+    * index.  But we don't add it to the join list --- caller must do that if
+    * appropriate.
     */
    pstate->p_rtable = lappend(pstate->p_rtable, rte);
 
-   return rte;
+   /*
+    * Build a ParseNamespaceItem, but don't add it to the pstate's namespace
+    * list --- caller must do that if appropriate.
+    */
+   return buildNSItemFromTupleDesc(rte, list_length(pstate->p_rtable),
+                                   tupdesc);
 }
 
 /*
  * Add an entry for a table function to the pstate's range table (p_rtable).
+ * Then, construct and return a ParseNamespaceItem for the new RTE.
  *
  * This is much like addRangeTableEntry() except that it makes a tablefunc RTE.
  */
-RangeTblEntry *
+ParseNamespaceItem *
 addRangeTableEntryForTableFunc(ParseState *pstate,
                               TableFunc *tf,
                               Alias *alias,
@@ -1806,20 +1989,28 @@ addRangeTableEntryForTableFunc(ParseState *pstate,
    rte->extraUpdatedCols = NULL;
 
    /*
-    * Add completed RTE to pstate's range table list, but not to join list
-    * nor namespace --- caller must do that if appropriate.
+    * Add completed RTE to pstate's range table list, so that we know its
+    * index.  But we don't add it to the join list --- caller must do that if
+    * appropriate.
     */
    pstate->p_rtable = lappend(pstate->p_rtable, rte);
 
-   return rte;
+   /*
+    * Build a ParseNamespaceItem, but don't add it to the pstate's namespace
+    * list --- caller must do that if appropriate.
+    */
+   return buildNSItemFromLists(rte, list_length(pstate->p_rtable),
+                               rte->coltypes, rte->coltypmods,
+                               rte->colcollations);
 }
 
 /*
  * Add an entry for a VALUES list to the pstate's range table (p_rtable).
+ * Then, construct and return a ParseNamespaceItem for the new RTE.
  *
  * This is much like addRangeTableEntry() except that it makes a values RTE.
  */
-RangeTblEntry *
+ParseNamespaceItem *
 addRangeTableEntryForValues(ParseState *pstate,
                            List *exprs,
                            List *coltypes,
@@ -1885,22 +2076,33 @@ addRangeTableEntryForValues(ParseState *pstate,
    rte->extraUpdatedCols = NULL;
 
    /*
-    * Add completed RTE to pstate's range table list, but not to join list
-    * nor namespace --- caller must do that if appropriate.
+    * Add completed RTE to pstate's range table list, so that we know its
+    * index.  But we don't add it to the join list --- caller must do that if
+    * appropriate.
     */
    pstate->p_rtable = lappend(pstate->p_rtable, rte);
 
-   return rte;
+   /*
+    * Build a ParseNamespaceItem, but don't add it to the pstate's namespace
+    * list --- caller must do that if appropriate.
+    */
+   return buildNSItemFromLists(rte, list_length(pstate->p_rtable),
+                               rte->coltypes, rte->coltypmods,
+                               rte->colcollations);
 }
 
 /*
  * Add an entry for a join to the pstate's range table (p_rtable).
+ * Then, construct and return a ParseNamespaceItem for the new RTE.
  *
  * This is much like addRangeTableEntry() except that it makes a join RTE.
+ * Also, it's more convenient for the caller to construct the
+ * ParseNamespaceColumn array, so we pass that in.
  */
-RangeTblEntry *
+ParseNamespaceItem *
 addRangeTableEntryForJoin(ParseState *pstate,
                          List *colnames,
+                         ParseNamespaceColumn *nscolumns,
                          JoinType jointype,
                          List *aliasvars,
                          Alias *alias,
@@ -1909,6 +2111,7 @@ addRangeTableEntryForJoin(ParseState *pstate,
    RangeTblEntry *rte = makeNode(RangeTblEntry);
    Alias      *eref;
    int         numaliases;
+   ParseNamespaceItem *nsitem;
 
    Assert(pstate != NULL);
 
@@ -1956,20 +2159,36 @@ addRangeTableEntryForJoin(ParseState *pstate,
    rte->extraUpdatedCols = NULL;
 
    /*
-    * Add completed RTE to pstate's range table list, but not to join list
-    * nor namespace --- caller must do that if appropriate.
+    * Add completed RTE to pstate's range table list, so that we know its
+    * index.  But we don't add it to the join list --- caller must do that if
+    * appropriate.
     */
    pstate->p_rtable = lappend(pstate->p_rtable, rte);
 
-   return rte;
+   /*
+    * Build a ParseNamespaceItem, but don't add it to the pstate's namespace
+    * list --- caller must do that if appropriate.
+    */
+   nsitem = (ParseNamespaceItem *) palloc(sizeof(ParseNamespaceItem));
+   nsitem->p_rte = rte;
+   nsitem->p_rtindex = list_length(pstate->p_rtable);
+   nsitem->p_nscolumns = nscolumns;
+   /* set default visibility flags; might get changed later */
+   nsitem->p_rel_visible = true;
+   nsitem->p_cols_visible = true;
+   nsitem->p_lateral_only = false;
+   nsitem->p_lateral_ok = true;
+
+   return nsitem;
 }
 
 /*
  * Add an entry for a CTE reference to the pstate's range table (p_rtable).
+ * Then, construct and return a ParseNamespaceItem for the new RTE.
  *
  * This is much like addRangeTableEntry() except that it makes a CTE RTE.
  */
-RangeTblEntry *
+ParseNamespaceItem *
 addRangeTableEntryForCTE(ParseState *pstate,
                         CommonTableExpr *cte,
                         Index levelsup,
@@ -2059,17 +2278,25 @@ addRangeTableEntryForCTE(ParseState *pstate,
    rte->extraUpdatedCols = NULL;
 
    /*
-    * Add completed RTE to pstate's range table list, but not to join list
-    * nor namespace --- caller must do that if appropriate.
+    * Add completed RTE to pstate's range table list, so that we know its
+    * index.  But we don't add it to the join list --- caller must do that if
+    * appropriate.
     */
    pstate->p_rtable = lappend(pstate->p_rtable, rte);
 
-   return rte;
+   /*
+    * Build a ParseNamespaceItem, but don't add it to the pstate's namespace
+    * list --- caller must do that if appropriate.
+    */
+   return buildNSItemFromLists(rte, list_length(pstate->p_rtable),
+                               rte->coltypes, rte->coltypmods,
+                               rte->colcollations);
 }
 
 /*
  * Add an entry for an ephemeral named relation reference to the pstate's
  * range table (p_rtable).
+ * Then, construct and return a ParseNamespaceItem for the new RTE.
  *
  * It is expected that the RangeVar, which up until now is only known to be an
  * ephemeral named relation, will (in conjunction with the QueryEnvironment in
@@ -2079,7 +2306,7 @@ addRangeTableEntryForCTE(ParseState *pstate,
  * This is much like addRangeTableEntry() except that it makes an RTE for an
  * ephemeral named relation.
  */
-RangeTblEntry *
+ParseNamespaceItem *
 addRangeTableEntryForENR(ParseState *pstate,
                         RangeVar *rv,
                         bool inFromCl)
@@ -2164,12 +2391,18 @@ addRangeTableEntryForENR(ParseState *pstate,
    rte->selectedCols = NULL;
 
    /*
-    * Add completed RTE to pstate's range table list, but not to join list
-    * nor namespace --- caller must do that if appropriate.
+    * Add completed RTE to pstate's range table list, so that we know its
+    * index.  But we don't add it to the join list --- caller must do that if
+    * appropriate.
     */
    pstate->p_rtable = lappend(pstate->p_rtable, rte);
 
-   return rte;
+   /*
+    * Build a ParseNamespaceItem, but don't add it to the pstate's namespace
+    * list --- caller must do that if appropriate.
+    */
+   return buildNSItemFromTupleDesc(rte, list_length(pstate->p_rtable),
+                                   tupdesc);
 }
 
 
@@ -2221,49 +2454,26 @@ isLockedRefname(ParseState *pstate, const char *refname)
 }
 
 /*
- * Add the given RTE as a top-level entry in the pstate's join list
+ * Add the given nsitem/RTE as a top-level entry in the pstate's join list
  * and/or namespace list.  (We assume caller has checked for any
- * namespace conflicts.)  The RTE is always marked as unconditionally
+ * namespace conflicts.)  The nsitem is always marked as unconditionally
  * visible, that is, not LATERAL-only.
- *
- * Note: some callers know that they can find the new ParseNamespaceItem
- * at the end of the pstate->p_namespace list.  This is a bit ugly but not
- * worth complicating this function's signature for.
  */
 void
-addRTEtoQuery(ParseState *pstate, RangeTblEntry *rte,
-             bool addToJoinList,
-             bool addToRelNameSpace, bool addToVarNameSpace)
+addNSItemToQuery(ParseState *pstate, ParseNamespaceItem *nsitem,
+                bool addToJoinList,
+                bool addToRelNameSpace, bool addToVarNameSpace)
 {
-   int         rtindex;
-
-   /*
-    * Most callers have just added the RTE to the rangetable, so it's likely
-    * to be the last entry.  Hence, it's a good idea to search the rangetable
-    * back-to-front.
-    */
-   for (rtindex = list_length(pstate->p_rtable); rtindex > 0; rtindex--)
-   {
-       if (rte == rt_fetch(rtindex, pstate->p_rtable))
-           break;
-   }
-   if (rtindex <= 0)
-       elog(ERROR, "RTE not found (internal error)");
-
    if (addToJoinList)
    {
        RangeTblRef *rtr = makeNode(RangeTblRef);
 
-       rtr->rtindex = rtindex;
+       rtr->rtindex = nsitem->p_rtindex;
        pstate->p_joinlist = lappend(pstate->p_joinlist, rtr);
    }
    if (addToRelNameSpace || addToVarNameSpace)
    {
-       ParseNamespaceItem *nsitem;
-
-       nsitem = (ParseNamespaceItem *) palloc(sizeof(ParseNamespaceItem));
-       nsitem->p_rte = rte;
-       nsitem->p_rtindex = rtindex;
+       /* Set the new nsitem's visibility flags correctly */
        nsitem->p_rel_visible = addToRelNameSpace;
        nsitem->p_cols_visible = addToVarNameSpace;
        nsitem->p_lateral_only = false;
@@ -2720,6 +2930,61 @@ expandTupleDesc(TupleDesc tupdesc, Alias *eref, int count, int offset,
    }
 }
 
+/*
+ * expandNSItemVars
+ *   Produce a list of Vars, and optionally a list of column names,
+ *   for the non-dropped columns of the nsitem.
+ *
+ * The emitted Vars are marked with the given sublevels_up and location.
+ *
+ * If colnames isn't NULL, a list of String items for the columns is stored
+ * there; note that it's just a subset of the RTE's eref list, and hence
+ * the list elements mustn't be modified.
+ */
+List *
+expandNSItemVars(ParseNamespaceItem *nsitem,
+                int sublevels_up, int location,
+                List **colnames)
+{
+   List       *result = NIL;
+   int         colindex;
+   ListCell   *lc;
+
+   if (colnames)
+       *colnames = NIL;
+   colindex = 0;
+   foreach(lc, nsitem->p_rte->eref->colnames)
+   {
+       Value      *colnameval = (Value *) lfirst(lc);
+       const char *colname = strVal(colnameval);
+       ParseNamespaceColumn *nscol = nsitem->p_nscolumns + colindex;
+
+       if (colname[0])
+       {
+           Var        *var;
+
+           Assert(nscol->p_varno > 0);
+           var = makeVar(nsitem->p_rtindex,
+                         colindex + 1,
+                         nscol->p_vartype,
+                         nscol->p_vartypmod,
+                         nscol->p_varcollid,
+                         sublevels_up);
+           var->location = location;
+           result = lappend(result, var);
+           if (colnames)
+               *colnames = lappend(*colnames, colnameval);
+       }
+       else
+       {
+           /* dropped column, ignore */
+           Assert(nscol->p_varno == 0);
+       }
+       colindex++;
+   }
+   return result;
+}
+
 /*
  * expandNSItemAttrs -
  *   Workhorse for "*" expansion: produce a list of targetentries
@@ -2739,8 +3004,7 @@ expandNSItemAttrs(ParseState *pstate, ParseNamespaceItem *nsitem,
               *var;
    List       *te_list = NIL;
 
-   expandRTE(rte, nsitem->p_rtindex, sublevels_up, location, false,
-             &names, &vars);
+   vars = expandNSItemVars(nsitem, sublevels_up, location, &names);
 
    /*
     * Require read access to the table.  This is normally redundant with the
@@ -2815,204 +3079,6 @@ get_rte_attribute_name(RangeTblEntry *rte, AttrNumber attnum)
    return NULL;                /* keep compiler quiet */
 }
 
-/*
- * get_rte_attribute_type
- *     Get attribute type/typmod/collation information from a RangeTblEntry
- */
-void
-get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
-                      Oid *vartype, int32 *vartypmod, Oid *varcollid)
-{
-   switch (rte->rtekind)
-   {
-       case RTE_RELATION:
-           {
-               /* Plain relation RTE --- get the attribute's type info */
-               HeapTuple   tp;
-               Form_pg_attribute att_tup;
-
-               tp = SearchSysCache2(ATTNUM,
-                                    ObjectIdGetDatum(rte->relid),
-                                    Int16GetDatum(attnum));
-               if (!HeapTupleIsValid(tp))  /* shouldn't happen */
-                   elog(ERROR, "cache lookup failed for attribute %d of relation %u",
-                        attnum, rte->relid);
-               att_tup = (Form_pg_attribute) GETSTRUCT(tp);
-
-               /*
-                * If dropped column, pretend it ain't there.  See notes in
-                * scanRTEForColumn.
-                */
-               if (att_tup->attisdropped)
-                   ereport(ERROR,
-                           (errcode(ERRCODE_UNDEFINED_COLUMN),
-                            errmsg("column \"%s\" of relation \"%s\" does not exist",
-                                   NameStr(att_tup->attname),
-                                   get_rel_name(rte->relid))));
-               *vartype = att_tup->atttypid;
-               *vartypmod = att_tup->atttypmod;
-               *varcollid = att_tup->attcollation;
-               ReleaseSysCache(tp);
-           }
-           break;
-       case RTE_SUBQUERY:
-           {
-               /* Subselect RTE --- get type info from subselect's tlist */
-               TargetEntry *te = get_tle_by_resno(rte->subquery->targetList,
-                                                  attnum);
-
-               if (te == NULL || te->resjunk)
-                   elog(ERROR, "subquery %s does not have attribute %d",
-                        rte->eref->aliasname, attnum);
-               *vartype = exprType((Node *) te->expr);
-               *vartypmod = exprTypmod((Node *) te->expr);
-               *varcollid = exprCollation((Node *) te->expr);
-           }
-           break;
-       case RTE_FUNCTION:
-           {
-               /* Function RTE */
-               ListCell   *lc;
-               int         atts_done = 0;
-
-               /* Identify which function covers the requested column */
-               foreach(lc, rte->functions)
-               {
-                   RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
-
-                   if (attnum > atts_done &&
-                       attnum <= atts_done + rtfunc->funccolcount)
-                   {
-                       TypeFuncClass functypclass;
-                       Oid         funcrettype;
-                       TupleDesc   tupdesc;
-
-                       attnum -= atts_done;    /* now relative to this func */
-                       functypclass = get_expr_result_type(rtfunc->funcexpr,
-                                                           &funcrettype,
-                                                           &tupdesc);
-
-                       if (functypclass == TYPEFUNC_COMPOSITE ||
-                           functypclass == TYPEFUNC_COMPOSITE_DOMAIN)
-                       {
-                           /* Composite data type, e.g. a table's row type */
-                           Form_pg_attribute att_tup;
-
-                           Assert(tupdesc);
-                           Assert(attnum <= tupdesc->natts);
-                           att_tup = TupleDescAttr(tupdesc, attnum - 1);
-
-                           /*
-                            * If dropped column, pretend it ain't there.  See
-                            * notes in scanRTEForColumn.
-                            */
-                           if (att_tup->attisdropped)
-                               ereport(ERROR,
-                                       (errcode(ERRCODE_UNDEFINED_COLUMN),
-                                        errmsg("column \"%s\" of relation \"%s\" does not exist",
-                                               NameStr(att_tup->attname),
-                                               rte->eref->aliasname)));
-                           *vartype = att_tup->atttypid;
-                           *vartypmod = att_tup->atttypmod;
-                           *varcollid = att_tup->attcollation;
-                       }
-                       else if (functypclass == TYPEFUNC_SCALAR)
-                       {
-                           /* Base data type, i.e. scalar */
-                           *vartype = funcrettype;
-                           *vartypmod = -1;
-                           *varcollid = exprCollation(rtfunc->funcexpr);
-                       }
-                       else if (functypclass == TYPEFUNC_RECORD)
-                       {
-                           *vartype = list_nth_oid(rtfunc->funccoltypes,
-                                                   attnum - 1);
-                           *vartypmod = list_nth_int(rtfunc->funccoltypmods,
-                                                     attnum - 1);
-                           *varcollid = list_nth_oid(rtfunc->funccolcollations,
-                                                     attnum - 1);
-                       }
-                       else
-                       {
-                           /*
-                            * addRangeTableEntryForFunction should've caught
-                            * this
-                            */
-                           elog(ERROR, "function in FROM has unsupported return type");
-                       }
-                       return;
-                   }
-                   atts_done += rtfunc->funccolcount;
-               }
-
-               /* If we get here, must be looking for the ordinality column */
-               if (rte->funcordinality && attnum == atts_done + 1)
-               {
-                   *vartype = INT8OID;
-                   *vartypmod = -1;
-                   *varcollid = InvalidOid;
-                   return;
-               }
-
-               /* this probably can't happen ... */
-               ereport(ERROR,
-                       (errcode(ERRCODE_UNDEFINED_COLUMN),
-                        errmsg("column %d of relation \"%s\" does not exist",
-                               attnum,
-                               rte->eref->aliasname)));
-           }
-           break;
-       case RTE_JOIN:
-           {
-               /*
-                * Join RTE --- get type info from join RTE's alias variable
-                */
-               Node       *aliasvar;
-
-               Assert(attnum > 0 && attnum <= list_length(rte->joinaliasvars));
-               aliasvar = (Node *) list_nth(rte->joinaliasvars, attnum - 1);
-               Assert(aliasvar != NULL);
-               *vartype = exprType(aliasvar);
-               *vartypmod = exprTypmod(aliasvar);
-               *varcollid = exprCollation(aliasvar);
-           }
-           break;
-       case RTE_TABLEFUNC:
-       case RTE_VALUES:
-       case RTE_CTE:
-       case RTE_NAMEDTUPLESTORE:
-           {
-               /*
-                * tablefunc, VALUES, CTE, or ENR RTE --- get type info from
-                * lists in the RTE
-                */
-               Assert(attnum > 0 && attnum <= list_length(rte->coltypes));
-               *vartype = list_nth_oid(rte->coltypes, attnum - 1);
-               *vartypmod = list_nth_int(rte->coltypmods, attnum - 1);
-               *varcollid = list_nth_oid(rte->colcollations, attnum - 1);
-
-               /* For ENR, better check for dropped column */
-               if (!OidIsValid(*vartype))
-                   ereport(ERROR,
-                           (errcode(ERRCODE_UNDEFINED_COLUMN),
-                            errmsg("column %d of relation \"%s\" does not exist",
-                                   attnum,
-                                   rte->eref->aliasname)));
-           }
-           break;
-       case RTE_RESULT:
-           /* this probably can't happen ... */
-           ereport(ERROR,
-                   (errcode(ERRCODE_UNDEFINED_COLUMN),
-                    errmsg("column %d of relation \"%s\" does not exist",
-                           attnum,
-                           rte->eref->aliasname)));
-           break;
-       default:
-           elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
-   }
-}
-
 /*
  * get_rte_attribute_is_dropped
  *     Check whether attempted attribute ref is to a dropped column
index 4953cc2a4c2d58748577269a92ec823846c47fb0..8476d3cb3f62ca5e25e9f8ebbba65e70719bf7cc 100644 (file)
@@ -551,7 +551,7 @@ transformAssignedExpr(ParseState *pstate,
             */
            Var        *var;
 
-           var = makeVar(pstate->p_target_rtindex, attrno,
+           var = makeVar(pstate->p_target_nsitem->p_rtindex, attrno,
                          attrtype, attrtypmod, attrcollation, 0);
            var->location = location;
 
@@ -1359,8 +1359,7 @@ ExpandSingleTable(ParseState *pstate, ParseNamespaceItem *nsitem,
        List       *vars;
        ListCell   *l;
 
-       expandRTE(rte, nsitem->p_rtindex, sublevels_up, location, false,
-                 NULL, &vars);
+       vars = expandNSItemVars(nsitem, sublevels_up, location, NULL);
 
        /*
         * Require read access to the table.  This is normally redundant with
@@ -1496,6 +1495,12 @@ expandRecordVariable(ParseState *pstate, Var *var, int levelsup)
    Assert(IsA(var, Var));
    Assert(var->vartype == RECORDOID);
 
+   /*
+    * Note: it's tempting to use GetNSItemByRangeTablePosn here so that we
+    * can use expandNSItemVars instead of expandRTE; but that does not work
+    * for some of the recursion cases below, where we have consed up a
+    * ParseState that lacks p_namespace data.
+    */
    netlevelsup = var->varlevelsup + levelsup;
    rte = GetRTEByRangeTablePosn(pstate, var->varno, netlevelsup);
    attnum = var->varattno;
index c593e3f279f4713af38cdc216f7d5af4aa6b4534..42095ab83060d627773b3c50bb3af47655b8bfd4 100644 (file)
@@ -2598,7 +2598,7 @@ IndexStmt *
 transformIndexStmt(Oid relid, IndexStmt *stmt, const char *queryString)
 {
    ParseState *pstate;
-   RangeTblEntry *rte;
+   ParseNamespaceItem *nsitem;
    ListCell   *l;
    Relation    rel;
 
@@ -2622,12 +2622,12 @@ transformIndexStmt(Oid relid, IndexStmt *stmt, const char *queryString)
     * relation, but we still need to open it.
     */
    rel = relation_open(relid, NoLock);
-   rte = addRangeTableEntryForRelation(pstate, rel,
-                                       AccessShareLock,
-                                       NULL, false, true);
+   nsitem = addRangeTableEntryForRelation(pstate, rel,
+                                          AccessShareLock,
+                                          NULL, false, true);
 
    /* no to join list, yes to namespaces */
-   addRTEtoQuery(pstate, rte, false, true, true);
+   addNSItemToQuery(pstate, nsitem, false, true, true);
 
    /* take care of the where clause */
    if (stmt->whereClause)
@@ -2707,8 +2707,8 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
 {
    Relation    rel;
    ParseState *pstate;
-   RangeTblEntry *oldrte;
-   RangeTblEntry *newrte;
+   ParseNamespaceItem *oldnsitem;
+   ParseNamespaceItem *newnsitem;
 
    /*
     * To avoid deadlock, make sure the first thing we do is grab
@@ -2729,20 +2729,20 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
 
    /*
     * NOTE: 'OLD' must always have a varno equal to 1 and 'NEW' equal to 2.
-    * Set up their RTEs in the main pstate for use in parsing the rule
-    * qualification.
+    * Set up their ParseNamespaceItems in the main pstate for use in parsing
+    * the rule qualification.
     */
-   oldrte = addRangeTableEntryForRelation(pstate, rel,
-                                          AccessShareLock,
-                                          makeAlias("old", NIL),
-                                          false, false);
-   newrte = addRangeTableEntryForRelation(pstate, rel,
-                                          AccessShareLock,
-                                          makeAlias("new", NIL),
-                                          false, false);
+   oldnsitem = addRangeTableEntryForRelation(pstate, rel,
+                                             AccessShareLock,
+                                             makeAlias("old", NIL),
+                                             false, false);
+   newnsitem = addRangeTableEntryForRelation(pstate, rel,
+                                             AccessShareLock,
+                                             makeAlias("new", NIL),
+                                             false, false);
    /* Must override addRangeTableEntry's default access-check flags */
-   oldrte->requiredPerms = 0;
-   newrte->requiredPerms = 0;
+   oldnsitem->p_rte->requiredPerms = 0;
+   newnsitem->p_rte->requiredPerms = 0;
 
    /*
     * They must be in the namespace too for lookup purposes, but only add the
@@ -2754,17 +2754,17 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
    switch (stmt->event)
    {
        case CMD_SELECT:
-           addRTEtoQuery(pstate, oldrte, false, true, true);
+           addNSItemToQuery(pstate, oldnsitem, false, true, true);
            break;
        case CMD_UPDATE:
-           addRTEtoQuery(pstate, oldrte, false, true, true);
-           addRTEtoQuery(pstate, newrte, false, true, true);
+           addNSItemToQuery(pstate, oldnsitem, false, true, true);
+           addNSItemToQuery(pstate, newnsitem, false, true, true);
            break;
        case CMD_INSERT:
-           addRTEtoQuery(pstate, newrte, false, true, true);
+           addNSItemToQuery(pstate, newnsitem, false, true, true);
            break;
        case CMD_DELETE:
-           addRTEtoQuery(pstate, oldrte, false, true, true);
+           addNSItemToQuery(pstate, oldnsitem, false, true, true);
            break;
        default:
            elog(ERROR, "unrecognized event type: %d",
@@ -2832,18 +2832,18 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
             * nor "*" in the rule actions.  We decide later whether to put
             * them in the joinlist.
             */
-           oldrte = addRangeTableEntryForRelation(sub_pstate, rel,
-                                                  AccessShareLock,
-                                                  makeAlias("old", NIL),
-                                                  false, false);
-           newrte = addRangeTableEntryForRelation(sub_pstate, rel,
-                                                  AccessShareLock,
-                                                  makeAlias("new", NIL),
-                                                  false, false);
-           oldrte->requiredPerms = 0;
-           newrte->requiredPerms = 0;
-           addRTEtoQuery(sub_pstate, oldrte, false, true, false);
-           addRTEtoQuery(sub_pstate, newrte, false, true, false);
+           oldnsitem = addRangeTableEntryForRelation(sub_pstate, rel,
+                                                     AccessShareLock,
+                                                     makeAlias("old", NIL),
+                                                     false, false);
+           newnsitem = addRangeTableEntryForRelation(sub_pstate, rel,
+                                                     AccessShareLock,
+                                                     makeAlias("new", NIL),
+                                                     false, false);
+           oldnsitem->p_rte->requiredPerms = 0;
+           newnsitem->p_rte->requiredPerms = 0;
+           addNSItemToQuery(sub_pstate, oldnsitem, false, true, false);
+           addNSItemToQuery(sub_pstate, newnsitem, false, true, false);
 
            /* Transform the rule action statement */
            top_subqry = transformStmt(sub_pstate,
@@ -2967,6 +2967,8 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
             */
            if (has_old || (has_new && stmt->event == CMD_UPDATE))
            {
+               RangeTblRef *rtr;
+
                /*
                 * If sub_qry is a setop, manipulating its jointree will do no
                 * good at all, because the jointree is dummy. (This should be
@@ -2976,11 +2978,11 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
                    ereport(ERROR,
                            (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                             errmsg("conditional UNION/INTERSECT/EXCEPT statements are not implemented")));
-               /* hack so we can use addRTEtoQuery() */
-               sub_pstate->p_rtable = sub_qry->rtable;
-               sub_pstate->p_joinlist = sub_qry->jointree->fromlist;
-               addRTEtoQuery(sub_pstate, oldrte, true, false, false);
-               sub_qry->jointree->fromlist = sub_pstate->p_joinlist;
+               /* hackishly add OLD to the already-built FROM clause */
+               rtr = makeNode(RangeTblRef);
+               rtr->rtindex = oldnsitem->p_rtindex;
+               sub_qry->jointree->fromlist =
+                   lappend(sub_qry->jointree->fromlist, rtr);
            }
 
            newactions = lappend(newactions, top_subqry);
@@ -3025,7 +3027,7 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
    List       *newcmds = NIL;
    bool        skipValidation = true;
    AlterTableCmd *newcmd;
-   RangeTblEntry *rte;
+   ParseNamespaceItem *nsitem;
 
    /*
     * We must not scribble on the passed-in AlterTableStmt, so copy it. (This
@@ -3040,13 +3042,13 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
    /* Set up pstate */
    pstate = make_parsestate(NULL);
    pstate->p_sourcetext = queryString;
-   rte = addRangeTableEntryForRelation(pstate,
-                                       rel,
-                                       AccessShareLock,
-                                       NULL,
-                                       false,
-                                       true);
-   addRTEtoQuery(pstate, rte, false, true, true);
+   nsitem = addRangeTableEntryForRelation(pstate,
+                                          rel,
+                                          AccessShareLock,
+                                          NULL,
+                                          false,
+                                          true);
+   addNSItemToQuery(pstate, nsitem, false, true, true);
 
    /* Set up CreateStmtContext */
    cxt.pstate = pstate;
index a2ceb83e99533375ff26be2785b9334304c93a6a..f8183cd488c985cfea99fbd999c27fb5baeb453b 100644 (file)
@@ -777,8 +777,8 @@ copy_table(Relation rel)
    copybuf = makeStringInfo();
 
    pstate = make_parsestate(NULL);
-   addRangeTableEntryForRelation(pstate, rel, AccessShareLock,
-                                 NULL, false, false);
+   (void) addRangeTableEntryForRelation(pstate, rel, AccessShareLock,
+                                        NULL, false, false);
 
    attnamelist = make_copy_attnamelist(relmapentry);
    cstate = BeginCopyFrom(pstate, rel, NULL, false, copy_read_data, attnamelist, NIL);
index 14e9d343f8e284a8918edddea0768798e61b83fe..e9fefec8b36208833d1c998cc9d3fdd93bd067b0 100644 (file)
@@ -3227,6 +3227,7 @@ rewriteTargetView(Query *parsetree, Relation view)
    {
        Index       old_exclRelIndex,
                    new_exclRelIndex;
+       ParseNamespaceItem *new_exclNSItem;
        RangeTblEntry *new_exclRte;
        List       *tmp_tlist;
 
@@ -3261,11 +3262,12 @@ rewriteTargetView(Query *parsetree, Relation view)
         */
        old_exclRelIndex = parsetree->onConflict->exclRelIndex;
 
-       new_exclRte = addRangeTableEntryForRelation(make_parsestate(NULL),
-                                                   base_rel,
-                                                   RowExclusiveLock,
-                                                   makeAlias("excluded", NIL),
-                                                   false, false);
+       new_exclNSItem = addRangeTableEntryForRelation(make_parsestate(NULL),
+                                                      base_rel,
+                                                      RowExclusiveLock,
+                                                      makeAlias("excluded", NIL),
+                                                      false, false);
+       new_exclRte = new_exclNSItem->p_rte;
        new_exclRte->relkind = RELKIND_COMPOSITE_TYPE;
        new_exclRte->requiredPerms = 0;
        /* other permissions fields in new_exclRte are already empty */
index 8e71b2ed5fc170afc478c2d417070c04f21235a4..d25819aa28b3855c365ff17f19df1d4b16db7b7e 100644 (file)
 #include "utils/relcache.h"
 
 
+/* Forward references for some structs declared below */
+typedef struct ParseState ParseState;
+typedef struct ParseNamespaceItem ParseNamespaceItem;
+typedef struct ParseNamespaceColumn ParseNamespaceColumn;
+
 /*
  * Expression kinds distinguished by transformExpr().  Many of these are not
  * semantically distinct so far as expression transformation goes; rather,
@@ -79,8 +84,6 @@ typedef enum ParseExprKind
 /*
  * Function signatures for parser hooks
  */
-typedef struct ParseState ParseState;
-
 typedef Node *(*PreParseColumnRefHook) (ParseState *pstate, ColumnRef *cref);
 typedef Node *(*PostParseColumnRefHook) (ParseState *pstate, ColumnRef *cref, Node *var);
 typedef Node *(*ParseParamRefHook) (ParseState *pstate, ParamRef *pref);
@@ -132,9 +135,7 @@ typedef Node *(*CoerceParamHook) (ParseState *pstate, Param *param,
  *
  * p_target_relation: target relation, if query is INSERT, UPDATE, or DELETE.
  *
- * p_target_rangetblentry: target relation's entry in the rtable list.
- *
- * p_target_rtindex: target relation's index in the rtable list.
+ * p_target_nsitem: target relation's ParseNamespaceItem.
  *
  * p_is_insert: true to process assignment expressions like INSERT, false
  * to process them like UPDATE.  (Note this can change intra-statement, for
@@ -174,7 +175,7 @@ typedef Node *(*CoerceParamHook) (ParseState *pstate, Param *param,
  */
 struct ParseState
 {
-   struct ParseState *parentParseState;    /* stack link */
+   ParseState *parentParseState;   /* stack link */
    const char *p_sourcetext;   /* source text, or NULL if not available */
    List       *p_rtable;       /* range table so far */
    List       *p_joinexprs;    /* JoinExprs for RTE_JOIN p_rtable entries */
@@ -187,8 +188,7 @@ struct ParseState
    List       *p_future_ctes;  /* common table exprs not yet in namespace */
    CommonTableExpr *p_parent_cte;  /* this query's containing CTE */
    Relation    p_target_relation;  /* INSERT/UPDATE/DELETE target rel */
-   RangeTblEntry *p_target_rangetblentry;  /* target rel's RTE, or NULL */
-   int         p_target_rtindex;   /* target rel's RT index, or 0 */
+   ParseNamespaceItem *p_target_nsitem;    /* target rel's NSItem, or NULL */
    bool        p_is_insert;    /* process assignment like INSERT not UPDATE */
    List       *p_windowdefs;   /* raw representations of window clauses */
    ParseExprKind p_expr_kind;  /* what kind of expression we're parsing */
@@ -225,6 +225,9 @@ struct ParseState
 /*
  * An element of a namespace list.
  *
+ * The p_nscolumns array contains info showing how to construct Vars
+ * referencing corresponding elements of the RTE's colnames list.
+ *
  * Namespace items with p_rel_visible set define which RTEs are accessible by
  * qualified names, while those with p_cols_visible set define which RTEs are
  * accessible by unqualified names.  These sets are different because a JOIN
@@ -249,15 +252,49 @@ struct ParseState
  * are more complicated than "must have different alias names", so in practice
  * code searching a namespace list has to check for ambiguous references.
  */
-typedef struct ParseNamespaceItem
+struct ParseNamespaceItem
 {
    RangeTblEntry *p_rte;       /* The relation's rangetable entry */
    int         p_rtindex;      /* The relation's index in the rangetable */
+   /* array of same length as p_rte->eref->colnames: */
+   ParseNamespaceColumn *p_nscolumns;  /* per-column data */
    bool        p_rel_visible;  /* Relation name is visible? */
    bool        p_cols_visible; /* Column names visible as unqualified refs? */
    bool        p_lateral_only; /* Is only visible to LATERAL expressions? */
    bool        p_lateral_ok;   /* If so, does join type allow use? */
-} ParseNamespaceItem;
+};
+
+/*
+ * Data about one column of a ParseNamespaceItem.
+ *
+ * We track the info needed to construct a Var referencing the column
+ * (but only for user-defined columns; system column references and
+ * whole-row references are handled separately).
+ *
+ * p_varno and p_varattno identify the semantic referent, which is a
+ * base-relation column unless the reference is to a join USING column that
+ * isn't semantically equivalent to either join input column (because it is a
+ * FULL join or the input column requires a type coercion).  In those cases
+ * p_varno and p_varattno refer to the JOIN RTE.
+ *
+ * p_varnosyn and p_varattnosyn are either identical to p_varno/p_varattno,
+ * or they specify the column's position in an aliased JOIN RTE that hides
+ * the semantic referent RTE's refname.  (That could be either the JOIN RTE
+ * in which this ParseNamespaceColumn entry exists, or some lower join level.)
+ *
+ * If an RTE contains a dropped column, its ParseNamespaceColumn struct
+ * is all-zeroes.  (Conventionally, test for p_varno == 0 to detect this.)
+ */
+struct ParseNamespaceColumn
+{
+   Index       p_varno;        /* rangetable index */
+   AttrNumber  p_varattno;     /* attribute number of the column */
+   Oid         p_vartype;      /* pg_type OID */
+   int32       p_vartypmod;    /* type modifier value */
+   Oid         p_varcollid;    /* OID of collation, or InvalidOid */
+   Index       p_varnosyn;     /* rangetable index of syntactic referent */
+   AttrNumber  p_varattnosyn;  /* attribute number of syntactic referent */
+};
 
 /* Support for parser_errposition_callback function */
 typedef struct ParseCallbackState
index 456dbc2de42a6beba9eec3ef311e232ca695d4bb..b8bff2375aedf23533b0aad8b59275e4a2426b73 100644 (file)
@@ -45,66 +45,70 @@ extern void markVarForSelectPriv(ParseState *pstate, Var *var,
                                 RangeTblEntry *rte);
 extern Relation parserOpenTable(ParseState *pstate, const RangeVar *relation,
                                int lockmode);
-extern RangeTblEntry *addRangeTableEntry(ParseState *pstate,
-                                        RangeVar *relation,
-                                        Alias *alias,
-                                        bool inh,
-                                        bool inFromCl);
-extern RangeTblEntry *addRangeTableEntryForRelation(ParseState *pstate,
-                                                   Relation rel,
-                                                   int lockmode,
-                                                   Alias *alias,
-                                                   bool inh,
-                                                   bool inFromCl);
-extern RangeTblEntry *addRangeTableEntryForSubquery(ParseState *pstate,
-                                                   Query *subquery,
-                                                   Alias *alias,
-                                                   bool lateral,
-                                                   bool inFromCl);
-extern RangeTblEntry *addRangeTableEntryForFunction(ParseState *pstate,
-                                                   List *funcnames,
-                                                   List *funcexprs,
-                                                   List *coldeflists,
-                                                   RangeFunction *rangefunc,
-                                                   bool lateral,
-                                                   bool inFromCl);
-extern RangeTblEntry *addRangeTableEntryForValues(ParseState *pstate,
-                                                 List *exprs,
-                                                 List *coltypes,
-                                                 List *coltypmods,
-                                                 List *colcollations,
-                                                 Alias *alias,
-                                                 bool lateral,
-                                                 bool inFromCl);
-extern RangeTblEntry *addRangeTableEntryForTableFunc(ParseState *pstate,
-                                                    TableFunc *tf,
+extern ParseNamespaceItem *addRangeTableEntry(ParseState *pstate,
+                                             RangeVar *relation,
+                                             Alias *alias,
+                                             bool inh,
+                                             bool inFromCl);
+extern ParseNamespaceItem *addRangeTableEntryForRelation(ParseState *pstate,
+                                                        Relation rel,
+                                                        int lockmode,
+                                                        Alias *alias,
+                                                        bool inh,
+                                                        bool inFromCl);
+extern ParseNamespaceItem *addRangeTableEntryForSubquery(ParseState *pstate,
+                                                        Query *subquery,
+                                                        Alias *alias,
+                                                        bool lateral,
+                                                        bool inFromCl);
+extern ParseNamespaceItem *addRangeTableEntryForFunction(ParseState *pstate,
+                                                        List *funcnames,
+                                                        List *funcexprs,
+                                                        List *coldeflists,
+                                                        RangeFunction *rangefunc,
+                                                        bool lateral,
+                                                        bool inFromCl);
+extern ParseNamespaceItem *addRangeTableEntryForValues(ParseState *pstate,
+                                                      List *exprs,
+                                                      List *coltypes,
+                                                      List *coltypmods,
+                                                      List *colcollations,
+                                                      Alias *alias,
+                                                      bool lateral,
+                                                      bool inFromCl);
+extern ParseNamespaceItem *addRangeTableEntryForTableFunc(ParseState *pstate,
+                                                         TableFunc *tf,
+                                                         Alias *alias,
+                                                         bool lateral,
+                                                         bool inFromCl);
+extern ParseNamespaceItem *addRangeTableEntryForJoin(ParseState *pstate,
+                                                    List *colnames,
+                                                    ParseNamespaceColumn *nscolumns,
+                                                    JoinType jointype,
+                                                    List *aliasvars,
                                                     Alias *alias,
-                                                    bool lateral,
                                                     bool inFromCl);
-extern RangeTblEntry *addRangeTableEntryForJoin(ParseState *pstate,
-                                               List *colnames,
-                                               JoinType jointype,
-                                               List *aliasvars,
-                                               Alias *alias,
-                                               bool inFromCl);
-extern RangeTblEntry *addRangeTableEntryForCTE(ParseState *pstate,
-                                              CommonTableExpr *cte,
-                                              Index levelsup,
-                                              RangeVar *rv,
-                                              bool inFromCl);
-extern RangeTblEntry *addRangeTableEntryForENR(ParseState *pstate,
-                                              RangeVar *rv,
-                                              bool inFromCl);
+extern ParseNamespaceItem *addRangeTableEntryForCTE(ParseState *pstate,
+                                                   CommonTableExpr *cte,
+                                                   Index levelsup,
+                                                   RangeVar *rv,
+                                                   bool inFromCl);
+extern ParseNamespaceItem *addRangeTableEntryForENR(ParseState *pstate,
+                                                   RangeVar *rv,
+                                                   bool inFromCl);
 extern bool isLockedRefname(ParseState *pstate, const char *refname);
-extern void addRTEtoQuery(ParseState *pstate, RangeTblEntry *rte,
-                         bool addToJoinList,
-                         bool addToRelNameSpace, bool addToVarNameSpace);
+extern void addNSItemToQuery(ParseState *pstate, ParseNamespaceItem *nsitem,
+                            bool addToJoinList,
+                            bool addToRelNameSpace, bool addToVarNameSpace);
 extern void errorMissingRTE(ParseState *pstate, RangeVar *relation) pg_attribute_noreturn();
 extern void errorMissingColumn(ParseState *pstate,
                               const char *relname, const char *colname, int location) pg_attribute_noreturn();
 extern void expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
                      int location, bool include_dropped,
                      List **colnames, List **colvars);
+extern List *expandNSItemVars(ParseNamespaceItem *nsitem,
+                             int sublevels_up, int location,
+                             List **colnames);
 extern List *expandNSItemAttrs(ParseState *pstate, ParseNamespaceItem *nsitem,
                               int sublevels_up, int location);
 extern int attnameAttNum(Relation rd, const char *attname, bool sysColOK);
index 11bd47b023ce58c9c4cdfcf5dfe7ed4fdf9375a0..3ed5862640eda6fe21ff9945652e0b48ff4594b5 100644 (file)
 extern char *get_rte_attribute_name(RangeTblEntry *rte, AttrNumber attnum);
 
 /*
- * Given an RTE and an attribute number, return the appropriate
- * type and typemod info for that attribute of that RTE.
- */
-extern void get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
-                                  Oid *vartype, int32 *vartypmod, Oid *varcollid);
-
-/*
- * Check whether an attribute of an RTE has been dropped (note that
- * get_rte_attribute_type will fail on such an attr)
+ * Check whether an attribute of an RTE has been dropped
  */
 extern bool get_rte_attribute_is_dropped(RangeTblEntry *rte,
                                         AttrNumber attnum);
index 4373790e99bd2e6e7c6f9568664b40029838e287..d1b7075bcc699a960c04e2d5516b6212ac575f27 100644 (file)
@@ -70,7 +70,7 @@ test_rls_hooks_permissive(CmdType cmdtype, Relation relation)
    Node       *e;
    ColumnRef  *c;
    ParseState *qual_pstate;
-   RangeTblEntry *rte;
+   ParseNamespaceItem *nsitem;
 
    if (strcmp(RelationGetRelationName(relation), "rls_test_permissive") != 0 &&
        strcmp(RelationGetRelationName(relation), "rls_test_both") != 0)
@@ -78,9 +78,10 @@ test_rls_hooks_permissive(CmdType cmdtype, Relation relation)
 
    qual_pstate = make_parsestate(NULL);
 
-   rte = addRangeTableEntryForRelation(qual_pstate, relation, AccessShareLock,
-                                       NULL, false, false);
-   addRTEtoQuery(qual_pstate, rte, false, true, true);
+   nsitem = addRangeTableEntryForRelation(qual_pstate,
+                                          relation, AccessShareLock,
+                                          NULL, false, false);
+   addNSItemToQuery(qual_pstate, nsitem, false, true, true);
 
    role = ObjectIdGetDatum(ACL_ID_PUBLIC);
 
@@ -134,8 +135,7 @@ test_rls_hooks_restrictive(CmdType cmdtype, Relation relation)
    Node       *e;
    ColumnRef  *c;
    ParseState *qual_pstate;
-   RangeTblEntry *rte;
-
+   ParseNamespaceItem *nsitem;
 
    if (strcmp(RelationGetRelationName(relation), "rls_test_restrictive") != 0 &&
        strcmp(RelationGetRelationName(relation), "rls_test_both") != 0)
@@ -143,9 +143,10 @@ test_rls_hooks_restrictive(CmdType cmdtype, Relation relation)
 
    qual_pstate = make_parsestate(NULL);
 
-   rte = addRangeTableEntryForRelation(qual_pstate, relation, AccessShareLock,
-                                       NULL, false, false);
-   addRTEtoQuery(qual_pstate, rte, false, true, true);
+   nsitem = addRangeTableEntryForRelation(qual_pstate,
+                                          relation, AccessShareLock,
+                                          NULL, false, false);
+   addNSItemToQuery(qual_pstate, nsitem, false, true, true);
 
    role = ObjectIdGetDatum(ACL_ID_PUBLIC);