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.c637
1 files changed, 467 insertions, 170 deletions
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index 802299c8966..491cbc5ef08 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.46 2000/08/08 15:42:04 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.47 2000/09/12 21:07:02 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -20,14 +20,25 @@
#include "access/htup.h"
#include "catalog/pg_type.h"
#include "nodes/makefuncs.h"
+#include "parser/parsetree.h"
#include "parser/parse_coerce.h"
+#include "parser/parse_expr.h"
#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"
+static Node *scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte,
+ char *colname);
+static Node *scanJoinForColumn(JoinExpr *join, char *colname,
+ int sublevels_up);
+static List *expandNamesVars(ParseState *pstate, List *names, List *vars);
+static void warnAutoRange(ParseState *pstate, char *refname);
+
+
/*
* Information defining the "system" attributes of every relation.
*/
@@ -65,40 +76,96 @@ static struct
#define SPECIALS ((int) (sizeof(special_attr)/sizeof(special_attr[0])))
-#ifdef NOT_USED
-/* refnameRangeTableEntries()
- * Given refname, return a list of range table entries
- * This is possible with JOIN syntax, where tables in a join
- * acquire the same reference name.
- * - thomas 2000-01-20
- * But at the moment we aren't carrying along a full list of
- * table/column aliases, so we don't have the full mechanism
- * to support outer joins in place yet.
- * - thomas 2000-03-04
+/*
+ * refnameRangeOrJoinEntry
+ * Given a refname, look to see if it matches any RTE or join table.
+ * If so, return a pointer to the RangeTblEntry or JoinExpr.
+ * Optionally get its nesting depth (0 = current). If sublevels_up
+ * is NULL, only consider items at the current nesting level.
*/
-
-static List *
-refnameRangeTableEntries(ParseState *pstate, char *refname)
+Node *
+refnameRangeOrJoinEntry(ParseState *pstate,
+ char *refname,
+ int *sublevels_up)
{
- List *rteList = NULL;
- List *temp;
+ if (sublevels_up)
+ *sublevels_up = 0;
while (pstate != NULL)
{
+ List *temp;
+ JoinExpr *join;
+
+ /*
+ * Check the rangetable for RTEs; if no match, recursively scan
+ * the jointree for join tables. We assume that no duplicate
+ * entries have been made in any one nesting level.
+ */
foreach(temp, pstate->p_rtable)
{
RangeTblEntry *rte = lfirst(temp);
if (strcmp(rte->eref->relname, refname) == 0)
- rteList = lappend(rteList, rte);
+ return (Node *) rte;
}
+
+ join = scanJoinTreeForRefname((Node *) pstate->p_jointree, refname);
+ if (join)
+ return (Node *) join;
+
pstate = pstate->parentParseState;
+ if (sublevels_up)
+ (*sublevels_up)++;
+ else
+ break;
}
- return rteList;
+ return NULL;
}
-#endif
-/* given refname, return a pointer to the range table entry */
+/* Recursively search a jointree for a joinexpr with given refname */
+JoinExpr *
+scanJoinTreeForRefname(Node *jtnode, char *refname)
+{
+ JoinExpr *result = NULL;
+
+ if (jtnode == NULL)
+ return NULL;
+ if (IsA(jtnode, List))
+ {
+ List *l;
+
+ foreach(l, (List *) jtnode)
+ {
+ result = scanJoinTreeForRefname(lfirst(l), refname);
+ if (result)
+ break;
+ }
+ }
+ else if (IsA(jtnode, RangeTblRef))
+ {
+ /* ignore ... */
+ }
+ else if (IsA(jtnode, JoinExpr))
+ {
+ JoinExpr *j = (JoinExpr *) jtnode;
+
+ if (j->alias && strcmp(j->alias->relname, refname) == 0)
+ return j;
+ result = scanJoinTreeForRefname(j->larg, refname);
+ if (! result)
+ result = scanJoinTreeForRefname(j->rarg, refname);
+ }
+ else
+ elog(ERROR, "scanJoinTreeForRefname: unexpected node type %d",
+ nodeTag(jtnode));
+ return result;
+}
+
+/*
+ * given refname, return a pointer to the range table entry.
+ *
+ * NOTE that this routine will ONLY find RTEs, not join tables.
+ */
RangeTblEntry *
refnameRangeTableEntry(ParseState *pstate, char *refname)
{
@@ -118,9 +185,13 @@ refnameRangeTableEntry(ParseState *pstate, char *refname)
return NULL;
}
-/* given refname, return RT index (starting with 1) of the relation,
+/*
+ * given refname, return RT index (starting with 1) of the relation,
* and optionally get its nesting depth (0 = current). If sublevels_up
* is NULL, only consider rels at the current nesting level.
+ * A zero result means name not found.
+ *
+ * NOTE that this routine will ONLY find RTEs, not join tables.
*/
int
refnameRangeTablePosn(ParseState *pstate, char *refname, int *sublevels_up)
@@ -152,114 +223,264 @@ refnameRangeTablePosn(ParseState *pstate, char *refname, int *sublevels_up)
}
/*
- * returns range entry if found, else NULL
+ * given an RTE, return RT index (starting with 1) of the entry,
+ * and optionally get its nesting depth (0 = current). If sublevels_up
+ * is NULL, only consider rels at the current nesting level.
+ * Raises error if RTE not found.
*/
-RangeTblEntry *
-colnameRangeTableEntry(ParseState *pstate, char *colname)
+int
+RTERangeTablePosn(ParseState *pstate, RangeTblEntry *rte, int *sublevels_up)
{
- List *et;
- List *rtable;
- RangeTblEntry *rte_result = NULL;
+ int index;
+ List *temp;
+
+ if (sublevels_up)
+ *sublevels_up = 0;
while (pstate != NULL)
{
- if (pstate->p_is_rule)
- rtable = lnext(lnext(pstate->p_rtable));
+ index = 1;
+ foreach(temp, pstate->p_rtable)
+ {
+ if (rte == (RangeTblEntry *) lfirst(temp))
+ return index;
+ index++;
+ }
+ pstate = pstate->parentParseState;
+ if (sublevels_up)
+ (*sublevels_up)++;
else
- rtable = pstate->p_rtable;
+ break;
+ }
+ elog(ERROR, "RTERangeTablePosn: RTE not found (internal error)");
+ return 0; /* keep compiler quiet */
+}
+
+/*
+ * scanRTEForColumn
+ * 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.
+ */
+static Node *
+scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte, char *colname)
+{
+ Node *result = NULL;
+ int attnum = 0;
+ List *c;
- foreach(et, rtable)
+ /*
+ * Scan the user column names (or aliases) for a match.
+ * Complain if multiple matches.
+ */
+ foreach(c, rte->eref->attrs)
+ {
+ attnum++;
+ if (strcmp(strVal(lfirst(c)), colname) == 0)
{
- RangeTblEntry *rte_candidate = NULL;
- RangeTblEntry *rte = lfirst(et);
+ if (result)
+ elog(ERROR, "Column reference \"%s\" is ambiguous", colname);
+ result = (Node *) make_var(pstate, rte, attnum);
+ }
+ }
- /* only consider RTEs mentioned in FROM or UPDATE/DELETE */
- if (!rte->inFromCl && rte != pstate->p_target_rangetblentry)
- continue;
+ /*
+ * If we have a unique match, return it. Note that this allows a user
+ * alias to override a system column name (such as OID) without error.
+ */
+ if (result)
+ return result;
- if (rte->eref->attrs != NULL)
- {
- List *c;
-
- foreach(c, rte->ref->attrs)
- {
- if (strcmp(strVal(lfirst(c)), colname) == 0)
- {
- if (rte_candidate != NULL)
- elog(ERROR, "Column '%s' is ambiguous"
- " (internal error)", colname);
- rte_candidate = rte;
- }
- }
- }
+ /*
+ * If the RTE represents a table (not a sub-select), consider system
+ * column names.
+ */
+ if (rte->relid != InvalidOid)
+ {
+ attnum = specialAttNum(colname);
+ if (attnum != InvalidAttrNumber)
+ result = (Node *) make_var(pstate, rte, attnum);
+ }
+
+ return result;
+}
+/*
+ * scanJoinForColumn
+ * 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.
+ */
+static Node *
+scanJoinForColumn(JoinExpr *join, char *colname, int sublevels_up)
+{
+ Node *result = NULL;
+ int attnum = 0;
+ List *c;
+
+ foreach(c, join->colnames)
+ {
+ attnum++;
+ if (strcmp(strVal(lfirst(c)), colname) == 0)
+ {
+ if (result)
+ elog(ERROR, "Column reference \"%s\" is ambiguous", colname);
+ result = copyObject(nth(attnum-1, join->colvars));
/*
- * Even if we have an attribute list in the RTE, look for the
- * column here anyway. This is the only way we will find
- * implicit columns like "oid". - thomas 2000-02-07
+ * If referencing an uplevel join item, we must adjust
+ * sublevels settings in the copied expression.
*/
- if ((rte_candidate == NULL)
- && (get_attnum(rte->relid, colname) != InvalidAttrNumber))
- rte_candidate = rte;
+ if (sublevels_up > 0)
+ IncrementVarSublevelsUp(result, sublevels_up, 0);
+ }
+ }
+ return result;
+}
+
+/*
+ * colnameToVar
+ * Search for an unqualified column name.
+ * If found, return the appropriate Var node (or expression).
+ * If not found, return NULL. If the name proves ambiguous, raise error.
+ */
+Node *
+colnameToVar(ParseState *pstate, char *colname)
+{
+ Node *result = NULL;
+ ParseState *orig_pstate = pstate;
+ int levels_up = 0;
- if (rte_candidate == NULL)
- continue;
+ while (pstate != NULL)
+ {
+ List *jt;
- if (rte_result != NULL)
+ /*
+ * We want to look only at top-level jointree items, and even for
+ * those, ignore RTEs that are marked as not inFromCl and not
+ * the query's target relation.
+ */
+ foreach(jt, pstate->p_jointree)
+ {
+ Node *jtnode = (Node *) lfirst(jt);
+ Node *newresult = NULL;
+
+ if (IsA(jtnode, RangeTblRef))
{
- if (!pstate->p_is_insert ||
+ int varno = ((RangeTblRef *) jtnode)->rtindex;
+ RangeTblEntry *rte = rt_fetch(varno, pstate->p_rtable);
+
+ if (! rte->inFromCl &&
rte != pstate->p_target_rangetblentry)
- elog(ERROR, "Column '%s' is ambiguous", colname);
+ continue;
+
+ /* use orig_pstate here to get the right sublevels_up */
+ newresult = scanRTEForColumn(orig_pstate, rte, colname);
+ }
+ else if (IsA(jtnode, JoinExpr))
+ {
+ JoinExpr *j = (JoinExpr *) jtnode;
+
+ newresult = scanJoinForColumn(j, colname, levels_up);
}
else
- rte_result = rte;
+ elog(ERROR, "colnameToVar: unexpected node type %d",
+ nodeTag(jtnode));
+
+ if (newresult)
+ {
+ if (result)
+ elog(ERROR, "Column reference \"%s\" is ambiguous",
+ colname);
+ result = newresult;
+ }
}
- if (rte_result != NULL)
+ if (result != NULL)
break; /* found */
pstate = pstate->parentParseState;
+ levels_up++;
}
- return rte_result;
+
+ return result;
}
/*
- * put new entry in pstate p_rtable structure, or return pointer
- * if pstate null
+ * qualifiedNameToVar
+ * Search for a qualified column name (refname + column name).
+ * If found, return the appropriate Var node (or expression).
+ * If not found, return NULL. If the name proves ambiguous, raise error.
+ */
+Node *
+qualifiedNameToVar(ParseState *pstate, char *refname, char *colname,
+ bool implicitRTEOK)
+{
+ Node *result;
+ Node *rteorjoin;
+ int sublevels_up;
+
+ rteorjoin = refnameRangeOrJoinEntry(pstate, refname, &sublevels_up);
+
+ if (rteorjoin == NULL)
+ {
+ if (! implicitRTEOK)
+ return NULL;
+ rteorjoin = (Node *) addImplicitRTE(pstate, refname);
+ sublevels_up = 0;
+ }
+
+ if (IsA(rteorjoin, RangeTblEntry))
+ result = scanRTEForColumn(pstate, (RangeTblEntry *) rteorjoin,
+ colname);
+ else if (IsA(rteorjoin, JoinExpr))
+ result = scanJoinForColumn((JoinExpr *) rteorjoin,
+ colname, sublevels_up);
+ else
+ {
+ elog(ERROR, "qualifiedNameToVar: unexpected node type %d",
+ nodeTag(rteorjoin));
+ result = NULL; /* keep compiler quiet */
+ }
+
+ return result;
+}
+
+/*
+ * Add an entry to the pstate's range table (p_rtable), unless the
+ * specified refname is already present, in which case raise error.
+ *
+ * If pstate is NULL, we just build an RTE and return it without worrying
+ * about membership in an rtable list.
*/
RangeTblEntry *
addRangeTableEntry(ParseState *pstate,
char *relname,
- Attr *ref,
+ Attr *alias,
bool inh,
- bool inFromCl,
- bool inJoinSet)
+ bool inFromCl)
{
+ char *refname = alias ? alias->relname : relname;
Relation rel;
RangeTblEntry *rte;
Attr *eref;
int maxattrs;
- int sublevels_up;
+ int numaliases;
int varattno;
- /* Look for an existing rte, if available... */
+ /* Check for conflicting RTE or jointable alias (at level 0 only) */
if (pstate != NULL)
{
- int rt_index = refnameRangeTablePosn(pstate, ref->relname,
- &sublevels_up);
+ Node *rteorjoin = refnameRangeOrJoinEntry(pstate, refname, NULL);
- if (rt_index != 0 && (!inFromCl || sublevels_up == 0))
- {
- if (!strcmp(ref->relname, "*OLD*") || !strcmp(ref->relname, "*NEW*"))
- return (RangeTblEntry *) nth(rt_index - 1, pstate->p_rtable);
- elog(ERROR, "Table name '%s' specified more than once", ref->relname);
- }
+ if (rteorjoin)
+ elog(ERROR, "Table name \"%s\" specified more than once",
+ refname);
}
rte = makeNode(RangeTblEntry);
rte->relname = relname;
- rte->ref = ref;
+ rte->alias = alias;
/*
* Get the rel's OID. This access also ensures that we have an
@@ -271,30 +492,34 @@ addRangeTableEntry(ParseState *pstate,
rte->relid = RelationGetRelid(rel);
maxattrs = RelationGetNumberOfAttributes(rel);
- eref = copyObject(ref);
- if (maxattrs < length(eref->attrs))
- elog(ERROR, "Table '%s' has %d columns available but %d columns specified",
- relname, maxattrs, length(eref->attrs));
+ eref = alias ? copyObject(alias) : makeAttr(refname, NULL);
+ numaliases = length(eref->attrs);
+
+ if (maxattrs < numaliases)
+ elog(ERROR, "Table \"%s\" has %d columns available but %d columns specified",
+ refname, maxattrs, numaliases);
/* fill in any unspecified alias columns */
- for (varattno = length(eref->attrs); varattno < maxattrs; varattno++)
+ for (varattno = numaliases; varattno < maxattrs; varattno++)
{
char *attrname;
attrname = pstrdup(NameStr(rel->rd_att->attrs[varattno]->attname));
eref->attrs = lappend(eref->attrs, makeString(attrname));
}
- heap_close(rel, AccessShareLock);
rte->eref = eref;
- /*
- * Flags: - this RTE should be expanded to include descendant tables,
- * - this RTE is in the FROM clause, - this RTE should be included in
- * the planner's final join.
+ heap_close(rel, AccessShareLock);
+
+ /*----------
+ * 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.
+ *----------
*/
rte->inh = inh;
rte->inFromCl = inFromCl;
- rte->inJoinSet = inJoinSet;
rte->skipAcl = false; /* always starts out false */
/*
@@ -306,118 +531,184 @@ addRangeTableEntry(ParseState *pstate,
return rte;
}
-/* expandTable()
- * Populates an Attr with table name and column names
- * This is similar to expandAll(), but does not create an RTE
- * if it does not already exist.
- * - thomas 2000-01-19
+/*
+ * Add the given RTE as a top-level entry in the pstate's join tree,
+ * unless there already is an entry for it.
*/
-Attr *
-expandTable(ParseState *pstate, char *refname, bool getaliases)
+void
+addRTEtoJoinTree(ParseState *pstate, RangeTblEntry *rte)
+{
+ int rtindex = RTERangeTablePosn(pstate, rte, NULL);
+ List *jt;
+ RangeTblRef *rtr;
+
+ foreach(jt, pstate->p_jointree)
+ {
+ Node *n = (Node *) lfirst(jt);
+
+ if (IsA(n, RangeTblRef))
+ {
+ if (rtindex == ((RangeTblRef *) n)->rtindex)
+ return; /* it's already being joined to */
+ }
+ }
+
+ /* Not present, so add it */
+ rtr = makeNode(RangeTblRef);
+ rtr->rtindex = rtindex;
+ pstate->p_jointree = lappend(pstate->p_jointree, rtr);
+}
+
+/*
+ * Add a POSTQUEL-style implicit RTE.
+ *
+ * We assume caller has already checked that there is no such RTE now.
+ */
+RangeTblEntry *
+addImplicitRTE(ParseState *pstate, char *relname)
{
- Attr *attr;
RangeTblEntry *rte;
+
+ rte = addRangeTableEntry(pstate, relname, NULL, false, false);
+ addRTEtoJoinTree(pstate, rte);
+ warnAutoRange(pstate, relname);
+
+ return rte;
+}
+
+/* expandRTE()
+ *
+ * Given a rangetable entry, create lists of its column names (aliases if
+ * provided, else real names) and Vars for each column. Only user columns
+ * are considered, since this is primarily used to expand '*' and determine
+ * the contents of JOIN tables.
+ *
+ * If only one of the two kinds of output list is needed, pass NULL for the
+ * output pointer for the unwanted one.
+ */
+void
+expandRTE(ParseState *pstate, RangeTblEntry *rte,
+ List **colnames, List **colvars)
+{
Relation rel;
int varattno,
- maxattrs;
+ maxattrs,
+ rtindex,
+ sublevels_up;
- rte = refnameRangeTableEntry(pstate, refname);
+ if (colnames)
+ *colnames = NIL;
+ if (colvars)
+ *colvars = NIL;
- if (getaliases && (rte != NULL))
- return rte->eref;
+ /* Need the RT index of the entry for creating Vars */
+ rtindex = RTERangeTablePosn(pstate, rte, &sublevels_up);
- if (rte != NULL)
- rel = heap_open(rte->relid, AccessShareLock);
- else
- rel = heap_openr(refname, AccessShareLock);
-
- if (rel == NULL)
- elog(ERROR, "Relation '%s' not found", refname);
+ rel = heap_open(rte->relid, AccessShareLock);
maxattrs = RelationGetNumberOfAttributes(rel);
- attr = makeAttr(refname, NULL);
-
for (varattno = 0; varattno < maxattrs; varattno++)
{
- char *attrname;
+ Form_pg_attribute attr = rel->rd_att->attrs[varattno];
#ifdef _DROP_COLUMN_HACK__
- if (COLUMN_IS_DROPPED(rel->rd_att->attrs[varattno]))
+ if (COLUMN_IS_DROPPED(attr))
continue;
#endif /* _DROP_COLUMN_HACK__ */
- attrname = pstrdup(NameStr(rel->rd_att->attrs[varattno]->attname));
- attr->attrs = lappend(attr->attrs, makeString(attrname));
+
+ 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 (colvars)
+ {
+ Var *varnode;
+
+ varnode = makeVar(rtindex, attr->attnum,
+ attr->atttypid, attr->atttypmod,
+ sublevels_up);
+
+ *colvars = lappend(*colvars, varnode);
+ }
}
heap_close(rel, AccessShareLock);
-
- return attr;
}
/*
- * expandAll -
- * makes a list of attributes
+ * expandRelAttrs -
+ * makes a list of TargetEntry nodes for the attributes of the rel
*/
List *
-expandAll(ParseState *pstate, char *relname, Attr *ref, int *this_resno)
+expandRelAttrs(ParseState *pstate, RangeTblEntry *rte)
{
- List *te_list = NIL;
- RangeTblEntry *rte;
- Relation rel;
- int varattno,
- maxattrs;
+ List *name_list,
+ *var_list;
- rte = refnameRangeTableEntry(pstate, ref->relname);
- if (rte == NULL)
- {
- rte = addRangeTableEntry(pstate, relname, ref,
- FALSE, FALSE, TRUE);
- warnAutoRange(pstate, ref->relname);
- }
+ expandRTE(pstate, rte, &name_list, &var_list);
- rel = heap_open(rte->relid, AccessShareLock);
+ return expandNamesVars(pstate, name_list, var_list);
+}
- maxattrs = RelationGetNumberOfAttributes(rel);
+/*
+ * expandJoinAttrs -
+ * makes a list of TargetEntry nodes for the attributes of the join
+ */
+List *
+expandJoinAttrs(ParseState *pstate, JoinExpr *join, int sublevels_up)
+{
+ List *vars;
- for (varattno = 0; varattno < maxattrs; varattno++)
- {
- char *attrname;
- char *label;
- Var *varnode;
- TargetEntry *te = makeNode(TargetEntry);
+ vars = copyObject(join->colvars);
+ /*
+ * If referencing an uplevel join item, we must adjust
+ * sublevels settings in the copied expression.
+ */
+ if (sublevels_up > 0)
+ IncrementVarSublevelsUp((Node *) vars, sublevels_up, 0);
-#ifdef _DROP_COLUMN_HACK__
- if (COLUMN_IS_DROPPED(rel->rd_att->attrs[varattno]))
- continue;
-#endif /* _DROP_COLUMN_HACK__ */
- attrname = pstrdup(NameStr(rel->rd_att->attrs[varattno]->attname));
+ return expandNamesVars(pstate,
+ copyObject(join->colnames),
+ vars);
+}
- /*
- * varattno is zero-based, so check that length() is always
- * greater
- */
- if (length(rte->eref->attrs) > varattno)
- label = pstrdup(strVal(nth(varattno, rte->eref->attrs)));
- else
- label = attrname;
- varnode = make_var(pstate, rte->relid, relname, attrname);
+/*
+ * expandNamesVars -
+ * Workhorse for "*" expansion: produce a list of targetentries
+ * given lists of column names (as String nodes) and var references.
+ */
+static List *
+expandNamesVars(ParseState *pstate, List *names, List *vars)
+{
+ List *te_list = NIL;
- /*
- * Even if the elements making up a set are complex, the set
- * itself is not.
- */
+ while (names)
+ {
+ char *label = strVal(lfirst(names));
+ Node *varnode = (Node *) lfirst(vars);
+ TargetEntry *te = makeNode(TargetEntry);
- te->resdom = makeResdom((AttrNumber) (*this_resno)++,
- varnode->vartype,
- varnode->vartypmod,
+ te->resdom = makeResdom((AttrNumber) (pstate->p_last_resno)++,
+ exprType(varnode),
+ exprTypmod(varnode),
label,
false);
- te->expr = (Node *) varnode;
+ te->expr = varnode;
te_list = lappend(te_list, te);
+
+ names = lnext(names);
+ vars = lnext(vars);
}
- heap_close(rel, AccessShareLock);
+ Assert(vars == NIL); /* lists not same length? */
return te_list;
}
@@ -531,11 +822,17 @@ attnumTypeId(Relation rd, int attid)
return rd->rd_att->attrs[attid - 1]->atttypid;
}
-void
+/*
+ * Generate a warning about an implicit RTE, if appropriate.
+ *
+ * Our current theory on this is that we should allow "SELECT foo.*"
+ * but warn about a mixture of explicit and implicit RTEs.
+ */
+static void
warnAutoRange(ParseState *pstate, char *refname)
{
- List *temp;
bool foundInFromCl = false;
+ List *temp;
foreach(temp, pstate->p_rtable)
{
@@ -548,8 +845,8 @@ warnAutoRange(ParseState *pstate, char *refname)
}
}
if (foundInFromCl)
- elog(NOTICE, "Adding missing FROM-clause entry%s for table %s",
- pstate->parentParseState != NULL ? " in subquery" : "",
- refname);
+ elog(NOTICE, "Adding missing FROM-clause entry%s for table \"%s\"",
+ pstate->parentParseState != NULL ? " in subquery" : "",
+ refname);
}