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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -51,37 +51,33 @@
#include "utils/rel.h"
#include "utils/syscache.h"
/* Convenience macro for the most common makeNamespaceItem() case */
#define makeDefaultNSItem(rte, rti) \
makeNamespaceItem(rte, rti, true, true, false, true)
static void extractRemainingColumns(List *common_colnames,
List *src_colnames, List *src_colvars,
List **res_colnames, List **res_colvars);
ParseNamespaceColumn *src_nscolumns,
List **res_colnames, List **res_colvars,
ParseNamespaceColumn *res_nscolumns);
static Node *transformJoinUsingClause(ParseState *pstate,
RangeTblEntry *leftRTE, RangeTblEntry *rightRTE,
List *leftVars, List *rightVars);
static Node *transformJoinOnClause(ParseState *pstate, JoinExpr *j,
List *namespace);
static RangeTblEntry *getRTEForSpecialRelationTypes(ParseState *pstate,
RangeVar *rv);
static RangeTblEntry *transformTableEntry(ParseState *pstate, RangeVar *r);
static RangeTblEntry *transformRangeSubselect(ParseState *pstate,
RangeSubselect *r);
static RangeTblEntry *transformRangeFunction(ParseState *pstate,
RangeFunction *r);
static RangeTblEntry *transformRangeTableFunc(ParseState *pstate,
RangeTableFunc *t);
static ParseNamespaceItem *transformTableEntry(ParseState *pstate, RangeVar *r);
static ParseNamespaceItem *transformRangeSubselect(ParseState *pstate,
RangeSubselect *r);
static ParseNamespaceItem *transformRangeFunction(ParseState *pstate,
RangeFunction *r);
static ParseNamespaceItem *transformRangeTableFunc(ParseState *pstate,
RangeTableFunc *t);
static TableSampleClause *transformRangeTableSample(ParseState *pstate,
RangeTableSample *rts);
static ParseNamespaceItem *getNSItemForSpecialRelationTypes(ParseState *pstate,
RangeVar *rv);
static Node *transformFromClauseItem(ParseState *pstate, Node *n,
RangeTblEntry **top_rte, int *top_rti,
ParseNamespaceItem **top_nsitem,
List **namespace);
static Node *buildMergedJoinVar(ParseState *pstate, JoinType jointype,
Var *l_colvar, Var *r_colvar);
static ParseNamespaceItem *makeNamespaceItem(RangeTblEntry *rte, int rtindex,
bool rel_visible, bool cols_visible,
bool lateral_only, bool lateral_ok);
static void setNamespaceColumnVisibility(List *namespace, bool cols_visible);
static void setNamespaceLateralState(List *namespace,
bool lateral_only, bool lateral_ok);
@ -130,13 +126,11 @@ transformFromClause(ParseState *pstate, List *frmList)
foreach(fl, frmList)
{
Node *n = lfirst(fl);
RangeTblEntry *rte;
int rtindex;
ParseNamespaceItem *nsitem;
List *namespace;
n = transformFromClauseItem(pstate, n,
&rte,
&rtindex,
&nsitem,
&namespace);
checkNameSpaceConflicts(pstate, pstate->p_namespace, namespace);
@ -183,8 +177,7 @@ int
setTargetTable(ParseState *pstate, RangeVar *relation,
bool inh, bool alsoSource, AclMode requiredPerms)
{
RangeTblEntry *rte;
int rtindex;
ParseNamespaceItem *nsitem;
/*
* ENRs hide tables of the same name, so we need to check for them first.
@ -212,19 +205,14 @@ setTargetTable(ParseState *pstate, RangeVar *relation,
RowExclusiveLock);
/*
* Now build an RTE.
* Now build an RTE and a ParseNamespaceItem.
*/
rte = addRangeTableEntryForRelation(pstate, pstate->p_target_relation,
RowExclusiveLock,
relation->alias, inh, false);
nsitem = addRangeTableEntryForRelation(pstate, pstate->p_target_relation,
RowExclusiveLock,
relation->alias, inh, false);
/* assume new rte is at end */
rtindex = list_length(pstate->p_rtable);
Assert(rte == rt_fetch(rtindex, pstate->p_rtable));
/* remember the RTE as being the query target */
pstate->p_target_rangetblentry = rte;
pstate->p_target_rtindex = rtindex;
/* remember the RTE/nsitem as being the query target */
pstate->p_target_nsitem = nsitem;
/*
* Override addRangeTableEntry's default ACL_SELECT permissions check, and
@ -235,28 +223,30 @@ setTargetTable(ParseState *pstate, RangeVar *relation,
* analysis, we will add the ACL_SELECT bit back again; see
* markVarForSelectPriv and its callers.
*/
rte->requiredPerms = requiredPerms;
nsitem->p_rte->requiredPerms = requiredPerms;
/*
* If UPDATE/DELETE, add table to joinlist and namespace.
*
* Note: some callers know that they can find the new ParseNamespaceItem
* at the end of the pstate->p_namespace list. This is a bit ugly but not
* worth complicating this function's signature for.
*/
if (alsoSource)
addRTEtoQuery(pstate, rte, true, true, true);
addNSItemToQuery(pstate, nsitem, true, true, true);
return rtindex;
return nsitem->p_rtindex;
}
/*
* Extract all not-in-common columns from column lists of a source table
*
* We hand back new lists in *res_colnames and *res_colvars. But
* res_nscolumns points to a caller-allocated array that we fill in
* the next few entries in.
*/
static void
extractRemainingColumns(List *common_colnames,
List *src_colnames, List *src_colvars,
List **res_colnames, List **res_colvars)
ParseNamespaceColumn *src_nscolumns,
List **res_colnames, List **res_colvars,
ParseNamespaceColumn *res_nscolumns)
{
List *new_colnames = NIL;
List *new_colvars = NIL;
@ -271,6 +261,14 @@ extractRemainingColumns(List *common_colnames,
bool match = false;
ListCell *cnames;
/*
* Ignore any dropped columns in the src_nscolumns input. (The list
* inputs won't contain entries for dropped columns.)
*/
while (src_nscolumns->p_varno == 0)
src_nscolumns++;
/* is current src column already accounted for in common_colnames? */
foreach(cnames, common_colnames)
{
char *ccolname = strVal(lfirst(cnames));
@ -284,9 +282,15 @@ extractRemainingColumns(List *common_colnames,
if (!match)
{
/* Nope, so emit it as next output column */
new_colnames = lappend(new_colnames, lfirst(lnames));
new_colvars = lappend(new_colvars, lfirst(lvars));
/* Copy the input relation's nscolumn data for this column */
*res_nscolumns = *src_nscolumns;
res_nscolumns++;
}
src_nscolumns++;
}
*res_colnames = new_colnames;
@ -388,25 +392,20 @@ transformJoinOnClause(ParseState *pstate, JoinExpr *j, List *namespace)
/*
* transformTableEntry --- transform a RangeVar (simple relation reference)
*/
static RangeTblEntry *
static ParseNamespaceItem *
transformTableEntry(ParseState *pstate, RangeVar *r)
{
RangeTblEntry *rte;
/* We need only build a range table entry */
rte = addRangeTableEntry(pstate, r, r->alias, r->inh, true);
return rte;
/* addRangeTableEntry does all the work */
return addRangeTableEntry(pstate, r, r->alias, r->inh, true);
}
/*
* transformRangeSubselect --- transform a sub-SELECT appearing in FROM
*/
static RangeTblEntry *
static ParseNamespaceItem *
transformRangeSubselect(ParseState *pstate, RangeSubselect *r)
{
Query *query;
RangeTblEntry *rte;
/*
* We require user to supply an alias for a subselect, per SQL92. To relax
@ -454,29 +453,26 @@ transformRangeSubselect(ParseState *pstate, RangeSubselect *r)
elog(ERROR, "unexpected non-SELECT command in subquery in FROM");
/*
* OK, build an RTE for the subquery.
* OK, build an RTE and nsitem for the subquery.
*/
rte = addRangeTableEntryForSubquery(pstate,
query,
r->alias,
r->lateral,
true);
return rte;
return addRangeTableEntryForSubquery(pstate,
query,
r->alias,
r->lateral,
true);
}
/*
* transformRangeFunction --- transform a function call appearing in FROM
*/
static RangeTblEntry *
static ParseNamespaceItem *
transformRangeFunction(ParseState *pstate, RangeFunction *r)
{
List *funcexprs = NIL;
List *funcnames = NIL;
List *coldeflists = NIL;
bool is_lateral;
RangeTblEntry *rte;
ListCell *lc;
/*
@ -677,13 +673,11 @@ transformRangeFunction(ParseState *pstate, RangeFunction *r)
is_lateral = r->lateral || contain_vars_of_level((Node *) funcexprs, 0);
/*
* OK, build an RTE for the function.
* OK, build an RTE and nsitem for the function.
*/
rte = addRangeTableEntryForFunction(pstate,
funcnames, funcexprs, coldeflists,
r, is_lateral, true);
return rte;
return addRangeTableEntryForFunction(pstate,
funcnames, funcexprs, coldeflists,
r, is_lateral, true);
}
/*
@ -694,13 +688,12 @@ transformRangeFunction(ParseState *pstate, RangeFunction *r)
* row-generating expression, the column-generating expressions, and the
* default value expressions.
*/
static RangeTblEntry *
static ParseNamespaceItem *
transformRangeTableFunc(ParseState *pstate, RangeTableFunc *rtf)
{
TableFunc *tf = makeNode(TableFunc);
const char *constructName;
Oid docType;
RangeTblEntry *rte;
bool is_lateral;
ListCell *col;
char **names;
@ -903,10 +896,8 @@ transformRangeTableFunc(ParseState *pstate, RangeTableFunc *rtf)
*/
is_lateral = rtf->lateral || contain_vars_of_level((Node *) tf, 0);
rte = addRangeTableEntryForTableFunc(pstate,
tf, rtf->alias, is_lateral, true);
return rte;
return addRangeTableEntryForTableFunc(pstate,
tf, rtf->alias, is_lateral, true);
}
/*
@ -1013,17 +1004,17 @@ transformRangeTableSample(ParseState *pstate, RangeTableSample *rts)
}
/*
* getRTEForSpecialRelationTypes
* getNSItemForSpecialRelationTypes
*
* If given RangeVar refers to a CTE or an EphemeralNamedRelation,
* build and return an appropriate RTE, otherwise return NULL
* build and return an appropriate ParseNamespaceItem, otherwise return NULL
*/
static RangeTblEntry *
getRTEForSpecialRelationTypes(ParseState *pstate, RangeVar *rv)
static ParseNamespaceItem *
getNSItemForSpecialRelationTypes(ParseState *pstate, RangeVar *rv)
{
ParseNamespaceItem *nsitem;
CommonTableExpr *cte;
Index levelsup;
RangeTblEntry *rte;
/*
* if it is a qualified name, it can't be a CTE or tuplestore reference
@ -1033,13 +1024,13 @@ getRTEForSpecialRelationTypes(ParseState *pstate, RangeVar *rv)
cte = scanNameSpaceForCTE(pstate, rv->relname, &levelsup);
if (cte)
rte = addRangeTableEntryForCTE(pstate, cte, levelsup, rv, true);
nsitem = addRangeTableEntryForCTE(pstate, cte, levelsup, rv, true);
else if (scanNameSpaceForENR(pstate, rv->relname))
rte = addRangeTableEntryForENR(pstate, rv, true);
nsitem = addRangeTableEntryForENR(pstate, rv, true);
else
rte = NULL;
nsitem = NULL;
return rte;
return nsitem;
}
/*
@ -1053,11 +1044,9 @@ getRTEForSpecialRelationTypes(ParseState *pstate, RangeVar *rv)
* The function return value is the node to add to the jointree (a
* RangeTblRef or JoinExpr). Additional output parameters are:
*
* *top_rte: receives the RTE corresponding to the jointree item.
* (We could extract this from the function return node, but it saves cycles
* to pass it back separately.)
*
* *top_rti: receives the rangetable index of top_rte. (Ditto.)
* *top_nsitem: receives the ParseNamespaceItem directly corresponding to the
* jointree item. (This is only used during internal recursion, not by
* outside callers.)
*
* *namespace: receives a List of ParseNamespaceItems for the RTEs exposed
* as table/column names by this item. (The lateral_only flags in these items
@ -1065,7 +1054,7 @@ getRTEForSpecialRelationTypes(ParseState *pstate, RangeVar *rv)
*/
static Node *
transformFromClauseItem(ParseState *pstate, Node *n,
RangeTblEntry **top_rte, int *top_rti,
ParseNamespaceItem **top_nsitem,
List **namespace)
{
if (IsA(n, RangeVar))
@ -1073,78 +1062,58 @@ transformFromClauseItem(ParseState *pstate, Node *n,
/* Plain relation reference, or perhaps a CTE reference */
RangeVar *rv = (RangeVar *) n;
RangeTblRef *rtr;
RangeTblEntry *rte;
int rtindex;
ParseNamespaceItem *nsitem;
/* Check if it's a CTE or tuplestore reference */
rte = getRTEForSpecialRelationTypes(pstate, rv);
nsitem = getNSItemForSpecialRelationTypes(pstate, rv);
/* if not found above, must be a table reference */
if (!rte)
rte = transformTableEntry(pstate, rv);
if (!nsitem)
nsitem = transformTableEntry(pstate, rv);
/* assume new rte is at end */
rtindex = list_length(pstate->p_rtable);
Assert(rte == rt_fetch(rtindex, pstate->p_rtable));
*top_rte = rte;
*top_rti = rtindex;
*namespace = list_make1(makeDefaultNSItem(rte, rtindex));
*top_nsitem = nsitem;
*namespace = list_make1(nsitem);
rtr = makeNode(RangeTblRef);
rtr->rtindex = rtindex;
rtr->rtindex = nsitem->p_rtindex;
return (Node *) rtr;
}
else if (IsA(n, RangeSubselect))
{
/* sub-SELECT is like a plain relation */
RangeTblRef *rtr;
RangeTblEntry *rte;
int rtindex;
ParseNamespaceItem *nsitem;
rte = transformRangeSubselect(pstate, (RangeSubselect *) n);
/* assume new rte is at end */
rtindex = list_length(pstate->p_rtable);
Assert(rte == rt_fetch(rtindex, pstate->p_rtable));
*top_rte = rte;
*top_rti = rtindex;
*namespace = list_make1(makeDefaultNSItem(rte, rtindex));
nsitem = transformRangeSubselect(pstate, (RangeSubselect *) n);
*top_nsitem = nsitem;
*namespace = list_make1(nsitem);
rtr = makeNode(RangeTblRef);
rtr->rtindex = rtindex;
rtr->rtindex = nsitem->p_rtindex;
return (Node *) rtr;
}
else if (IsA(n, RangeFunction))
{
/* function is like a plain relation */
RangeTblRef *rtr;
RangeTblEntry *rte;
int rtindex;
ParseNamespaceItem *nsitem;
rte = transformRangeFunction(pstate, (RangeFunction *) n);
/* assume new rte is at end */
rtindex = list_length(pstate->p_rtable);
Assert(rte == rt_fetch(rtindex, pstate->p_rtable));
*top_rte = rte;
*top_rti = rtindex;
*namespace = list_make1(makeDefaultNSItem(rte, rtindex));
nsitem = transformRangeFunction(pstate, (RangeFunction *) n);
*top_nsitem = nsitem;
*namespace = list_make1(nsitem);
rtr = makeNode(RangeTblRef);
rtr->rtindex = rtindex;
rtr->rtindex = nsitem->p_rtindex;
return (Node *) rtr;
}
else if (IsA(n, RangeTableFunc))
{
/* table function is like a plain relation */
RangeTblRef *rtr;
RangeTblEntry *rte;
int rtindex;
ParseNamespaceItem *nsitem;
rte = transformRangeTableFunc(pstate, (RangeTableFunc *) n);
/* assume new rte is at end */
rtindex = list_length(pstate->p_rtable);
Assert(rte == rt_fetch(rtindex, pstate->p_rtable));
*top_rte = rte;
*top_rti = rtindex;
*namespace = list_make1(makeDefaultNSItem(rte, rtindex));
nsitem = transformRangeTableFunc(pstate, (RangeTableFunc *) n);
*top_nsitem = nsitem;
*namespace = list_make1(nsitem);
rtr = makeNode(RangeTblRef);
rtr->rtindex = rtindex;
rtr->rtindex = nsitem->p_rtindex;
return (Node *) rtr;
}
else if (IsA(n, RangeTableSample))
@ -1152,19 +1121,17 @@ transformFromClauseItem(ParseState *pstate, Node *n,
/* TABLESAMPLE clause (wrapping some other valid FROM node) */
RangeTableSample *rts = (RangeTableSample *) n;
Node *rel;
RangeTblRef *rtr;
RangeTblEntry *rte;
/* Recursively transform the contained relation */
rel = transformFromClauseItem(pstate, rts->relation,
top_rte, top_rti, namespace);
/* Currently, grammar could only return a RangeVar as contained rel */
rtr = castNode(RangeTblRef, rel);
rte = rt_fetch(rtr->rtindex, pstate->p_rtable);
top_nsitem, namespace);
rte = (*top_nsitem)->p_rte;
/* We only support this on plain relations and matviews */
if (rte->relkind != RELKIND_RELATION &&
rte->relkind != RELKIND_MATVIEW &&
rte->relkind != RELKIND_PARTITIONED_TABLE)
if (rte->rtekind != RTE_RELATION ||
(rte->relkind != RELKIND_RELATION &&
rte->relkind != RELKIND_MATVIEW &&
rte->relkind != RELKIND_PARTITIONED_TABLE))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("TABLESAMPLE clause can only be applied to tables and materialized views"),
@ -1172,16 +1139,15 @@ transformFromClauseItem(ParseState *pstate, Node *n,
/* Transform TABLESAMPLE details and attach to the RTE */
rte->tablesample = transformRangeTableSample(pstate, rts);
return (Node *) rtr;
return rel;
}
else if (IsA(n, JoinExpr))
{
/* A newfangled join expression */
JoinExpr *j = (JoinExpr *) n;
RangeTblEntry *l_rte;
RangeTblEntry *r_rte;
int l_rtindex;
int r_rtindex;
ParseNamespaceItem *nsitem;
ParseNamespaceItem *l_nsitem;
ParseNamespaceItem *r_nsitem;
List *l_namespace,
*r_namespace,
*my_namespace,
@ -1191,9 +1157,10 @@ transformFromClauseItem(ParseState *pstate, Node *n,
*l_colvars,
*r_colvars,
*res_colvars;
ParseNamespaceColumn *res_nscolumns;
int res_colindex;
bool lateral_ok;
int sv_namespace_length;
RangeTblEntry *rte;
int k;
/*
@ -1201,8 +1168,7 @@ transformFromClauseItem(ParseState *pstate, Node *n,
* it in this order for correct visibility of LATERAL references.
*/
j->larg = transformFromClauseItem(pstate, j->larg,
&l_rte,
&l_rtindex,
&l_nsitem,
&l_namespace);
/*
@ -1225,8 +1191,7 @@ transformFromClauseItem(ParseState *pstate, Node *n,
/* And now we can process the RHS */
j->rarg = transformFromClauseItem(pstate, j->rarg,
&r_rte,
&r_rtindex,
&r_nsitem,
&r_namespace);
/* Remove the left-side RTEs from the namespace list again */
@ -1248,12 +1213,10 @@ transformFromClauseItem(ParseState *pstate, Node *n,
/*
* Extract column name and var lists from both subtrees
*
* Note: expandRTE returns new lists, safe for me to modify
* Note: expandNSItemVars returns new lists, safe for me to modify
*/
expandRTE(l_rte, l_rtindex, 0, -1, false,
&l_colnames, &l_colvars);
expandRTE(r_rte, r_rtindex, 0, -1, false,
&r_colnames, &r_colvars);
l_colvars = expandNSItemVars(l_nsitem, 0, -1, &l_colnames);
r_colvars = expandNSItemVars(r_nsitem, 0, -1, &r_colnames);
/*
* Natural join does not explicitly specify columns; must generate
@ -1302,6 +1265,12 @@ transformFromClauseItem(ParseState *pstate, Node *n,
res_colnames = NIL;
res_colvars = NIL;
/* this may be larger than needed, but it's not worth being exact */
res_nscolumns = (ParseNamespaceColumn *)
palloc0((list_length(l_colnames) + list_length(r_colnames)) *
sizeof(ParseNamespaceColumn));
res_colindex = 0;
if (j->usingClause)
{
/*
@ -1325,6 +1294,8 @@ transformFromClauseItem(ParseState *pstate, Node *n,
int r_index = -1;
Var *l_colvar,
*r_colvar;
Node *u_colvar;
ParseNamespaceColumn *res_nscolumn;
/* Check for USING(foo,foo) */
foreach(col, res_colnames)
@ -1390,16 +1361,58 @@ transformFromClauseItem(ParseState *pstate, Node *n,
r_usingvars = lappend(r_usingvars, r_colvar);
res_colnames = lappend(res_colnames, lfirst(ucol));
res_colvars = lappend(res_colvars,
buildMergedJoinVar(pstate,
j->jointype,
l_colvar,
r_colvar));
u_colvar = buildMergedJoinVar(pstate,
j->jointype,
l_colvar,
r_colvar);
res_colvars = lappend(res_colvars, u_colvar);
res_nscolumn = res_nscolumns + res_colindex;
res_colindex++;
if (u_colvar == (Node *) l_colvar)
{
/* Merged column is equivalent to left input */
res_nscolumn->p_varno = l_colvar->varno;
res_nscolumn->p_varattno = l_colvar->varattno;
res_nscolumn->p_vartype = l_colvar->vartype;
res_nscolumn->p_vartypmod = l_colvar->vartypmod;
res_nscolumn->p_varcollid = l_colvar->varcollid;
/* XXX these are not quite right, but doesn't matter yet */
res_nscolumn->p_varnosyn = l_colvar->varno;
res_nscolumn->p_varattnosyn = l_colvar->varattno;
}
else if (u_colvar == (Node *) r_colvar)
{
/* Merged column is equivalent to right input */
res_nscolumn->p_varno = r_colvar->varno;
res_nscolumn->p_varattno = r_colvar->varattno;
res_nscolumn->p_vartype = r_colvar->vartype;
res_nscolumn->p_vartypmod = r_colvar->vartypmod;
res_nscolumn->p_varcollid = r_colvar->varcollid;
/* XXX these are not quite right, but doesn't matter yet */
res_nscolumn->p_varnosyn = r_colvar->varno;
res_nscolumn->p_varattnosyn = r_colvar->varattno;
}
else
{
/*
* Merged column is not semantically equivalent to either
* input, so it needs to be referenced as the join output
* column. We don't know the join's varno yet, so we'll
* replace these zeroes below.
*/
res_nscolumn->p_varno = 0;
res_nscolumn->p_varattno = res_colindex;
res_nscolumn->p_vartype = exprType(u_colvar);
res_nscolumn->p_vartypmod = exprTypmod(u_colvar);
res_nscolumn->p_varcollid = exprCollation(u_colvar);
res_nscolumn->p_varnosyn = 0;
res_nscolumn->p_varattnosyn = res_colindex;
}
}
j->quals = transformJoinUsingClause(pstate,
l_rte,
r_rte,
l_nsitem->p_rte,
r_nsitem->p_rte,
l_usingvars,
r_usingvars);
}
@ -1416,10 +1429,16 @@ transformFromClauseItem(ParseState *pstate, Node *n,
/* Add remaining columns from each side to the output columns */
extractRemainingColumns(res_colnames,
l_colnames, l_colvars,
&l_colnames, &l_colvars);
l_nsitem->p_nscolumns,
&l_colnames, &l_colvars,
res_nscolumns + res_colindex);
res_colindex += list_length(l_colvars);
extractRemainingColumns(res_colnames,
r_colnames, r_colvars,
&r_colnames, &r_colvars);
r_nsitem->p_nscolumns,
&r_colnames, &r_colvars,
res_nscolumns + res_colindex);
res_colindex += list_length(r_colvars);
res_colnames = list_concat(res_colnames, l_colnames);
res_colvars = list_concat(res_colvars, l_colvars);
res_colnames = list_concat(res_colnames, r_colnames);
@ -1441,21 +1460,41 @@ transformFromClauseItem(ParseState *pstate, Node *n,
}
/*
* Now build an RTE for the result of the join
* Now build an RTE and nsitem for the result of the join.
* res_nscolumns isn't totally done yet, but that's OK because
* addRangeTableEntryForJoin doesn't examine it, only store a pointer.
*/
rte = addRangeTableEntryForJoin(pstate,
res_colnames,
j->jointype,
res_colvars,
j->alias,
true);
nsitem = addRangeTableEntryForJoin(pstate,
res_colnames,
res_nscolumns,
j->jointype,
res_colvars,
j->alias,
true);
/* assume new rte is at end */
j->rtindex = list_length(pstate->p_rtable);
Assert(rte == rt_fetch(j->rtindex, pstate->p_rtable));
j->rtindex = nsitem->p_rtindex;
*top_rte = rte;
*top_rti = j->rtindex;
/*
* Now that we know the join RTE's rangetable index, we can fix up the
* res_nscolumns data in places where it should contain that.
*/
Assert(res_colindex == list_length(nsitem->p_rte->eref->colnames));
for (k = 0; k < res_colindex; k++)
{
ParseNamespaceColumn *nscol = res_nscolumns + k;
/* fill in join RTI for merged columns */
if (nscol->p_varno == 0)
nscol->p_varno = j->rtindex;
if (nscol->p_varnosyn == 0)
nscol->p_varnosyn = j->rtindex;
/* if join has an alias, it syntactically hides all inputs */
if (j->alias)
{
nscol->p_varnosyn = j->rtindex;
nscol->p_varattnosyn = k + 1;
}
}
/* make a matching link to the JoinExpr for later use */
for (k = list_length(pstate->p_joinexprs) + 1; k < j->rtindex; k++)
@ -1483,13 +1522,13 @@ transformFromClauseItem(ParseState *pstate, Node *n,
* The join RTE itself is always made visible for unqualified column
* names. It's visible as a relation name only if it has an alias.
*/
*namespace = lappend(my_namespace,
makeNamespaceItem(rte,
j->rtindex,
(j->alias != NULL),
true,
false,
true));
nsitem->p_rel_visible = (j->alias != NULL);
nsitem->p_cols_visible = true;
nsitem->p_lateral_only = false;
nsitem->p_lateral_ok = true;
*top_nsitem = nsitem;
*namespace = lappend(my_namespace, nsitem);
return (Node *) j;
}
@ -1617,27 +1656,6 @@ buildMergedJoinVar(ParseState *pstate, JoinType jointype,
return res_node;
}
/*
* makeNamespaceItem -
* Convenience subroutine to construct a ParseNamespaceItem.
*/
static ParseNamespaceItem *
makeNamespaceItem(RangeTblEntry *rte, int rtindex,
bool rel_visible, bool cols_visible,
bool lateral_only, bool lateral_ok)
{
ParseNamespaceItem *nsitem;
nsitem = (ParseNamespaceItem *) palloc(sizeof(ParseNamespaceItem));
nsitem->p_rte = rte;
nsitem->p_rtindex = rtindex;
nsitem->p_rel_visible = rel_visible;
nsitem->p_cols_visible = cols_visible;
nsitem->p_lateral_only = lateral_only;
nsitem->p_lateral_ok = lateral_ok;
return nsitem;
}
/*
* setNamespaceColumnVisibility -
* Convenience subroutine to update cols_visible flags in a namespace list.
@ -3163,8 +3181,8 @@ transformOnConflictArbiter(ParseState *pstate,
*/
save_namespace = pstate->p_namespace;
pstate->p_namespace = NIL;
addRTEtoQuery(pstate, pstate->p_target_rangetblentry,
false, false, true);
addNSItemToQuery(pstate, pstate->p_target_nsitem,
false, false, true);
if (infer->indexElems)
*arbiterExpr = resolve_unique_index_expr(pstate, infer,
@ -3189,7 +3207,7 @@ transformOnConflictArbiter(ParseState *pstate,
if (infer->conname)
{
Oid relid = RelationGetRelid(pstate->p_target_relation);
RangeTblEntry *rte = pstate->p_target_rangetblentry;
RangeTblEntry *rte = pstate->p_target_nsitem->p_rte;
Bitmapset *conattnos;
conattnos = get_relation_constraint_attnos(relid, infer->conname,

View File

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

View File

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

View File

@ -472,7 +472,8 @@ check_lateral_ref_ok(ParseState *pstate, ParseNamespaceItem *nsitem,
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
errmsg("invalid reference to FROM-clause entry for table \"%s\"",
refname),
(rte == pstate->p_target_rangetblentry) ?
(pstate->p_target_nsitem != NULL &&
rte == pstate->p_target_nsitem->p_rte) ?
errhint("There is an entry for table \"%s\", but it cannot be referenced from this part of the query.",
refname) :
errdetail("The combining JOIN type must be INNER or LEFT for a LATERAL reference."),
@ -669,9 +670,6 @@ scanNSItemForColumn(ParseState *pstate, ParseNamespaceItem *nsitem,
RangeTblEntry *rte = nsitem->p_rte;
int attnum;
Var *var;
Oid vartypeid;
int32 vartypmod;
Oid varcollid;
/*
* Scan the RTE's column names (or aliases) for a match. Complain if
@ -703,11 +701,39 @@ scanNSItemForColumn(ParseState *pstate, ParseNamespaceItem *nsitem,
parser_errposition(pstate, location)));
/* Found a valid match, so build a Var */
get_rte_attribute_type(rte, attnum,
&vartypeid, &vartypmod, &varcollid);
var = makeVar(nsitem->p_rtindex, attnum,
vartypeid, vartypmod, varcollid,
sublevels_up);
if (attnum > InvalidAttrNumber)
{
/* Get attribute data from the ParseNamespaceColumn array */
ParseNamespaceColumn *nscol = &nsitem->p_nscolumns[attnum - 1];
/* Complain if dropped column. See notes in scanRTEForColumn. */
if (nscol->p_varno == 0)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("column \"%s\" of relation \"%s\" does not exist",
colname,
rte->eref->aliasname)));
var = makeVar(nsitem->p_rtindex,
attnum,
nscol->p_vartype,
nscol->p_vartypmod,
nscol->p_varcollid,
sublevels_up);
}
else
{
/* System column, so use predetermined type data */
const FormData_pg_attribute *sysatt;
sysatt = SystemAttributeDefinition(attnum);
var = makeVar(nsitem->p_rtindex,
attnum,
sysatt->atttypid,
sysatt->atttypmod,
sysatt->attcollation,
sublevels_up);
}
var->location = location;
/* Require read access to the column */
@ -753,11 +779,9 @@ scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte,
* don't bother to test for that case here.
*
* Should this somehow go wrong and we try to access a dropped column,
* we'll still catch it by virtue of the checks in
* get_rte_attribute_type(), which is called by scanNSItemForColumn().
* That routine has to do a cache lookup anyway, so the check there is
* cheap. Callers interested in finding match with shortest distance need
* to defend against this directly, though.
* we'll still catch it by virtue of the check in scanNSItemForColumn().
* Callers interested in finding match with shortest distance need to
* defend against this directly, though.
*/
foreach(c, rte->eref->colnames)
{
@ -1200,6 +1224,121 @@ chooseScalarFunctionAlias(Node *funcexpr, char *funcname,
return funcname;
}
/*
* buildNSItemFromTupleDesc
* Build a ParseNamespaceItem, given a tupdesc describing the columns.
*
* rte: the new RangeTblEntry for the rel
* rtindex: its index in the rangetable list
* tupdesc: the physical column information
*/
static ParseNamespaceItem *
buildNSItemFromTupleDesc(RangeTblEntry *rte, Index rtindex, TupleDesc tupdesc)
{
ParseNamespaceItem *nsitem;
ParseNamespaceColumn *nscolumns;
int maxattrs = tupdesc->natts;
int varattno;
/* colnames must have the same number of entries as the nsitem */
Assert(maxattrs == list_length(rte->eref->colnames));
/* extract per-column data from the tupdesc */
nscolumns = (ParseNamespaceColumn *)
palloc0(maxattrs * sizeof(ParseNamespaceColumn));
for (varattno = 0; varattno < maxattrs; varattno++)
{
Form_pg_attribute attr = TupleDescAttr(tupdesc, varattno);
/* For a dropped column, just leave the entry as zeroes */
if (attr->attisdropped)
continue;
nscolumns[varattno].p_varno = rtindex;
nscolumns[varattno].p_varattno = varattno + 1;
nscolumns[varattno].p_vartype = attr->atttypid;
nscolumns[varattno].p_vartypmod = attr->atttypmod;
nscolumns[varattno].p_varcollid = attr->attcollation;
nscolumns[varattno].p_varnosyn = rtindex;
nscolumns[varattno].p_varattnosyn = varattno + 1;
}
/* ... and build the nsitem */
nsitem = (ParseNamespaceItem *) palloc(sizeof(ParseNamespaceItem));
nsitem->p_rte = rte;
nsitem->p_rtindex = rtindex;
nsitem->p_nscolumns = nscolumns;
/* set default visibility flags; might get changed later */
nsitem->p_rel_visible = true;
nsitem->p_cols_visible = true;
nsitem->p_lateral_only = false;
nsitem->p_lateral_ok = true;
return nsitem;
}
/*
* buildNSItemFromLists
* Build a ParseNamespaceItem, given column type information in lists.
*
* rte: the new RangeTblEntry for the rel
* rtindex: its index in the rangetable list
* coltypes: per-column datatype OIDs
* coltypmods: per-column type modifiers
* colcollation: per-column collation OIDs
*/
static ParseNamespaceItem *
buildNSItemFromLists(RangeTblEntry *rte, Index rtindex,
List *coltypes, List *coltypmods, List *colcollations)
{
ParseNamespaceItem *nsitem;
ParseNamespaceColumn *nscolumns;
int maxattrs = list_length(coltypes);
int varattno;
ListCell *lct;
ListCell *lcm;
ListCell *lcc;
/* colnames must have the same number of entries as the nsitem */
Assert(maxattrs == list_length(rte->eref->colnames));
Assert(maxattrs == list_length(coltypmods));
Assert(maxattrs == list_length(colcollations));
/* extract per-column data from the lists */
nscolumns = (ParseNamespaceColumn *)
palloc0(maxattrs * sizeof(ParseNamespaceColumn));
varattno = 0;
forthree(lct, coltypes,
lcm, coltypmods,
lcc, colcollations)
{
nscolumns[varattno].p_varno = rtindex;
nscolumns[varattno].p_varattno = varattno + 1;
nscolumns[varattno].p_vartype = lfirst_oid(lct);
nscolumns[varattno].p_vartypmod = lfirst_int(lcm);
nscolumns[varattno].p_varcollid = lfirst_oid(lcc);
nscolumns[varattno].p_varnosyn = rtindex;
nscolumns[varattno].p_varattnosyn = varattno + 1;
varattno++;
}
/* ... and build the nsitem */
nsitem = (ParseNamespaceItem *) palloc(sizeof(ParseNamespaceItem));
nsitem->p_rte = rte;
nsitem->p_rtindex = rtindex;
nsitem->p_nscolumns = nscolumns;
/* set default visibility flags; might get changed later */
nsitem->p_rel_visible = true;
nsitem->p_cols_visible = true;
nsitem->p_lateral_only = false;
nsitem->p_lateral_ok = true;
return nsitem;
}
/*
* Open a table during parse analysis
*
@ -1255,11 +1394,15 @@ parserOpenTable(ParseState *pstate, const RangeVar *relation, int lockmode)
/*
* Add an entry for a relation to the pstate's range table (p_rtable).
* Then, construct and return a ParseNamespaceItem for the new RTE.
*
* We do not link the ParseNamespaceItem into the pstate here; it's the
* caller's job to do that in the appropriate way.
*
* Note: formerly this checked for refname conflicts, but that's wrong.
* Caller is responsible for checking for conflicts in the appropriate scope.
*/
RangeTblEntry *
ParseNamespaceItem *
addRangeTableEntry(ParseState *pstate,
RangeVar *relation,
Alias *alias,
@ -1270,6 +1413,7 @@ addRangeTableEntry(ParseState *pstate,
char *refname = alias ? alias->aliasname : relation->relname;
LOCKMODE lockmode;
Relation rel;
ParseNamespaceItem *nsitem;
Assert(pstate != NULL);
@ -1301,13 +1445,6 @@ addRangeTableEntry(ParseState *pstate,
rte->eref = makeAlias(refname, NIL);
buildRelationAliases(rel->rd_att, alias, rte->eref);
/*
* Drop the rel refcount, but keep the access lock till end of transaction
* so that the table can't be deleted or have its schema modified
* underneath us.
*/
table_close(rel, NoLock);
/*
* Set flags and access permissions.
*
@ -1326,16 +1463,32 @@ addRangeTableEntry(ParseState *pstate,
rte->extraUpdatedCols = NULL;
/*
* Add completed RTE to pstate's range table list, but not to join list
* nor namespace --- caller must do that if appropriate.
* Add completed RTE to pstate's range table list, so that we know its
* index. But we don't add it to the join list --- caller must do that if
* appropriate.
*/
pstate->p_rtable = lappend(pstate->p_rtable, rte);
return rte;
/*
* Build a ParseNamespaceItem, but don't add it to the pstate's namespace
* list --- caller must do that if appropriate.
*/
nsitem = buildNSItemFromTupleDesc(rte, list_length(pstate->p_rtable),
rel->rd_att);
/*
* Drop the rel refcount, but keep the access lock till end of transaction
* so that the table can't be deleted or have its schema modified
* underneath us.
*/
table_close(rel, NoLock);
return nsitem;
}
/*
* Add an entry for a relation to the pstate's range table (p_rtable).
* Then, construct and return a ParseNamespaceItem for the new RTE.
*
* This is just like addRangeTableEntry() except that it makes an RTE
* given an already-open relation instead of a RangeVar reference.
@ -1349,7 +1502,7 @@ addRangeTableEntry(ParseState *pstate,
* would require importing storage/lock.h into parse_relation.h. Since
* LOCKMODE is typedef'd as int anyway, that seems like overkill.
*/
RangeTblEntry *
ParseNamespaceItem *
addRangeTableEntryForRelation(ParseState *pstate,
Relation rel,
int lockmode,
@ -1398,21 +1551,28 @@ addRangeTableEntryForRelation(ParseState *pstate,
rte->extraUpdatedCols = NULL;
/*
* Add completed RTE to pstate's range table list, but not to join list
* nor namespace --- caller must do that if appropriate.
* Add completed RTE to pstate's range table list, so that we know its
* index. But we don't add it to the join list --- caller must do that if
* appropriate.
*/
pstate->p_rtable = lappend(pstate->p_rtable, rte);
return rte;
/*
* Build a ParseNamespaceItem, but don't add it to the pstate's namespace
* list --- caller must do that if appropriate.
*/
return buildNSItemFromTupleDesc(rte, list_length(pstate->p_rtable),
rel->rd_att);
}
/*
* Add an entry for a subquery to the pstate's range table (p_rtable).
* Then, construct and return a ParseNamespaceItem for the new RTE.
*
* This is just like addRangeTableEntry() except that it makes a subquery RTE.
* This is much like addRangeTableEntry() except that it makes a subquery RTE.
* Note that an alias clause *must* be supplied.
*/
RangeTblEntry *
ParseNamespaceItem *
addRangeTableEntryForSubquery(ParseState *pstate,
Query *subquery,
Alias *alias,
@ -1423,6 +1583,9 @@ addRangeTableEntryForSubquery(ParseState *pstate,
char *refname = alias->aliasname;
Alias *eref;
int numaliases;
List *coltypes,
*coltypmods,
*colcollations;
int varattno;
ListCell *tlistitem;
@ -1435,7 +1598,8 @@ addRangeTableEntryForSubquery(ParseState *pstate,
eref = copyObject(alias);
numaliases = list_length(eref->colnames);
/* fill in any unspecified alias columns */
/* fill in any unspecified alias columns, and extract column type info */
coltypes = coltypmods = colcollations = NIL;
varattno = 0;
foreach(tlistitem, subquery->targetList)
{
@ -1452,6 +1616,12 @@ addRangeTableEntryForSubquery(ParseState *pstate,
attrname = pstrdup(te->resname);
eref->colnames = lappend(eref->colnames, makeString(attrname));
}
coltypes = lappend_oid(coltypes,
exprType((Node *) te->expr));
coltypmods = lappend_int(coltypmods,
exprTypmod((Node *) te->expr));
colcollations = lappend_oid(colcollations,
exprCollation((Node *) te->expr));
}
if (varattno < numaliases)
ereport(ERROR,
@ -1478,21 +1648,27 @@ addRangeTableEntryForSubquery(ParseState *pstate,
rte->extraUpdatedCols = NULL;
/*
* Add completed RTE to pstate's range table list, but not to join list
* nor namespace --- caller must do that if appropriate.
* Add completed RTE to pstate's range table list, so that we know its
* index. But we don't add it to the join list --- caller must do that if
* appropriate.
*/
pstate->p_rtable = lappend(pstate->p_rtable, rte);
return rte;
/*
* Build a ParseNamespaceItem, but don't add it to the pstate's namespace
* list --- caller must do that if appropriate.
*/
return buildNSItemFromLists(rte, list_length(pstate->p_rtable),
coltypes, coltypmods, colcollations);
}
/*
* Add an entry for a function (or functions) to the pstate's range table
* (p_rtable).
* (p_rtable). Then, construct and return a ParseNamespaceItem for the new RTE.
*
* This is just like addRangeTableEntry() except that it makes a function RTE.
* This is much like addRangeTableEntry() except that it makes a function RTE.
*/
RangeTblEntry *
ParseNamespaceItem *
addRangeTableEntryForFunction(ParseState *pstate,
List *funcnames,
List *funcexprs,
@ -1742,20 +1918,27 @@ addRangeTableEntryForFunction(ParseState *pstate,
rte->extraUpdatedCols = NULL;
/*
* Add completed RTE to pstate's range table list, but not to join list
* nor namespace --- caller must do that if appropriate.
* Add completed RTE to pstate's range table list, so that we know its
* index. But we don't add it to the join list --- caller must do that if
* appropriate.
*/
pstate->p_rtable = lappend(pstate->p_rtable, rte);
return rte;
/*
* Build a ParseNamespaceItem, but don't add it to the pstate's namespace
* list --- caller must do that if appropriate.
*/
return buildNSItemFromTupleDesc(rte, list_length(pstate->p_rtable),
tupdesc);
}
/*
* Add an entry for a table function to the pstate's range table (p_rtable).
* Then, construct and return a ParseNamespaceItem for the new RTE.
*
* This is much like addRangeTableEntry() except that it makes a tablefunc RTE.
*/
RangeTblEntry *
ParseNamespaceItem *
addRangeTableEntryForTableFunc(ParseState *pstate,
TableFunc *tf,
Alias *alias,
@ -1806,20 +1989,28 @@ addRangeTableEntryForTableFunc(ParseState *pstate,
rte->extraUpdatedCols = NULL;
/*
* Add completed RTE to pstate's range table list, but not to join list
* nor namespace --- caller must do that if appropriate.
* Add completed RTE to pstate's range table list, so that we know its
* index. But we don't add it to the join list --- caller must do that if
* appropriate.
*/
pstate->p_rtable = lappend(pstate->p_rtable, rte);
return rte;
/*
* Build a ParseNamespaceItem, but don't add it to the pstate's namespace
* list --- caller must do that if appropriate.
*/
return buildNSItemFromLists(rte, list_length(pstate->p_rtable),
rte->coltypes, rte->coltypmods,
rte->colcollations);
}
/*
* Add an entry for a VALUES list to the pstate's range table (p_rtable).
* Then, construct and return a ParseNamespaceItem for the new RTE.
*
* This is much like addRangeTableEntry() except that it makes a values RTE.
*/
RangeTblEntry *
ParseNamespaceItem *
addRangeTableEntryForValues(ParseState *pstate,
List *exprs,
List *coltypes,
@ -1885,22 +2076,33 @@ addRangeTableEntryForValues(ParseState *pstate,
rte->extraUpdatedCols = NULL;
/*
* Add completed RTE to pstate's range table list, but not to join list
* nor namespace --- caller must do that if appropriate.
* Add completed RTE to pstate's range table list, so that we know its
* index. But we don't add it to the join list --- caller must do that if
* appropriate.
*/
pstate->p_rtable = lappend(pstate->p_rtable, rte);
return rte;
/*
* Build a ParseNamespaceItem, but don't add it to the pstate's namespace
* list --- caller must do that if appropriate.
*/
return buildNSItemFromLists(rte, list_length(pstate->p_rtable),
rte->coltypes, rte->coltypmods,
rte->colcollations);
}
/*
* Add an entry for a join to the pstate's range table (p_rtable).
* Then, construct and return a ParseNamespaceItem for the new RTE.
*
* This is much like addRangeTableEntry() except that it makes a join RTE.
* Also, it's more convenient for the caller to construct the
* ParseNamespaceColumn array, so we pass that in.
*/
RangeTblEntry *
ParseNamespaceItem *
addRangeTableEntryForJoin(ParseState *pstate,
List *colnames,
ParseNamespaceColumn *nscolumns,
JoinType jointype,
List *aliasvars,
Alias *alias,
@ -1909,6 +2111,7 @@ addRangeTableEntryForJoin(ParseState *pstate,
RangeTblEntry *rte = makeNode(RangeTblEntry);
Alias *eref;
int numaliases;
ParseNamespaceItem *nsitem;
Assert(pstate != NULL);
@ -1956,20 +2159,36 @@ addRangeTableEntryForJoin(ParseState *pstate,
rte->extraUpdatedCols = NULL;
/*
* Add completed RTE to pstate's range table list, but not to join list
* nor namespace --- caller must do that if appropriate.
* Add completed RTE to pstate's range table list, so that we know its
* index. But we don't add it to the join list --- caller must do that if
* appropriate.
*/
pstate->p_rtable = lappend(pstate->p_rtable, rte);
return rte;
/*
* Build a ParseNamespaceItem, but don't add it to the pstate's namespace
* list --- caller must do that if appropriate.
*/
nsitem = (ParseNamespaceItem *) palloc(sizeof(ParseNamespaceItem));
nsitem->p_rte = rte;
nsitem->p_rtindex = list_length(pstate->p_rtable);
nsitem->p_nscolumns = nscolumns;
/* set default visibility flags; might get changed later */
nsitem->p_rel_visible = true;
nsitem->p_cols_visible = true;
nsitem->p_lateral_only = false;
nsitem->p_lateral_ok = true;
return nsitem;
}
/*
* Add an entry for a CTE reference to the pstate's range table (p_rtable).
* Then, construct and return a ParseNamespaceItem for the new RTE.
*
* This is much like addRangeTableEntry() except that it makes a CTE RTE.
*/
RangeTblEntry *
ParseNamespaceItem *
addRangeTableEntryForCTE(ParseState *pstate,
CommonTableExpr *cte,
Index levelsup,
@ -2059,17 +2278,25 @@ addRangeTableEntryForCTE(ParseState *pstate,
rte->extraUpdatedCols = NULL;
/*
* Add completed RTE to pstate's range table list, but not to join list
* nor namespace --- caller must do that if appropriate.
* Add completed RTE to pstate's range table list, so that we know its
* index. But we don't add it to the join list --- caller must do that if
* appropriate.
*/
pstate->p_rtable = lappend(pstate->p_rtable, rte);
return rte;
/*
* Build a ParseNamespaceItem, but don't add it to the pstate's namespace
* list --- caller must do that if appropriate.
*/
return buildNSItemFromLists(rte, list_length(pstate->p_rtable),
rte->coltypes, rte->coltypmods,
rte->colcollations);
}
/*
* Add an entry for an ephemeral named relation reference to the pstate's
* range table (p_rtable).
* Then, construct and return a ParseNamespaceItem for the new RTE.
*
* It is expected that the RangeVar, which up until now is only known to be an
* ephemeral named relation, will (in conjunction with the QueryEnvironment in
@ -2079,7 +2306,7 @@ addRangeTableEntryForCTE(ParseState *pstate,
* This is much like addRangeTableEntry() except that it makes an RTE for an
* ephemeral named relation.
*/
RangeTblEntry *
ParseNamespaceItem *
addRangeTableEntryForENR(ParseState *pstate,
RangeVar *rv,
bool inFromCl)
@ -2164,12 +2391,18 @@ addRangeTableEntryForENR(ParseState *pstate,
rte->selectedCols = NULL;
/*
* Add completed RTE to pstate's range table list, but not to join list
* nor namespace --- caller must do that if appropriate.
* Add completed RTE to pstate's range table list, so that we know its
* index. But we don't add it to the join list --- caller must do that if
* appropriate.
*/
pstate->p_rtable = lappend(pstate->p_rtable, rte);
return rte;
/*
* Build a ParseNamespaceItem, but don't add it to the pstate's namespace
* list --- caller must do that if appropriate.
*/
return buildNSItemFromTupleDesc(rte, list_length(pstate->p_rtable),
tupdesc);
}
@ -2221,49 +2454,26 @@ isLockedRefname(ParseState *pstate, const char *refname)
}
/*
* Add the given RTE as a top-level entry in the pstate's join list
* Add the given nsitem/RTE as a top-level entry in the pstate's join list
* and/or namespace list. (We assume caller has checked for any
* namespace conflicts.) The RTE is always marked as unconditionally
* namespace conflicts.) The nsitem is always marked as unconditionally
* visible, that is, not LATERAL-only.
*
* Note: some callers know that they can find the new ParseNamespaceItem
* at the end of the pstate->p_namespace list. This is a bit ugly but not
* worth complicating this function's signature for.
*/
void
addRTEtoQuery(ParseState *pstate, RangeTblEntry *rte,
bool addToJoinList,
bool addToRelNameSpace, bool addToVarNameSpace)
addNSItemToQuery(ParseState *pstate, ParseNamespaceItem *nsitem,
bool addToJoinList,
bool addToRelNameSpace, bool addToVarNameSpace)
{
int rtindex;
/*
* Most callers have just added the RTE to the rangetable, so it's likely
* to be the last entry. Hence, it's a good idea to search the rangetable
* back-to-front.
*/
for (rtindex = list_length(pstate->p_rtable); rtindex > 0; rtindex--)
{
if (rte == rt_fetch(rtindex, pstate->p_rtable))
break;
}
if (rtindex <= 0)
elog(ERROR, "RTE not found (internal error)");
if (addToJoinList)
{
RangeTblRef *rtr = makeNode(RangeTblRef);
rtr->rtindex = rtindex;
rtr->rtindex = nsitem->p_rtindex;
pstate->p_joinlist = lappend(pstate->p_joinlist, rtr);
}
if (addToRelNameSpace || addToVarNameSpace)
{
ParseNamespaceItem *nsitem;
nsitem = (ParseNamespaceItem *) palloc(sizeof(ParseNamespaceItem));
nsitem->p_rte = rte;
nsitem->p_rtindex = rtindex;
/* Set the new nsitem's visibility flags correctly */
nsitem->p_rel_visible = addToRelNameSpace;
nsitem->p_cols_visible = addToVarNameSpace;
nsitem->p_lateral_only = false;
@ -2720,6 +2930,61 @@ expandTupleDesc(TupleDesc tupdesc, Alias *eref, int count, int offset,
}
}
/*
* expandNSItemVars
* Produce a list of Vars, and optionally a list of column names,
* for the non-dropped columns of the nsitem.
*
* The emitted Vars are marked with the given sublevels_up and location.
*
* If colnames isn't NULL, a list of String items for the columns is stored
* there; note that it's just a subset of the RTE's eref list, and hence
* the list elements mustn't be modified.
*/
List *
expandNSItemVars(ParseNamespaceItem *nsitem,
int sublevels_up, int location,
List **colnames)
{
List *result = NIL;
int colindex;
ListCell *lc;
if (colnames)
*colnames = NIL;
colindex = 0;
foreach(lc, nsitem->p_rte->eref->colnames)
{
Value *colnameval = (Value *) lfirst(lc);
const char *colname = strVal(colnameval);
ParseNamespaceColumn *nscol = nsitem->p_nscolumns + colindex;
if (colname[0])
{
Var *var;
Assert(nscol->p_varno > 0);
var = makeVar(nsitem->p_rtindex,
colindex + 1,
nscol->p_vartype,
nscol->p_vartypmod,
nscol->p_varcollid,
sublevels_up);
var->location = location;
result = lappend(result, var);
if (colnames)
*colnames = lappend(*colnames, colnameval);
}
else
{
/* dropped column, ignore */
Assert(nscol->p_varno == 0);
}
colindex++;
}
return result;
}
/*
* expandNSItemAttrs -
* Workhorse for "*" expansion: produce a list of targetentries
@ -2739,8 +3004,7 @@ expandNSItemAttrs(ParseState *pstate, ParseNamespaceItem *nsitem,
*var;
List *te_list = NIL;
expandRTE(rte, nsitem->p_rtindex, sublevels_up, location, false,
&names, &vars);
vars = expandNSItemVars(nsitem, sublevels_up, location, &names);
/*
* Require read access to the table. This is normally redundant with the
@ -2815,204 +3079,6 @@ get_rte_attribute_name(RangeTblEntry *rte, AttrNumber attnum)
return NULL; /* keep compiler quiet */
}
/*
* get_rte_attribute_type
* Get attribute type/typmod/collation information from a RangeTblEntry
*/
void
get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
Oid *vartype, int32 *vartypmod, Oid *varcollid)
{
switch (rte->rtekind)
{
case RTE_RELATION:
{
/* Plain relation RTE --- get the attribute's type info */
HeapTuple tp;
Form_pg_attribute att_tup;
tp = SearchSysCache2(ATTNUM,
ObjectIdGetDatum(rte->relid),
Int16GetDatum(attnum));
if (!HeapTupleIsValid(tp)) /* shouldn't happen */
elog(ERROR, "cache lookup failed for attribute %d of relation %u",
attnum, rte->relid);
att_tup = (Form_pg_attribute) GETSTRUCT(tp);
/*
* If dropped column, pretend it ain't there. See notes in
* scanRTEForColumn.
*/
if (att_tup->attisdropped)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("column \"%s\" of relation \"%s\" does not exist",
NameStr(att_tup->attname),
get_rel_name(rte->relid))));
*vartype = att_tup->atttypid;
*vartypmod = att_tup->atttypmod;
*varcollid = att_tup->attcollation;
ReleaseSysCache(tp);
}
break;
case RTE_SUBQUERY:
{
/* Subselect RTE --- get type info from subselect's tlist */
TargetEntry *te = get_tle_by_resno(rte->subquery->targetList,
attnum);
if (te == NULL || te->resjunk)
elog(ERROR, "subquery %s does not have attribute %d",
rte->eref->aliasname, attnum);
*vartype = exprType((Node *) te->expr);
*vartypmod = exprTypmod((Node *) te->expr);
*varcollid = exprCollation((Node *) te->expr);
}
break;
case RTE_FUNCTION:
{
/* Function RTE */
ListCell *lc;
int atts_done = 0;
/* Identify which function covers the requested column */
foreach(lc, rte->functions)
{
RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
if (attnum > atts_done &&
attnum <= atts_done + rtfunc->funccolcount)
{
TypeFuncClass functypclass;
Oid funcrettype;
TupleDesc tupdesc;
attnum -= atts_done; /* now relative to this func */
functypclass = get_expr_result_type(rtfunc->funcexpr,
&funcrettype,
&tupdesc);
if (functypclass == TYPEFUNC_COMPOSITE ||
functypclass == TYPEFUNC_COMPOSITE_DOMAIN)
{
/* Composite data type, e.g. a table's row type */
Form_pg_attribute att_tup;
Assert(tupdesc);
Assert(attnum <= tupdesc->natts);
att_tup = TupleDescAttr(tupdesc, attnum - 1);
/*
* If dropped column, pretend it ain't there. See
* notes in scanRTEForColumn.
*/
if (att_tup->attisdropped)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("column \"%s\" of relation \"%s\" does not exist",
NameStr(att_tup->attname),
rte->eref->aliasname)));
*vartype = att_tup->atttypid;
*vartypmod = att_tup->atttypmod;
*varcollid = att_tup->attcollation;
}
else if (functypclass == TYPEFUNC_SCALAR)
{
/* Base data type, i.e. scalar */
*vartype = funcrettype;
*vartypmod = -1;
*varcollid = exprCollation(rtfunc->funcexpr);
}
else if (functypclass == TYPEFUNC_RECORD)
{
*vartype = list_nth_oid(rtfunc->funccoltypes,
attnum - 1);
*vartypmod = list_nth_int(rtfunc->funccoltypmods,
attnum - 1);
*varcollid = list_nth_oid(rtfunc->funccolcollations,
attnum - 1);
}
else
{
/*
* addRangeTableEntryForFunction should've caught
* this
*/
elog(ERROR, "function in FROM has unsupported return type");
}
return;
}
atts_done += rtfunc->funccolcount;
}
/* If we get here, must be looking for the ordinality column */
if (rte->funcordinality && attnum == atts_done + 1)
{
*vartype = INT8OID;
*vartypmod = -1;
*varcollid = InvalidOid;
return;
}
/* this probably can't happen ... */
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("column %d of relation \"%s\" does not exist",
attnum,
rte->eref->aliasname)));
}
break;
case RTE_JOIN:
{
/*
* Join RTE --- get type info from join RTE's alias variable
*/
Node *aliasvar;
Assert(attnum > 0 && attnum <= list_length(rte->joinaliasvars));
aliasvar = (Node *) list_nth(rte->joinaliasvars, attnum - 1);
Assert(aliasvar != NULL);
*vartype = exprType(aliasvar);
*vartypmod = exprTypmod(aliasvar);
*varcollid = exprCollation(aliasvar);
}
break;
case RTE_TABLEFUNC:
case RTE_VALUES:
case RTE_CTE:
case RTE_NAMEDTUPLESTORE:
{
/*
* tablefunc, VALUES, CTE, or ENR RTE --- get type info from
* lists in the RTE
*/
Assert(attnum > 0 && attnum <= list_length(rte->coltypes));
*vartype = list_nth_oid(rte->coltypes, attnum - 1);
*vartypmod = list_nth_int(rte->coltypmods, attnum - 1);
*varcollid = list_nth_oid(rte->colcollations, attnum - 1);
/* For ENR, better check for dropped column */
if (!OidIsValid(*vartype))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("column %d of relation \"%s\" does not exist",
attnum,
rte->eref->aliasname)));
}
break;
case RTE_RESULT:
/* this probably can't happen ... */
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("column %d of relation \"%s\" does not exist",
attnum,
rte->eref->aliasname)));
break;
default:
elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
}
}
/*
* get_rte_attribute_is_dropped
* Check whether attempted attribute ref is to a dropped column

View File

@ -551,7 +551,7 @@ transformAssignedExpr(ParseState *pstate,
*/
Var *var;
var = makeVar(pstate->p_target_rtindex, attrno,
var = makeVar(pstate->p_target_nsitem->p_rtindex, attrno,
attrtype, attrtypmod, attrcollation, 0);
var->location = location;
@ -1359,8 +1359,7 @@ ExpandSingleTable(ParseState *pstate, ParseNamespaceItem *nsitem,
List *vars;
ListCell *l;
expandRTE(rte, nsitem->p_rtindex, sublevels_up, location, false,
NULL, &vars);
vars = expandNSItemVars(nsitem, sublevels_up, location, NULL);
/*
* Require read access to the table. This is normally redundant with
@ -1496,6 +1495,12 @@ expandRecordVariable(ParseState *pstate, Var *var, int levelsup)
Assert(IsA(var, Var));
Assert(var->vartype == RECORDOID);
/*
* Note: it's tempting to use GetNSItemByRangeTablePosn here so that we
* can use expandNSItemVars instead of expandRTE; but that does not work
* for some of the recursion cases below, where we have consed up a
* ParseState that lacks p_namespace data.
*/
netlevelsup = var->varlevelsup + levelsup;
rte = GetRTEByRangeTablePosn(pstate, var->varno, netlevelsup);
attnum = var->varattno;

View File

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

View File

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

View File

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

View File

@ -19,6 +19,11 @@
#include "utils/relcache.h"
/* Forward references for some structs declared below */
typedef struct ParseState ParseState;
typedef struct ParseNamespaceItem ParseNamespaceItem;
typedef struct ParseNamespaceColumn ParseNamespaceColumn;
/*
* Expression kinds distinguished by transformExpr(). Many of these are not
* semantically distinct so far as expression transformation goes; rather,
@ -79,8 +84,6 @@ typedef enum ParseExprKind
/*
* Function signatures for parser hooks
*/
typedef struct ParseState ParseState;
typedef Node *(*PreParseColumnRefHook) (ParseState *pstate, ColumnRef *cref);
typedef Node *(*PostParseColumnRefHook) (ParseState *pstate, ColumnRef *cref, Node *var);
typedef Node *(*ParseParamRefHook) (ParseState *pstate, ParamRef *pref);
@ -132,9 +135,7 @@ typedef Node *(*CoerceParamHook) (ParseState *pstate, Param *param,
*
* p_target_relation: target relation, if query is INSERT, UPDATE, or DELETE.
*
* p_target_rangetblentry: target relation's entry in the rtable list.
*
* p_target_rtindex: target relation's index in the rtable list.
* p_target_nsitem: target relation's ParseNamespaceItem.
*
* p_is_insert: true to process assignment expressions like INSERT, false
* to process them like UPDATE. (Note this can change intra-statement, for
@ -174,7 +175,7 @@ typedef Node *(*CoerceParamHook) (ParseState *pstate, Param *param,
*/
struct ParseState
{
struct ParseState *parentParseState; /* stack link */
ParseState *parentParseState; /* stack link */
const char *p_sourcetext; /* source text, or NULL if not available */
List *p_rtable; /* range table so far */
List *p_joinexprs; /* JoinExprs for RTE_JOIN p_rtable entries */
@ -187,8 +188,7 @@ struct ParseState
List *p_future_ctes; /* common table exprs not yet in namespace */
CommonTableExpr *p_parent_cte; /* this query's containing CTE */
Relation p_target_relation; /* INSERT/UPDATE/DELETE target rel */
RangeTblEntry *p_target_rangetblentry; /* target rel's RTE, or NULL */
int p_target_rtindex; /* target rel's RT index, or 0 */
ParseNamespaceItem *p_target_nsitem; /* target rel's NSItem, or NULL */
bool p_is_insert; /* process assignment like INSERT not UPDATE */
List *p_windowdefs; /* raw representations of window clauses */
ParseExprKind p_expr_kind; /* what kind of expression we're parsing */
@ -225,6 +225,9 @@ struct ParseState
/*
* An element of a namespace list.
*
* The p_nscolumns array contains info showing how to construct Vars
* referencing corresponding elements of the RTE's colnames list.
*
* Namespace items with p_rel_visible set define which RTEs are accessible by
* qualified names, while those with p_cols_visible set define which RTEs are
* accessible by unqualified names. These sets are different because a JOIN
@ -249,15 +252,49 @@ struct ParseState
* are more complicated than "must have different alias names", so in practice
* code searching a namespace list has to check for ambiguous references.
*/
typedef struct ParseNamespaceItem
struct ParseNamespaceItem
{
RangeTblEntry *p_rte; /* The relation's rangetable entry */
int p_rtindex; /* The relation's index in the rangetable */
/* array of same length as p_rte->eref->colnames: */
ParseNamespaceColumn *p_nscolumns; /* per-column data */
bool p_rel_visible; /* Relation name is visible? */
bool p_cols_visible; /* Column names visible as unqualified refs? */
bool p_lateral_only; /* Is only visible to LATERAL expressions? */
bool p_lateral_ok; /* If so, does join type allow use? */
} ParseNamespaceItem;
};
/*
* Data about one column of a ParseNamespaceItem.
*
* We track the info needed to construct a Var referencing the column
* (but only for user-defined columns; system column references and
* whole-row references are handled separately).
*
* p_varno and p_varattno identify the semantic referent, which is a
* base-relation column unless the reference is to a join USING column that
* isn't semantically equivalent to either join input column (because it is a
* FULL join or the input column requires a type coercion). In those cases
* p_varno and p_varattno refer to the JOIN RTE.
*
* p_varnosyn and p_varattnosyn are either identical to p_varno/p_varattno,
* or they specify the column's position in an aliased JOIN RTE that hides
* the semantic referent RTE's refname. (That could be either the JOIN RTE
* in which this ParseNamespaceColumn entry exists, or some lower join level.)
*
* If an RTE contains a dropped column, its ParseNamespaceColumn struct
* is all-zeroes. (Conventionally, test for p_varno == 0 to detect this.)
*/
struct ParseNamespaceColumn
{
Index p_varno; /* rangetable index */
AttrNumber p_varattno; /* attribute number of the column */
Oid p_vartype; /* pg_type OID */
int32 p_vartypmod; /* type modifier value */
Oid p_varcollid; /* OID of collation, or InvalidOid */
Index p_varnosyn; /* rangetable index of syntactic referent */
AttrNumber p_varattnosyn; /* attribute number of syntactic referent */
};
/* Support for parser_errposition_callback function */
typedef struct ParseCallbackState

View File

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

View File

@ -38,15 +38,7 @@
extern char *get_rte_attribute_name(RangeTblEntry *rte, AttrNumber attnum);
/*
* Given an RTE and an attribute number, return the appropriate
* type and typemod info for that attribute of that RTE.
*/
extern void get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
Oid *vartype, int32 *vartypmod, Oid *varcollid);
/*
* Check whether an attribute of an RTE has been dropped (note that
* get_rte_attribute_type will fail on such an attr)
* Check whether an attribute of an RTE has been dropped
*/
extern bool get_rte_attribute_is_dropped(RangeTblEntry *rte,
AttrNumber attnum);

View File

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