diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 01ecd9f980..0fdff2918f 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -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. diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index c442e202b5..c93a788798 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -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); diff --git a/src/backend/commands/policy.c b/src/backend/commands/policy.c index 818010b7c3..6e990a3818 100644 --- a/src/backend/commands/policy.c +++ b/src/backend/commands/policy.c @@ -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); diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 57781a522e..01bc292ada 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -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) diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index c5c7b2101c..b9b1262e30 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -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, diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c index f18fb29c16..06bc2b76ed 100644 --- a/src/backend/commands/view.c +++ b/src/backend/commands/view.c @@ -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; diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index fd8f24aeea..3650e8329d 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -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); diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index 01125ad8cf..447a61ef8c 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -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) diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c index 04ebd877ab..5fa42d307a 100644 --- a/src/backend/parser/parse_clause.c +++ b/src/backend/parser/parse_clause.c @@ -51,37 +51,33 @@ #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); + if (!nsitem) + nsitem = 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)); + *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; + ParseNamespaceItem *nsitem; - 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)); + 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; + ParseNamespaceItem *nsitem; - 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)); + 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; + ParseNamespaceItem *nsitem; - 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)); + 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, diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index 8e9cde7bd0..929f758ef4 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -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, diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 02b8d0aca3..831db4af95 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -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. diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c index 6dc33e2411..d7c4bae8cc 100644 --- a/src/backend/parser/parse_relation.c +++ b/src/backend/parser/parse_relation.c @@ -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 diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c index 4953cc2a4c..8476d3cb3f 100644 --- a/src/backend/parser/parse_target.c +++ b/src/backend/parser/parse_target.c @@ -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; diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c index c593e3f279..42095ab830 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -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; diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c index a2ceb83e99..f8183cd488 100644 --- a/src/backend/replication/logical/tablesync.c +++ b/src/backend/replication/logical/tablesync.c @@ -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); diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c index 14e9d343f8..e9fefec8b3 100644 --- a/src/backend/rewrite/rewriteHandler.c +++ b/src/backend/rewrite/rewriteHandler.c @@ -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 */ diff --git a/src/include/parser/parse_node.h b/src/include/parser/parse_node.h index 8e71b2ed5f..d25819aa28 100644 --- a/src/include/parser/parse_node.h +++ b/src/include/parser/parse_node.h @@ -19,6 +19,11 @@ #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 diff --git a/src/include/parser/parse_relation.h b/src/include/parser/parse_relation.h index 456dbc2de4..b8bff2375a 100644 --- a/src/include/parser/parse_relation.h +++ b/src/include/parser/parse_relation.h @@ -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); diff --git a/src/include/parser/parsetree.h b/src/include/parser/parsetree.h index 11bd47b023..3ed5862640 100644 --- a/src/include/parser/parsetree.h +++ b/src/include/parser/parsetree.h @@ -38,15 +38,7 @@ 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); diff --git a/src/test/modules/test_rls_hooks/test_rls_hooks.c b/src/test/modules/test_rls_hooks/test_rls_hooks.c index 4373790e99..d1b7075bcc 100644 --- a/src/test/modules/test_rls_hooks/test_rls_hooks.c +++ b/src/test/modules/test_rls_hooks/test_rls_hooks.c @@ -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);