Make parser rely more heavily on the ParseNamespaceItem data structure.

When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs.  In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.

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

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

Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
This commit is contained in:
Tom Lane 2020-01-02 11:29:01 -05:00
parent 198c7153dc
commit 5815696bc6
20 changed files with 923 additions and 790 deletions

View File

@ -2531,7 +2531,7 @@ AddRelationNewConstraints(Relation rel,
TupleConstr *oldconstr; TupleConstr *oldconstr;
int numoldchecks; int numoldchecks;
ParseState *pstate; ParseState *pstate;
RangeTblEntry *rte; ParseNamespaceItem *nsitem;
int numchecks; int numchecks;
List *checknames; List *checknames;
ListCell *cell; ListCell *cell;
@ -2554,13 +2554,13 @@ AddRelationNewConstraints(Relation rel,
*/ */
pstate = make_parsestate(NULL); pstate = make_parsestate(NULL);
pstate->p_sourcetext = queryString; pstate->p_sourcetext = queryString;
rte = addRangeTableEntryForRelation(pstate, nsitem = addRangeTableEntryForRelation(pstate,
rel, rel,
AccessShareLock, AccessShareLock,
NULL, NULL,
false, false,
true); true);
addRTEtoQuery(pstate, rte, true, true, true); addNSItemToQuery(pstate, nsitem, true, true, true);
/* /*
* Process column default expressions. * Process column default expressions.

View File

@ -882,6 +882,7 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
if (stmt->relation) if (stmt->relation)
{ {
LOCKMODE lockmode = is_from ? RowExclusiveLock : AccessShareLock; LOCKMODE lockmode = is_from ? RowExclusiveLock : AccessShareLock;
ParseNamespaceItem *nsitem;
RangeTblEntry *rte; RangeTblEntry *rte;
TupleDesc tupDesc; TupleDesc tupDesc;
List *attnums; List *attnums;
@ -894,14 +895,15 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
relid = RelationGetRelid(rel); relid = RelationGetRelid(rel);
rte = addRangeTableEntryForRelation(pstate, rel, lockmode, nsitem = addRangeTableEntryForRelation(pstate, rel, lockmode,
NULL, false, false); NULL, false, false);
rte = nsitem->p_rte;
rte->requiredPerms = (is_from ? ACL_INSERT : ACL_SELECT); rte->requiredPerms = (is_from ? ACL_INSERT : ACL_SELECT);
if (stmt->whereClause) if (stmt->whereClause)
{ {
/* add rte to column namespace */ /* add nsitem to query namespace */
addRTEtoQuery(pstate, rte, false, true, true); addNSItemToQuery(pstate, nsitem, false, true, true);
/* Transform the raw expression tree */ /* Transform the raw expression tree */
whereClause = transformExpr(pstate, stmt->whereClause, EXPR_KIND_COPY_WHERE); whereClause = transformExpr(pstate, stmt->whereClause, EXPR_KIND_COPY_WHERE);

View File

@ -568,9 +568,9 @@ RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid policy_id)
qual_expr = stringToNode(qual_value); qual_expr = stringToNode(qual_value);
/* Add this rel to the parsestate's rangetable, for dependencies */ /* Add this rel to the parsestate's rangetable, for dependencies */
addRangeTableEntryForRelation(qual_pstate, rel, (void) addRangeTableEntryForRelation(qual_pstate, rel,
AccessShareLock, AccessShareLock,
NULL, false, false); NULL, false, false);
qual_parse_rtable = qual_pstate->p_rtable; qual_parse_rtable = qual_pstate->p_rtable;
free_parsestate(qual_pstate); free_parsestate(qual_pstate);
@ -592,9 +592,9 @@ RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid policy_id)
with_check_qual = stringToNode(with_check_value); with_check_qual = stringToNode(with_check_value);
/* Add this rel to the parsestate's rangetable, for dependencies */ /* Add this rel to the parsestate's rangetable, for dependencies */
addRangeTableEntryForRelation(with_check_pstate, rel, (void) addRangeTableEntryForRelation(with_check_pstate, rel,
AccessShareLock, AccessShareLock,
NULL, false, false); NULL, false, false);
with_check_parse_rtable = with_check_pstate->p_rtable; with_check_parse_rtable = with_check_pstate->p_rtable;
free_parsestate(with_check_pstate); free_parsestate(with_check_pstate);
@ -699,7 +699,7 @@ CreatePolicy(CreatePolicyStmt *stmt)
ArrayType *role_ids; ArrayType *role_ids;
ParseState *qual_pstate; ParseState *qual_pstate;
ParseState *with_check_pstate; ParseState *with_check_pstate;
RangeTblEntry *rte; ParseNamespaceItem *nsitem;
Node *qual; Node *qual;
Node *with_check_qual; Node *with_check_qual;
ScanKeyData skey[2]; ScanKeyData skey[2];
@ -755,16 +755,16 @@ CreatePolicy(CreatePolicyStmt *stmt)
target_table = relation_open(table_id, NoLock); target_table = relation_open(table_id, NoLock);
/* Add for the regular security quals */ /* Add for the regular security quals */
rte = addRangeTableEntryForRelation(qual_pstate, target_table, nsitem = addRangeTableEntryForRelation(qual_pstate, target_table,
AccessShareLock, AccessShareLock,
NULL, false, false); NULL, false, false);
addRTEtoQuery(qual_pstate, rte, false, true, true); addNSItemToQuery(qual_pstate, nsitem, false, true, true);
/* Add for the with-check quals */ /* Add for the with-check quals */
rte = addRangeTableEntryForRelation(with_check_pstate, target_table, nsitem = addRangeTableEntryForRelation(with_check_pstate, target_table,
AccessShareLock, AccessShareLock,
NULL, false, false); NULL, false, false);
addRTEtoQuery(with_check_pstate, rte, false, true, true); addNSItemToQuery(with_check_pstate, nsitem, false, true, true);
qual = transformWhereClause(qual_pstate, qual = transformWhereClause(qual_pstate,
copyObject(stmt->qual), copyObject(stmt->qual),
@ -933,14 +933,14 @@ AlterPolicy(AlterPolicyStmt *stmt)
/* Parse the using policy clause */ /* Parse the using policy clause */
if (stmt->qual) if (stmt->qual)
{ {
RangeTblEntry *rte; ParseNamespaceItem *nsitem;
ParseState *qual_pstate = make_parsestate(NULL); ParseState *qual_pstate = make_parsestate(NULL);
rte = addRangeTableEntryForRelation(qual_pstate, target_table, nsitem = addRangeTableEntryForRelation(qual_pstate, target_table,
AccessShareLock, AccessShareLock,
NULL, false, false); NULL, false, false);
addRTEtoQuery(qual_pstate, rte, false, true, true); addNSItemToQuery(qual_pstate, nsitem, false, true, true);
qual = transformWhereClause(qual_pstate, copyObject(stmt->qual), qual = transformWhereClause(qual_pstate, copyObject(stmt->qual),
EXPR_KIND_POLICY, EXPR_KIND_POLICY,
@ -956,14 +956,14 @@ AlterPolicy(AlterPolicyStmt *stmt)
/* Parse the with-check policy clause */ /* Parse the with-check policy clause */
if (stmt->with_check) if (stmt->with_check)
{ {
RangeTblEntry *rte; ParseNamespaceItem *nsitem;
ParseState *with_check_pstate = make_parsestate(NULL); ParseState *with_check_pstate = make_parsestate(NULL);
rte = addRangeTableEntryForRelation(with_check_pstate, target_table, nsitem = addRangeTableEntryForRelation(with_check_pstate, target_table,
AccessShareLock, AccessShareLock,
NULL, false, false); 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, with_check_qual = transformWhereClause(with_check_pstate,
copyObject(stmt->with_check), copyObject(stmt->with_check),
@ -1107,9 +1107,9 @@ AlterPolicy(AlterPolicyStmt *stmt)
qual = stringToNode(qual_value); qual = stringToNode(qual_value);
/* Add this rel to the parsestate's rangetable, for dependencies */ /* Add this rel to the parsestate's rangetable, for dependencies */
addRangeTableEntryForRelation(qual_pstate, target_table, (void) addRangeTableEntryForRelation(qual_pstate, target_table,
AccessShareLock, AccessShareLock,
NULL, false, false); NULL, false, false);
qual_parse_rtable = qual_pstate->p_rtable; qual_parse_rtable = qual_pstate->p_rtable;
free_parsestate(qual_pstate); free_parsestate(qual_pstate);
@ -1149,9 +1149,10 @@ AlterPolicy(AlterPolicyStmt *stmt)
with_check_qual = stringToNode(with_check_value); with_check_qual = stringToNode(with_check_value);
/* Add this rel to the parsestate's rangetable, for dependencies */ /* Add this rel to the parsestate's rangetable, for dependencies */
addRangeTableEntryForRelation(with_check_pstate, target_table, (void) addRangeTableEntryForRelation(with_check_pstate,
AccessShareLock, target_table,
NULL, false, false); AccessShareLock,
NULL, false, false);
with_check_parse_rtable = with_check_pstate->p_rtable; with_check_parse_rtable = with_check_pstate->p_rtable;
free_parsestate(with_check_pstate); free_parsestate(with_check_pstate);

View File

@ -918,7 +918,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
defaultPartOid; defaultPartOid;
Relation parent, Relation parent,
defaultRel = NULL; defaultRel = NULL;
RangeTblEntry *rte; ParseNamespaceItem *nsitem;
/* Already have strong enough lock on the parent */ /* Already have strong enough lock on the parent */
parent = table_open(parentId, NoLock); parent = table_open(parentId, NoLock);
@ -962,13 +962,14 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
pstate->p_sourcetext = queryString; pstate->p_sourcetext = queryString;
/* /*
* Add an RTE containing this relation, so that transformExpr called * Add an nsitem containing this relation, so that transformExpr
* on partition bound expressions is able to report errors using a * called on partition bound expressions is able to report errors
* proper context. * using a proper context.
*/ */
rte = addRangeTableEntryForRelation(pstate, rel, AccessShareLock, nsitem = addRangeTableEntryForRelation(pstate, rel, AccessShareLock,
NULL, false, false); NULL, false, false);
addRTEtoQuery(pstate, rte, false, true, true); addNSItemToQuery(pstate, nsitem, false, true, true);
bound = transformPartitionBound(pstate, parent, stmt->partbound); bound = transformPartitionBound(pstate, parent, stmt->partbound);
/* /*
@ -14970,7 +14971,7 @@ transformPartitionSpec(Relation rel, PartitionSpec *partspec, char *strategy)
{ {
PartitionSpec *newspec; PartitionSpec *newspec;
ParseState *pstate; ParseState *pstate;
RangeTblEntry *rte; ParseNamespaceItem *nsitem;
ListCell *l; ListCell *l;
newspec = makeNode(PartitionSpec); newspec = makeNode(PartitionSpec);
@ -15004,9 +15005,9 @@ transformPartitionSpec(Relation rel, PartitionSpec *partspec, char *strategy)
* rangetable entry. We need a ParseState for transformExpr. * rangetable entry. We need a ParseState for transformExpr.
*/ */
pstate = make_parsestate(NULL); pstate = make_parsestate(NULL);
rte = addRangeTableEntryForRelation(pstate, rel, AccessShareLock, nsitem = addRangeTableEntryForRelation(pstate, rel, AccessShareLock,
NULL, false, true); NULL, false, true);
addRTEtoQuery(pstate, rte, true, true, true); addNSItemToQuery(pstate, nsitem, true, true, true);
/* take care of any partition expressions */ /* take care of any partition expressions */
foreach(l, partspec->partParams) foreach(l, partspec->partParams)

View File

@ -565,7 +565,7 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
if (!whenClause && stmt->whenClause) if (!whenClause && stmt->whenClause)
{ {
ParseState *pstate; ParseState *pstate;
RangeTblEntry *rte; ParseNamespaceItem *nsitem;
List *varList; List *varList;
ListCell *lc; ListCell *lc;
@ -574,20 +574,20 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
pstate->p_sourcetext = 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. * 'OLD' must always have varno equal to 1 and 'NEW' equal to 2.
*/ */
rte = addRangeTableEntryForRelation(pstate, rel, nsitem = addRangeTableEntryForRelation(pstate, rel,
AccessShareLock, AccessShareLock,
makeAlias("old", NIL), makeAlias("old", NIL),
false, false); false, false);
addRTEtoQuery(pstate, rte, false, true, true); addNSItemToQuery(pstate, nsitem, false, true, true);
rte = addRangeTableEntryForRelation(pstate, rel, nsitem = addRangeTableEntryForRelation(pstate, rel,
AccessShareLock, AccessShareLock,
makeAlias("new", NIL), makeAlias("new", NIL),
false, false); false, false);
addRTEtoQuery(pstate, rte, false, true, true); addNSItemToQuery(pstate, nsitem, false, true, true);
/* Transform expression. Copy to be sure we don't modify original */ /* Transform expression. Copy to be sure we don't modify original */
whenClause = transformWhereClause(pstate, whenClause = transformWhereClause(pstate,

View File

@ -341,6 +341,7 @@ UpdateRangeTableOfViewParse(Oid viewOid, Query *viewParse)
{ {
Relation viewRel; Relation viewRel;
List *new_rt; List *new_rt;
ParseNamespaceItem *nsitem;
RangeTblEntry *rt_entry1, RangeTblEntry *rt_entry1,
*rt_entry2; *rt_entry2;
ParseState *pstate; ParseState *pstate;
@ -365,14 +366,17 @@ UpdateRangeTableOfViewParse(Oid viewOid, Query *viewParse)
* Create the 2 new range table entries and form the new range table... * Create the 2 new range table entries and form the new range table...
* OLD first, then NEW.... * OLD first, then NEW....
*/ */
rt_entry1 = addRangeTableEntryForRelation(pstate, viewRel, nsitem = addRangeTableEntryForRelation(pstate, viewRel,
AccessShareLock, AccessShareLock,
makeAlias("old", NIL), makeAlias("old", NIL),
false, false); false, false);
rt_entry2 = addRangeTableEntryForRelation(pstate, viewRel, rt_entry1 = nsitem->p_rte;
AccessShareLock, nsitem = addRangeTableEntryForRelation(pstate, viewRel,
makeAlias("new", NIL), AccessShareLock,
false, false); makeAlias("new", NIL),
false, false);
rt_entry2 = nsitem->p_rte;
/* Must override addRangeTableEntry's default access-check flags */ /* Must override addRangeTableEntry's default access-check flags */
rt_entry1->requiredPerms = 0; rt_entry1->requiredPerms = 0;
rt_entry2->requiredPerms = 0; rt_entry2->requiredPerms = 0;

View File

@ -1217,6 +1217,7 @@ convert_ANY_sublink_to_join(PlannerInfo *root, SubLink *sublink,
Query *subselect = (Query *) sublink->subselect; Query *subselect = (Query *) sublink->subselect;
Relids upper_varnos; Relids upper_varnos;
int rtindex; int rtindex;
ParseNamespaceItem *nsitem;
RangeTblEntry *rte; RangeTblEntry *rte;
RangeTblRef *rtr; RangeTblRef *rtr;
List *subquery_vars; 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 * below). Therefore this is a lot easier than what pull_up_subqueries has
* to go through. * to go through.
*/ */
rte = addRangeTableEntryForSubquery(pstate, nsitem = addRangeTableEntryForSubquery(pstate,
subselect, subselect,
makeAlias("ANY_subquery", NIL), makeAlias("ANY_subquery", NIL),
false, false,
false); false);
rte = nsitem->p_rte;
parse->rtable = lappend(parse->rtable, rte); parse->rtable = lappend(parse->rtable, rte);
rtindex = list_length(parse->rtable); rtindex = list_length(parse->rtable);

View File

@ -415,9 +415,7 @@ transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt)
stmt->relation->inh, stmt->relation->inh,
true, true,
ACL_DELETE); ACL_DELETE);
nsitem = pstate->p_target_nsitem;
/* grab the namespace item made by setTargetTable */
nsitem = (ParseNamespaceItem *) llast(pstate->p_namespace);
/* there's no DISTINCT in DELETE */ /* there's no DISTINCT in DELETE */
qry->distinctClause = NIL; qry->distinctClause = NIL;
@ -476,8 +474,8 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
List *sub_namespace; List *sub_namespace;
List *icolumns; List *icolumns;
List *attrnos; List *attrnos;
ParseNamespaceItem *nsitem;
RangeTblEntry *rte; RangeTblEntry *rte;
RangeTblRef *rtr;
ListCell *icols; ListCell *icols;
ListCell *attnos; ListCell *attnos;
ListCell *lc; ListCell *lc;
@ -611,18 +609,14 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
/* /*
* Make the source be a subquery in the INSERT's rangetable, and add * 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, nsitem = addRangeTableEntryForSubquery(pstate,
selectQuery, selectQuery,
makeAlias("*SELECT*", NIL), makeAlias("*SELECT*", NIL),
false, false,
false); false);
rtr = makeNode(RangeTblRef); addNSItemToQuery(pstate, nsitem, true, false, false);
/* 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);
/*---------- /*----------
* Generate an expression list for the INSERT that selects all the * Generate an expression list for the INSERT that selects all the
@ -652,7 +646,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
expr = tle->expr; expr = tle->expr;
else else
{ {
Var *var = makeVarFromTargetEntry(rtr->rtindex, tle); Var *var = makeVarFromTargetEntry(nsitem->p_rtindex, tle);
var->location = exprLocation((Node *) tle->expr); var->location = exprLocation((Node *) tle->expr);
expr = (Expr *) var; expr = (Expr *) var;
@ -774,19 +768,15 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
/* /*
* Generate the VALUES RTE * Generate the VALUES RTE
*/ */
rte = addRangeTableEntryForValues(pstate, exprsLists, nsitem = addRangeTableEntryForValues(pstate, exprsLists,
coltypes, coltypmods, colcollations, coltypes, coltypmods, colcollations,
NULL, lateral, true); NULL, lateral, true);
rtr = makeNode(RangeTblRef); addNSItemToQuery(pstate, nsitem, true, false, false);
/* 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);
/* /*
* Generate list of Vars referencing the RTE * 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 * 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. * Generate query's target list using the computed list of expressions.
* Also, mark all the target columns as needing insert permissions. * 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; qry->targetList = NIL;
Assert(list_length(exprList) <= list_length(icolumns)); Assert(list_length(exprList) <= list_length(icolumns));
forthree(lc, exprList, icols, icolumns, attnos, attrnos) forthree(lc, exprList, icols, icolumns, attnos, attrnos)
@ -863,8 +853,8 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
if (stmt->returningList) if (stmt->returningList)
{ {
pstate->p_namespace = NIL; pstate->p_namespace = NIL;
addRTEtoQuery(pstate, pstate->p_target_rangetblentry, addNSItemToQuery(pstate, pstate->p_target_nsitem,
false, true, true); false, true, true);
qry->returningList = transformReturningList(pstate, qry->returningList = transformReturningList(pstate,
stmt->returningList); stmt->returningList);
} }
@ -999,7 +989,6 @@ transformOnConflictClause(ParseState *pstate,
Oid arbiterConstraint; Oid arbiterConstraint;
List *onConflictSet = NIL; List *onConflictSet = NIL;
Node *onConflictWhere = NULL; Node *onConflictWhere = NULL;
RangeTblEntry *exclRte = NULL;
int exclRelIndex = 0; int exclRelIndex = 0;
List *exclRelTlist = NIL; List *exclRelTlist = NIL;
OnConflictExpr *result; OnConflictExpr *result;
@ -1012,6 +1001,8 @@ transformOnConflictClause(ParseState *pstate,
if (onConflictClause->action == ONCONFLICT_UPDATE) if (onConflictClause->action == ONCONFLICT_UPDATE)
{ {
Relation targetrel = pstate->p_target_relation; Relation targetrel = pstate->p_target_relation;
ParseNamespaceItem *exclNSItem;
RangeTblEntry *exclRte;
/* /*
* All INSERT expressions have been parsed, get ready for potentially * 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 * relation, and no permission checks are required on it. (We'll
* check the actual target relation, instead.) * check the actual target relation, instead.)
*/ */
exclRte = addRangeTableEntryForRelation(pstate, exclNSItem = addRangeTableEntryForRelation(pstate,
targetrel, targetrel,
RowExclusiveLock, RowExclusiveLock,
makeAlias("excluded", NIL), makeAlias("excluded", NIL),
false, false); false, false);
exclRte = exclNSItem->p_rte;
exclRelIndex = exclNSItem->p_rtindex;
exclRte->relkind = RELKIND_COMPOSITE_TYPE; exclRte->relkind = RELKIND_COMPOSITE_TYPE;
exclRte->requiredPerms = 0; exclRte->requiredPerms = 0;
/* other permissions fields in exclRte are already empty */ /* other permissions fields in exclRte are already empty */
exclRelIndex = list_length(pstate->p_rtable);
/* Create EXCLUDED rel's targetlist for use by EXPLAIN */ /* Create EXCLUDED rel's targetlist for use by EXPLAIN */
exclRelTlist = BuildOnConflictExcludedTargetlist(targetrel, exclRelTlist = BuildOnConflictExcludedTargetlist(targetrel,
exclRelIndex); exclRelIndex);
@ -1044,9 +1036,9 @@ transformOnConflictClause(ParseState *pstate,
* Add EXCLUDED and the target RTE to the namespace, so that they can * Add EXCLUDED and the target RTE to the namespace, so that they can
* be used in the UPDATE subexpressions. * be used in the UPDATE subexpressions.
*/ */
addRTEtoQuery(pstate, exclRte, false, true, true); addNSItemToQuery(pstate, exclNSItem, false, true, true);
addRTEtoQuery(pstate, pstate->p_target_rangetblentry, addNSItemToQuery(pstate, pstate->p_target_nsitem,
false, true, true); false, true, true);
/* /*
* Now transform the UPDATE subexpressions. * Now transform the UPDATE subexpressions.
@ -1343,7 +1335,6 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
List **colexprs = NULL; List **colexprs = NULL;
int sublist_length = -1; int sublist_length = -1;
bool lateral = false; bool lateral = false;
RangeTblEntry *rte;
ParseNamespaceItem *nsitem; ParseNamespaceItem *nsitem;
ListCell *lc; ListCell *lc;
ListCell *lc2; ListCell *lc2;
@ -1511,14 +1502,10 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
/* /*
* Generate the VALUES RTE * Generate the VALUES RTE
*/ */
rte = addRangeTableEntryForValues(pstate, exprsLists, nsitem = addRangeTableEntryForValues(pstate, exprsLists,
coltypes, coltypmods, colcollations, coltypes, coltypmods, colcollations,
NULL, lateral, true); NULL, lateral, true);
addRTEtoQuery(pstate, rte, true, true, true); addNSItemToQuery(pstate, nsitem, true, true, true);
/* grab the namespace item made by addRTEtoQuery */
nsitem = (ParseNamespaceItem *) llast(pstate->p_namespace);
Assert(rte == nsitem->p_rte);
/* /*
* Generate a targetlist as though expanding "*" * Generate a targetlist as though expanding "*"
@ -1593,7 +1580,9 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
*targetnames, *targetnames,
*sv_namespace; *sv_namespace;
int sv_rtable_length; int sv_rtable_length;
RangeTblEntry *jrte; ParseNamespaceItem *jnsitem;
ParseNamespaceColumn *sortnscolumns;
int sortcolindex;
int tllen; int tllen;
qry->commandType = CMD_SELECT; qry->commandType = CMD_SELECT;
@ -1686,6 +1675,9 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
qry->targetList = NIL; qry->targetList = NIL;
targetvars = NIL; targetvars = NIL;
targetnames = NIL; targetnames = NIL;
sortnscolumns = (ParseNamespaceColumn *)
palloc0(list_length(sostmt->colTypes) * sizeof(ParseNamespaceColumn));
sortcolindex = 0;
forfour(lct, sostmt->colTypes, forfour(lct, sostmt->colTypes,
lcm, sostmt->colTypmods, lcm, sostmt->colTypmods,
@ -1716,6 +1708,14 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
qry->targetList = lappend(qry->targetList, tle); qry->targetList = lappend(qry->targetList, tle);
targetvars = lappend(targetvars, var); targetvars = lappend(targetvars, var);
targetnames = lappend(targetnames, makeString(colName)); 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); sv_rtable_length = list_length(pstate->p_rtable);
jrte = addRangeTableEntryForJoin(pstate, jnsitem = addRangeTableEntryForJoin(pstate,
targetnames, targetnames,
JOIN_INNER, sortnscolumns,
targetvars, JOIN_INNER,
NULL, targetvars,
false); NULL,
false);
sv_namespace = pstate->p_namespace; sv_namespace = pstate->p_namespace;
pstate->p_namespace = NIL; pstate->p_namespace = NIL;
/* add jrte to column namespace only */ /* add jnsitem to column namespace only */
addRTEtoQuery(pstate, jrte, false, false, true); addNSItemToQuery(pstate, jnsitem, false, false, true);
/* /*
* For now, we don't support resjunk sort clauses on the output of a * 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, EXPR_KIND_ORDER_BY,
false /* allow SQL92 rules */ ); false /* allow SQL92 rules */ );
/* restore namespace, remove jrte from rtable */ /* restore namespace, remove join RTE from rtable */
pstate->p_namespace = sv_namespace; pstate->p_namespace = sv_namespace;
pstate->p_rtable = list_truncate(pstate->p_rtable, sv_rtable_length); pstate->p_rtable = list_truncate(pstate->p_rtable, sv_rtable_length);
@ -1869,7 +1870,7 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt,
/* Process leaf SELECT */ /* Process leaf SELECT */
Query *selectQuery; Query *selectQuery;
char selectName[32]; char selectName[32];
RangeTblEntry *rte PG_USED_FOR_ASSERTS_ONLY; ParseNamespaceItem *nsitem;
RangeTblRef *rtr; RangeTblRef *rtr;
ListCell *tl; ListCell *tl;
@ -1926,19 +1927,17 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt,
*/ */
snprintf(selectName, sizeof(selectName), "*SELECT* %d", snprintf(selectName, sizeof(selectName), "*SELECT* %d",
list_length(pstate->p_rtable) + 1); list_length(pstate->p_rtable) + 1);
rte = addRangeTableEntryForSubquery(pstate, nsitem = addRangeTableEntryForSubquery(pstate,
selectQuery, selectQuery,
makeAlias(selectName, NIL), makeAlias(selectName, NIL),
false, false,
false); false);
/* /*
* Return a RangeTblRef to replace the SelectStmt in the set-op tree. * Return a RangeTblRef to replace the SelectStmt in the set-op tree.
*/ */
rtr = makeNode(RangeTblRef); rtr = makeNode(RangeTblRef);
/* assume new rte is at end */ rtr->rtindex = nsitem->p_rtindex;
rtr->rtindex = list_length(pstate->p_rtable);
Assert(rte == rt_fetch(rtr->rtindex, pstate->p_rtable));
return (Node *) rtr; return (Node *) rtr;
} }
else else
@ -2236,9 +2235,7 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
stmt->relation->inh, stmt->relation->inh,
true, true,
ACL_UPDATE); ACL_UPDATE);
nsitem = pstate->p_target_nsitem;
/* grab the namespace item made by setTargetTable */
nsitem = (ParseNamespaceItem *) llast(pstate->p_namespace);
/* subqueries in FROM cannot access the result relation */ /* subqueries in FROM cannot access the result relation */
nsitem->p_lateral_only = true; nsitem->p_lateral_only = true;
@ -2297,7 +2294,7 @@ transformUpdateTargetList(ParseState *pstate, List *origTlist)
pstate->p_next_resno = RelationGetNumberOfAttributes(pstate->p_target_relation) + 1; pstate->p_next_resno = RelationGetNumberOfAttributes(pstate->p_target_relation) + 1;
/* Prepare non-junk columns for assignment to target table */ /* 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); orig_tl = list_head(origTlist);
foreach(tl, tlist) foreach(tl, tlist)

View File

@ -51,37 +51,33 @@
#include "utils/rel.h" #include "utils/rel.h"
#include "utils/syscache.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, static void extractRemainingColumns(List *common_colnames,
List *src_colnames, List *src_colvars, 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, static Node *transformJoinUsingClause(ParseState *pstate,
RangeTblEntry *leftRTE, RangeTblEntry *rightRTE, RangeTblEntry *leftRTE, RangeTblEntry *rightRTE,
List *leftVars, List *rightVars); List *leftVars, List *rightVars);
static Node *transformJoinOnClause(ParseState *pstate, JoinExpr *j, static Node *transformJoinOnClause(ParseState *pstate, JoinExpr *j,
List *namespace); List *namespace);
static RangeTblEntry *getRTEForSpecialRelationTypes(ParseState *pstate, static ParseNamespaceItem *transformTableEntry(ParseState *pstate, RangeVar *r);
RangeVar *rv); static ParseNamespaceItem *transformRangeSubselect(ParseState *pstate,
static RangeTblEntry *transformTableEntry(ParseState *pstate, RangeVar *r); RangeSubselect *r);
static RangeTblEntry *transformRangeSubselect(ParseState *pstate, static ParseNamespaceItem *transformRangeFunction(ParseState *pstate,
RangeSubselect *r); RangeFunction *r);
static RangeTblEntry *transformRangeFunction(ParseState *pstate, static ParseNamespaceItem *transformRangeTableFunc(ParseState *pstate,
RangeFunction *r); RangeTableFunc *t);
static RangeTblEntry *transformRangeTableFunc(ParseState *pstate,
RangeTableFunc *t);
static TableSampleClause *transformRangeTableSample(ParseState *pstate, static TableSampleClause *transformRangeTableSample(ParseState *pstate,
RangeTableSample *rts); RangeTableSample *rts);
static ParseNamespaceItem *getNSItemForSpecialRelationTypes(ParseState *pstate,
RangeVar *rv);
static Node *transformFromClauseItem(ParseState *pstate, Node *n, static Node *transformFromClauseItem(ParseState *pstate, Node *n,
RangeTblEntry **top_rte, int *top_rti, ParseNamespaceItem **top_nsitem,
List **namespace); List **namespace);
static Node *buildMergedJoinVar(ParseState *pstate, JoinType jointype, static Node *buildMergedJoinVar(ParseState *pstate, JoinType jointype,
Var *l_colvar, Var *r_colvar); 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 setNamespaceColumnVisibility(List *namespace, bool cols_visible);
static void setNamespaceLateralState(List *namespace, static void setNamespaceLateralState(List *namespace,
bool lateral_only, bool lateral_ok); bool lateral_only, bool lateral_ok);
@ -130,13 +126,11 @@ transformFromClause(ParseState *pstate, List *frmList)
foreach(fl, frmList) foreach(fl, frmList)
{ {
Node *n = lfirst(fl); Node *n = lfirst(fl);
RangeTblEntry *rte; ParseNamespaceItem *nsitem;
int rtindex;
List *namespace; List *namespace;
n = transformFromClauseItem(pstate, n, n = transformFromClauseItem(pstate, n,
&rte, &nsitem,
&rtindex,
&namespace); &namespace);
checkNameSpaceConflicts(pstate, pstate->p_namespace, namespace); checkNameSpaceConflicts(pstate, pstate->p_namespace, namespace);
@ -183,8 +177,7 @@ int
setTargetTable(ParseState *pstate, RangeVar *relation, setTargetTable(ParseState *pstate, RangeVar *relation,
bool inh, bool alsoSource, AclMode requiredPerms) bool inh, bool alsoSource, AclMode requiredPerms)
{ {
RangeTblEntry *rte; ParseNamespaceItem *nsitem;
int rtindex;
/* /*
* ENRs hide tables of the same name, so we need to check for them first. * 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); RowExclusiveLock);
/* /*
* Now build an RTE. * Now build an RTE and a ParseNamespaceItem.
*/ */
rte = addRangeTableEntryForRelation(pstate, pstate->p_target_relation, nsitem = addRangeTableEntryForRelation(pstate, pstate->p_target_relation,
RowExclusiveLock, RowExclusiveLock,
relation->alias, inh, false); relation->alias, inh, false);
/* assume new rte is at end */ /* remember the RTE/nsitem as being the query target */
rtindex = list_length(pstate->p_rtable); pstate->p_target_nsitem = nsitem;
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;
/* /*
* Override addRangeTableEntry's default ACL_SELECT permissions check, and * 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 * analysis, we will add the ACL_SELECT bit back again; see
* markVarForSelectPriv and its callers. * markVarForSelectPriv and its callers.
*/ */
rte->requiredPerms = requiredPerms; nsitem->p_rte->requiredPerms = requiredPerms;
/* /*
* If UPDATE/DELETE, add table to joinlist and namespace. * 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) 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 * 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 static void
extractRemainingColumns(List *common_colnames, extractRemainingColumns(List *common_colnames,
List *src_colnames, List *src_colvars, 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_colnames = NIL;
List *new_colvars = NIL; List *new_colvars = NIL;
@ -271,6 +261,14 @@ extractRemainingColumns(List *common_colnames,
bool match = false; bool match = false;
ListCell *cnames; 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) foreach(cnames, common_colnames)
{ {
char *ccolname = strVal(lfirst(cnames)); char *ccolname = strVal(lfirst(cnames));
@ -284,9 +282,15 @@ extractRemainingColumns(List *common_colnames,
if (!match) if (!match)
{ {
/* Nope, so emit it as next output column */
new_colnames = lappend(new_colnames, lfirst(lnames)); new_colnames = lappend(new_colnames, lfirst(lnames));
new_colvars = lappend(new_colvars, lfirst(lvars)); 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; *res_colnames = new_colnames;
@ -388,25 +392,20 @@ transformJoinOnClause(ParseState *pstate, JoinExpr *j, List *namespace)
/* /*
* transformTableEntry --- transform a RangeVar (simple relation reference) * transformTableEntry --- transform a RangeVar (simple relation reference)
*/ */
static RangeTblEntry * static ParseNamespaceItem *
transformTableEntry(ParseState *pstate, RangeVar *r) transformTableEntry(ParseState *pstate, RangeVar *r)
{ {
RangeTblEntry *rte; /* addRangeTableEntry does all the work */
return addRangeTableEntry(pstate, r, r->alias, r->inh, true);
/* We need only build a range table entry */
rte = addRangeTableEntry(pstate, r, r->alias, r->inh, true);
return rte;
} }
/* /*
* transformRangeSubselect --- transform a sub-SELECT appearing in FROM * transformRangeSubselect --- transform a sub-SELECT appearing in FROM
*/ */
static RangeTblEntry * static ParseNamespaceItem *
transformRangeSubselect(ParseState *pstate, RangeSubselect *r) transformRangeSubselect(ParseState *pstate, RangeSubselect *r)
{ {
Query *query; Query *query;
RangeTblEntry *rte;
/* /*
* We require user to supply an alias for a subselect, per SQL92. To relax * 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"); 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, return addRangeTableEntryForSubquery(pstate,
query, query,
r->alias, r->alias,
r->lateral, r->lateral,
true); true);
return rte;
} }
/* /*
* transformRangeFunction --- transform a function call appearing in FROM * transformRangeFunction --- transform a function call appearing in FROM
*/ */
static RangeTblEntry * static ParseNamespaceItem *
transformRangeFunction(ParseState *pstate, RangeFunction *r) transformRangeFunction(ParseState *pstate, RangeFunction *r)
{ {
List *funcexprs = NIL; List *funcexprs = NIL;
List *funcnames = NIL; List *funcnames = NIL;
List *coldeflists = NIL; List *coldeflists = NIL;
bool is_lateral; bool is_lateral;
RangeTblEntry *rte;
ListCell *lc; ListCell *lc;
/* /*
@ -677,13 +673,11 @@ transformRangeFunction(ParseState *pstate, RangeFunction *r)
is_lateral = r->lateral || contain_vars_of_level((Node *) funcexprs, 0); 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, return addRangeTableEntryForFunction(pstate,
funcnames, funcexprs, coldeflists, funcnames, funcexprs, coldeflists,
r, is_lateral, true); r, is_lateral, true);
return rte;
} }
/* /*
@ -694,13 +688,12 @@ transformRangeFunction(ParseState *pstate, RangeFunction *r)
* row-generating expression, the column-generating expressions, and the * row-generating expression, the column-generating expressions, and the
* default value expressions. * default value expressions.
*/ */
static RangeTblEntry * static ParseNamespaceItem *
transformRangeTableFunc(ParseState *pstate, RangeTableFunc *rtf) transformRangeTableFunc(ParseState *pstate, RangeTableFunc *rtf)
{ {
TableFunc *tf = makeNode(TableFunc); TableFunc *tf = makeNode(TableFunc);
const char *constructName; const char *constructName;
Oid docType; Oid docType;
RangeTblEntry *rte;
bool is_lateral; bool is_lateral;
ListCell *col; ListCell *col;
char **names; char **names;
@ -903,10 +896,8 @@ transformRangeTableFunc(ParseState *pstate, RangeTableFunc *rtf)
*/ */
is_lateral = rtf->lateral || contain_vars_of_level((Node *) tf, 0); is_lateral = rtf->lateral || contain_vars_of_level((Node *) tf, 0);
rte = addRangeTableEntryForTableFunc(pstate, return addRangeTableEntryForTableFunc(pstate,
tf, rtf->alias, is_lateral, true); tf, rtf->alias, is_lateral, true);
return rte;
} }
/* /*
@ -1013,17 +1004,17 @@ transformRangeTableSample(ParseState *pstate, RangeTableSample *rts)
} }
/* /*
* getRTEForSpecialRelationTypes * getNSItemForSpecialRelationTypes
* *
* If given RangeVar refers to a CTE or an EphemeralNamedRelation, * 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 * static ParseNamespaceItem *
getRTEForSpecialRelationTypes(ParseState *pstate, RangeVar *rv) getNSItemForSpecialRelationTypes(ParseState *pstate, RangeVar *rv)
{ {
ParseNamespaceItem *nsitem;
CommonTableExpr *cte; CommonTableExpr *cte;
Index levelsup; Index levelsup;
RangeTblEntry *rte;
/* /*
* if it is a qualified name, it can't be a CTE or tuplestore reference * 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); cte = scanNameSpaceForCTE(pstate, rv->relname, &levelsup);
if (cte) if (cte)
rte = addRangeTableEntryForCTE(pstate, cte, levelsup, rv, true); nsitem = addRangeTableEntryForCTE(pstate, cte, levelsup, rv, true);
else if (scanNameSpaceForENR(pstate, rv->relname)) else if (scanNameSpaceForENR(pstate, rv->relname))
rte = addRangeTableEntryForENR(pstate, rv, true); nsitem = addRangeTableEntryForENR(pstate, rv, true);
else 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 * The function return value is the node to add to the jointree (a
* RangeTblRef or JoinExpr). Additional output parameters are: * RangeTblRef or JoinExpr). Additional output parameters are:
* *
* *top_rte: receives the RTE corresponding to the jointree item. * *top_nsitem: receives the ParseNamespaceItem directly corresponding to the
* (We could extract this from the function return node, but it saves cycles * jointree item. (This is only used during internal recursion, not by
* to pass it back separately.) * outside callers.)
*
* *top_rti: receives the rangetable index of top_rte. (Ditto.)
* *
* *namespace: receives a List of ParseNamespaceItems for the RTEs exposed * *namespace: receives a List of ParseNamespaceItems for the RTEs exposed
* as table/column names by this item. (The lateral_only flags in these items * 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 * static Node *
transformFromClauseItem(ParseState *pstate, Node *n, transformFromClauseItem(ParseState *pstate, Node *n,
RangeTblEntry **top_rte, int *top_rti, ParseNamespaceItem **top_nsitem,
List **namespace) List **namespace)
{ {
if (IsA(n, RangeVar)) if (IsA(n, RangeVar))
@ -1073,78 +1062,58 @@ transformFromClauseItem(ParseState *pstate, Node *n,
/* Plain relation reference, or perhaps a CTE reference */ /* Plain relation reference, or perhaps a CTE reference */
RangeVar *rv = (RangeVar *) n; RangeVar *rv = (RangeVar *) n;
RangeTblRef *rtr; RangeTblRef *rtr;
RangeTblEntry *rte; ParseNamespaceItem *nsitem;
int rtindex;
/* Check if it's a CTE or tuplestore reference */ /* 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 not found above, must be a table reference */
if (!rte) if (!nsitem)
rte = transformTableEntry(pstate, rv); nsitem = transformTableEntry(pstate, rv);
/* assume new rte is at end */ *top_nsitem = nsitem;
rtindex = list_length(pstate->p_rtable); *namespace = list_make1(nsitem);
Assert(rte == rt_fetch(rtindex, pstate->p_rtable));
*top_rte = rte;
*top_rti = rtindex;
*namespace = list_make1(makeDefaultNSItem(rte, rtindex));
rtr = makeNode(RangeTblRef); rtr = makeNode(RangeTblRef);
rtr->rtindex = rtindex; rtr->rtindex = nsitem->p_rtindex;
return (Node *) rtr; return (Node *) rtr;
} }
else if (IsA(n, RangeSubselect)) else if (IsA(n, RangeSubselect))
{ {
/* sub-SELECT is like a plain relation */ /* sub-SELECT is like a plain relation */
RangeTblRef *rtr; RangeTblRef *rtr;
RangeTblEntry *rte; ParseNamespaceItem *nsitem;
int rtindex;
rte = transformRangeSubselect(pstate, (RangeSubselect *) n); nsitem = transformRangeSubselect(pstate, (RangeSubselect *) n);
/* assume new rte is at end */ *top_nsitem = nsitem;
rtindex = list_length(pstate->p_rtable); *namespace = list_make1(nsitem);
Assert(rte == rt_fetch(rtindex, pstate->p_rtable));
*top_rte = rte;
*top_rti = rtindex;
*namespace = list_make1(makeDefaultNSItem(rte, rtindex));
rtr = makeNode(RangeTblRef); rtr = makeNode(RangeTblRef);
rtr->rtindex = rtindex; rtr->rtindex = nsitem->p_rtindex;
return (Node *) rtr; return (Node *) rtr;
} }
else if (IsA(n, RangeFunction)) else if (IsA(n, RangeFunction))
{ {
/* function is like a plain relation */ /* function is like a plain relation */
RangeTblRef *rtr; RangeTblRef *rtr;
RangeTblEntry *rte; ParseNamespaceItem *nsitem;
int rtindex;
rte = transformRangeFunction(pstate, (RangeFunction *) n); nsitem = transformRangeFunction(pstate, (RangeFunction *) n);
/* assume new rte is at end */ *top_nsitem = nsitem;
rtindex = list_length(pstate->p_rtable); *namespace = list_make1(nsitem);
Assert(rte == rt_fetch(rtindex, pstate->p_rtable));
*top_rte = rte;
*top_rti = rtindex;
*namespace = list_make1(makeDefaultNSItem(rte, rtindex));
rtr = makeNode(RangeTblRef); rtr = makeNode(RangeTblRef);
rtr->rtindex = rtindex; rtr->rtindex = nsitem->p_rtindex;
return (Node *) rtr; return (Node *) rtr;
} }
else if (IsA(n, RangeTableFunc)) else if (IsA(n, RangeTableFunc))
{ {
/* table function is like a plain relation */ /* table function is like a plain relation */
RangeTblRef *rtr; RangeTblRef *rtr;
RangeTblEntry *rte; ParseNamespaceItem *nsitem;
int rtindex;
rte = transformRangeTableFunc(pstate, (RangeTableFunc *) n); nsitem = transformRangeTableFunc(pstate, (RangeTableFunc *) n);
/* assume new rte is at end */ *top_nsitem = nsitem;
rtindex = list_length(pstate->p_rtable); *namespace = list_make1(nsitem);
Assert(rte == rt_fetch(rtindex, pstate->p_rtable));
*top_rte = rte;
*top_rti = rtindex;
*namespace = list_make1(makeDefaultNSItem(rte, rtindex));
rtr = makeNode(RangeTblRef); rtr = makeNode(RangeTblRef);
rtr->rtindex = rtindex; rtr->rtindex = nsitem->p_rtindex;
return (Node *) rtr; return (Node *) rtr;
} }
else if (IsA(n, RangeTableSample)) else if (IsA(n, RangeTableSample))
@ -1152,19 +1121,17 @@ transformFromClauseItem(ParseState *pstate, Node *n,
/* TABLESAMPLE clause (wrapping some other valid FROM node) */ /* TABLESAMPLE clause (wrapping some other valid FROM node) */
RangeTableSample *rts = (RangeTableSample *) n; RangeTableSample *rts = (RangeTableSample *) n;
Node *rel; Node *rel;
RangeTblRef *rtr;
RangeTblEntry *rte; RangeTblEntry *rte;
/* Recursively transform the contained relation */ /* Recursively transform the contained relation */
rel = transformFromClauseItem(pstate, rts->relation, rel = transformFromClauseItem(pstate, rts->relation,
top_rte, top_rti, namespace); top_nsitem, namespace);
/* Currently, grammar could only return a RangeVar as contained rel */ rte = (*top_nsitem)->p_rte;
rtr = castNode(RangeTblRef, rel);
rte = rt_fetch(rtr->rtindex, pstate->p_rtable);
/* We only support this on plain relations and matviews */ /* We only support this on plain relations and matviews */
if (rte->relkind != RELKIND_RELATION && if (rte->rtekind != RTE_RELATION ||
rte->relkind != RELKIND_MATVIEW && (rte->relkind != RELKIND_RELATION &&
rte->relkind != RELKIND_PARTITIONED_TABLE) rte->relkind != RELKIND_MATVIEW &&
rte->relkind != RELKIND_PARTITIONED_TABLE))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("TABLESAMPLE clause can only be applied to tables and materialized views"), 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 */ /* Transform TABLESAMPLE details and attach to the RTE */
rte->tablesample = transformRangeTableSample(pstate, rts); rte->tablesample = transformRangeTableSample(pstate, rts);
return (Node *) rtr; return rel;
} }
else if (IsA(n, JoinExpr)) else if (IsA(n, JoinExpr))
{ {
/* A newfangled join expression */ /* A newfangled join expression */
JoinExpr *j = (JoinExpr *) n; JoinExpr *j = (JoinExpr *) n;
RangeTblEntry *l_rte; ParseNamespaceItem *nsitem;
RangeTblEntry *r_rte; ParseNamespaceItem *l_nsitem;
int l_rtindex; ParseNamespaceItem *r_nsitem;
int r_rtindex;
List *l_namespace, List *l_namespace,
*r_namespace, *r_namespace,
*my_namespace, *my_namespace,
@ -1191,9 +1157,10 @@ transformFromClauseItem(ParseState *pstate, Node *n,
*l_colvars, *l_colvars,
*r_colvars, *r_colvars,
*res_colvars; *res_colvars;
ParseNamespaceColumn *res_nscolumns;
int res_colindex;
bool lateral_ok; bool lateral_ok;
int sv_namespace_length; int sv_namespace_length;
RangeTblEntry *rte;
int k; int k;
/* /*
@ -1201,8 +1168,7 @@ transformFromClauseItem(ParseState *pstate, Node *n,
* it in this order for correct visibility of LATERAL references. * it in this order for correct visibility of LATERAL references.
*/ */
j->larg = transformFromClauseItem(pstate, j->larg, j->larg = transformFromClauseItem(pstate, j->larg,
&l_rte, &l_nsitem,
&l_rtindex,
&l_namespace); &l_namespace);
/* /*
@ -1225,8 +1191,7 @@ transformFromClauseItem(ParseState *pstate, Node *n,
/* And now we can process the RHS */ /* And now we can process the RHS */
j->rarg = transformFromClauseItem(pstate, j->rarg, j->rarg = transformFromClauseItem(pstate, j->rarg,
&r_rte, &r_nsitem,
&r_rtindex,
&r_namespace); &r_namespace);
/* Remove the left-side RTEs from the namespace list again */ /* 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 * 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_colvars = expandNSItemVars(l_nsitem, 0, -1, &l_colnames);
&l_colnames, &l_colvars); r_colvars = expandNSItemVars(r_nsitem, 0, -1, &r_colnames);
expandRTE(r_rte, r_rtindex, 0, -1, false,
&r_colnames, &r_colvars);
/* /*
* Natural join does not explicitly specify columns; must generate * Natural join does not explicitly specify columns; must generate
@ -1302,6 +1265,12 @@ transformFromClauseItem(ParseState *pstate, Node *n,
res_colnames = NIL; res_colnames = NIL;
res_colvars = 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) if (j->usingClause)
{ {
/* /*
@ -1325,6 +1294,8 @@ transformFromClauseItem(ParseState *pstate, Node *n,
int r_index = -1; int r_index = -1;
Var *l_colvar, Var *l_colvar,
*r_colvar; *r_colvar;
Node *u_colvar;
ParseNamespaceColumn *res_nscolumn;
/* Check for USING(foo,foo) */ /* Check for USING(foo,foo) */
foreach(col, res_colnames) foreach(col, res_colnames)
@ -1390,16 +1361,58 @@ transformFromClauseItem(ParseState *pstate, Node *n,
r_usingvars = lappend(r_usingvars, r_colvar); r_usingvars = lappend(r_usingvars, r_colvar);
res_colnames = lappend(res_colnames, lfirst(ucol)); res_colnames = lappend(res_colnames, lfirst(ucol));
res_colvars = lappend(res_colvars, u_colvar = buildMergedJoinVar(pstate,
buildMergedJoinVar(pstate, j->jointype,
j->jointype, l_colvar,
l_colvar, r_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, j->quals = transformJoinUsingClause(pstate,
l_rte, l_nsitem->p_rte,
r_rte, r_nsitem->p_rte,
l_usingvars, l_usingvars,
r_usingvars); r_usingvars);
} }
@ -1416,10 +1429,16 @@ transformFromClauseItem(ParseState *pstate, Node *n,
/* Add remaining columns from each side to the output columns */ /* Add remaining columns from each side to the output columns */
extractRemainingColumns(res_colnames, extractRemainingColumns(res_colnames,
l_colnames, l_colvars, 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, extractRemainingColumns(res_colnames,
r_colnames, r_colvars, 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_colnames = list_concat(res_colnames, l_colnames);
res_colvars = list_concat(res_colvars, l_colvars); res_colvars = list_concat(res_colvars, l_colvars);
res_colnames = list_concat(res_colnames, r_colnames); 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, nsitem = addRangeTableEntryForJoin(pstate,
res_colnames, res_colnames,
j->jointype, res_nscolumns,
res_colvars, j->jointype,
j->alias, res_colvars,
true); j->alias,
true);
/* assume new rte is at end */ j->rtindex = nsitem->p_rtindex;
j->rtindex = list_length(pstate->p_rtable);
Assert(rte == rt_fetch(j->rtindex, pstate->p_rtable));
*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 */ /* make a matching link to the JoinExpr for later use */
for (k = list_length(pstate->p_joinexprs) + 1; k < j->rtindex; k++) 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 * 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. * names. It's visible as a relation name only if it has an alias.
*/ */
*namespace = lappend(my_namespace, nsitem->p_rel_visible = (j->alias != NULL);
makeNamespaceItem(rte, nsitem->p_cols_visible = true;
j->rtindex, nsitem->p_lateral_only = false;
(j->alias != NULL), nsitem->p_lateral_ok = true;
true,
false, *top_nsitem = nsitem;
true)); *namespace = lappend(my_namespace, nsitem);
return (Node *) j; return (Node *) j;
} }
@ -1617,27 +1656,6 @@ buildMergedJoinVar(ParseState *pstate, JoinType jointype,
return res_node; 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 - * setNamespaceColumnVisibility -
* Convenience subroutine to update cols_visible flags in a namespace list. * Convenience subroutine to update cols_visible flags in a namespace list.
@ -3163,8 +3181,8 @@ transformOnConflictArbiter(ParseState *pstate,
*/ */
save_namespace = pstate->p_namespace; save_namespace = pstate->p_namespace;
pstate->p_namespace = NIL; pstate->p_namespace = NIL;
addRTEtoQuery(pstate, pstate->p_target_rangetblentry, addNSItemToQuery(pstate, pstate->p_target_nsitem,
false, false, true); false, false, true);
if (infer->indexElems) if (infer->indexElems)
*arbiterExpr = resolve_unique_index_expr(pstate, infer, *arbiterExpr = resolve_unique_index_expr(pstate, infer,
@ -3189,7 +3207,7 @@ transformOnConflictArbiter(ParseState *pstate,
if (infer->conname) if (infer->conname)
{ {
Oid relid = RelationGetRelid(pstate->p_target_relation); Oid relid = RelationGetRelid(pstate->p_target_relation);
RangeTblEntry *rte = pstate->p_target_rangetblentry; RangeTblEntry *rte = pstate->p_target_nsitem->p_rte;
Bitmapset *conattnos; Bitmapset *conattnos;
conattnos = get_relation_constraint_attnos(relid, infer->conname, conattnos = get_relation_constraint_attnos(relid, infer->conname,

View File

@ -1010,11 +1010,10 @@ coerce_record_to_complex(ParseState *pstate, Node *node,
int rtindex = ((Var *) node)->varno; int rtindex = ((Var *) node)->varno;
int sublevels_up = ((Var *) node)->varlevelsup; int sublevels_up = ((Var *) node)->varlevelsup;
int vlocation = ((Var *) node)->location; int vlocation = ((Var *) node)->location;
RangeTblEntry *rte; ParseNamespaceItem *nsitem;
rte = GetRTEByRangeTablePosn(pstate, rtindex, sublevels_up); nsitem = GetNSItemByRangeTablePosn(pstate, rtindex, sublevels_up);
expandRTE(rte, rtindex, sublevels_up, vlocation, false, args = expandNSItemVars(nsitem, sublevels_up, vlocation, NULL);
NULL, &args);
} }
else else
ereport(ERROR, ereport(ERROR,

View File

@ -2656,8 +2656,8 @@ static Node *
transformCurrentOfExpr(ParseState *pstate, CurrentOfExpr *cexpr) transformCurrentOfExpr(ParseState *pstate, CurrentOfExpr *cexpr)
{ {
/* CURRENT OF can only appear at top level of UPDATE/DELETE */ /* CURRENT OF can only appear at top level of UPDATE/DELETE */
Assert(pstate->p_target_rtindex > 0); Assert(pstate->p_target_nsitem != NULL);
cexpr->cvarno = pstate->p_target_rtindex; cexpr->cvarno = pstate->p_target_nsitem->p_rtindex;
/* /*
* Check to see if the cursor name matches a parameter of type REFCURSOR. * Check to see if the cursor name matches a parameter of type REFCURSOR.

View File

@ -472,7 +472,8 @@ check_lateral_ref_ok(ParseState *pstate, ParseNamespaceItem *nsitem,
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE), (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
errmsg("invalid reference to FROM-clause entry for table \"%s\"", errmsg("invalid reference to FROM-clause entry for table \"%s\"",
refname), 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.", errhint("There is an entry for table \"%s\", but it cannot be referenced from this part of the query.",
refname) : refname) :
errdetail("The combining JOIN type must be INNER or LEFT for a LATERAL reference."), 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; RangeTblEntry *rte = nsitem->p_rte;
int attnum; int attnum;
Var *var; Var *var;
Oid vartypeid;
int32 vartypmod;
Oid varcollid;
/* /*
* Scan the RTE's column names (or aliases) for a match. Complain if * 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))); parser_errposition(pstate, location)));
/* Found a valid match, so build a Var */ /* Found a valid match, so build a Var */
get_rte_attribute_type(rte, attnum, if (attnum > InvalidAttrNumber)
&vartypeid, &vartypmod, &varcollid); {
var = makeVar(nsitem->p_rtindex, attnum, /* Get attribute data from the ParseNamespaceColumn array */
vartypeid, vartypmod, varcollid, ParseNamespaceColumn *nscol = &nsitem->p_nscolumns[attnum - 1];
sublevels_up);
/* 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; var->location = location;
/* Require read access to the column */ /* Require read access to the column */
@ -753,11 +779,9 @@ scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte,
* don't bother to test for that case here. * don't bother to test for that case here.
* *
* Should this somehow go wrong and we try to access a dropped column, * Should this somehow go wrong and we try to access a dropped column,
* we'll still catch it by virtue of the checks in * we'll still catch it by virtue of the check in scanNSItemForColumn().
* get_rte_attribute_type(), which is called by scanNSItemForColumn(). * Callers interested in finding match with shortest distance need to
* That routine has to do a cache lookup anyway, so the check there is * defend against this directly, though.
* cheap. Callers interested in finding match with shortest distance need
* to defend against this directly, though.
*/ */
foreach(c, rte->eref->colnames) foreach(c, rte->eref->colnames)
{ {
@ -1200,6 +1224,121 @@ chooseScalarFunctionAlias(Node *funcexpr, char *funcname,
return 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 * 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). * 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. * Note: formerly this checked for refname conflicts, but that's wrong.
* Caller is responsible for checking for conflicts in the appropriate scope. * Caller is responsible for checking for conflicts in the appropriate scope.
*/ */
RangeTblEntry * ParseNamespaceItem *
addRangeTableEntry(ParseState *pstate, addRangeTableEntry(ParseState *pstate,
RangeVar *relation, RangeVar *relation,
Alias *alias, Alias *alias,
@ -1270,6 +1413,7 @@ addRangeTableEntry(ParseState *pstate,
char *refname = alias ? alias->aliasname : relation->relname; char *refname = alias ? alias->aliasname : relation->relname;
LOCKMODE lockmode; LOCKMODE lockmode;
Relation rel; Relation rel;
ParseNamespaceItem *nsitem;
Assert(pstate != NULL); Assert(pstate != NULL);
@ -1301,13 +1445,6 @@ addRangeTableEntry(ParseState *pstate,
rte->eref = makeAlias(refname, NIL); rte->eref = makeAlias(refname, NIL);
buildRelationAliases(rel->rd_att, alias, rte->eref); 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. * Set flags and access permissions.
* *
@ -1326,16 +1463,32 @@ addRangeTableEntry(ParseState *pstate,
rte->extraUpdatedCols = NULL; rte->extraUpdatedCols = NULL;
/* /*
* Add completed RTE to pstate's range table list, but not to join list * Add completed RTE to pstate's range table list, so that we know its
* nor namespace --- caller must do that if appropriate. * 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); 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). * 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 * This is just like addRangeTableEntry() except that it makes an RTE
* given an already-open relation instead of a RangeVar reference. * 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 * would require importing storage/lock.h into parse_relation.h. Since
* LOCKMODE is typedef'd as int anyway, that seems like overkill. * LOCKMODE is typedef'd as int anyway, that seems like overkill.
*/ */
RangeTblEntry * ParseNamespaceItem *
addRangeTableEntryForRelation(ParseState *pstate, addRangeTableEntryForRelation(ParseState *pstate,
Relation rel, Relation rel,
int lockmode, int lockmode,
@ -1398,21 +1551,28 @@ addRangeTableEntryForRelation(ParseState *pstate,
rte->extraUpdatedCols = NULL; rte->extraUpdatedCols = NULL;
/* /*
* Add completed RTE to pstate's range table list, but not to join list * Add completed RTE to pstate's range table list, so that we know its
* nor namespace --- caller must do that if appropriate. * 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); 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). * 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. * Note that an alias clause *must* be supplied.
*/ */
RangeTblEntry * ParseNamespaceItem *
addRangeTableEntryForSubquery(ParseState *pstate, addRangeTableEntryForSubquery(ParseState *pstate,
Query *subquery, Query *subquery,
Alias *alias, Alias *alias,
@ -1423,6 +1583,9 @@ addRangeTableEntryForSubquery(ParseState *pstate,
char *refname = alias->aliasname; char *refname = alias->aliasname;
Alias *eref; Alias *eref;
int numaliases; int numaliases;
List *coltypes,
*coltypmods,
*colcollations;
int varattno; int varattno;
ListCell *tlistitem; ListCell *tlistitem;
@ -1435,7 +1598,8 @@ addRangeTableEntryForSubquery(ParseState *pstate,
eref = copyObject(alias); eref = copyObject(alias);
numaliases = list_length(eref->colnames); 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; varattno = 0;
foreach(tlistitem, subquery->targetList) foreach(tlistitem, subquery->targetList)
{ {
@ -1452,6 +1616,12 @@ addRangeTableEntryForSubquery(ParseState *pstate,
attrname = pstrdup(te->resname); attrname = pstrdup(te->resname);
eref->colnames = lappend(eref->colnames, makeString(attrname)); 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) if (varattno < numaliases)
ereport(ERROR, ereport(ERROR,
@ -1478,21 +1648,27 @@ addRangeTableEntryForSubquery(ParseState *pstate,
rte->extraUpdatedCols = NULL; rte->extraUpdatedCols = NULL;
/* /*
* Add completed RTE to pstate's range table list, but not to join list * Add completed RTE to pstate's range table list, so that we know its
* nor namespace --- caller must do that if appropriate. * 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); 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 * 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, addRangeTableEntryForFunction(ParseState *pstate,
List *funcnames, List *funcnames,
List *funcexprs, List *funcexprs,
@ -1742,20 +1918,27 @@ addRangeTableEntryForFunction(ParseState *pstate,
rte->extraUpdatedCols = NULL; rte->extraUpdatedCols = NULL;
/* /*
* Add completed RTE to pstate's range table list, but not to join list * Add completed RTE to pstate's range table list, so that we know its
* nor namespace --- caller must do that if appropriate. * 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); 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). * 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. * This is much like addRangeTableEntry() except that it makes a tablefunc RTE.
*/ */
RangeTblEntry * ParseNamespaceItem *
addRangeTableEntryForTableFunc(ParseState *pstate, addRangeTableEntryForTableFunc(ParseState *pstate,
TableFunc *tf, TableFunc *tf,
Alias *alias, Alias *alias,
@ -1806,20 +1989,28 @@ addRangeTableEntryForTableFunc(ParseState *pstate,
rte->extraUpdatedCols = NULL; rte->extraUpdatedCols = NULL;
/* /*
* Add completed RTE to pstate's range table list, but not to join list * Add completed RTE to pstate's range table list, so that we know its
* nor namespace --- caller must do that if appropriate. * 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); 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). * 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. * This is much like addRangeTableEntry() except that it makes a values RTE.
*/ */
RangeTblEntry * ParseNamespaceItem *
addRangeTableEntryForValues(ParseState *pstate, addRangeTableEntryForValues(ParseState *pstate,
List *exprs, List *exprs,
List *coltypes, List *coltypes,
@ -1885,22 +2076,33 @@ addRangeTableEntryForValues(ParseState *pstate,
rte->extraUpdatedCols = NULL; rte->extraUpdatedCols = NULL;
/* /*
* Add completed RTE to pstate's range table list, but not to join list * Add completed RTE to pstate's range table list, so that we know its
* nor namespace --- caller must do that if appropriate. * 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); 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). * 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. * 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, addRangeTableEntryForJoin(ParseState *pstate,
List *colnames, List *colnames,
ParseNamespaceColumn *nscolumns,
JoinType jointype, JoinType jointype,
List *aliasvars, List *aliasvars,
Alias *alias, Alias *alias,
@ -1909,6 +2111,7 @@ addRangeTableEntryForJoin(ParseState *pstate,
RangeTblEntry *rte = makeNode(RangeTblEntry); RangeTblEntry *rte = makeNode(RangeTblEntry);
Alias *eref; Alias *eref;
int numaliases; int numaliases;
ParseNamespaceItem *nsitem;
Assert(pstate != NULL); Assert(pstate != NULL);
@ -1956,20 +2159,36 @@ addRangeTableEntryForJoin(ParseState *pstate,
rte->extraUpdatedCols = NULL; rte->extraUpdatedCols = NULL;
/* /*
* Add completed RTE to pstate's range table list, but not to join list * Add completed RTE to pstate's range table list, so that we know its
* nor namespace --- caller must do that if appropriate. * 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); 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). * 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. * This is much like addRangeTableEntry() except that it makes a CTE RTE.
*/ */
RangeTblEntry * ParseNamespaceItem *
addRangeTableEntryForCTE(ParseState *pstate, addRangeTableEntryForCTE(ParseState *pstate,
CommonTableExpr *cte, CommonTableExpr *cte,
Index levelsup, Index levelsup,
@ -2059,17 +2278,25 @@ addRangeTableEntryForCTE(ParseState *pstate,
rte->extraUpdatedCols = NULL; rte->extraUpdatedCols = NULL;
/* /*
* Add completed RTE to pstate's range table list, but not to join list * Add completed RTE to pstate's range table list, so that we know its
* nor namespace --- caller must do that if appropriate. * 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); 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 * Add an entry for an ephemeral named relation reference to the pstate's
* range table (p_rtable). * 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 * 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 * 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 * This is much like addRangeTableEntry() except that it makes an RTE for an
* ephemeral named relation. * ephemeral named relation.
*/ */
RangeTblEntry * ParseNamespaceItem *
addRangeTableEntryForENR(ParseState *pstate, addRangeTableEntryForENR(ParseState *pstate,
RangeVar *rv, RangeVar *rv,
bool inFromCl) bool inFromCl)
@ -2164,12 +2391,18 @@ addRangeTableEntryForENR(ParseState *pstate,
rte->selectedCols = NULL; rte->selectedCols = NULL;
/* /*
* Add completed RTE to pstate's range table list, but not to join list * Add completed RTE to pstate's range table list, so that we know its
* nor namespace --- caller must do that if appropriate. * 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); 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 * 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. * 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 void
addRTEtoQuery(ParseState *pstate, RangeTblEntry *rte, addNSItemToQuery(ParseState *pstate, ParseNamespaceItem *nsitem,
bool addToJoinList, bool addToJoinList,
bool addToRelNameSpace, bool addToVarNameSpace) 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) if (addToJoinList)
{ {
RangeTblRef *rtr = makeNode(RangeTblRef); RangeTblRef *rtr = makeNode(RangeTblRef);
rtr->rtindex = rtindex; rtr->rtindex = nsitem->p_rtindex;
pstate->p_joinlist = lappend(pstate->p_joinlist, rtr); pstate->p_joinlist = lappend(pstate->p_joinlist, rtr);
} }
if (addToRelNameSpace || addToVarNameSpace) if (addToRelNameSpace || addToVarNameSpace)
{ {
ParseNamespaceItem *nsitem; /* Set the new nsitem's visibility flags correctly */
nsitem = (ParseNamespaceItem *) palloc(sizeof(ParseNamespaceItem));
nsitem->p_rte = rte;
nsitem->p_rtindex = rtindex;
nsitem->p_rel_visible = addToRelNameSpace; nsitem->p_rel_visible = addToRelNameSpace;
nsitem->p_cols_visible = addToVarNameSpace; nsitem->p_cols_visible = addToVarNameSpace;
nsitem->p_lateral_only = false; 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 - * expandNSItemAttrs -
* Workhorse for "*" expansion: produce a list of targetentries * Workhorse for "*" expansion: produce a list of targetentries
@ -2739,8 +3004,7 @@ expandNSItemAttrs(ParseState *pstate, ParseNamespaceItem *nsitem,
*var; *var;
List *te_list = NIL; List *te_list = NIL;
expandRTE(rte, nsitem->p_rtindex, sublevels_up, location, false, vars = expandNSItemVars(nsitem, sublevels_up, location, &names);
&names, &vars);
/* /*
* Require read access to the table. This is normally redundant with the * 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 */ 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 * get_rte_attribute_is_dropped
* Check whether attempted attribute ref is to a dropped column * Check whether attempted attribute ref is to a dropped column

View File

@ -551,7 +551,7 @@ transformAssignedExpr(ParseState *pstate,
*/ */
Var *var; Var *var;
var = makeVar(pstate->p_target_rtindex, attrno, var = makeVar(pstate->p_target_nsitem->p_rtindex, attrno,
attrtype, attrtypmod, attrcollation, 0); attrtype, attrtypmod, attrcollation, 0);
var->location = location; var->location = location;
@ -1359,8 +1359,7 @@ ExpandSingleTable(ParseState *pstate, ParseNamespaceItem *nsitem,
List *vars; List *vars;
ListCell *l; ListCell *l;
expandRTE(rte, nsitem->p_rtindex, sublevels_up, location, false, vars = expandNSItemVars(nsitem, sublevels_up, location, NULL);
NULL, &vars);
/* /*
* Require read access to the table. This is normally redundant with * 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(IsA(var, Var));
Assert(var->vartype == RECORDOID); 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; netlevelsup = var->varlevelsup + levelsup;
rte = GetRTEByRangeTablePosn(pstate, var->varno, netlevelsup); rte = GetRTEByRangeTablePosn(pstate, var->varno, netlevelsup);
attnum = var->varattno; attnum = var->varattno;

View File

@ -2598,7 +2598,7 @@ IndexStmt *
transformIndexStmt(Oid relid, IndexStmt *stmt, const char *queryString) transformIndexStmt(Oid relid, IndexStmt *stmt, const char *queryString)
{ {
ParseState *pstate; ParseState *pstate;
RangeTblEntry *rte; ParseNamespaceItem *nsitem;
ListCell *l; ListCell *l;
Relation rel; Relation rel;
@ -2622,12 +2622,12 @@ transformIndexStmt(Oid relid, IndexStmt *stmt, const char *queryString)
* relation, but we still need to open it. * relation, but we still need to open it.
*/ */
rel = relation_open(relid, NoLock); rel = relation_open(relid, NoLock);
rte = addRangeTableEntryForRelation(pstate, rel, nsitem = addRangeTableEntryForRelation(pstate, rel,
AccessShareLock, AccessShareLock,
NULL, false, true); NULL, false, true);
/* no to join list, yes to namespaces */ /* 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 */ /* take care of the where clause */
if (stmt->whereClause) if (stmt->whereClause)
@ -2707,8 +2707,8 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
{ {
Relation rel; Relation rel;
ParseState *pstate; ParseState *pstate;
RangeTblEntry *oldrte; ParseNamespaceItem *oldnsitem;
RangeTblEntry *newrte; ParseNamespaceItem *newnsitem;
/* /*
* To avoid deadlock, make sure the first thing we do is grab * 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. * 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 * Set up their ParseNamespaceItems in the main pstate for use in parsing
* qualification. * the rule qualification.
*/ */
oldrte = addRangeTableEntryForRelation(pstate, rel, oldnsitem = addRangeTableEntryForRelation(pstate, rel,
AccessShareLock, AccessShareLock,
makeAlias("old", NIL), makeAlias("old", NIL),
false, false); false, false);
newrte = addRangeTableEntryForRelation(pstate, rel, newnsitem = addRangeTableEntryForRelation(pstate, rel,
AccessShareLock, AccessShareLock,
makeAlias("new", NIL), makeAlias("new", NIL),
false, false); false, false);
/* Must override addRangeTableEntry's default access-check flags */ /* Must override addRangeTableEntry's default access-check flags */
oldrte->requiredPerms = 0; oldnsitem->p_rte->requiredPerms = 0;
newrte->requiredPerms = 0; newnsitem->p_rte->requiredPerms = 0;
/* /*
* They must be in the namespace too for lookup purposes, but only add the * 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) switch (stmt->event)
{ {
case CMD_SELECT: case CMD_SELECT:
addRTEtoQuery(pstate, oldrte, false, true, true); addNSItemToQuery(pstate, oldnsitem, false, true, true);
break; break;
case CMD_UPDATE: case CMD_UPDATE:
addRTEtoQuery(pstate, oldrte, false, true, true); addNSItemToQuery(pstate, oldnsitem, false, true, true);
addRTEtoQuery(pstate, newrte, false, true, true); addNSItemToQuery(pstate, newnsitem, false, true, true);
break; break;
case CMD_INSERT: case CMD_INSERT:
addRTEtoQuery(pstate, newrte, false, true, true); addNSItemToQuery(pstate, newnsitem, false, true, true);
break; break;
case CMD_DELETE: case CMD_DELETE:
addRTEtoQuery(pstate, oldrte, false, true, true); addNSItemToQuery(pstate, oldnsitem, false, true, true);
break; break;
default: default:
elog(ERROR, "unrecognized event type: %d", 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 * nor "*" in the rule actions. We decide later whether to put
* them in the joinlist. * them in the joinlist.
*/ */
oldrte = addRangeTableEntryForRelation(sub_pstate, rel, oldnsitem = addRangeTableEntryForRelation(sub_pstate, rel,
AccessShareLock, AccessShareLock,
makeAlias("old", NIL), makeAlias("old", NIL),
false, false); false, false);
newrte = addRangeTableEntryForRelation(sub_pstate, rel, newnsitem = addRangeTableEntryForRelation(sub_pstate, rel,
AccessShareLock, AccessShareLock,
makeAlias("new", NIL), makeAlias("new", NIL),
false, false); false, false);
oldrte->requiredPerms = 0; oldnsitem->p_rte->requiredPerms = 0;
newrte->requiredPerms = 0; newnsitem->p_rte->requiredPerms = 0;
addRTEtoQuery(sub_pstate, oldrte, false, true, false); addNSItemToQuery(sub_pstate, oldnsitem, false, true, false);
addRTEtoQuery(sub_pstate, newrte, false, true, false); addNSItemToQuery(sub_pstate, newnsitem, false, true, false);
/* Transform the rule action statement */ /* Transform the rule action statement */
top_subqry = transformStmt(sub_pstate, top_subqry = transformStmt(sub_pstate,
@ -2967,6 +2967,8 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
*/ */
if (has_old || (has_new && stmt->event == CMD_UPDATE)) if (has_old || (has_new && stmt->event == CMD_UPDATE))
{ {
RangeTblRef *rtr;
/* /*
* If sub_qry is a setop, manipulating its jointree will do no * If sub_qry is a setop, manipulating its jointree will do no
* good at all, because the jointree is dummy. (This should be * good at all, because the jointree is dummy. (This should be
@ -2976,11 +2978,11 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("conditional UNION/INTERSECT/EXCEPT statements are not implemented"))); errmsg("conditional UNION/INTERSECT/EXCEPT statements are not implemented")));
/* hack so we can use addRTEtoQuery() */ /* hackishly add OLD to the already-built FROM clause */
sub_pstate->p_rtable = sub_qry->rtable; rtr = makeNode(RangeTblRef);
sub_pstate->p_joinlist = sub_qry->jointree->fromlist; rtr->rtindex = oldnsitem->p_rtindex;
addRTEtoQuery(sub_pstate, oldrte, true, false, false); sub_qry->jointree->fromlist =
sub_qry->jointree->fromlist = sub_pstate->p_joinlist; lappend(sub_qry->jointree->fromlist, rtr);
} }
newactions = lappend(newactions, top_subqry); newactions = lappend(newactions, top_subqry);
@ -3025,7 +3027,7 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
List *newcmds = NIL; List *newcmds = NIL;
bool skipValidation = true; bool skipValidation = true;
AlterTableCmd *newcmd; AlterTableCmd *newcmd;
RangeTblEntry *rte; ParseNamespaceItem *nsitem;
/* /*
* We must not scribble on the passed-in AlterTableStmt, so copy it. (This * 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 */ /* Set up pstate */
pstate = make_parsestate(NULL); pstate = make_parsestate(NULL);
pstate->p_sourcetext = queryString; pstate->p_sourcetext = queryString;
rte = addRangeTableEntryForRelation(pstate, nsitem = addRangeTableEntryForRelation(pstate,
rel, rel,
AccessShareLock, AccessShareLock,
NULL, NULL,
false, false,
true); true);
addRTEtoQuery(pstate, rte, false, true, true); addNSItemToQuery(pstate, nsitem, false, true, true);
/* Set up CreateStmtContext */ /* Set up CreateStmtContext */
cxt.pstate = pstate; cxt.pstate = pstate;

View File

@ -777,8 +777,8 @@ copy_table(Relation rel)
copybuf = makeStringInfo(); copybuf = makeStringInfo();
pstate = make_parsestate(NULL); pstate = make_parsestate(NULL);
addRangeTableEntryForRelation(pstate, rel, AccessShareLock, (void) addRangeTableEntryForRelation(pstate, rel, AccessShareLock,
NULL, false, false); NULL, false, false);
attnamelist = make_copy_attnamelist(relmapentry); attnamelist = make_copy_attnamelist(relmapentry);
cstate = BeginCopyFrom(pstate, rel, NULL, false, copy_read_data, attnamelist, NIL); cstate = BeginCopyFrom(pstate, rel, NULL, false, copy_read_data, attnamelist, NIL);

View File

@ -3227,6 +3227,7 @@ rewriteTargetView(Query *parsetree, Relation view)
{ {
Index old_exclRelIndex, Index old_exclRelIndex,
new_exclRelIndex; new_exclRelIndex;
ParseNamespaceItem *new_exclNSItem;
RangeTblEntry *new_exclRte; RangeTblEntry *new_exclRte;
List *tmp_tlist; List *tmp_tlist;
@ -3261,11 +3262,12 @@ rewriteTargetView(Query *parsetree, Relation view)
*/ */
old_exclRelIndex = parsetree->onConflict->exclRelIndex; old_exclRelIndex = parsetree->onConflict->exclRelIndex;
new_exclRte = addRangeTableEntryForRelation(make_parsestate(NULL), new_exclNSItem = addRangeTableEntryForRelation(make_parsestate(NULL),
base_rel, base_rel,
RowExclusiveLock, RowExclusiveLock,
makeAlias("excluded", NIL), makeAlias("excluded", NIL),
false, false); false, false);
new_exclRte = new_exclNSItem->p_rte;
new_exclRte->relkind = RELKIND_COMPOSITE_TYPE; new_exclRte->relkind = RELKIND_COMPOSITE_TYPE;
new_exclRte->requiredPerms = 0; new_exclRte->requiredPerms = 0;
/* other permissions fields in new_exclRte are already empty */ /* other permissions fields in new_exclRte are already empty */

View File

@ -19,6 +19,11 @@
#include "utils/relcache.h" #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 * Expression kinds distinguished by transformExpr(). Many of these are not
* semantically distinct so far as expression transformation goes; rather, * semantically distinct so far as expression transformation goes; rather,
@ -79,8 +84,6 @@ typedef enum ParseExprKind
/* /*
* Function signatures for parser hooks * Function signatures for parser hooks
*/ */
typedef struct ParseState ParseState;
typedef Node *(*PreParseColumnRefHook) (ParseState *pstate, ColumnRef *cref); typedef Node *(*PreParseColumnRefHook) (ParseState *pstate, ColumnRef *cref);
typedef Node *(*PostParseColumnRefHook) (ParseState *pstate, ColumnRef *cref, Node *var); typedef Node *(*PostParseColumnRefHook) (ParseState *pstate, ColumnRef *cref, Node *var);
typedef Node *(*ParseParamRefHook) (ParseState *pstate, ParamRef *pref); 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_relation: target relation, if query is INSERT, UPDATE, or DELETE.
* *
* p_target_rangetblentry: target relation's entry in the rtable list. * p_target_nsitem: target relation's ParseNamespaceItem.
*
* p_target_rtindex: target relation's index in the rtable list.
* *
* p_is_insert: true to process assignment expressions like INSERT, false * p_is_insert: true to process assignment expressions like INSERT, false
* to process them like UPDATE. (Note this can change intra-statement, for * 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
{ {
struct ParseState *parentParseState; /* stack link */ ParseState *parentParseState; /* stack link */
const char *p_sourcetext; /* source text, or NULL if not available */ const char *p_sourcetext; /* source text, or NULL if not available */
List *p_rtable; /* range table so far */ List *p_rtable; /* range table so far */
List *p_joinexprs; /* JoinExprs for RTE_JOIN p_rtable entries */ 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 */ List *p_future_ctes; /* common table exprs not yet in namespace */
CommonTableExpr *p_parent_cte; /* this query's containing CTE */ CommonTableExpr *p_parent_cte; /* this query's containing CTE */
Relation p_target_relation; /* INSERT/UPDATE/DELETE target rel */ Relation p_target_relation; /* INSERT/UPDATE/DELETE target rel */
RangeTblEntry *p_target_rangetblentry; /* target rel's RTE, or NULL */ ParseNamespaceItem *p_target_nsitem; /* target rel's NSItem, or NULL */
int p_target_rtindex; /* target rel's RT index, or 0 */
bool p_is_insert; /* process assignment like INSERT not UPDATE */ bool p_is_insert; /* process assignment like INSERT not UPDATE */
List *p_windowdefs; /* raw representations of window clauses */ List *p_windowdefs; /* raw representations of window clauses */
ParseExprKind p_expr_kind; /* what kind of expression we're parsing */ ParseExprKind p_expr_kind; /* what kind of expression we're parsing */
@ -225,6 +225,9 @@ struct ParseState
/* /*
* An element of a namespace list. * 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 * 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 * qualified names, while those with p_cols_visible set define which RTEs are
* accessible by unqualified names. These sets are different because a JOIN * 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 * are more complicated than "must have different alias names", so in practice
* code searching a namespace list has to check for ambiguous references. * code searching a namespace list has to check for ambiguous references.
*/ */
typedef struct ParseNamespaceItem struct ParseNamespaceItem
{ {
RangeTblEntry *p_rte; /* The relation's rangetable entry */ RangeTblEntry *p_rte; /* The relation's rangetable entry */
int p_rtindex; /* The relation's index in the rangetable */ 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_rel_visible; /* Relation name is visible? */
bool p_cols_visible; /* Column names visible as unqualified refs? */ bool p_cols_visible; /* Column names visible as unqualified refs? */
bool p_lateral_only; /* Is only visible to LATERAL expressions? */ bool p_lateral_only; /* Is only visible to LATERAL expressions? */
bool p_lateral_ok; /* If so, does join type allow use? */ 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 */ /* Support for parser_errposition_callback function */
typedef struct ParseCallbackState typedef struct ParseCallbackState

View File

@ -45,66 +45,70 @@ extern void markVarForSelectPriv(ParseState *pstate, Var *var,
RangeTblEntry *rte); RangeTblEntry *rte);
extern Relation parserOpenTable(ParseState *pstate, const RangeVar *relation, extern Relation parserOpenTable(ParseState *pstate, const RangeVar *relation,
int lockmode); int lockmode);
extern RangeTblEntry *addRangeTableEntry(ParseState *pstate, extern ParseNamespaceItem *addRangeTableEntry(ParseState *pstate,
RangeVar *relation, RangeVar *relation,
Alias *alias, Alias *alias,
bool inh, bool inh,
bool inFromCl); bool inFromCl);
extern RangeTblEntry *addRangeTableEntryForRelation(ParseState *pstate, extern ParseNamespaceItem *addRangeTableEntryForRelation(ParseState *pstate,
Relation rel, Relation rel,
int lockmode, int lockmode,
Alias *alias, Alias *alias,
bool inh, bool inh,
bool inFromCl); bool inFromCl);
extern RangeTblEntry *addRangeTableEntryForSubquery(ParseState *pstate, extern ParseNamespaceItem *addRangeTableEntryForSubquery(ParseState *pstate,
Query *subquery, Query *subquery,
Alias *alias, Alias *alias,
bool lateral, bool lateral,
bool inFromCl); bool inFromCl);
extern RangeTblEntry *addRangeTableEntryForFunction(ParseState *pstate, extern ParseNamespaceItem *addRangeTableEntryForFunction(ParseState *pstate,
List *funcnames, List *funcnames,
List *funcexprs, List *funcexprs,
List *coldeflists, List *coldeflists,
RangeFunction *rangefunc, RangeFunction *rangefunc,
bool lateral, bool lateral,
bool inFromCl); bool inFromCl);
extern RangeTblEntry *addRangeTableEntryForValues(ParseState *pstate, extern ParseNamespaceItem *addRangeTableEntryForValues(ParseState *pstate,
List *exprs, List *exprs,
List *coltypes, List *coltypes,
List *coltypmods, List *coltypmods,
List *colcollations, List *colcollations,
Alias *alias, Alias *alias,
bool lateral, bool lateral,
bool inFromCl); bool inFromCl);
extern RangeTblEntry *addRangeTableEntryForTableFunc(ParseState *pstate, extern ParseNamespaceItem *addRangeTableEntryForTableFunc(ParseState *pstate,
TableFunc *tf, TableFunc *tf,
Alias *alias,
bool lateral,
bool inFromCl);
extern ParseNamespaceItem *addRangeTableEntryForJoin(ParseState *pstate,
List *colnames,
ParseNamespaceColumn *nscolumns,
JoinType jointype,
List *aliasvars,
Alias *alias, Alias *alias,
bool lateral,
bool inFromCl); bool inFromCl);
extern RangeTblEntry *addRangeTableEntryForJoin(ParseState *pstate, extern ParseNamespaceItem *addRangeTableEntryForCTE(ParseState *pstate,
List *colnames, CommonTableExpr *cte,
JoinType jointype, Index levelsup,
List *aliasvars, RangeVar *rv,
Alias *alias, bool inFromCl);
bool inFromCl); extern ParseNamespaceItem *addRangeTableEntryForENR(ParseState *pstate,
extern RangeTblEntry *addRangeTableEntryForCTE(ParseState *pstate, RangeVar *rv,
CommonTableExpr *cte, bool inFromCl);
Index levelsup,
RangeVar *rv,
bool inFromCl);
extern RangeTblEntry *addRangeTableEntryForENR(ParseState *pstate,
RangeVar *rv,
bool inFromCl);
extern bool isLockedRefname(ParseState *pstate, const char *refname); extern bool isLockedRefname(ParseState *pstate, const char *refname);
extern void addRTEtoQuery(ParseState *pstate, RangeTblEntry *rte, extern void addNSItemToQuery(ParseState *pstate, ParseNamespaceItem *nsitem,
bool addToJoinList, bool addToJoinList,
bool addToRelNameSpace, bool addToVarNameSpace); bool addToRelNameSpace, bool addToVarNameSpace);
extern void errorMissingRTE(ParseState *pstate, RangeVar *relation) pg_attribute_noreturn(); extern void errorMissingRTE(ParseState *pstate, RangeVar *relation) pg_attribute_noreturn();
extern void errorMissingColumn(ParseState *pstate, extern void errorMissingColumn(ParseState *pstate,
const char *relname, const char *colname, int location) pg_attribute_noreturn(); const char *relname, const char *colname, int location) pg_attribute_noreturn();
extern void expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up, extern void expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
int location, bool include_dropped, int location, bool include_dropped,
List **colnames, List **colvars); List **colnames, List **colvars);
extern List *expandNSItemVars(ParseNamespaceItem *nsitem,
int sublevels_up, int location,
List **colnames);
extern List *expandNSItemAttrs(ParseState *pstate, ParseNamespaceItem *nsitem, extern List *expandNSItemAttrs(ParseState *pstate, ParseNamespaceItem *nsitem,
int sublevels_up, int location); int sublevels_up, int location);
extern int attnameAttNum(Relation rd, const char *attname, bool sysColOK); extern int attnameAttNum(Relation rd, const char *attname, bool sysColOK);

View File

@ -38,15 +38,7 @@
extern char *get_rte_attribute_name(RangeTblEntry *rte, AttrNumber attnum); extern char *get_rte_attribute_name(RangeTblEntry *rte, AttrNumber attnum);
/* /*
* Given an RTE and an attribute number, return the appropriate * Check whether an attribute of an RTE has been dropped
* 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)
*/ */
extern bool get_rte_attribute_is_dropped(RangeTblEntry *rte, extern bool get_rte_attribute_is_dropped(RangeTblEntry *rte,
AttrNumber attnum); AttrNumber attnum);

View File

@ -70,7 +70,7 @@ test_rls_hooks_permissive(CmdType cmdtype, Relation relation)
Node *e; Node *e;
ColumnRef *c; ColumnRef *c;
ParseState *qual_pstate; ParseState *qual_pstate;
RangeTblEntry *rte; ParseNamespaceItem *nsitem;
if (strcmp(RelationGetRelationName(relation), "rls_test_permissive") != 0 && if (strcmp(RelationGetRelationName(relation), "rls_test_permissive") != 0 &&
strcmp(RelationGetRelationName(relation), "rls_test_both") != 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); qual_pstate = make_parsestate(NULL);
rte = addRangeTableEntryForRelation(qual_pstate, relation, AccessShareLock, nsitem = addRangeTableEntryForRelation(qual_pstate,
NULL, false, false); relation, AccessShareLock,
addRTEtoQuery(qual_pstate, rte, false, true, true); NULL, false, false);
addNSItemToQuery(qual_pstate, nsitem, false, true, true);
role = ObjectIdGetDatum(ACL_ID_PUBLIC); role = ObjectIdGetDatum(ACL_ID_PUBLIC);
@ -134,8 +135,7 @@ test_rls_hooks_restrictive(CmdType cmdtype, Relation relation)
Node *e; Node *e;
ColumnRef *c; ColumnRef *c;
ParseState *qual_pstate; ParseState *qual_pstate;
RangeTblEntry *rte; ParseNamespaceItem *nsitem;
if (strcmp(RelationGetRelationName(relation), "rls_test_restrictive") != 0 && if (strcmp(RelationGetRelationName(relation), "rls_test_restrictive") != 0 &&
strcmp(RelationGetRelationName(relation), "rls_test_both") != 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); qual_pstate = make_parsestate(NULL);
rte = addRangeTableEntryForRelation(qual_pstate, relation, AccessShareLock, nsitem = addRangeTableEntryForRelation(qual_pstate,
NULL, false, false); relation, AccessShareLock,
addRTEtoQuery(qual_pstate, rte, false, true, true); NULL, false, false);
addNSItemToQuery(qual_pstate, nsitem, false, true, true);
role = ObjectIdGetDatum(ACL_ID_PUBLIC); role = ObjectIdGetDatum(ACL_ID_PUBLIC);