Commit 2ffa740b authored by Tom Lane's avatar Tom Lane

Fix ruleutils to cope with conflicts from adding/dropping/renaming columns.

In commit 11e13185, we improved the
rule/view dumping code so that it would produce valid query representations
even if some of the tables involved in a query had been renamed since the
query was parsed.  This patch extends that idea to fix problems that occur
when individual columns are renamed, or added or dropped.  As before, the
core of the fix is to assign unique new aliases when a name conflict has
been created.  This is complicated by the JOIN USING feature, which
requires the same column alias to be used in both input relations, but we
can handle that with a sufficiently complex approach to assigning aliases.

A fortiori, this patch takes care of situations where the query didn't have
unique column names to begin with, such as in a recent complaint from Bryan
Nuse.  (Because of expansion of "SELECT *", re-parsing a dumped query can
require column name uniqueness even though the original text did not.)
parent 7eb559a8
...@@ -653,9 +653,9 @@ elapsed_time(instr_time *starttime) ...@@ -653,9 +653,9 @@ elapsed_time(instr_time *starttime)
* Prescan the planstate tree to identify which RTEs are referenced * Prescan the planstate tree to identify which RTEs are referenced
* *
* Adds the relid of each referenced RTE to *rels_used. The result controls * Adds the relid of each referenced RTE to *rels_used. The result controls
* which RTEs are assigned aliases by select_rtable_names_for_explain. This * which RTEs are assigned aliases by select_rtable_names_for_explain.
* ensures that we don't confusingly assign un-suffixed aliases to RTEs that * This ensures that we don't confusingly assign un-suffixed aliases to RTEs
* never appear in the EXPLAIN output (such as inheritance parents). * that never appear in the EXPLAIN output (such as inheritance parents).
*/ */
static void static void
ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used) ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
...@@ -1954,6 +1954,8 @@ ExplainTargetRel(Plan *plan, Index rti, ExplainState *es) ...@@ -1954,6 +1954,8 @@ ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
rte = rt_fetch(rti, es->rtable); rte = rt_fetch(rti, es->rtable);
refname = (char *) list_nth(es->rtable_names, rti - 1); refname = (char *) list_nth(es->rtable_names, rti - 1);
if (refname == NULL)
refname = rte->eref->aliasname;
switch (nodeTag(plan)) switch (nodeTag(plan))
{ {
...@@ -2026,8 +2028,7 @@ ExplainTargetRel(Plan *plan, Index rti, ExplainState *es) ...@@ -2026,8 +2028,7 @@ ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
quote_identifier(objectname)); quote_identifier(objectname));
else if (objectname != NULL) else if (objectname != NULL)
appendStringInfo(es->str, " %s", quote_identifier(objectname)); appendStringInfo(es->str, " %s", quote_identifier(objectname));
if (refname != NULL && if (objectname == NULL || strcmp(refname, objectname) != 0)
(objectname == NULL || strcmp(refname, objectname) != 0))
appendStringInfo(es->str, " %s", quote_identifier(refname)); appendStringInfo(es->str, " %s", quote_identifier(refname));
} }
else else
...@@ -2036,8 +2037,7 @@ ExplainTargetRel(Plan *plan, Index rti, ExplainState *es) ...@@ -2036,8 +2037,7 @@ ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
ExplainPropertyText(objecttag, objectname, es); ExplainPropertyText(objecttag, objectname, es);
if (namespace != NULL) if (namespace != NULL)
ExplainPropertyText("Schema", namespace, es); ExplainPropertyText("Schema", namespace, es);
if (refname != NULL) ExplainPropertyText("Alias", refname, es);
ExplainPropertyText("Alias", refname, es);
} }
} }
......
...@@ -888,9 +888,7 @@ DefineDomain(CreateDomainStmt *stmt) ...@@ -888,9 +888,7 @@ DefineDomain(CreateDomainStmt *stmt)
*/ */
defaultValue = defaultValue =
deparse_expression(defaultExpr, deparse_expression(defaultExpr,
deparse_context_for(domainName, NIL, false, false);
InvalidOid),
false, false);
defaultValueBin = nodeToString(defaultExpr); defaultValueBin = nodeToString(defaultExpr);
} }
} }
...@@ -2143,9 +2141,7 @@ AlterDomainDefault(List *names, Node *defaultRaw) ...@@ -2143,9 +2141,7 @@ AlterDomainDefault(List *names, Node *defaultRaw)
* easier for pg_dump). * easier for pg_dump).
*/ */
defaultValue = deparse_expression(defaultExpr, defaultValue = deparse_expression(defaultExpr,
deparse_context_for(NameStr(typTup->typname), NIL, false, false);
InvalidOid),
false, false);
/* /*
* Form an updated tuple with the new default and write it back. * Form an updated tuple with the new default and write it back.
...@@ -2941,14 +2937,9 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, ...@@ -2941,14 +2937,9 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
/* /*
* Deparse it to produce text for consrc. * Deparse it to produce text for consrc.
*
* Since VARNOs aren't allowed in domain constraints, relation context
* isn't required as anything other than a shell.
*/ */
ccsrc = deparse_expression(expr, ccsrc = deparse_expression(expr,
deparse_context_for(domainName, NIL, false, false);
InvalidOid),
false, false);
/* /*
* Store the constraint in pg_constraint * Store the constraint in pg_constraint
......
This diff is collapsed.
This diff is collapsed.
...@@ -224,7 +224,7 @@ SELECT relname, relkind, reloptions FROM pg_class ...@@ -224,7 +224,7 @@ SELECT relname, relkind, reloptions FROM pg_class
'mysecview3'::regclass, 'mysecview4'::regclass) 'mysecview3'::regclass, 'mysecview4'::regclass)
ORDER BY relname; ORDER BY relname;
-- Test view decompilation in the face of renaming conflicts -- Test view decompilation in the face of relation renaming conflicts
CREATE TABLE tt1 (f1 int, f2 int, f3 text); CREATE TABLE tt1 (f1 int, f2 int, f3 text);
CREATE TABLE tx1 (x1 int, x2 int, x3 text); CREATE TABLE tx1 (x1 int, x2 int, x3 text);
...@@ -286,7 +286,110 @@ ALTER TABLE tmp1 RENAME TO tx1; ...@@ -286,7 +286,110 @@ ALTER TABLE tmp1 RENAME TO tx1;
\d+ aliased_view_3 \d+ aliased_view_3
\d+ aliased_view_4 \d+ aliased_view_4
-- Test view decompilation in the face of column addition/deletion/renaming
create table tt2 (a int, b int, c int);
create table tt3 (ax int8, b int2, c numeric);
create table tt4 (ay int, b int, q int);
create view v1 as select * from tt2 natural join tt3;
create view v1a as select * from (tt2 natural join tt3) j;
create view v2 as select * from tt2 join tt3 using (b,c) join tt4 using (b);
create view v2a as select * from (tt2 join tt3 using (b,c) join tt4 using (b)) j;
create view v3 as select * from tt2 join tt3 using (b,c) full join tt4 using (b);
select pg_get_viewdef('v1', true);
select pg_get_viewdef('v1a', true);
select pg_get_viewdef('v2', true);
select pg_get_viewdef('v2a', true);
select pg_get_viewdef('v3', true);
alter table tt2 add column d int;
alter table tt2 add column e int;
select pg_get_viewdef('v1', true);
select pg_get_viewdef('v1a', true);
select pg_get_viewdef('v2', true);
select pg_get_viewdef('v2a', true);
select pg_get_viewdef('v3', true);
alter table tt3 rename c to d;
select pg_get_viewdef('v1', true);
select pg_get_viewdef('v1a', true);
select pg_get_viewdef('v2', true);
select pg_get_viewdef('v2a', true);
select pg_get_viewdef('v3', true);
alter table tt3 add column c int;
alter table tt3 add column e int;
select pg_get_viewdef('v1', true);
select pg_get_viewdef('v1a', true);
select pg_get_viewdef('v2', true);
select pg_get_viewdef('v2a', true);
select pg_get_viewdef('v3', true);
alter table tt2 drop column d;
select pg_get_viewdef('v1', true);
select pg_get_viewdef('v1a', true);
select pg_get_viewdef('v2', true);
select pg_get_viewdef('v2a', true);
select pg_get_viewdef('v3', true);
create table tt5 (a int, b int);
create table tt6 (c int, d int);
create view vv1 as select * from (tt5 cross join tt6) j(aa,bb,cc,dd);
select pg_get_viewdef('vv1', true);
alter table tt5 add column c int;
select pg_get_viewdef('vv1', true);
alter table tt5 add column cc int;
select pg_get_viewdef('vv1', true);
alter table tt5 drop column c;
select pg_get_viewdef('vv1', true);
-- Unnamed FULL JOIN USING is lots of fun too
create table tt7 (x int, xx int, y int);
alter table tt7 drop column xx;
create table tt8 (x int, z int);
create view vv2 as
select * from (values(1,2,3,4,5)) v(a,b,c,d,e)
union all
select * from tt7 full join tt8 using (x), tt8 tt8x;
select pg_get_viewdef('vv2', true);
create view vv3 as
select * from (values(1,2,3,4,5,6)) v(a,b,c,x,e,f)
union all
select * from
tt7 full join tt8 using (x),
tt7 tt7x full join tt8 tt8x using (x);
select pg_get_viewdef('vv3', true);
create view vv4 as
select * from (values(1,2,3,4,5,6,7)) v(a,b,c,x,e,f,g)
union all
select * from
tt7 full join tt8 using (x),
tt7 tt7x full join tt8 tt8x using (x) full join tt8 tt8y using (x);
select pg_get_viewdef('vv4', true);
alter table tt7 add column zz int;
alter table tt7 add column z int;
alter table tt7 drop column zz;
alter table tt8 add column z2 int;
select pg_get_viewdef('vv2', true);
select pg_get_viewdef('vv3', true);
select pg_get_viewdef('vv4', true);
-- clean up all the random objects we made above
set client_min_messages = warning;
DROP SCHEMA temp_view_test CASCADE; DROP SCHEMA temp_view_test CASCADE;
DROP SCHEMA testviewschm2 CASCADE; DROP SCHEMA testviewschm2 CASCADE;
SET search_path to public;
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