aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2002-08-08 17:00:19 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2002-08-08 17:00:19 +0000
commit9459db8ea9c84444f53495c09f2908b353ff95ea (patch)
treed191340839f259a9e47c5828a218006c73cfe741
parentd176fad58059b7e652998a37da5cb9788ec7ea40 (diff)
downloadpostgresql-9459db8ea9c84444f53495c09f2908b353ff95ea.tar.gz
postgresql-9459db8ea9c84444f53495c09f2908b353ff95ea.zip
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.
-rw-r--r--src/backend/parser/parse_relation.c41
-rw-r--r--src/backend/utils/adt/ruleutils.c115
2 files changed, 100 insertions, 56 deletions
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index 229eab829a5..6713c665098 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.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)
return "*";
/*
- * If there is an alias, use it. (This path should always be taken
- * for non-relation RTEs.)
+ * If there is a user-written column alias, use it.
*/
- if (attnum > 0 && attnum <= length(rte->eref->colnames))
- return strVal(nth(attnum - 1, rte->eref->colnames));
+ if (rte->alias &&
+ 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 alias name list is too short (which probably can't happen
- * anymore). Neither of these cases is valid for a non-relation RTE.
+ * If the RTE is a relation, go to the system catalogs not the
+ * eref->colnames list. This is a little slower but it will give
+ * 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);
+ if (rte->rtekind == RTE_RELATION)
+ {
+ attname = get_attname(rte->relid, attnum);
+ if (attname == NULL)
+ elog(ERROR, "cache lookup of attribute %d in relation %u failed",
+ attnum, rte->relid);
+ return attname;
+ }
/*
- * Use the real name of the table's column
+ * Otherwise use the column name from eref. There should always be one.
*/
- attname = get_attname(rte->relid, attnum);
- if (attname == NULL)
- elog(ERROR, "cache lookup of attribute %d in relation %u failed",
- attnum, rte->relid);
- return attname;
+ 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 */
}
/*
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 98bbba534aa..302f9a75ce7 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -3,7 +3,7 @@
* back to source text
*
* 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.
*
@@ -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 void make_ruledef(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_select_query_def(Query *query, deparse_context *context);
+static void get_query_def(Query *query, StringInfo buf, List *parentnamespace,
+ 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_update_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_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,
- deparse_context *context);
+ deparse_context *context,
+ TupleDesc resultDesc);
static Node *get_rule_sortgroupclause(SortClause *srt, List *tlist,
bool force_colno,
deparse_context *context);
@@ -936,25 +940,22 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
foreach(action, actions)
{
query = (Query *) lfirst(action);
- get_query_def(query, buf, NIL);
+ get_query_def(query, buf, NIL, NULL);
appendStringInfo(buf, "; ");
}
appendStringInfo(buf, ");");
}
+ else if (length(actions) == 0)
+ {
+ appendStringInfo(buf, "NOTHING;");
+ }
else
{
- if (length(actions) == 0)
- {
- appendStringInfo(buf, "NOTHING;");
- }
- else
- {
- Query *query;
+ Query *query;
- query = (Query *) lfirst(actions);
- get_query_def(query, buf, NIL);
- appendStringInfo(buf, ";");
- }
+ query = (Query *) lfirst(actions);
+ get_query_def(query, buf, NIL, NULL);
+ appendStringInfo(buf, ";");
}
}
@@ -975,6 +976,7 @@ make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
char *ev_qual;
char *ev_action;
List *actions = NIL;
+ Relation ev_relation;
int fno;
bool isnull;
@@ -1010,25 +1012,31 @@ make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
query = (Query *) lfirst(actions);
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");
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, ";");
+
+ heap_close(ev_relation, AccessShareLock);
}
/* ----------
- * get_query_def - Parse back one action from
- * the parsetree in the actions
- * list
+ * get_query_def - Parse back one query parsetree
+ *
+ * If resultDesc is not NULL, then it is the output tuple descriptor for
+ * the view represented by a SELECT query.
* ----------
*/
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_namespace dpns;
@@ -1044,7 +1052,7 @@ get_query_def(Query *query, StringInfo buf, List *parentnamespace)
switch (query->commandType)
{
case CMD_SELECT:
- get_select_query_def(query, &context);
+ get_select_query_def(query, &context, resultDesc);
break;
case CMD_UPDATE:
@@ -1080,7 +1088,8 @@ get_query_def(Query *query, StringInfo buf, List *parentnamespace)
* ----------
*/
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;
bool force_colno;
@@ -1094,13 +1103,13 @@ get_select_query_def(Query *query, deparse_context *context)
*/
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 */
force_colno = true;
}
else
{
- get_basic_select_query(query, context);
+ get_basic_select_query(query, context, resultDesc);
force_colno = false;
}
@@ -1151,11 +1160,13 @@ get_select_query_def(Query *query, deparse_context *context)
}
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;
char *sep;
List *l;
+ int colno;
/*
* Build up the query string - first we say SELECT
@@ -1186,23 +1197,37 @@ get_basic_select_query(Query *query, deparse_context *context)
/* Then we tell what to select (the targetlist) */
sep = " ";
+ colno = 0;
foreach(l, query->targetList)
{
TargetEntry *tle = (TargetEntry *) lfirst(l);
bool tell_as = false;
+ char *colname;
if (tle->resdom->resjunk)
continue; /* ignore junk entries */
appendStringInfo(buf, sep);
sep = ", ";
+ colno++;
/* Do NOT use get_tle_expr here; see its comments! */
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 ... */
if (!IsA(tle->expr, Var))
- tell_as = (strcmp(tle->resdom->resname, "?column?") != 0);
+ tell_as = (strcmp(colname, "?column?") != 0);
else
{
Var *var = (Var *) (tle->expr);
@@ -1212,13 +1237,12 @@ get_basic_select_query(Query *query, deparse_context *context)
get_names_for_var(var, context, &schemaname, &refname, &attname);
tell_as = (attname == NULL ||
- strcmp(attname, tle->resdom->resname) != 0);
+ strcmp(attname, colname) != 0);
}
/* and do if so */
if (tell_as)
- appendStringInfo(buf, " AS %s",
- quote_identifier(tle->resdom->resname));
+ appendStringInfo(buf, " AS %s", quote_identifier(colname));
}
/* Add the FROM clause if needed */
@@ -1256,7 +1280,8 @@ get_basic_select_query(Query *query, deparse_context *context)
}
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;
@@ -1267,14 +1292,14 @@ get_setop_query(Node *setOp, Query *query, deparse_context *context)
Query *subquery = rte->subquery;
Assert(subquery != NULL);
- get_query_def(subquery, buf, context->namespaces);
+ get_query_def(subquery, buf, context->namespaces, resultDesc);
}
else if (IsA(setOp, SetOperationStmt))
{
SetOperationStmt *op = (SetOperationStmt *) setOp;
appendStringInfo(buf, "((");
- get_setop_query(op->larg, query, context);
+ get_setop_query(op->larg, query, context, resultDesc);
switch (op->op)
{
case SETOP_UNION:
@@ -1294,7 +1319,7 @@ get_setop_query(Node *setOp, Query *query, deparse_context *context)
appendStringInfo(buf, "ALL (");
else
appendStringInfo(buf, "(");
- get_setop_query(op->rarg, query, context);
+ get_setop_query(op->rarg, query, context, resultDesc);
appendStringInfo(buf, "))");
}
else
@@ -1405,7 +1430,7 @@ get_insert_query_def(Query *query, deparse_context *context)
appendStringInfoChar(buf, ')');
}
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)
if (need_paren)
appendStringInfoChar(buf, '(');
- get_query_def(query, buf, context->namespaces);
+ get_query_def(query, buf, context->namespaces, NULL);
if (need_paren)
appendStringInfo(buf, "))");
@@ -2491,7 +2516,7 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
case RTE_SUBQUERY:
/* Subquery RTE */
appendStringInfoChar(buf, '(');
- get_query_def(rte->subquery, buf, context->namespaces);
+ get_query_def(rte->subquery, buf, context->namespaces, NULL);
appendStringInfoChar(buf, ')');
break;
case RTE_FUNCTION:
@@ -2521,6 +2546,18 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
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))
{