Skip to content

Commit 9459db8

Browse files
committed
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.
1 parent d176fad commit 9459db8

File tree

2 files changed

+100
-56
lines changed

2 files changed

+100
-56
lines changed

src/backend/parser/parse_relation.c

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.76 2002/08/08 01:44:30 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.77 2002/08/08 17:00:19 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -1499,29 +1499,36 @@ get_rte_attribute_name(RangeTblEntry *rte, AttrNumber attnum)
14991499
return "*";
15001500

15011501
/*
1502-
* If there is an alias, use it. (This path should always be taken
1503-
* for non-relation RTEs.)
1502+
* If there is a user-written column alias, use it.
15041503
*/
1505-
if (attnum > 0 && attnum <= length(rte->eref->colnames))
1506-
return strVal(nth(attnum - 1, rte->eref->colnames));
1504+
if (rte->alias &&
1505+
attnum > 0 && attnum <= length(rte->alias->colnames))
1506+
return strVal(nth(attnum - 1, rte->alias->colnames));
15071507

15081508
/*
1509-
* Can get here for a system attribute (which never has an alias), or
1510-
* if alias name list is too short (which probably can't happen
1511-
* anymore). Neither of these cases is valid for a non-relation RTE.
1509+
* If the RTE is a relation, go to the system catalogs not the
1510+
* eref->colnames list. This is a little slower but it will give
1511+
* the right answer if the column has been renamed since the eref
1512+
* list was built (which can easily happen for rules).
15121513
*/
1513-
if (rte->rtekind != RTE_RELATION)
1514-
elog(ERROR, "Invalid attnum %d for rangetable entry %s",
1515-
attnum, rte->eref->aliasname);
1514+
if (rte->rtekind == RTE_RELATION)
1515+
{
1516+
attname = get_attname(rte->relid, attnum);
1517+
if (attname == NULL)
1518+
elog(ERROR, "cache lookup of attribute %d in relation %u failed",
1519+
attnum, rte->relid);
1520+
return attname;
1521+
}
15161522

15171523
/*
1518-
* Use the real name of the table's column
1524+
* Otherwise use the column name from eref. There should always be one.
15191525
*/
1520-
attname = get_attname(rte->relid, attnum);
1521-
if (attname == NULL)
1522-
elog(ERROR, "cache lookup of attribute %d in relation %u failed",
1523-
attnum, rte->relid);
1524-
return attname;
1526+
if (attnum > 0 && attnum <= length(rte->eref->colnames))
1527+
return strVal(nth(attnum - 1, rte->eref->colnames));
1528+
1529+
elog(ERROR, "Invalid attnum %d for rangetable entry %s",
1530+
attnum, rte->eref->aliasname);
1531+
return NULL; /* keep compiler quiet */
15251532
}
15261533

