aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/catalog/dependency.c9
-rw-r--r--src/backend/optimizer/path/allpaths.c25
-rw-r--r--src/backend/optimizer/prep/prepjointree.c32
-rw-r--r--src/backend/optimizer/util/var.c10
-rw-r--r--src/backend/parser/parse_clause.c10
-rw-r--r--src/backend/parser/parse_coerce.c29
-rw-r--r--src/backend/parser/parse_relation.c494
-rw-r--r--src/backend/parser/parse_target.c23
-rw-r--r--src/backend/rewrite/rewriteHandler.c7
-rw-r--r--src/backend/rewrite/rewriteManip.c64
-rw-r--r--src/backend/utils/adt/ruleutils.c72
-rw-r--r--src/include/nodes/parsenodes.h18
-rw-r--r--src/include/nodes/primnodes.h8
-rw-r--r--src/include/parser/parse_relation.h11
-rw-r--r--src/include/parser/parsetree.h4
-rw-r--r--src/include/rewrite/rewriteManip.h4
16 files changed, 464 insertions, 356 deletions
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index 9d4e1c6a5c4..59c3151cdf2 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.36 2004/05/26 04:41:06 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.37 2004/08/19 20:57:40 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -970,10 +970,15 @@ find_expr_references_walker(Node *node,
if (var->varno <= 0 || var->varno > list_length(rtable))
elog(ERROR, "invalid varno %d", var->varno);
rte = rt_fetch(var->varno, rtable);
+ /*
+ * A whole-row Var references no specific columns, so adds no new
+ * dependency.
+ */
+ if (var->varattno == InvalidAttrNumber)
+ return false;
if (rte->rtekind == RTE_RELATION)
{
/* If it's a plain relation, reference this column */
- /* NB: this code works for whole-row Var with attno 0, too */
add_object_address(OCLASS_CLASS, rte->relid, var->varattno,
&context->addrs);
}
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 24a51149e45..d770c9175bc 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.118 2004/06/05 01:55:04 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.119 2004/08/19 20:57:40 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -57,10 +57,10 @@ static void compare_tlist_datatypes(List *tlist, List *colTypes,
bool *differentTypes);
static bool qual_is_pushdown_safe(Query *subquery, Index rti, Node *qual,
bool *differentTypes);
-static void subquery_push_qual(Query *subquery,
- RangeTblEntry *rte, Index rti, Node *qual);
+static void subquery_push_qual(Query *subquery, List *rtable,
+ Index rti, Node *qual);
static void recurse_push_qual(Node *setOp, Query *topquery,
- RangeTblEntry *rte, Index rti, Node *qual);
+ List *rtable, Index rti, Node *qual);
/*
@@ -376,7 +376,7 @@ set_subquery_pathlist(Query *root, RelOptInfo *rel,
if (qual_is_pushdown_safe(subquery, rti, clause, differentTypes))
{
/* Push it down */
- subquery_push_qual(subquery, rte, rti, clause);
+ subquery_push_qual(subquery, root->rtable, rti, clause);
}
else
{
@@ -780,12 +780,13 @@ qual_is_pushdown_safe(Query *subquery, Index rti, Node *qual,
* subquery_push_qual - push down a qual that we have determined is safe
*/
static void
-subquery_push_qual(Query *subquery, RangeTblEntry *rte, Index rti, Node *qual)
+subquery_push_qual(Query *subquery, List *rtable, Index rti, Node *qual)
{
if (subquery->setOperations != NULL)
{
/* Recurse to push it separately to each component query */
- recurse_push_qual(subquery->setOperations, subquery, rte, rti, qual);
+ recurse_push_qual(subquery->setOperations, subquery,
+ rtable, rti, qual);
}
else
{
@@ -799,7 +800,7 @@ subquery_push_qual(Query *subquery, RangeTblEntry *rte, Index rti, Node *qual)
* This step also ensures that when we are pushing into a setop tree,
* each component query gets its own copy of the qual.
*/
- qual = ResolveNew(qual, rti, 0, rte,
+ qual = ResolveNew(qual, rti, 0, rtable,
subquery->targetList,
CMD_SELECT, 0);
subquery->havingQual = make_and_qual(subquery->havingQual,
@@ -818,7 +819,7 @@ subquery_push_qual(Query *subquery, RangeTblEntry *rte, Index rti, Node *qual)
*/
static void
recurse_push_qual(Node *setOp, Query *topquery,
- RangeTblEntry *rte, Index rti, Node *qual)
+ List *rtable, Index rti, Node *qual)
{
if (IsA(setOp, RangeTblRef))
{
@@ -827,14 +828,14 @@ recurse_push_qual(Node *setOp, Query *topquery,
Query *subquery = subrte->subquery;
Assert(subquery != NULL);
- subquery_push_qual(subquery, rte, rti, qual);
+ subquery_push_qual(subquery, rtable, rti, qual);
}
else if (IsA(setOp, SetOperationStmt))
{
SetOperationStmt *op = (SetOperationStmt *) setOp;
- recurse_push_qual(op->larg, topquery, rte, rti, qual);
- recurse_push_qual(op->rarg, topquery, rte, rti, qual);
+ recurse_push_qual(op->larg, topquery, rtable, rti, qual);
+ recurse_push_qual(op->rarg, topquery, rtable, rti, qual);
}
else
{
diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c
index 1eb4d5504a1..430ec9e5db7 100644
--- a/src/backend/optimizer/prep/prepjointree.c
+++ b/src/backend/optimizer/prep/prepjointree.c
@@ -16,7 +16,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.20 2004/05/30 23:40:29 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.21 2004/08/19 20:57:40 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -46,7 +46,7 @@ typedef struct reduce_outer_joins_state
static bool is_simple_subquery(Query *subquery);
static bool has_nullable_targetlist(Query *subquery);
static void resolvenew_in_jointree(Node *jtnode, int varno,
- RangeTblEntry *rte, List *subtlist);
+ List *rtable, List *subtlist);
static reduce_outer_joins_state *reduce_outer_joins_pass1(Node *jtnode);
static void reduce_outer_joins_pass2(Node *jtnode,
reduce_outer_joins_state *state,
@@ -243,16 +243,19 @@ pull_up_subqueries(Query *parse, Node *jtnode, bool below_outer_join)
subtlist = subquery->targetList;
parse->targetList = (List *)
ResolveNew((Node *) parse->targetList,
- varno, 0, rte, subtlist, CMD_SELECT, 0);
+ varno, 0, parse->rtable,
+ subtlist, CMD_SELECT, 0);
resolvenew_in_jointree((Node *) parse->jointree, varno,
- rte, subtlist);
+ parse->rtable, subtlist);
Assert(parse->setOperations == NULL);
parse->havingQual =
ResolveNew(parse->havingQual,
- varno, 0, rte, subtlist, CMD_SELECT, 0);
+ varno, 0, parse->rtable,
+ subtlist, CMD_SELECT, 0);
parse->in_info_list = (List *)
ResolveNew((Node *) parse->in_info_list,
- varno, 0, rte, subtlist, CMD_SELECT, 0);
+ varno, 0, parse->rtable,
+ subtlist, CMD_SELECT, 0);
foreach(rt, parse->rtable)
{
@@ -261,7 +264,8 @@ pull_up_subqueries(Query *parse, Node *jtnode, bool below_outer_join)
if (otherrte->rtekind == RTE_JOIN)
otherrte->joinaliasvars = (List *)
ResolveNew((Node *) otherrte->joinaliasvars,
- varno, 0, rte, subtlist, CMD_SELECT, 0);
+ varno, 0, parse->rtable,
+ subtlist, CMD_SELECT, 0);
}
/*
@@ -477,7 +481,7 @@ has_nullable_targetlist(Query *subquery)
*/
static void
resolvenew_in_jointree(Node *jtnode, int varno,
- RangeTblEntry *rte, List *subtlist)
+ List *rtable, List *subtlist)
{
if (jtnode == NULL)
return;
@@ -491,18 +495,20 @@ resolvenew_in_jointree(Node *jtnode, int varno,
ListCell *l;
foreach(l, f->fromlist)
- resolvenew_in_jointree(lfirst(l), varno, rte, subtlist);
+ resolvenew_in_jointree(lfirst(l), varno, rtable, subtlist);
f->quals = ResolveNew(f->quals,
- varno, 0, rte, subtlist, CMD_SELECT, 0);
+ varno, 0, rtable,
+ subtlist, CMD_SELECT, 0);
}
else if (IsA(jtnode, JoinExpr))
{
JoinExpr *j = (JoinExpr *) jtnode;
- resolvenew_in_jointree(j->larg, varno, rte, subtlist);
- resolvenew_in_jointree(j->rarg, varno, rte, subtlist);
+ resolvenew_in_jointree(j->larg, varno, rtable, subtlist);
+ resolvenew_in_jointree(j->rarg, varno, rtable, subtlist);
j->quals = ResolveNew(j->quals,
- varno, 0, rte, subtlist, CMD_SELECT, 0);
+ varno, 0, rtable,
+ subtlist, CMD_SELECT, 0);
/*
* We don't bother to update the colvars list, since it won't be
diff --git a/src/backend/optimizer/util/var.c b/src/backend/optimizer/util/var.c
index e46655e17db..94e0f15e289 100644
--- a/src/backend/optimizer/util/var.c
+++ b/src/backend/optimizer/util/var.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/util/var.c,v 1.59 2004/06/01 04:47:46 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/util/var.c,v 1.60 2004/08/19 20:57:40 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -515,11 +515,19 @@ flatten_join_alias_vars_mutator(Node *node,
/* Must expand whole-row reference */
RowExpr *rowexpr;
List *fields = NIL;
+ AttrNumber attnum;
ListCell *l;
+ attnum = 0;
foreach(l, rte->joinaliasvars)
{
newvar = (Node *) lfirst(l);
+ attnum++;
+ /* Ignore dropped columns */
+ if (get_rte_attribute_is_dropped(context->root->rtable,
+ var->varno,
+ attnum))
+ continue;
/*
* If we are expanding an alias carried down from an upper
* query, must adjust its varlevelsup fields.
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index b3a6b67f5c3..156dbac5aad 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.133 2004/06/16 01:26:44 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.134 2004/08/19 20:57:40 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -655,8 +655,8 @@ transformFromClauseItem(ParseState *pstate, Node *n, List **containedRels)
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(j->larg));
leftrti = 0; /* keep compiler quiet */
}
- rte = rt_fetch(leftrti, pstate->p_rtable);
- expandRTE(pstate, rte, &l_colnames, &l_colvars);
+ expandRTE(pstate->p_rtable, leftrti, 0, false,
+ &l_colnames, &l_colvars);
if (IsA(j->rarg, RangeTblRef))
rightrti = ((RangeTblRef *) j->rarg)->rtindex;
@@ -667,8 +667,8 @@ transformFromClauseItem(ParseState *pstate, Node *n, List **containedRels)
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(j->rarg));
rightrti = 0; /* keep compiler quiet */
}
- rte = rt_fetch(rightrti, pstate->p_rtable);
- expandRTE(pstate, rte, &r_colnames, &r_colvars);
+ expandRTE(pstate->p_rtable, rightrti, 0, false,
+ &r_colnames, &r_colvars);
/*
* Natural join does not explicitly specify columns; must generate
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index 8065b261beb..8d892fcffe1 100644
--- a/src/backend/parser/parse_coerce.c
+++ b/src/backend/parser/parse_coerce.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.120 2004/08/17 18:47:08 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.121 2004/08/19 20:57:40 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -662,29 +662,12 @@ coerce_record_to_complex(ParseState *pstate, Node *node,
else if (node && IsA(node, Var) &&
((Var *) node)->varattno == InvalidAttrNumber)
{
- RangeTblEntry *rte;
- AttrNumber nfields;
- AttrNumber nf;
-
- rte = GetRTEByRangeTablePosn(pstate,
- ((Var *) node)->varno,
- ((Var *) node)->varlevelsup);
- nfields = list_length(rte->eref->colnames);
- for (nf = 1; nf <= nfields; nf++)
- {
- Oid vartype;
- int32 vartypmod;
+ int rtindex = ((Var *) node)->varno;
+ int sublevels_up = ((Var *) node)->varlevelsup;
+ List *rtable;
- if (get_rte_attribute_is_dropped(rte, nf))
- continue;
- get_rte_attribute_type(rte, nf, &vartype, &vartypmod);
- args = lappend(args,
- makeVar(((Var *) node)->varno,
- nf,
- vartype,
- vartypmod,
- ((Var *) node)->varlevelsup));
- }
+ rtable = GetLevelNRangeTable(pstate, sublevels_up);
+ expandRTE(rtable, rtindex, sublevels_up, false, NULL, &args);
}
else
ereport(ERROR,
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index 3f32f8c80f5..1a9aa2cd73f 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.97 2004/08/17 18:47:08 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.98 2004/08/19 20:57:40 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -42,6 +42,10 @@ static Node *scanNameSpaceForRelid(ParseState *pstate, Node *nsnode,
static void scanNameSpaceForConflict(ParseState *pstate, Node *nsnode,
RangeTblEntry *rte1, const char *aliasname1);
static bool isForUpdate(ParseState *pstate, char *refname);
+static void expandRelation(Oid relid, Alias *eref,
+ int rtindex, int sublevels_up,
+ bool include_dropped,
+ List **colnames, List **colvars);
static int specialAttNum(const char *attname);
static void warnAutoRange(ParseState *pstate, RangeVar *relation);
@@ -439,6 +443,27 @@ GetRTEByRangeTablePosn(ParseState *pstate,
}
/*
+ * GetLevelNRangeTable
+ * Get the rangetable list for the N'th query level up from current.
+ */
+List *
+GetLevelNRangeTable(ParseState *pstate, int sublevels_up)
+{
+ int index = 0;
+
+ while (pstate != NULL)
+ {
+ if (index == sublevels_up)
+ return pstate->p_rtable;
+ index++;
+ pstate = pstate->parentParseState;
+ }
+
+ elog(ERROR, "rangetable not found (internal error)");
+ return NIL; /* 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.
@@ -464,27 +489,20 @@ scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte, char *colname)
* Scan the user column names (or aliases) for a match. Complain if
* multiple matches.
*
- * Note: because eref->colnames may include names of dropped columns, we
- * need to check for non-droppedness before accepting a match. This
- * takes an extra cache lookup, but we can skip the lookup most of the
- * time by exploiting the knowledge that dropped columns are assigned
- * dummy names starting with '.', which is an unusual choice for
- * actual column names.
+ * Note: eref->colnames may include entries for dropped columns,
+ * but those will be empty strings that cannot match any legal SQL
+ * identifier, so we don't bother to test for that case here.
*
- * Should the user try to fool us by altering pg_attribute.attname for a
- * dropped column, we'll still catch it by virtue of the checks in
- * get_rte_attribute_type(), which is called by make_var(). That
- * routine has to do a cache lookup anyway, so the check there is
- * cheap.
+ * 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 make_var(). That routine
+ * has to do a cache lookup anyway, so the check there is cheap.
*/
foreach(c, rte->eref->colnames)
{
attnum++;
if (strcmp(strVal(lfirst(c)), colname) == 0)
{
- if (colname[0] == '.' && /* see note above */
- get_rte_attribute_is_dropped(rte, attnum))
- continue;
if (result)
ereport(ERROR,
(errcode(ERRCODE_AMBIGUOUS_COLUMN),
@@ -634,6 +652,81 @@ qualifiedNameToVar(ParseState *pstate,
}
/*
+ * buildRelationAliases
+ * Construct the eref column name list for a relation RTE.
+ * This code is also used for the case of a function RTE returning
+ * a named composite type.
+ *
+ * tupdesc: the physical column information
+ * alias: the user-supplied alias, or NULL if none
+ * eref: the eref Alias to store column names in
+ *
+ * eref->colnames is filled in. Also, alias->colnames is rebuilt to insert
+ * empty strings for any dropped columns, so that it will be one-to-one with
+ * physical column numbers.
+ */
+static void
+buildRelationAliases(TupleDesc tupdesc, Alias *alias, Alias *eref)
+{
+ int maxattrs = tupdesc->natts;
+ ListCell *aliaslc;
+ int numaliases;
+ int varattno;
+ int numdropped = 0;
+
+ Assert(eref->colnames == NIL);
+
+ if (alias)
+ {
+ aliaslc = list_head(alias->colnames);
+ numaliases = list_length(alias->colnames);
+ /* We'll rebuild the alias colname list */
+ alias->colnames = NIL;
+ }
+ else
+ {
+ aliaslc = NULL;
+ numaliases = 0;
+ }
+
+ for (varattno = 0; varattno < maxattrs; varattno++)
+ {
+ Form_pg_attribute attr = tupdesc->attrs[varattno];
+ Value *attrname;
+
+ if (attr->attisdropped)
+ {
+ /* Always insert an empty string for a dropped column */
+ attrname = makeString(pstrdup(""));
+ if (aliaslc)
+ alias->colnames = lappend(alias->colnames, attrname);
+ numdropped++;
+ }
+ else if (aliaslc)
+ {
+ /* Use the next user-supplied alias */
+ attrname = (Value *) lfirst(aliaslc);
+ aliaslc = lnext(aliaslc);
+ alias->colnames = lappend(alias->colnames, attrname);
+ }
+ else
+ {
+ attrname = makeString(pstrdup(NameStr(attr->attname)));
+ /* we're done with the alias if any */
+ }
+
+ eref->colnames = lappend(eref->colnames, attrname);
+ }
+
+ /* Too many user-supplied aliases? */
+ if (aliaslc)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
+ errmsg("table \"%s\" has %d columns available but %d columns specified",
+ eref->aliasname, maxattrs - numdropped, numaliases)));
+}
+
+/*
* Add an entry for a relation to the pstate's range table (p_rtable).
*
* If pstate is NULL, we just build an RTE and return it without adding it
@@ -653,10 +746,6 @@ addRangeTableEntry(ParseState *pstate,
char *refname = alias ? alias->aliasname : relation->relname;
LOCKMODE lockmode;
Relation rel;
- Alias *eref;
- int maxattrs;
- int numaliases;
- int varattno;
rte->rtekind = RTE_RELATION;
rte->alias = alias;
@@ -671,29 +760,12 @@ addRangeTableEntry(ParseState *pstate,
rel = heap_openrv(relation, lockmode);
rte->relid = RelationGetRelid(rel);
- eref = alias ? (Alias *) copyObject(alias) : makeAlias(refname, NIL);
- numaliases = list_length(eref->colnames);
-
/*
- * Since the rel is open anyway, let's check that the number of column
- * aliases is reasonable. - Thomas 2000-02-04
+ * Build the list of effective column names using user-supplied aliases
+ * and/or actual column names.
*/
- maxattrs = RelationGetNumberOfAttributes(rel);
- if (maxattrs < numaliases)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
- errmsg("table \"%s\" has %d columns available but %d columns specified",
- RelationGetRelationName(rel), maxattrs, numaliases)));
-
- /* fill in any unspecified alias columns using actual column names */
- for (varattno = numaliases; varattno < maxattrs; varattno++)
- {
- char *attrname;
-
- attrname = pstrdup(NameStr(rel->rd_att->attrs[varattno]->attname));
- eref->colnames = lappend(eref->colnames, makeString(attrname));
- }
- rte->eref = eref;
+ rte->eref = makeAlias(refname, NIL);
+ buildRelationAliases(rel->rd_att, alias, rte->eref);
/*
* Drop the rel refcount, but keep the access lock till end of
@@ -747,10 +819,6 @@ addRangeTableEntryForRelation(ParseState *pstate,
char *refname = alias->aliasname;
LOCKMODE lockmode;
Relation rel;
- Alias *eref;
- int maxattrs;
- int numaliases;
- int varattno;
rte->rtekind = RTE_RELATION;
rte->alias = alias;
@@ -765,29 +833,12 @@ addRangeTableEntryForRelation(ParseState *pstate,
rel = heap_open(relid, lockmode);
rte->relid = relid;
- eref = (Alias *) copyObject(alias);
- numaliases = list_length(eref->colnames);
-
/*
- * Since the rel is open anyway, let's check that the number of column
- * aliases is reasonable. - Thomas 2000-02-04
+ * Build the list of effective column names using user-supplied aliases
+ * and/or actual column names.
*/
- maxattrs = RelationGetNumberOfAttributes(rel);
- if (maxattrs < numaliases)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
- errmsg("table \"%s\" has %d columns available but %d columns specified",
- RelationGetRelationName(rel), maxattrs, numaliases)));
-
- /* fill in any unspecified alias columns using actual column names */
- for (varattno = numaliases; varattno < maxattrs; varattno++)
- {
- char *attrname;
-
- attrname = pstrdup(NameStr(rel->rd_att->attrs[varattno]->attname));
- eref->colnames = lappend(eref->colnames, makeString(attrname));
- }
- rte->eref = eref;
+ rte->eref = makeAlias(refname, NIL);
+ buildRelationAliases(rel->rd_att, alias, rte->eref);
/*
* Drop the rel refcount, but keep the access lock till end of
@@ -918,8 +969,6 @@ addRangeTableEntryForFunction(ParseState *pstate,
Alias *alias = rangefunc->alias;
List *coldeflist = rangefunc->coldeflist;
Alias *eref;
- int numaliases;
- int varattno;
rte->rtekind = RTE_FUNCTION;
rte->relid = InvalidOid;
@@ -928,11 +977,9 @@ addRangeTableEntryForFunction(ParseState *pstate,
rte->coldeflist = coldeflist;
rte->alias = alias;
- eref = alias ? (Alias *) copyObject(alias) : makeAlias(funcname, NIL);
+ eref = makeAlias(alias ? alias->aliasname : funcname, NIL);
rte->eref = eref;
- numaliases = list_length(eref->colnames);
-
/*
* Now determine if the function returns a simple or composite type,
* and check/add column aliases.
@@ -969,7 +1016,6 @@ addRangeTableEntryForFunction(ParseState *pstate,
*/
Oid funcrelid = typeidTypeRelid(funcrettype);
Relation rel;
- int maxattrs;
if (!OidIsValid(funcrelid)) /* shouldn't happen if typtype is
* 'c' */
@@ -981,26 +1027,8 @@ addRangeTableEntryForFunction(ParseState *pstate,
*/
rel = relation_open(funcrelid, AccessShareLock);
- /*
- * Since the rel is open anyway, let's check that the number of
- * column aliases is reasonable.
- */
- maxattrs = RelationGetNumberOfAttributes(rel);
- if (maxattrs < numaliases)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
- errmsg("table \"%s\" has %d columns available but %d columns specified",
- RelationGetRelationName(rel),
- maxattrs, numaliases)));
-
- /* fill in alias columns using actual column names */
- for (varattno = numaliases; varattno < maxattrs; varattno++)
- {
- char *attrname;
-
- attrname = pstrdup(NameStr(rel->rd_att->attrs[varattno]->attname));
- eref->colnames = lappend(eref->colnames, makeString(attrname));
- }
+ /* Build the column alias list */
+ buildRelationAliases(rel->rd_att, alias, eref);
/*
* Drop the rel refcount, but keep the access lock till end of
@@ -1015,12 +1043,16 @@ addRangeTableEntryForFunction(ParseState *pstate,
* Must be a base data type, i.e. scalar. Just add one alias
* column named for the function.
*/
- if (numaliases > 1)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
- errmsg("too many column aliases specified for function %s",
- funcname)));
- if (numaliases == 0)
+ if (alias && alias->colnames != NIL)
+ {
+ if (list_length(alias->colnames) != 1)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
+ errmsg("too many column aliases specified for function %s",
+ funcname)));
+ eref->colnames = copyObject(alias->colnames);
+ }
+ else
eref->colnames = list_make1(makeString(eref->aliasname));
}
else if (functyptype == 'p' && funcrettype == RECORDOID)
@@ -1028,7 +1060,6 @@ addRangeTableEntryForFunction(ParseState *pstate,
ListCell *col;
/* Use the column definition list to form the alias list */
- eref->colnames = NIL;
foreach(col, coldeflist)
{
ColumnDef *n = lfirst(col);
@@ -1202,77 +1233,42 @@ addImplicitRTE(ParseState *pstate, RangeVar *relation)
return rte;
}
-/* expandRTE()
+/*
+ * expandRTE -- expand the columns of a rangetable entry
*
- * 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.
+ * This creates lists of an RTE's column names (aliases if provided, else
+ * real names) and Vars for each column. Only user columns are considered.
+ * If include_dropped is FALSE then dropped columns are omitted from the
+ * results. If include_dropped is TRUE then empty strings and NULL constants
+ * (not Vars!) are returned for dropped columns.
*
+ * The target RTE is the rtindex'th entry of rtable. (The whole rangetable
+ * must be passed since we need it to determine dropped-ness for JOIN columns.)
+ * sublevels_up is the varlevelsup value to use in the created Vars.
+ *
+ * The output lists go into *colnames and *colvars.
* 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,
+expandRTE(List *rtable, int rtindex, int sublevels_up,
+ bool include_dropped,
List **colnames, List **colvars)
{
- int rtindex,
- sublevels_up,
- varattno;
+ RangeTblEntry *rte = rt_fetch(rtindex, rtable);
+ int varattno;
if (colnames)
*colnames = NIL;
if (colvars)
*colvars = NIL;
- /* Need the RT index of the entry for creating Vars */
- rtindex = RTERangeTablePosn(pstate, rte, &sublevels_up);
-
switch (rte->rtekind)
{
case RTE_RELATION:
- {
- /* Ordinary relation RTE */
- Relation rel;
- int maxattrs;
- int numaliases;
-
- rel = heap_open(rte->relid, AccessShareLock);
- maxattrs = RelationGetNumberOfAttributes(rel);
- numaliases = list_length(rte->eref->colnames);
-
- for (varattno = 0; varattno < maxattrs; varattno++)
- {
- Form_pg_attribute attr = rel->rd_att->attrs[varattno];
-
- if (attr->attisdropped)
- continue;
-
- if (colnames)
- {
- char *label;
-
- if (varattno < numaliases)
- label = strVal(list_nth(rte->eref->colnames, varattno));
- 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);
- }
+ /* Ordinary relation RTE */
+ expandRelation(rte->relid, rte->eref, rtindex, sublevels_up,
+ include_dropped, colnames, colvars);
break;
case RTE_SUBQUERY:
{
@@ -1318,60 +1314,22 @@ expandRTE(ParseState *pstate, RangeTblEntry *rte,
/* Function RTE */
Oid funcrettype = exprType(rte->funcexpr);
char functyptype = get_typtype(funcrettype);
- List *coldeflist = rte->coldeflist;
if (functyptype == 'c')
{
/*
- * Composite data type, i.e. a table's row type Same
- * as ordinary relation RTE
+ * Composite data type, i.e. a table's row type
+ *
+ * Same as ordinary relation RTE
*/
Oid funcrelid = typeidTypeRelid(funcrettype);
- Relation rel;
- int maxattrs;
- int numaliases;
if (!OidIsValid(funcrelid)) /* shouldn't happen */
elog(ERROR, "invalid typrelid for complex type %u",
funcrettype);
- rel = relation_open(funcrelid, AccessShareLock);
- maxattrs = RelationGetNumberOfAttributes(rel);
- numaliases = list_length(rte->eref->colnames);
-
- for (varattno = 0; varattno < maxattrs; varattno++)
- {
- Form_pg_attribute attr = rel->rd_att->attrs[varattno];
-
- if (attr->attisdropped)
- continue;
-
- if (colnames)
- {
- char *label;
-
- if (varattno < numaliases)
- label = strVal(list_nth(rte->eref->colnames, varattno));
- 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);
- }
- }
-
- relation_close(rel, AccessShareLock);
+ expandRelation(funcrelid, rte->eref, rtindex, sublevels_up,
+ include_dropped, colnames, colvars);
}
else if (functyptype == 'b' || functyptype == 'd')
{
@@ -1395,6 +1353,7 @@ expandRTE(ParseState *pstate, RangeTblEntry *rte,
}
else if (functyptype == 'p' && funcrettype == RECORDOID)
{
+ List *coldeflist = rte->coldeflist;
ListCell *col;
int attnum = 0;
@@ -1447,11 +1406,41 @@ expandRTE(ParseState *pstate, RangeTblEntry *rte,
{
varattno++;
+ /*
+ * During ordinary parsing, there will never be any
+ * deleted columns in the join; but we have to check
+ * since this routine is also used by the rewriter,
+ * and joins found in stored rules might have join
+ * columns for since-deleted columns.
+ */
+ if (get_rte_attribute_is_dropped(rtable, rtindex,
+ varattno))
+ {
+ if (include_dropped)
+ {
+ if (colnames)
+ *colnames = lappend(*colnames,
+ makeString(pstrdup("")));
+ if (colvars)
+ {
+ /*
+ * can't use atttypid here, but it doesn't
+ * really matter what type the Const claims to
+ * be.
+ */
+ *colvars = lappend(*colvars,
+ makeNullConst(INT4OID));
+ }
+ }
+ continue;
+ }
+
if (colnames)
{
char *label = strVal(lfirst(colname));
- *colnames = lappend(*colnames, makeString(pstrdup(label)));
+ *colnames = lappend(*colnames,
+ makeString(pstrdup(label)));
}
if (colvars)
@@ -1475,12 +1464,77 @@ expandRTE(ParseState *pstate, RangeTblEntry *rte,
}
/*
+ * expandRelation -- expandRTE subroutine
+ */
+static void
+expandRelation(Oid relid, Alias *eref, int rtindex, int sublevels_up,
+ bool include_dropped,
+ List **colnames, List **colvars)
+{
+ Relation rel;
+ int varattno;
+ int maxattrs;
+ int numaliases;
+
+ rel = relation_open(relid, AccessShareLock);
+ maxattrs = RelationGetNumberOfAttributes(rel);
+ numaliases = list_length(eref->colnames);
+
+ for (varattno = 0; varattno < maxattrs; varattno++)
+ {
+ Form_pg_attribute attr = rel->rd_att->attrs[varattno];
+
+ if (attr->attisdropped)
+ {
+ if (include_dropped)
+ {
+ if (colnames)
+ *colnames = lappend(*colnames, makeString(pstrdup("")));
+ if (colvars)
+ {
+ /*
+ * can't use atttypid here, but it doesn't really matter
+ * what type the Const claims to be.
+ */
+ *colvars = lappend(*colvars, makeNullConst(INT4OID));
+ }
+ }
+ continue;
+ }
+
+ if (colnames)
+ {
+ char *label;
+
+ if (varattno < numaliases)
+ label = strVal(list_nth(eref->colnames, varattno));
+ 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);
+ }
+ }
+
+ relation_close(rel, AccessShareLock);
+}
+
+/*
* expandRelAttrs -
* Workhorse for "*" expansion: produce a list of targetentries
* for the attributes of the rte
*/
List *
-expandRelAttrs(ParseState *pstate, RangeTblEntry *rte)
+expandRelAttrs(ParseState *pstate, List *rtable, int rtindex, int sublevels_up)
{
List *names,
*vars;
@@ -1488,9 +1542,9 @@ expandRelAttrs(ParseState *pstate, RangeTblEntry *rte)
*var;
List *te_list = NIL;
- expandRTE(pstate, rte, &names, &vars);
+ expandRTE(rtable, rtindex, sublevels_up, false, &names, &vars);
- forboth (name, names, var, vars)
+ forboth(name, names, var, vars)
{
char *label = strVal(lfirst(name));
Node *varnode = (Node *) lfirst(var);
@@ -1698,15 +1752,16 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
* Check whether attempted attribute ref is to a dropped column
*/
bool
-get_rte_attribute_is_dropped(RangeTblEntry *rte, AttrNumber attnum)
+get_rte_attribute_is_dropped(List *rtable, int rtindex, AttrNumber attnum)
{
+ RangeTblEntry *rte = rt_fetch(rtindex, rtable);
bool result;
switch (rte->rtekind)
{
case RTE_RELATION:
{
- /* Plain relation RTE --- get the attribute's type info */
+ /* Plain relation RTE --- get the attribute's catalog entry */
HeapTuple tp;
Form_pg_attribute att_tup;
@@ -1723,10 +1778,38 @@ get_rte_attribute_is_dropped(RangeTblEntry *rte, AttrNumber attnum)
}
break;
case RTE_SUBQUERY:
- case RTE_JOIN:
- /* Subselect and join RTEs never have dropped columns */
+ /* Subselect RTEs never have dropped columns */
result = false;
break;
+ case RTE_JOIN:
+ {
+ /*
+ * A join RTE would not have dropped columns when constructed,
+ * but one in a stored rule might contain columns that were
+ * dropped from the underlying tables, if said columns are
+ * nowhere explicitly referenced in the rule. So we have to
+ * recursively look at the referenced column.
+ */
+ Var *aliasvar;
+
+ if (attnum <= 0 ||
+ attnum > list_length(rte->joinaliasvars))
+ elog(ERROR, "invalid varattno %d", attnum);
+ aliasvar = (Var *) list_nth(rte->joinaliasvars, attnum - 1);
+ /*
+ * If the list item isn't a simple Var, then it must
+ * represent a merged column, ie a USING column, and so it
+ * couldn't possibly be dropped (since it's referenced in
+ * the join clause).
+ */
+ if (!IsA(aliasvar, Var))
+ result = false;
+ else
+ result = get_rte_attribute_is_dropped(rtable,
+ aliasvar->varno,
+ aliasvar->varattno);
+ }
+ break;
case RTE_FUNCTION:
{
/* Function RTE */
@@ -1736,8 +1819,9 @@ get_rte_attribute_is_dropped(RangeTblEntry *rte, AttrNumber attnum)
if (OidIsValid(funcrelid))
{
/*
- * Composite data type, i.e. a table's row type Same
- * as ordinary relation RTE
+ * Composite data type, i.e. a table's row type
+ *
+ * Same as ordinary relation RTE
*/
HeapTuple tp;
Form_pg_attribute att_tup;
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index 7dcbc7b7b74..1ca2b457936 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.122 2004/06/19 18:19:55 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.123 2004/08/19 20:57:40 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -699,6 +699,8 @@ ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref)
char *relname;
RangeTblEntry *rte;
int sublevels_up;
+ int rtindex;
+ List *rtable;
switch (numnames)
{
@@ -743,7 +745,10 @@ ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref)
rte = addImplicitRTE(pstate, makeRangeVar(schemaname,
relname));
- return expandRelAttrs(pstate, rte);
+ rtindex = RTERangeTablePosn(pstate, rte, &sublevels_up);
+ rtable = GetLevelNRangeTable(pstate, sublevels_up);
+
+ return expandRelAttrs(pstate, rtable, rtindex, sublevels_up);
}
}
@@ -765,29 +770,31 @@ ExpandAllTables(ParseState *pstate)
foreach(ns, pstate->p_namespace)
{
Node *n = (Node *) lfirst(ns);
+ int rtindex;
RangeTblEntry *rte;
if (IsA(n, RangeTblRef))
- rte = rt_fetch(((RangeTblRef *) n)->rtindex,
- pstate->p_rtable);
+ rtindex = ((RangeTblRef *) n)->rtindex;
else if (IsA(n, JoinExpr))
- rte = rt_fetch(((JoinExpr *) n)->rtindex,
- pstate->p_rtable);
+ rtindex = ((JoinExpr *) n)->rtindex;
else
{
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(n));
- rte = NULL; /* keep compiler quiet */
+ rtindex = 0; /* keep compiler quiet */
}
/*
* Ignore added-on relations that were not listed in the FROM
* clause.
*/
+ rte = rt_fetch(rtindex, pstate->p_rtable);
if (!rte->inFromCl)
continue;
found_table = true;
- target = list_concat(target, expandRelAttrs(pstate, rte));
+ target = list_concat(target,
+ expandRelAttrs(pstate, pstate->p_rtable,
+ rtindex, 0));
}
/* Check for SELECT *; */
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index fadc7416ad9..7358d745f78 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.141 2004/08/07 17:40:49 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.142 2004/08/19 20:57:40 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -214,8 +214,7 @@ rewriteRuleAction(Query *parsetree,
sub_action = (Query *) ResolveNew((Node *) sub_action,
new_varno,
0,
- rt_fetch(new_varno,
- sub_action->rtable),
+ sub_action->rtable,
parsetree->targetList,
event,
current_varno);
@@ -1040,7 +1039,7 @@ CopyAndAddInvertedQual(Query *parsetree,
new_qual = ResolveNew(new_qual,
PRS2_NEW_VARNO,
0,
- rt_fetch(rt_index, parsetree->rtable),
+ parsetree->rtable,
parsetree->targetList,
event,
rt_index);
diff --git a/src/backend/rewrite/rewriteManip.c b/src/backend/rewrite/rewriteManip.c
index 86412e90634..6480d8853b5 100644
--- a/src/backend/rewrite/rewriteManip.c
+++ b/src/backend/rewrite/rewriteManip.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/rewrite/rewriteManip.c,v 1.85 2004/08/17 18:47:09 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/rewrite/rewriteManip.c,v 1.86 2004/08/19 20:57:40 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -18,7 +18,7 @@
#include "optimizer/clauses.h"
#include "optimizer/tlist.h"
#include "parser/parsetree.h"
-#include "parser/parse_clause.h"
+#include "parser/parse_relation.h"
#include "rewrite/rewriteManip.h"
#include "utils/lsyscache.h"
@@ -853,9 +853,10 @@ AddInvertedQual(Query *parsetree, Node *qual)
* If not, we either change the unmatched Var's varno to update_varno
* (when event == CMD_UPDATE) or replace it with a constant NULL.
*
- * The caller must also provide target_rte, the RTE describing the target
- * relation. This is needed to handle whole-row Vars referencing the target.
- * We expand such Vars into RowExpr constructs.
+ * The caller must also provide target_rtable, the rangetable containing
+ * the target relation (which must be described by the target_varno'th
+ * RTE in that list). This is needed to handle whole-row Vars referencing
+ * the target. We expand such Vars into RowExpr constructs.
*
* Note: the business with inserted_sublink is needed to update hasSubLinks
* in subqueries when the replacement adds a subquery inside a subquery.
@@ -868,7 +869,7 @@ typedef struct
{
int target_varno;
int sublevels_up;
- RangeTblEntry *target_rte;
+ List *target_rtable;
List *targetlist;
int event;
int update_varno;
@@ -931,40 +932,21 @@ ResolveNew_mutator(Node *node, ResolveNew_context *context)
if (var->varattno == InvalidAttrNumber)
{
/* Must expand whole-tuple reference into RowExpr */
- RangeTblEntry *rte = context->target_rte;
RowExpr *rowexpr;
- List *fields = NIL;
- AttrNumber nfields = list_length(rte->eref->colnames);
- AttrNumber nf;
-
- for (nf = 1; nf <= nfields; nf++)
- {
- if (get_rte_attribute_is_dropped(rte, nf))
- {
- /*
- * can't determine att type here, but it doesn't
- * really matter what type the Const claims to be.
- */
- fields = lappend(fields,
- makeNullConst(INT4OID));
- }
- else
- {
- Oid vartype;
- int32 vartypmod;
- Var *newvar;
-
- get_rte_attribute_type(rte, nf, &vartype, &vartypmod);
- newvar = makeVar(this_varno,
- nf,
- vartype,
- vartypmod,
- this_varlevelsup);
- fields = lappend(fields,
- resolve_one_var(newvar, context));
- }
- }
-
+ List *fields;
+
+ /*
+ * If generating an expansion for a var of a named rowtype
+ * (ie, this is a plain relation RTE), then we must include
+ * dummy items for dropped columns. If the var is RECORD
+ * (ie, this is a JOIN), then omit dropped columns.
+ */
+ expandRTE(context->target_rtable, this_varno, this_varlevelsup,
+ (var->vartype != RECORDOID),
+ NULL, &fields);
+ /* Adjust the generated per-field Vars... */
+ fields = (List *) ResolveNew_mutator((Node *) fields,
+ context);
rowexpr = makeNode(RowExpr);
rowexpr->args = fields;
rowexpr->row_typeid = var->vartype;
@@ -1003,14 +985,14 @@ ResolveNew_mutator(Node *node, ResolveNew_context *context)
Node *
ResolveNew(Node *node, int target_varno, int sublevels_up,
- RangeTblEntry *target_rte,
+ List *target_rtable,
List *targetlist, int event, int update_varno)
{
ResolveNew_context context;
context.target_varno = target_varno;
context.sublevels_up = sublevels_up;
- context.target_rte = target_rte;
+ context.target_rtable = target_rtable;
context.targetlist = targetlist;
context.event = event;
context.update_varno = update_varno;
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 8e1420d9267..52089d22118 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -3,7 +3,7 @@
* back to source text
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.177 2004/08/17 18:47:09 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.178 2004/08/19 20:57:41 tgl Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
@@ -203,6 +203,8 @@ static void get_sublink_expr(SubLink *sublink, deparse_context *context);
static void get_from_clause(Query *query, deparse_context *context);
static void get_from_clause_item(Node *jtnode, Query *query,
deparse_context *context);
+static void get_from_clause_alias(Alias *alias, int varno,
+ Query *query, deparse_context *context);
static void get_from_clause_coldeflist(List *coldeflist,
deparse_context *context);
static void get_opclass_name(Oid opclass, Oid actual_datatype,
@@ -3962,20 +3964,8 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
appendStringInfo(buf, " %s",
quote_identifier(rte->alias->aliasname));
gavealias = true;
- if (rte->alias->colnames != NIL && coldeflist == NIL)
- {
- ListCell *col;
-
- appendStringInfoChar(buf, '(');
- foreach(col, rte->alias->colnames)
- {
- if (col != list_head(rte->alias->colnames))
- appendStringInfo(buf, ", ");
- appendStringInfoString(buf,
- quote_identifier(strVal(lfirst(col))));
- }
- appendStringInfoChar(buf, ')');
- }
+ if (coldeflist == NIL)
+ get_from_clause_alias(rte->alias, varno, query, context);
}
else if (rte->rtekind == RTE_RELATION &&
strcmp(rte->eref->aliasname, get_rel_name(rte->relid)) != 0)
@@ -4128,20 +4118,7 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
{
appendStringInfo(buf, " %s",
quote_identifier(j->alias->aliasname));
- if (j->alias->colnames != NIL)
- {
- ListCell *col;
-
- appendStringInfoChar(buf, '(');
- foreach(col, j->alias->colnames)
- {
- if (col != list_head(j->alias->colnames))
- appendStringInfo(buf, ", ");
- appendStringInfoString(buf,
- quote_identifier(strVal(lfirst(col))));
- }
- appendStringInfoChar(buf, ')');
- }
+ get_from_clause_alias(j->alias, j->rtindex, query, context);
}
}
else
@@ -4150,6 +4127,43 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
}
/*
+ * get_from_clause_alias - reproduce column alias list
+ *
+ * This is tricky because we must ignore dropped columns.
+ */
+static void
+get_from_clause_alias(Alias *alias, int varno,
+ Query *query, deparse_context *context)
+{
+ StringInfo buf = context->buf;
+ ListCell *col;
+ AttrNumber attnum;
+ bool first = true;
+
+ if (alias == NULL || alias->colnames == NIL)
+ return; /* definitely nothing to do */
+
+ attnum = 0;
+ foreach(col, alias->colnames)
+ {
+ attnum++;
+ if (get_rte_attribute_is_dropped(query->rtable, varno, attnum))
+ continue;
+ if (first)
+ {
+ appendStringInfoChar(buf, '(');
+ first = false;
+ }
+ else
+ appendStringInfo(buf, ", ");
+ appendStringInfoString(buf,
+ quote_identifier(strVal(lfirst(col))));
+ }
+ if (!first)
+ appendStringInfoChar(buf, ')');
+}
+
+/*
* get_from_clause_coldeflist - reproduce FROM clause coldeflist
*
* The coldeflist is appended immediately (no space) to buf. Caller is
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 80230e34446..aff28bea08f 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.265 2004/08/04 21:34:24 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.266 2004/08/19 20:57:41 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -447,6 +447,22 @@ typedef struct DefElem
* eref->aliasname is required to be present, and should generally be used
* to identify the RTE for error messages etc.
*
+ * In RELATION RTEs, the colnames in both alias and eref are indexed by
+ * physical attribute number; this means there must be colname entries for
+ * dropped columns. When building an RTE we insert empty strings ("") for
+ * dropped columns. Note however that a stored rule may have nonempty
+ * colnames for columns dropped since the rule was created (and for that
+ * matter the colnames might be out of date due to column renamings).
+ * The same comments apply to FUNCTION RTEs when the function's return type
+ * is a named composite type.
+ *
+ * In JOIN RTEs, the colnames in both alias and eref are one-to-one with
+ * joinaliasvars entries. A JOIN RTE will omit columns of its inputs when
+ * those columns are known to be dropped at parse time. Again, however,
+ * a stored rule might contain entries for columns dropped since the rule
+ * was created. (This is only possible for columns not actually referenced
+ * in the rule.)
+ *
* inh is TRUE for relation references that should be expanded to include
* inheritance children, if the rel has any. This *must* be FALSE for
* RTEs other than RTE_RELATION entries.
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index 5abdbd548fd..56f359978d4 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -10,7 +10,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.101 2004/08/17 18:47:09 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.102 2004/08/19 20:57:41 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -98,9 +98,9 @@ typedef struct Resdom
* specifies an alias for a range variable; the alias might also
* specify renaming of columns within the table.
*
- * Note: colnames is a list of Value nodes (always strings). In an RTE's
- * eref Alias, the colnames list includes dropped columns, so that the
- * colname list position matches the physical attribute number.
+ * Note: colnames is a list of Value nodes (always strings). In Alias structs
+ * associated with RTEs, there may be entries corresponding to dropped
+ * columns; these are normally empty strings (""). See parsenodes.h for info.
*/
typedef struct Alias
{
diff --git a/src/include/parser/parse_relation.h b/src/include/parser/parse_relation.h
index 724639dd96a..afb6c6303d6 100644
--- a/src/include/parser/parse_relation.h
+++ b/src/include/parser/parse_relation.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/parser/parse_relation.h,v 1.44 2004/04/18 18:12:58 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/parser/parse_relation.h,v 1.45 2004/08/19 20:57:41 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -30,6 +30,7 @@ extern int RTERangeTablePosn(ParseState *pstate,
extern RangeTblEntry *GetRTEByRangeTablePosn(ParseState *pstate,
int varno,
int sublevels_up);
+extern List *GetLevelNRangeTable(ParseState *pstate, int sublevels_up);
extern Node *scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte,
char *colname);
extern Node *colNameToVar(ParseState *pstate, char *colname, bool localonly);
@@ -66,9 +67,11 @@ extern RangeTblEntry *addRangeTableEntryForJoin(ParseState *pstate,
extern void addRTEtoQuery(ParseState *pstate, RangeTblEntry *rte,
bool addToJoinList, bool addToNameSpace);
extern RangeTblEntry *addImplicitRTE(ParseState *pstate, RangeVar *relation);
-extern void expandRTE(ParseState *pstate, RangeTblEntry *rte,
- List **colnames, List **colvars);
-extern List *expandRelAttrs(ParseState *pstate, RangeTblEntry *rte);
+extern void expandRTE(List *rtable, int rtindex, int sublevels_up,
+ bool include_dropped,
+ List **colnames, List **colvars);
+extern List *expandRelAttrs(ParseState *pstate, List *rtable,
+ int rtindex, int sublevels_up);
extern int attnameAttNum(Relation rd, const char *attname, bool sysColOK);
extern Name attnumAttName(Relation rd, int attid);
extern Oid attnumTypeId(Relation rd, int attid);
diff --git a/src/include/parser/parsetree.h b/src/include/parser/parsetree.h
index e7f401ac315..a972cd73312 100644
--- a/src/include/parser/parsetree.h
+++ b/src/include/parser/parsetree.h
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/parser/parsetree.h,v 1.25 2004/08/17 18:47:09 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/parser/parsetree.h,v 1.26 2004/08/19 20:57:41 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -59,7 +59,7 @@ extern void get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
* Check whether an attribute of an RTE has been dropped (note that
* get_rte_attribute_type will fail on such an attr)
*/
-extern bool get_rte_attribute_is_dropped(RangeTblEntry *rte,
+extern bool get_rte_attribute_is_dropped(List *rtable, int rtindex,
AttrNumber attnum);
diff --git a/src/include/rewrite/rewriteManip.h b/src/include/rewrite/rewriteManip.h
index ce4702de35b..a17fd918b22 100644
--- a/src/include/rewrite/rewriteManip.h
+++ b/src/include/rewrite/rewriteManip.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/rewrite/rewriteManip.h,v 1.35 2004/05/10 22:44:49 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/rewrite/rewriteManip.h,v 1.36 2004/08/19 20:57:41 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -38,7 +38,7 @@ extern bool checkExprHasAggs(Node *node);
extern bool checkExprHasSubLink(Node *node);
extern Node *ResolveNew(Node *node, int target_varno, int sublevels_up,
- RangeTblEntry *target_rte,
+ List *target_rtable,
List *targetlist, int event, int update_varno);
#endif /* REWRITEMANIP_H */