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.c348
1 files changed, 74 insertions, 274 deletions
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index 39d18ffbf8a..5786ac44d07 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.110 2005/06/04 19:19:42 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.111 2005/06/05 00:38:09 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -34,12 +34,9 @@
/* GUC parameter */
bool add_missing_from;
-static Node *scanNameSpaceForRefname(ParseState *pstate, Node *nsnode,
- const char *refname);
-static Node *scanNameSpaceForRelid(ParseState *pstate, Node *nsnode,
- Oid relid);
-static void scanNameSpaceForConflict(ParseState *pstate, Node *nsnode,
- RangeTblEntry *rte1, const char *aliasname1);
+static RangeTblEntry *scanNameSpaceForRefname(ParseState *pstate,
+ const char *refname);
+static RangeTblEntry *scanNameSpaceForRelid(ParseState *pstate, Oid relid);
static bool isLockedRel(ParseState *pstate, char *refname);
static void expandRelation(Oid relid, Alias *eref,
int rtindex, int sublevels_up,
@@ -97,188 +94,92 @@ refnameRangeTblEntry(ParseState *pstate,
while (pstate != NULL)
{
- Node *nsnode;
+ RangeTblEntry *result;
if (OidIsValid(relId))
- nsnode = scanNameSpaceForRelid(pstate,
- (Node *) pstate->p_namespace,
- relId);
+ result = scanNameSpaceForRelid(pstate, relId);
else
- nsnode = scanNameSpaceForRefname(pstate,
- (Node *) pstate->p_namespace,
- refname);
+ result = scanNameSpaceForRefname(pstate, refname);
- if (nsnode)
- {
- /* should get an RTE or JoinExpr */
- if (IsA(nsnode, RangeTblEntry))
- return (RangeTblEntry *) nsnode;
- Assert(IsA(nsnode, JoinExpr));
- return rt_fetch(((JoinExpr *) nsnode)->rtindex, pstate->p_rtable);
- }
+ if (result)
+ return result;
- pstate = pstate->parentParseState;
if (sublevels_up)
(*sublevels_up)++;
else
break;
+
+ pstate = pstate->parentParseState;
}
return NULL;
}
/*
- * Recursively search a namespace for an RTE or joinexpr matching the
- * given unqualified refname. Return the node if a unique match, or NULL
+ * Search the query's table namespace for an RTE matching the
+ * given unqualified refname. Return the RTE if a unique match, or NULL
* if no match. Raise error if multiple matches.
- *
- * The top level of p_namespace is a list, and we recurse into any joins
- * that are not subqueries.
*/
-static Node *
-scanNameSpaceForRefname(ParseState *pstate, Node *nsnode,
- const char *refname)
+static RangeTblEntry *
+scanNameSpaceForRefname(ParseState *pstate, const char *refname)
{
- Node *result = NULL;
- Node *newresult;
+ RangeTblEntry *result = NULL;
+ ListCell *l;
- if (nsnode == NULL)
- return NULL;
- if (IsA(nsnode, RangeTblRef))
+ foreach(l, pstate->p_relnamespace)
{
- int varno = ((RangeTblRef *) nsnode)->rtindex;
- RangeTblEntry *rte = rt_fetch(varno, pstate->p_rtable);
+ RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
if (strcmp(rte->eref->aliasname, refname) == 0)
- result = (Node *) rte;
- }
- else if (IsA(nsnode, JoinExpr))
- {
- JoinExpr *j = (JoinExpr *) nsnode;
-
- if (j->alias)
{
- if (strcmp(j->alias->aliasname, refname) == 0)
- return (Node *) j; /* matched a join alias */
-
- /*
- * Tables within an aliased join are invisible from outside
- * the join, according to the scope rules of SQL92 (the join
- * is considered a subquery). So, stop here.
- */
- return NULL;
- }
- result = scanNameSpaceForRefname(pstate, j->larg, refname);
- newresult = scanNameSpaceForRefname(pstate, j->rarg, refname);
- if (!result)
- result = newresult;
- else if (newresult)
- ereport(ERROR,
- (errcode(ERRCODE_AMBIGUOUS_ALIAS),
- errmsg("table reference \"%s\" is ambiguous",
- refname)));
- }
- else if (IsA(nsnode, List))
- {
- ListCell *l;
-
- foreach(l, (List *) nsnode)
- {
- newresult = scanNameSpaceForRefname(pstate, lfirst(l), refname);
- if (!result)
- result = newresult;
- else if (newresult)
+ if (result)
ereport(ERROR,
(errcode(ERRCODE_AMBIGUOUS_ALIAS),
errmsg("table reference \"%s\" is ambiguous",
refname)));
+ result = rte;
}
}
- else
- elog(ERROR, "unrecognized node type: %d", (int) nodeTag(nsnode));
return result;
}
/*
- * Recursively search a namespace for a relation RTE matching the
- * given relation OID. Return the node if a unique match, or NULL
+ * Search the query's table namespace for a relation RTE matching the
+ * given relation OID. Return the RTE if a unique match, or NULL
* if no match. Raise error if multiple matches (which shouldn't
* happen if the namespace was checked correctly when it was created).
*
- * The top level of p_namespace is a list, and we recurse into any joins
- * that are not subqueries.
- *
* See the comments for refnameRangeTblEntry to understand why this
* acts the way it does.
*/
-static Node *
-scanNameSpaceForRelid(ParseState *pstate, Node *nsnode, Oid relid)
+static RangeTblEntry *
+scanNameSpaceForRelid(ParseState *pstate, Oid relid)
{
- Node *result = NULL;
- Node *newresult;
+ RangeTblEntry *result = NULL;
+ ListCell *l;
- if (nsnode == NULL)
- return NULL;
- if (IsA(nsnode, RangeTblRef))
+ foreach(l, pstate->p_relnamespace)
{
- int varno = ((RangeTblRef *) nsnode)->rtindex;
- RangeTblEntry *rte = rt_fetch(varno, pstate->p_rtable);
+ RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
/* yes, the test for alias==NULL should be there... */
if (rte->rtekind == RTE_RELATION &&
rte->relid == relid &&
rte->alias == NULL)
- result = (Node *) rte;
- }
- else if (IsA(nsnode, JoinExpr))
- {
- JoinExpr *j = (JoinExpr *) nsnode;
-
- if (j->alias)
{
- /*
- * Tables within an aliased join are invisible from outside
- * the join, according to the scope rules of SQL92 (the join
- * is considered a subquery). So, stop here.
- */
- return NULL;
- }
- result = scanNameSpaceForRelid(pstate, j->larg, relid);
- newresult = scanNameSpaceForRelid(pstate, j->rarg, relid);
- if (!result)
- result = newresult;
- else if (newresult)
- ereport(ERROR,
- (errcode(ERRCODE_AMBIGUOUS_ALIAS),
- errmsg("table reference %u is ambiguous",
- relid)));
- }
- else if (IsA(nsnode, List))
- {
- ListCell *l;
-
- foreach(l, (List *) nsnode)
- {
- newresult = scanNameSpaceForRelid(pstate, lfirst(l), relid);
- if (!result)
- result = newresult;
- else if (newresult)
+ if (result)
ereport(ERROR,
(errcode(ERRCODE_AMBIGUOUS_ALIAS),
errmsg("table reference %u is ambiguous",
relid)));
+ result = rte;
}
}
- else
- elog(ERROR, "unrecognized node type: %d", (int) nodeTag(nsnode));
return result;
}
/*
- * Recursively check for name conflicts between two namespaces or
- * namespace subtrees. Raise an error if any is found.
- *
- * Works by recursively scanning namespace1 for RTEs and join nodes,
- * and for each one recursively scanning namespace2 for a match.
+ * Check for relation-name conflicts between two relnamespace lists.
+ * Raise an error if any is found.
*
* Note: we assume that each given argument does not contain conflicts
* itself; we just want to know if the two can be merged together.
@@ -288,108 +189,33 @@ scanNameSpaceForRelid(ParseState *pstate, Node *nsnode, Oid relid)
* are for different relation OIDs (implying they are in different schemas).
*/
void
-checkNameSpaceConflicts(ParseState *pstate, Node *namespace1,
- Node *namespace2)
+checkNameSpaceConflicts(ParseState *pstate, List *namespace1,
+ List *namespace2)
{
- if (namespace1 == NULL)
- return;
- if (IsA(namespace1, RangeTblRef))
- {
- int varno = ((RangeTblRef *) namespace1)->rtindex;
- RangeTblEntry *rte = rt_fetch(varno, pstate->p_rtable);
-
- if (rte->rtekind == RTE_RELATION && rte->alias == NULL)
- scanNameSpaceForConflict(pstate, namespace2,
- rte, rte->eref->aliasname);
- else
- scanNameSpaceForConflict(pstate, namespace2,
- NULL, rte->eref->aliasname);
- }
- else if (IsA(namespace1, JoinExpr))
- {
- JoinExpr *j = (JoinExpr *) namespace1;
-
- if (j->alias)
- {
- scanNameSpaceForConflict(pstate, namespace2,
- NULL, j->alias->aliasname);
-
- /*
- * Tables within an aliased join are invisible from outside
- * the join, according to the scope rules of SQL92 (the join
- * is considered a subquery). So, stop here.
- */
- return;
- }
- checkNameSpaceConflicts(pstate, j->larg, namespace2);
- checkNameSpaceConflicts(pstate, j->rarg, namespace2);
- }
- else if (IsA(namespace1, List))
- {
- ListCell *l;
-
- foreach(l, (List *) namespace1)
- checkNameSpaceConflicts(pstate, lfirst(l), namespace2);
- }
- else
- elog(ERROR, "unrecognized node type: %d", (int) nodeTag(namespace1));
-}
+ ListCell *l1;
-/*
- * Subroutine for checkNameSpaceConflicts: scan namespace2
- */
-static void
-scanNameSpaceForConflict(ParseState *pstate, Node *nsnode,
- RangeTblEntry *rte1, const char *aliasname1)
-{
- if (nsnode == NULL)
- return;
- if (IsA(nsnode, RangeTblRef))
+ foreach(l1, namespace1)
{
- int varno = ((RangeTblRef *) nsnode)->rtindex;
- RangeTblEntry *rte = rt_fetch(varno, pstate->p_rtable);
-
- if (strcmp(rte->eref->aliasname, aliasname1) != 0)
- return; /* definitely no conflict */
- if (rte->rtekind == RTE_RELATION && rte->alias == NULL &&
- rte1 != NULL && rte->relid != rte1->relid)
- return; /* no conflict per SQL92 rule */
- ereport(ERROR,
- (errcode(ERRCODE_DUPLICATE_ALIAS),
- errmsg("table name \"%s\" specified more than once",
- aliasname1)));
- }
- else if (IsA(nsnode, JoinExpr))
- {
- JoinExpr *j = (JoinExpr *) nsnode;
+ RangeTblEntry *rte1 = (RangeTblEntry *) lfirst(l1);
+ const char *aliasname1 = rte1->eref->aliasname;
+ ListCell *l2;
- if (j->alias)
+ foreach(l2, namespace2)
{
- if (strcmp(j->alias->aliasname, aliasname1) == 0)
- ereport(ERROR,
- (errcode(ERRCODE_DUPLICATE_ALIAS),
+ RangeTblEntry *rte2 = (RangeTblEntry *) lfirst(l2);
+
+ if (strcmp(rte2->eref->aliasname, aliasname1) != 0)
+ continue; /* definitely no conflict */
+ if (rte1->rtekind == RTE_RELATION && rte1->alias == NULL &&
+ rte2->rtekind == RTE_RELATION && rte2->alias == NULL &&
+ rte1->relid != rte2->relid)
+ continue; /* no conflict per SQL92 rule */
+ ereport(ERROR,
+ (errcode(ERRCODE_DUPLICATE_ALIAS),
errmsg("table name \"%s\" specified more than once",
aliasname1)));
-
- /*
- * Tables within an aliased join are invisible from outside
- * the join, according to the scope rules of SQL92 (the join
- * is considered a subquery). So, stop here.
- */
- return;
}
- scanNameSpaceForConflict(pstate, j->larg, rte1, aliasname1);
- scanNameSpaceForConflict(pstate, j->rarg, rte1, aliasname1);
}
- else if (IsA(nsnode, List))
- {
- ListCell *l;
-
- foreach(l, (List *) nsnode)
- scanNameSpaceForConflict(pstate, lfirst(l), rte1, aliasname1);
- }
- else
- elog(ERROR, "unrecognized node type: %d", (int) nodeTag(nsnode));
}
/*
@@ -541,48 +367,18 @@ colNameToVar(ParseState *pstate, char *colname, bool localonly)
{
Node *result = NULL;
ParseState *orig_pstate = pstate;
- int levels_up = 0;
while (pstate != NULL)
{
- ListCell *ns;
-
- /*
- * We need to look only at top-level namespace items, and even for
- * those, ignore RTEs that are marked as not inFromCl and not the
- * query's target relation.
- */
- foreach(ns, pstate->p_namespace)
- {
- Node *nsnode = (Node *) lfirst(ns);
- Node *newresult = NULL;
-
- if (IsA(nsnode, RangeTblRef))
- {
- int varno = ((RangeTblRef *) nsnode)->rtindex;
- RangeTblEntry *rte = rt_fetch(varno, pstate->p_rtable);
-
- if (!rte->inFromCl &&
- rte != pstate->p_target_rangetblentry)
- continue;
-
- /* use orig_pstate here to get the right sublevels_up */
- newresult = scanRTEForColumn(orig_pstate, rte, colname);
- }
- else if (IsA(nsnode, JoinExpr))
- {
- int varno = ((JoinExpr *) nsnode)->rtindex;
- RangeTblEntry *rte = rt_fetch(varno, pstate->p_rtable);
+ ListCell *l;
- /* joins are always inFromCl, so no need to check */
- Assert(rte->inFromCl);
+ foreach(l, pstate->p_varnamespace)
+ {
+ RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
+ Node *newresult;
- /* use orig_pstate here to get the right sublevels_up */
- newresult = scanRTEForColumn(orig_pstate, rte, colname);
- }
- else
- elog(ERROR, "unrecognized node type: %d",
- (int) nodeTag(nsnode));
+ /* use orig_pstate here to get the right sublevels_up */
+ newresult = scanRTEForColumn(orig_pstate, rte, colname);
if (newresult)
{
@@ -599,7 +395,6 @@ colNameToVar(ParseState *pstate, char *colname, bool localonly)
break; /* found, or don't want to look at parent */
pstate = pstate->parentParseState;
- levels_up++;
}
return result;
@@ -1136,22 +931,26 @@ isLockedRel(ParseState *pstate, char *refname)
/*
* Add the given RTE as a top-level entry in the pstate's join list
- * and/or name space list. (We assume caller has checked for any
- * namespace conflict.)
+ * and/or name space lists. (We assume caller has checked for any
+ * namespace conflicts.)
*/
void
addRTEtoQuery(ParseState *pstate, RangeTblEntry *rte,
- bool addToJoinList, bool addToNameSpace)
+ bool addToJoinList,
+ bool addToRelNameSpace, bool addToVarNameSpace)
{
- int rtindex = RTERangeTablePosn(pstate, rte, NULL);
- RangeTblRef *rtr = makeNode(RangeTblRef);
-
- rtr->rtindex = rtindex;
-
if (addToJoinList)
+ {
+ int rtindex = RTERangeTablePosn(pstate, rte, NULL);
+ RangeTblRef *rtr = makeNode(RangeTblRef);
+
+ rtr->rtindex = rtindex;
pstate->p_joinlist = lappend(pstate->p_joinlist, rtr);
- if (addToNameSpace)
- pstate->p_namespace = lappend(pstate->p_namespace, rtr);
+ }
+ if (addToRelNameSpace)
+ pstate->p_relnamespace = lappend(pstate->p_relnamespace, rte);
+ if (addToVarNameSpace)
+ pstate->p_varnamespace = lappend(pstate->p_varnamespace, rte);
}
/*
@@ -1166,7 +965,8 @@ addImplicitRTE(ParseState *pstate, RangeVar *relation)
RangeTblEntry *rte;
rte = addRangeTableEntry(pstate, relation, NULL, false, false);
- addRTEtoQuery(pstate, rte, true, true);
+ /* Add to joinlist and relnamespace, but not varnamespace */
+ addRTEtoQuery(pstate, rte, true, true, false);
warnAutoRange(pstate, relation);
return rte;