15271534
/*

src/backend/utils/adt/ruleutils.c

Lines changed: 76 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* back to source text
44
*
55
* IDENTIFICATION
6-
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.113 2002/08/08 01:44:31 tgl Exp $
6+
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.114 2002/08/08 17:00:19 tgl Exp $
77
*
88
* This software is copyrighted by Jan Wieck - Hamburg.
99
*
@@ -118,15 +118,19 @@ static char *query_getviewrule = "SELECT * FROM pg_catalog.pg_rewrite WHERE ev_c
118118
static text *pg_do_getviewdef(Oid viewoid);
119119
static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc);
120120
static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc);
121-
static void get_query_def(Query *query, StringInfo buf, List *parentnamespace);
122-
static void get_select_query_def(Query *query, deparse_context *context);
121+
static void get_query_def(Query *query, StringInfo buf, List *parentnamespace,
122+
TupleDesc resultDesc);
123+
static void get_select_query_def(Query *query, deparse_context *context,
124+
TupleDesc resultDesc);
123125
static void get_insert_query_def(Query *query, deparse_context *context);
124126
static void get_update_query_def(Query *query, deparse_context *context);
125127
static void get_delete_query_def(Query *query, deparse_context *context);
126128
static void get_utility_query_def(Query *query, deparse_context *context);
127-
static void get_basic_select_query(Query *query, deparse_context *context);
129+
static void get_basic_select_query(Query *query, deparse_context *context,
130+
TupleDesc resultDesc);
128131
static void get_setop_query(Node *setOp, Query *query,
129-
deparse_context *context);
132+
deparse_context *context,
133+
TupleDesc resultDesc);
130134
static Node *get_rule_sortgroupclause(SortClause *srt, List *tlist,
131135
bool force_colno,
132136
deparse_context *context);
@@ -936,25 +940,22 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
936940
foreach(action, actions)
937941
{
938942
query = (Query *) lfirst(action);
939-
get_query_def(query, buf, NIL);
943+
get_query_def(query, buf, NIL, NULL);
940944
appendStringInfo(buf, "; ");
941945
}
942946
appendStringInfo(buf, ");");
943947
}
948+
else if (length(actions) == 0)
949+
{
950+
appendStringInfo(buf, "NOTHING;");
951+
}
944952
else
945953
{
946-
if (length(actions) == 0)
947-
{
948-
appendStringInfo(buf, "NOTHING;");
949-
}
950-
else
951-
{
952-
Query *query;
954+
Query *query;
953955

954-
query = (Query *) lfirst(actions);
955-
get_query_def(query, buf, NIL);
956-
appendStringInfo(buf, ";");
957-
}
956+
query = (Query *) lfirst(actions);
957+
get_query_def(query, buf, NIL, NULL);
958+
appendStringInfo(buf, ";");
958959
}
959960
}
960961

@@ -975,6 +976,7 @@ make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
975976
char *ev_qual;
976977
char *ev_action;
977978
List *actions = NIL;
979+
Relation ev_relation;
978980
int fno;
979981
bool isnull;
980982

@@ -1010,25 +1012,31 @@ make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
10101012
query = (Query *) lfirst(actions);
10111013

10121014
if (ev_type != '1' || ev_attr >= 0 || !is_instead ||
1013-
strcmp(ev_qual, "<>") != 0)
1015+
strcmp(ev_qual, "<>") != 0 || query->commandType != CMD_SELECT)
10141016
{
10151017
appendStringInfo(buf, "Not a view");
10161018
return;
10171019
}
10181020

1019-
get_query_def(query, buf, NIL);
1021+
ev_relation = heap_open(ev_class, AccessShareLock);
1022+
1023+
get_query_def(query, buf, NIL, RelationGetDescr(ev_relation));
10201024
appendStringInfo(buf, ";");
1025+
1026+
heap_close(ev_relation, AccessShareLock);
10211027
}
10221028

10231029

10241030
/* ----------
1025-
* get_query_def - Parse back one action from
1026-
* the parsetree in the actions
1027-
* list
1031+
* get_query_def - Parse back one query parsetree
1032+
*
1033+
* If resultDesc is not NULL, then it is the output tuple descriptor for
1034+
* the view represented by a SELECT query.
10281035
* ----------
10291036
*/
10301037
static void
1031-
get_query_def(Query *query, StringInfo buf, List *parentnamespace)
1038+
get_query_def(Query *query, StringInfo buf, List *parentnamespace,
1039+
TupleDesc resultDesc)
10321040
{
10331041
deparse_context context;
10341042
deparse_namespace dpns;
@@ -1044,7 +1052,7 @@ get_query_def(Query *query, StringInfo buf, List *parentnamespace)
10441052
switch (query->commandType)
10451053
{
10461054
case CMD_SELECT:
1047-
get_select_query_def(query, &context);
1055+
get_select_query_def(query, &context, resultDesc);
10481056
break;
10491057

10501058
case CMD_UPDATE:
@@ -1080,7 +1088,8 @@ get_query_def(Query *query, StringInfo buf, List *parentnamespace)
10801088
* ----------
10811089
*/
10821090
static void
1083-
get_select_query_def(Query *query, deparse_context *context)
1091+
get_select_query_def(Query *query, deparse_context *context,
1092+
TupleDesc resultDesc)
10841093
{
10851094
StringInfo buf = context->buf;
10861095
bool force_colno;
@@ -1094,13 +1103,13 @@ get_select_query_def(Query *query, deparse_context *context)
10941103
*/
10951104
if (query->setOperations)
10961105
{
1097-
get_setop_query(query->setOperations, query, context);
1106+
get_setop_query(query->setOperations, query, context, resultDesc);
10981107
/* ORDER BY clauses must be simple in this case */
10991108
force_colno = true;
11001109
}
11011110
else
11021111
{
1103-
get_basic_select_query(query, context);
1112+
get_basic_select_query(query, context, resultDesc);
11041113
force_colno = false;
11051114
}
11061115

@@ -1151,11 +1160,13 @@ get_select_query_def(Query *query, deparse_context *context)
11511160
}
11521161

11531162
static void
1154-
get_basic_select_query(Query *query, deparse_context *context)
1163+
get_basic_select_query(Query *query, deparse_context *context,
1164+
TupleDesc resultDesc)
11551165
{
11561166
StringInfo buf = context->buf;
11571167
char *sep;
11581168
List *l;
1169+
int colno;
11591170

11601171
/*
11611172
* Build up the query string - first we say SELECT
@@ -1186,23 +1197,37 @@ get_basic_select_query(Query *query, deparse_context *context)
11861197

11871198
/* Then we tell what to select (the targetlist) */
11881199
sep = " ";
1200+
colno = 0;
11891201
foreach(l, query->targetList)
11901202
{
11911203
TargetEntry *tle = (TargetEntry *) lfirst(l);
11921204
bool tell_as = false;
1205+
char *colname;
11931206

11941207
if (tle->resdom->resjunk)
11951208
continue; /* ignore junk entries */
11961209

11971210
appendStringInfo(buf, sep);
11981211
sep = ", ";
1212+
colno++;
11991213

12001214
/* Do NOT use get_tle_expr here; see its comments! */
12011215
get_rule_expr(tle->expr, context);
12021216

1217+
/*
1218+
* Figure out what the result column should be called. In the
1219+
* context of a view, use the view's tuple descriptor (so as to
1220+
* pick up the effects of any column RENAME that's been done on the
1221+
* view). Otherwise, just use what we can find in the TLE.
1222+
*/
1223+
if (resultDesc && colno <= resultDesc->natts)
1224+
colname = NameStr(resultDesc->attrs[colno-1]->attname);
1225+
else
1226+
colname = tle->resdom->resname;
1227+
12031228
/* Check if we must say AS ... */
12041229
if (!IsA(tle->expr, Var))
1205-
tell_as = (strcmp(tle->resdom->resname, "?column?") != 0);
1230+
tell_as = (strcmp(colname, "?column?") != 0);
12061231
else
12071232
{
12081233
Var *var = (Var *) (tle->expr);
@@ -1212,13 +1237,12 @@ get_basic_select_query(Query *query, deparse_context *context)
12121237

12131238
get_names_for_var(var, context, &schemaname, &refname, &attname);
12141239
tell_as = (attname == NULL ||
1215-
strcmp(attname, tle->resdom->resname) != 0);
1240+
strcmp(attname, colname) != 0);
12161241
}
12171242

12181243
/* and do if so */
12191244
if (tell_as)
1220-
appendStringInfo(buf, " AS %s",
1221-
quote_identifier(tle->resdom->resname));
1245+
appendStringInfo(buf, " AS %s", quote_identifier(colname));
12221246
}
12231247

12241248
/* Add the FROM clause if needed */
@@ -1256,7 +1280,8 @@ get_basic_select_query(Query *query, deparse_context *context)
12561280
}
12571281

12581282
static void
1259-
get_setop_query(Node *setOp, Query *query, deparse_context *context)
1283+
get_setop_query(Node *setOp, Query *query, deparse_context *context,
1284+
TupleDesc resultDesc)
12601285
{
12611286
StringInfo buf = context->buf;
12621287

@@ -1267,14 +1292,14 @@ get_setop_query(Node *setOp, Query *query, deparse_context *context)
12671292
Query *subquery = rte->subquery;
12681293

12691294
Assert(subquery != NULL);
1270-
get_query_def(subquery, buf, context->namespaces);
1295+
get_query_def(subquery, buf, context->namespaces, resultDesc);
12711296
}
12721297
else if (IsA(setOp, SetOperationStmt))
12731298
{
12741299
SetOperationStmt *op = (SetOperationStmt *) setOp;
12751300

12761301
appendStringInfo(buf, "((");
1277-
get_setop_query(op->larg, query, context);
1302+
get_setop_query(op->larg, query, context, resultDesc);
12781303
switch (op->op)
12791304
{
12801305
case SETOP_UNION:
@@ -1294,7 +1319,7 @@ get_setop_query(Node *setOp, Query *query, deparse_context *context)
12941319
appendStringInfo(buf, "ALL (");
12951320
else
12961321
appendStringInfo(buf, "(");
1297-
get_setop_query(op->rarg, query, context);
1322+
get_setop_query(op->rarg, query, context, resultDesc);
12981323
appendStringInfo(buf, "))");
12991324
}
13001325
else
@@ -1405,7 +1430,7 @@ get_insert_query_def(Query *query, deparse_context *context)
14051430
appendStringInfoChar(buf, ')');
14061431
}
14071432
else
1408-
get_query_def(select_rte->subquery, buf, NIL);
1433+
get_query_def(select_rte->subquery, buf, NIL, NULL);
14091434
}
14101435

