Commit 9459db8e authored by Tom Lane's avatar Tom Lane

Cause view/rule display to work as expected after rename of an underlying

table or column, or of an output column of the view itself.
parent d176fad5
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.76 2002/08/08 01:44:30 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.77 2002/08/08 17:00:19 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1499,29 +1499,36 @@ get_rte_attribute_name(RangeTblEntry *rte, AttrNumber attnum) ...@@ -1499,29 +1499,36 @@ get_rte_attribute_name(RangeTblEntry *rte, AttrNumber attnum)
return "*"; return "*";
/* /*
* If there is an alias, use it. (This path should always be taken * If there is a user-written column alias, use it.
* for non-relation RTEs.)
*/ */
if (attnum > 0 && attnum <= length(rte->eref->colnames)) if (rte->alias &&
return strVal(nth(attnum - 1, rte->eref->colnames)); attnum > 0 && attnum <= length(rte->alias->colnames))
return strVal(nth(attnum - 1, rte->alias->colnames));
/* /*
* Can get here for a system attribute (which never has an alias), or * If the RTE is a relation, go to the system catalogs not the
* if alias name list is too short (which probably can't happen * eref->colnames list. This is a little slower but it will give
* anymore). Neither of these cases is valid for a non-relation RTE. * the right answer if the column has been renamed since the eref
*/ * list was built (which can easily happen for rules).
if (rte->rtekind != RTE_RELATION)
elog(ERROR, "Invalid attnum %d for rangetable entry %s",
attnum, rte->eref->aliasname);
/*
* Use the real name of the table's column
*/ */
if (rte->rtekind == RTE_RELATION)
{
attname = get_attname(rte->relid, attnum); attname = get_attname(rte->relid, attnum);
if (attname == NULL) if (attname == NULL)
elog(ERROR, "cache lookup of attribute %d in relation %u failed", elog(ERROR, "cache lookup of attribute %d in relation %u failed",
attnum, rte->relid); attnum, rte->relid);
return attname; return attname;
}
/*
* Otherwise use the column name from eref. There should always be one.
*/
if (attnum > 0 && attnum <= length(rte->eref->colnames))
return strVal(nth(attnum - 1, rte->eref->colnames));
elog(ERROR, "Invalid attnum %d for rangetable entry %s",
attnum, rte->eref->aliasname);
return NULL; /* keep compiler quiet */
} }
/* /*
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* back to source text * back to source text
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.113 2002/08/08 01:44:31 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.114 2002/08/08 17:00:19 tgl Exp $
* *
* This software is copyrighted by Jan Wieck - Hamburg. * This software is copyrighted by Jan Wieck - Hamburg.
* *
...@@ -118,15 +118,19 @@ static char *query_getviewrule = "SELECT * FROM pg_catalog.pg_rewrite WHERE ev_c ...@@ -118,15 +118,19 @@ static char *query_getviewrule = "SELECT * FROM pg_catalog.pg_rewrite WHERE ev_c
static text *pg_do_getviewdef(Oid viewoid); static text *pg_do_getviewdef(Oid viewoid);
static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc); static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc);
static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc); static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc);
static void get_query_def(Query *query, StringInfo buf, List *parentnamespace); static void get_query_def(Query *query, StringInfo buf, List *parentnamespace,
static void get_select_query_def(Query *query, deparse_context *context); TupleDesc resultDesc);
static void get_select_query_def(Query *query, deparse_context *context,
TupleDesc resultDesc);
static void get_insert_query_def(Query *query, deparse_context *context); static void get_insert_query_def(Query *query, deparse_context *context);
static void get_update_query_def(Query *query, deparse_context *context); static void get_update_query_def(Query *query, deparse_context *context);
static void get_delete_query_def(Query *query, deparse_context *context); static void get_delete_query_def(Query *query, deparse_context *context);
static void get_utility_query_def(Query *query, deparse_context *context); static void get_utility_query_def(Query *query, deparse_context *context);
static void get_basic_select_query(Query *query, deparse_context *context); static void get_basic_select_query(Query *query, deparse_context *context,
TupleDesc resultDesc);
static void get_setop_query(Node *setOp, Query *query, static void get_setop_query(Node *setOp, Query *query,
deparse_context *context); deparse_context *context,
TupleDesc resultDesc);
static Node *get_rule_sortgroupclause(SortClause *srt, List *tlist, static Node *get_rule_sortgroupclause(SortClause *srt, List *tlist,
bool force_colno, bool force_colno,
deparse_context *context); deparse_context *context);
...@@ -936,14 +940,12 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc) ...@@ -936,14 +940,12 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
foreach(action, actions) foreach(action, actions)
{ {
query = (Query *) lfirst(action); query = (Query *) lfirst(action);
get_query_def(query, buf, NIL); get_query_def(query, buf, NIL, NULL);
appendStringInfo(buf, "; "); appendStringInfo(buf, "; ");
} }
appendStringInfo(buf, ");"); appendStringInfo(buf, ");");
} }
else else if (length(actions) == 0)
{
if (length(actions) == 0)
{ {
appendStringInfo(buf, "NOTHING;"); appendStringInfo(buf, "NOTHING;");
} }
...@@ -952,10 +954,9 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc) ...@@ -952,10 +954,9 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
Query *query; Query *query;
query = (Query *) lfirst(actions); query = (Query *) lfirst(actions);
get_query_def(query, buf, NIL); get_query_def(query, buf, NIL, NULL);
appendStringInfo(buf, ";"); appendStringInfo(buf, ";");
} }
}
} }
...@@ -975,6 +976,7 @@ make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc) ...@@ -975,6 +976,7 @@ make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
char *ev_qual; char *ev_qual;
char *ev_action; char *ev_action;
List *actions = NIL; List *actions = NIL;
Relation ev_relation;
int fno; int fno;
bool isnull; bool isnull;
...@@ -1010,25 +1012,31 @@ make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc) ...@@ -1010,25 +1012,31 @@ make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
query = (Query *) lfirst(actions); query = (Query *) lfirst(actions);
if (ev_type != '1' || ev_attr >= 0 || !is_instead || if (ev_type != '1' || ev_attr >= 0 || !is_instead ||
strcmp(ev_qual, "<>") != 0) strcmp(ev_qual, "<>") != 0 || query->commandType != CMD_SELECT)
{ {
appendStringInfo(buf, "Not a view"); appendStringInfo(buf, "Not a view");
return; return;
} }
get_query_def(query, buf, NIL); ev_relation = heap_open(ev_class, AccessShareLock);
get_query_def(query, buf, NIL, RelationGetDescr(ev_relation));
appendStringInfo(buf, ";"); appendStringInfo(buf, ";");
heap_close(ev_relation, AccessShareLock);
} }
/* ---------- /* ----------
* get_query_def - Parse back one action from * get_query_def - Parse back one query parsetree
* the parsetree in the actions *
* list * If resultDesc is not NULL, then it is the output tuple descriptor for
* the view represented by a SELECT query.
* ---------- * ----------
*/ */
static void static void
get_query_def(Query *query, StringInfo buf, List *parentnamespace) get_query_def(Query *query, StringInfo buf, List *parentnamespace,
TupleDesc resultDesc)
{ {
deparse_context context; deparse_context context;
deparse_namespace dpns; deparse_namespace dpns;
...@@ -1044,7 +1052,7 @@ get_query_def(Query *query, StringInfo buf, List *parentnamespace) ...@@ -1044,7 +1052,7 @@ get_query_def(Query *query, StringInfo buf, List *parentnamespace)
switch (query->commandType) switch (query->commandType)
{ {
case CMD_SELECT: case CMD_SELECT:
get_select_query_def(query, &context); get_select_query_def(query, &context, resultDesc);
break; break;
case CMD_UPDATE: case CMD_UPDATE:
...@@ -1080,7 +1088,8 @@ get_query_def(Query *query, StringInfo buf, List *parentnamespace) ...@@ -1080,7 +1088,8 @@ get_query_def(Query *query, StringInfo buf, List *parentnamespace)
* ---------- * ----------
*/ */
static void static void
get_select_query_def(Query *query, deparse_context *context) get_select_query_def(Query *query, deparse_context *context,
TupleDesc resultDesc)
{ {
StringInfo buf = context->buf; StringInfo buf = context->buf;
bool force_colno; bool force_colno;
...@@ -1094,13 +1103,13 @@ get_select_query_def(Query *query, deparse_context *context) ...@@ -1094,13 +1103,13 @@ get_select_query_def(Query *query, deparse_context *context)
*/ */
if (query->setOperations) if (query->setOperations)
{ {
get_setop_query(query->setOperations, query, context); get_setop_query(query->setOperations, query, context, resultDesc);
/* ORDER BY clauses must be simple in this case */ /* ORDER BY clauses must be simple in this case */
force_colno = true; force_colno = true;
} }
else else
{ {
get_basic_select_query(query, context); get_basic_select_query(query, context, resultDesc);
force_colno = false; force_colno = false;
} }
...@@ -1151,11 +1160,13 @@ get_select_query_def(Query *query, deparse_context *context) ...@@ -1151,11 +1160,13 @@ get_select_query_def(Query *query, deparse_context *context)
} }
static void static void
get_basic_select_query(Query *query, deparse_context *context) get_basic_select_query(Query *query, deparse_context *context,
TupleDesc resultDesc)
{ {
StringInfo buf = context->buf; StringInfo buf = context->buf;
char *sep; char *sep;
List *l; List *l;
int colno;
/* /*
* Build up the query string - first we say SELECT * Build up the query string - first we say SELECT
...@@ -1186,23 +1197,37 @@ get_basic_select_query(Query *query, deparse_context *context) ...@@ -1186,23 +1197,37 @@ get_basic_select_query(Query *query, deparse_context *context)
/* Then we tell what to select (the targetlist) */ /* Then we tell what to select (the targetlist) */
sep = " "; sep = " ";
colno = 0;
foreach(l, query->targetList) foreach(l, query->targetList)
{ {
TargetEntry *tle = (TargetEntry *) lfirst(l); TargetEntry *tle = (TargetEntry *) lfirst(l);
bool tell_as = false; bool tell_as = false;
char *colname;
if (tle->resdom->resjunk) if (tle->resdom->resjunk)
continue; /* ignore junk entries */ continue; /* ignore junk entries */
appendStringInfo(buf, sep); appendStringInfo(buf, sep);
sep = ", "; sep = ", ";
colno++;
/* Do NOT use get_tle_expr here; see its comments! */ /* Do NOT use get_tle_expr here; see its comments! */
get_rule_expr(tle->expr, context); get_rule_expr(tle->expr, context);
/*
* Figure out what the result column should be called. In the
* context of a view, use the view's tuple descriptor (so as to
* pick up the effects of any column RENAME that's been done on the
* view). Otherwise, just use what we can find in the TLE.
*/
if (resultDesc && colno <= resultDesc->natts)
colname = NameStr(resultDesc->attrs[colno-1]->attname);
else
colname = tle->resdom->resname;
/* Check if we must say AS ... */ /* Check if we must say AS ... */
if (!IsA(tle->expr, Var)) if (!IsA(tle->expr, Var))
tell_as = (strcmp(tle->resdom->resname, "?column?") != 0); tell_as = (strcmp(colname, "?column?") != 0);
else else
{ {
Var *var = (Var *) (tle->expr); Var *var = (Var *) (tle->expr);
...@@ -1212,13 +1237,12 @@ get_basic_select_query(Query *query, deparse_context *context) ...@@ -1212,13 +1237,12 @@ get_basic_select_query(Query *query, deparse_context *context)
get_names_for_var(var, context, &schemaname, &refname, &attname); get_names_for_var(var, context, &schemaname, &refname, &attname);
tell_as = (attname == NULL || tell_as = (attname == NULL ||
strcmp(attname, tle->resdom->resname) != 0); strcmp(attname, colname) != 0);
} }
/* and do if so */ /* and do if so */
if (tell_as) if (tell_as)
appendStringInfo(buf, " AS %s", appendStringInfo(buf, " AS %s", quote_identifier(colname));
quote_identifier(tle->resdom->resname));
} }
/* Add the FROM clause if needed */ /* Add the FROM clause if needed */
...@@ -1256,7 +1280,8 @@ get_basic_select_query(Query *query, deparse_context *context) ...@@ -1256,7 +1280,8 @@ get_basic_select_query(Query *query, deparse_context *context)
} }
static void static void
get_setop_query(Node *setOp, Query *query, deparse_context *context) get_setop_query(Node *setOp, Query *query, deparse_context *context,
TupleDesc resultDesc)
{ {
StringInfo buf = context->buf; StringInfo buf = context->buf;
...@@ -1267,14 +1292,14 @@ get_setop_query(Node *setOp, Query *query, deparse_context *context) ...@@ -1267,14 +1292,14 @@ get_setop_query(Node *setOp, Query *query, deparse_context *context)
Query *subquery = rte->subquery; Query *subquery = rte->subquery;
Assert(subquery != NULL); Assert(subquery != NULL);
get_query_def(subquery, buf, context->namespaces); get_query_def(subquery, buf, context->namespaces, resultDesc);
} }
else if (IsA(setOp, SetOperationStmt)) else if (IsA(setOp, SetOperationStmt))
{ {
SetOperationStmt *op = (SetOperationStmt *) setOp; SetOperationStmt *op = (SetOperationStmt *) setOp;
appendStringInfo(buf, "(("); appendStringInfo(buf, "((");
get_setop_query(op->larg, query, context); get_setop_query(op->larg, query, context, resultDesc);
switch (op->op) switch (op->op)
{ {
case SETOP_UNION: case SETOP_UNION:
...@@ -1294,7 +1319,7 @@ get_setop_query(Node *setOp, Query *query, deparse_context *context) ...@@ -1294,7 +1319,7 @@ get_setop_query(Node *setOp, Query *query, deparse_context *context)
appendStringInfo(buf, "ALL ("); appendStringInfo(buf, "ALL (");
else else
appendStringInfo(buf, "("); appendStringInfo(buf, "(");
get_setop_query(op->rarg, query, context); get_setop_query(op->rarg, query, context, resultDesc);
appendStringInfo(buf, "))"); appendStringInfo(buf, "))");
} }
else else
...@@ -1405,7 +1430,7 @@ get_insert_query_def(Query *query, deparse_context *context) ...@@ -1405,7 +1430,7 @@ get_insert_query_def(Query *query, deparse_context *context)
appendStringInfoChar(buf, ')'); appendStringInfoChar(buf, ')');
} }
else else
get_query_def(select_rte->subquery, buf, NIL); get_query_def(select_rte->subquery, buf, NIL, NULL);
} }
...@@ -2418,7 +2443,7 @@ get_sublink_expr(Node *node, deparse_context *context) ...@@ -2418,7 +2443,7 @@ get_sublink_expr(Node *node, deparse_context *context)
if (need_paren) if (need_paren)
appendStringInfoChar(buf, '('); appendStringInfoChar(buf, '(');
get_query_def(query, buf, context->namespaces); get_query_def(query, buf, context->namespaces, NULL);
if (need_paren) if (need_paren)
appendStringInfo(buf, "))"); appendStringInfo(buf, "))");
...@@ -2491,7 +2516,7 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context) ...@@ -2491,7 +2516,7 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
case RTE_SUBQUERY: case RTE_SUBQUERY:
/* Subquery RTE */ /* Subquery RTE */
appendStringInfoChar(buf, '('); appendStringInfoChar(buf, '(');
get_query_def(rte->subquery, buf, context->namespaces); get_query_def(rte->subquery, buf, context->namespaces, NULL);
appendStringInfoChar(buf, ')'); appendStringInfoChar(buf, ')');
break; break;
case RTE_FUNCTION: case RTE_FUNCTION:
...@@ -2521,6 +2546,18 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context) ...@@ -2521,6 +2546,18 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
appendStringInfoChar(buf, ')'); appendStringInfoChar(buf, ')');
} }
} }
else if (rte->rtekind == RTE_RELATION &&
strcmp(rte->eref->aliasname, get_rel_name(rte->relid)) != 0)
{
/*
* Apparently the rel has been renamed since the rule was made.
* Emit a fake alias clause so that variable references will
* still work. This is not a 100% solution but should work in
* most reasonable situations.
*/
appendStringInfo(buf, " %s",
quote_identifier(rte->eref->aliasname));
}
} }
else if (IsA(jtnode, JoinExpr)) else if (IsA(jtnode, JoinExpr))
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment