diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index 9d4e1c6a5c48773571b2d948d3769dbccee4ada0..59c3151cdf2f3f1b621e975f337d3f0a92a667ba 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 24a51149e45db497082592979efd84d173e0aeac..d770c9175bc644f18fc6fae0ffa3f7681ce9ecc1 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 1eb4d5504a1981c34b9a292ec776f74246baed1e..430ec9e5db725205f43a0aea716929dc8b63b63f 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 e46655e17dbd1868d1c941728782ec7959f9a2d9..94e0f15e289fd3c345797308a887c8e9df8ef169 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 b3a6b67f5c399a0c100744b1bfea15d1aa4f1e4a..156dbac5aad69181197ff5e2a88461caddd44c15 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 8065b261beb1935c7592d81c6c40843e31470b3c..8d892fcffe12272a01161576c3528638a8168f6f 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 3f32f8c80f5340f7aac15270e9b05e96a142f560..1a9aa2cd73fa76cb21413c5910b81a986e485e45 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); @@ -438,6 +442,27 @@ GetRTEByRangeTablePosn(ParseState *pstate, return rt_fetch(varno, pstate->p_rtable); } +/* + * 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. @@ -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), @@ -633,6 +651,81 @@ qualifiedNameToVar(ParseState *pstate, return scanRTEForColumn(pstate, rte, colname); } +/* + * 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). * @@ -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) @@ -1474,13 +1463,78 @@ 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 7dcbc7b7b741d0e9a04d54ff1e3824730cd37b36..1ca2b457936ac606e164b6a61a88205260c4f8bd 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 fadc7416ad958d32d0580450db20e81b4a69a86e..7358d745f78604a1d16e8192890f2bd0ca887ef2 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 86412e90634adf34a0c47e82c09c23d0d1d39320..6480d8853b5d95f518abc3efe565b6cad61bee3d 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 8e1420d9267b037212034c5d83a08a96f32be277..52089d221185137c5d1cccc5266534fbdb9edcbf 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 @@ -4149,6 +4126,43 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context) (int) nodeTag(jtnode)); } +/* + * 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 * diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 80230e344466fd6d5033ee8178042acb21348bc4..aff28bea08fb67104ee91235c918bb5869f56149 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 5abdbd548fd3fc40e80e8e06fdbe6e5e573e2ccf..56f359978d4a1d60efd2912793b3ab68e883c92c 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 724639dd96ad56d820b6fb891a39e96d4f12e83a..afb6c6303d6b13605f9eb99bfa9281495a9b3835 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 e7f401ac315c896d4a12d4b17b31c019898c442b..a972cd733122dd42e10bc8d203c463962ce7a532 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 ce4702de35ba49dd29fca8543617c850b186b985..a17fd918b22235723c11503f460def1bf56fb1a3 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 */