aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_relation.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser/parse_relation.c')
-rw-r--r--src/backend/parser/parse_relation.c253
1 files changed, 204 insertions, 49 deletions
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index baae0a578cf..3fccd95cb18 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.48 2000/09/25 18:14:54 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.49 2000/09/29 18:21:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -26,7 +26,6 @@
#include "parser/parse_relation.h"
#include "parser/parse_type.h"
#include "rewrite/rewriteManip.h"
-#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
@@ -98,7 +97,7 @@ refnameRangeOrJoinEntry(ParseState *pstate,
/*
* Check the rangetable for RTEs; if no match, recursively scan
- * the jointree for join tables. We assume that no duplicate
+ * the joinlist for join tables. We assume that no duplicate
* entries have been made in any one nesting level.
*/
foreach(temp, pstate->p_rtable)
@@ -109,7 +108,7 @@ refnameRangeOrJoinEntry(ParseState *pstate,
return (Node *) rte;
}
- join = scanJoinTreeForRefname((Node *) pstate->p_jointree, refname);
+ join = scanJoinListForRefname((Node *) pstate->p_joinlist, refname);
if (join)
return (Node *) join;
@@ -122,9 +121,14 @@ refnameRangeOrJoinEntry(ParseState *pstate,
return NULL;
}
-/* Recursively search a jointree for a joinexpr with given refname */
+/*
+ * Recursively search a joinlist for a joinexpr with given refname
+ *
+ * Note that during parse analysis, we don't expect to find a FromExpr node
+ * in p_joinlist; its top level is just a bare List.
+ */
JoinExpr *
-scanJoinTreeForRefname(Node *jtnode, char *refname)
+scanJoinListForRefname(Node *jtnode, char *refname)
{
JoinExpr *result = NULL;
@@ -136,7 +140,7 @@ scanJoinTreeForRefname(Node *jtnode, char *refname)
foreach(l, (List *) jtnode)
{
- result = scanJoinTreeForRefname(lfirst(l), refname);
+ result = scanJoinListForRefname(lfirst(l), refname);
if (result)
break;
}
@@ -151,12 +155,12 @@ scanJoinTreeForRefname(Node *jtnode, char *refname)
if (j->alias && strcmp(j->alias->relname, refname) == 0)
return j;
- result = scanJoinTreeForRefname(j->larg, refname);
+ result = scanJoinListForRefname(j->larg, refname);
if (! result)
- result = scanJoinTreeForRefname(j->rarg, refname);
+ result = scanJoinListForRefname(j->rarg, refname);
}
else
- elog(ERROR, "scanJoinTreeForRefname: unexpected node type %d",
+ elog(ERROR, "scanJoinListForRefname: unexpected node type %d",
nodeTag(jtnode));
return result;
}
@@ -261,6 +265,9 @@ RTERangeTablePosn(ParseState *pstate, RangeTblEntry *rte, int *sublevels_up)
* Search the column names of a single RTE for the given name.
* If found, return an appropriate Var node, else return NULL.
* If the name proves ambiguous within this RTE, raise error.
+ *
+ * Side effect: if we find a match, mark the RTE as requiring read access.
+ * See comments in setTargetTable().
*/
static Node *
scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte, char *colname)
@@ -281,6 +288,7 @@ scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte, char *colname)
if (result)
elog(ERROR, "Column reference \"%s\" is ambiguous", colname);
result = (Node *) make_var(pstate, rte, attnum);
+ rte->checkForRead = true;
}
}
@@ -299,7 +307,10 @@ scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte, char *colname)
{
attnum = specialAttNum(colname);
if (attnum != InvalidAttrNumber)
+ {
result = (Node *) make_var(pstate, rte, attnum);
+ rte->checkForRead = true;
+ }
}
return result;
@@ -310,6 +321,11 @@ scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte, char *colname)
* Search the column names of a single join table for the given name.
* If found, return an appropriate Var node or expression, else return NULL.
* If the name proves ambiguous within this jointable, raise error.
+ *
+ * NOTE: unlike scanRTEForColumn, there's no need to worry about forcing
+ * checkForRead true for the referenced tables. This is so because a join
+ * expression can only appear in a FROM clause, and any table named in
+ * FROM will be marked checkForRead from the beginning.
*/
static Node *
scanJoinForColumn(JoinExpr *join, char *colname, int sublevels_up)
@@ -359,7 +375,7 @@ colnameToVar(ParseState *pstate, char *colname)
* those, ignore RTEs that are marked as not inFromCl and not
* the query's target relation.
*/
- foreach(jt, pstate->p_jointree)
+ foreach(jt, pstate->p_joinlist)
{
Node *jtnode = (Node *) lfirst(jt);
Node *newresult = NULL;
@@ -446,8 +462,9 @@ qualifiedNameToVar(ParseState *pstate, char *refname, char *colname,
}
/*
- * Add an entry to the pstate's range table (p_rtable), unless the
- * specified refname is already present, in which case raise error.
+ * Add an entry for a relation to the pstate's range table (p_rtable).
+ *
+ * If the specified refname is already present, raise error.
*
* If pstate is NULL, we just build an RTE and return it without worrying
* about membership in an rtable list.
@@ -481,6 +498,7 @@ addRangeTableEntry(ParseState *pstate,
rte->relname = relname;
rte->alias = alias;
+ rte->subquery = NULL;
/*
* Get the rel's OID. This access also ensures that we have an
@@ -492,7 +510,7 @@ addRangeTableEntry(ParseState *pstate,
rte->relid = RelationGetRelid(rel);
maxattrs = RelationGetNumberOfAttributes(rel);
- eref = alias ? copyObject(alias) : makeAttr(refname, NULL);
+ eref = alias ? (Attr *) copyObject(alias) : makeAttr(refname, NULL);
numaliases = length(eref->attrs);
if (maxattrs < numaliases)
@@ -515,12 +533,18 @@ addRangeTableEntry(ParseState *pstate,
* Flags:
* - this RTE should be expanded to include descendant tables,
* - this RTE is in the FROM clause,
- * - this RTE should not be checked for access rights.
+ * - this RTE should be checked for read/write access rights.
+ *
+ * The initial default on access checks is always check-for-READ-access,
+ * which is the right thing for all except target tables.
*----------
*/
rte->inh = inh;
rte->inFromCl = inFromCl;
- rte->skipAcl = false; /* always starts out false */
+ rte->checkForRead = true;
+ rte->checkForWrite = false;
+
+ rte->checkAsUser = InvalidOid; /* not set-uid by default, either */
/*
* Add completed RTE to range table list.
@@ -532,17 +556,105 @@ addRangeTableEntry(ParseState *pstate,
}
/*
- * Add the given RTE as a top-level entry in the pstate's join tree,
+ * Add an entry for a subquery to the pstate's range table (p_rtable).
+ *
+ * This is just like addRangeTableEntry() except that it makes a subquery RTE.
+ * Note that an alias clause *must* be supplied.
+ */
+RangeTblEntry *
+addRangeTableEntryForSubquery(ParseState *pstate,
+ Query *subquery,
+ Attr *alias,
+ bool inFromCl)
+{
+ char *refname = alias->relname;
+ RangeTblEntry *rte;
+ Attr *eref;
+ int numaliases;
+ int varattno;
+ List *tlistitem;
+
+ /* Check for conflicting RTE or jointable alias (at level 0 only) */
+ if (pstate != NULL)
+ {
+ Node *rteorjoin = refnameRangeOrJoinEntry(pstate, refname, NULL);
+
+ if (rteorjoin)
+ elog(ERROR, "Table name \"%s\" specified more than once",
+ refname);
+ }
+
+ rte = makeNode(RangeTblEntry);
+
+ rte->relname = NULL;
+ rte->relid = InvalidOid;
+ rte->subquery = subquery;
+ rte->alias = alias;
+
+ eref = copyObject(alias);
+ numaliases = length(eref->attrs);
+
+ /* fill in any unspecified alias columns */
+ varattno = 0;
+ foreach(tlistitem, subquery->targetList)
+ {
+ TargetEntry *te = (TargetEntry *) lfirst(tlistitem);
+
+ if (te->resdom->resjunk)
+ continue;
+ varattno++;
+ Assert(varattno == te->resdom->resno);
+ if (varattno > numaliases)
+ {
+ char *attrname;
+
+ attrname = pstrdup(te->resdom->resname);
+ eref->attrs = lappend(eref->attrs, makeString(attrname));
+ }
+ }
+ if (varattno < numaliases)
+ elog(ERROR, "Table \"%s\" has %d columns available but %d columns specified",
+ refname, varattno, numaliases);
+
+ rte->eref = eref;
+
+ /*----------
+ * Flags:
+ * - this RTE should be expanded to include descendant tables,
+ * - this RTE is in the FROM clause,
+ * - this RTE should be checked for read/write access rights.
+ *
+ * Subqueries are never checked for access rights.
+ *----------
+ */
+ rte->inh = false; /* never true for subqueries */
+ rte->inFromCl = inFromCl;
+ rte->checkForRead = false;
+ rte->checkForWrite = false;
+
+ rte->checkAsUser = InvalidOid;
+
+ /*
+ * Add completed RTE to range table list.
+ */
+ if (pstate != NULL)
+ pstate->p_rtable = lappend(pstate->p_rtable, rte);
+
+ return rte;
+}
+
+/*
+ * Add the given RTE as a top-level entry in the pstate's join list,
* unless there already is an entry for it.
*/
void
-addRTEtoJoinTree(ParseState *pstate, RangeTblEntry *rte)
+addRTEtoJoinList(ParseState *pstate, RangeTblEntry *rte)
{
int rtindex = RTERangeTablePosn(pstate, rte, NULL);
List *jt;
RangeTblRef *rtr;
- foreach(jt, pstate->p_jointree)
+ foreach(jt, pstate->p_joinlist)
{
Node *n = (Node *) lfirst(jt);
@@ -556,7 +668,7 @@ addRTEtoJoinTree(ParseState *pstate, RangeTblEntry *rte)
/* Not present, so add it */
rtr = makeNode(RangeTblRef);
rtr->rtindex = rtindex;
- pstate->p_jointree = lappend(pstate->p_jointree, rtr);
+ pstate->p_joinlist = lappend(pstate->p_joinlist, rtr);
}
/*
@@ -570,7 +682,7 @@ addImplicitRTE(ParseState *pstate, char *relname)
RangeTblEntry *rte;
rte = addRangeTableEntry(pstate, relname, NULL, false, false);
- addRTEtoJoinTree(pstate, rte);
+ addRTEtoJoinList(pstate, rte);
warnAutoRange(pstate, relname);
return rte;
@@ -590,11 +702,9 @@ void
expandRTE(ParseState *pstate, RangeTblEntry *rte,
List **colnames, List **colvars)
{
- Relation rel;
- int varattno,
- maxattrs,
- rtindex,
- sublevels_up;
+ int rtindex,
+ sublevels_up,
+ varattno;
if (colnames)
*colnames = NIL;
@@ -604,43 +714,88 @@ expandRTE(ParseState *pstate, RangeTblEntry *rte,
/* Need the RT index of the entry for creating Vars */
rtindex = RTERangeTablePosn(pstate, rte, &sublevels_up);
- rel = heap_open(rte->relid, AccessShareLock);
+ if (rte->relname)
+ {
+ /* Ordinary relation RTE */
+ Relation rel;
+ int maxattrs;
- maxattrs = RelationGetNumberOfAttributes(rel);
+ rel = heap_openr(rte->relname, AccessShareLock);
- for (varattno = 0; varattno < maxattrs; varattno++)
- {
- Form_pg_attribute attr = rel->rd_att->attrs[varattno];
+ maxattrs = RelationGetNumberOfAttributes(rel);
+
+ for (varattno = 0; varattno < maxattrs; varattno++)
+ {
+ Form_pg_attribute attr = rel->rd_att->attrs[varattno];
#ifdef _DROP_COLUMN_HACK__
- if (COLUMN_IS_DROPPED(attr))
- continue;
+ if (COLUMN_IS_DROPPED(attr))
+ continue;
#endif /* _DROP_COLUMN_HACK__ */
- if (colnames)
- {
- char *label;
+ if (colnames)
+ {
+ char *label;
- if (varattno < length(rte->eref->attrs))
- label = strVal(nth(varattno, rte->eref->attrs));
- else
- label = NameStr(attr->attname);
- *colnames = lappend(*colnames, makeString(pstrdup(label)));
+ if (varattno < length(rte->eref->attrs))
+ label = strVal(nth(varattno, rte->eref->attrs));
+ else
+ label = NameStr(attr->attname);
+ *colnames = lappend(*colnames, makeString(pstrdup(label)));
+ }
+
+ if (colvars)
+ {
+ Var *varnode;
+
+ varnode = makeVar(rtindex, attr->attnum,
+ attr->atttypid, attr->atttypmod,
+ sublevels_up);
+
+ *colvars = lappend(*colvars, varnode);
+ }
}
- if (colvars)
+ heap_close(rel, AccessShareLock);
+ }
+ else
+ {
+ /* Subquery RTE */
+ List *aliasp = rte->eref->attrs;
+ List *tlistitem;
+
+ varattno = 0;
+ foreach(tlistitem, rte->subquery->targetList)
{
- Var *varnode;
+ TargetEntry *te = (TargetEntry *) lfirst(tlistitem);
+
+ if (te->resdom->resjunk)
+ continue;
+ varattno++;
+ Assert(varattno == te->resdom->resno);
+
+ if (colnames)
+ {
+ /* Assume there is one alias per target item */
+ char *label = strVal(lfirst(aliasp));
- varnode = makeVar(rtindex, attr->attnum,
- attr->atttypid, attr->atttypmod,
- sublevels_up);
+ *colnames = lappend(*colnames, makeString(pstrdup(label)));
+ aliasp = lnext(aliasp);
+ }
- *colvars = lappend(*colvars, varnode);
+ if (colvars)
+ {
+ Var *varnode;
+
+ varnode = makeVar(rtindex, varattno,
+ te->resdom->restype,
+ te->resdom->restypmod,
+ sublevels_up);
+
+ *colvars = lappend(*colvars, varnode);
+ }
}
}
-
- heap_close(rel, AccessShareLock);
}
/*