14111436

@@ -2418,7 +2443,7 @@ get_sublink_expr(Node *node, deparse_context *context)
24182443
if (need_paren)
24192444
appendStringInfoChar(buf, '(');
24202445

2421-
get_query_def(query, buf, context->namespaces);
2446+
get_query_def(query, buf, context->namespaces, NULL);
24222447

24232448
if (need_paren)
24242449
appendStringInfo(buf, "))");
@@ -2491,7 +2516,7 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
24912516
case RTE_SUBQUERY:
24922517
/* Subquery RTE */
24932518
appendStringInfoChar(buf, '(');
2494-
get_query_def(rte->subquery, buf, context->namespaces);
2519+
get_query_def(rte->subquery, buf, context->namespaces, NULL);
24952520
appendStringInfoChar(buf, ')');
24962521
break;
24972522
case RTE_FUNCTION:
@@ -2521,6 +2546,18 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
25212546
appendStringInfoChar(buf, ')');
25222547
}
25232548
}
2549+
else if (rte->rtekind == RTE_RELATION &&
2550+
strcmp(rte->eref->aliasname, get_rel_name(rte->relid)) != 0)
2551+
{
2552+
/*
2553+
* Apparently the rel has been renamed since the rule was made.
2554+
* Emit a fake alias clause so that variable references will
2555+
* still work. This is not a 100% solution but should work in
2556+
* most reasonable situations.
2557+
*/
2558+
appendStringInfo(buf, " %s",
2559+
quote_identifier(rte->eref->aliasname));
2560+
}
25242561
}
25252562
else if (IsA(jtnode, JoinExpr))
25262563
{

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy