Obtaining a more consistent view definition when a UNION subquery contains undecorated constants

From: Jimmy Yih <jyih(at)pivotal(dot)io>
To: pgsql-hackers(at)postgresql(dot)org
Cc: Jim Doty <jdoty(at)pivotal(dot)io>
Subject: Obtaining a more consistent view definition when a UNION subquery contains undecorated constants
Date: 2018-09-27 21:48:42
Message-ID: CAOMx_OBi4YGirtugHBQeuK2NL7SpqwxenUW+jQ7AhDGL0DPhjw@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hello,

A colleague and I were playing around with dumping views and found an
inconsistency for a view definition involving subqueries and undecorated
constants in a UNION. When we took that view definition and restored it,
dumping the view gave different syntax again. Although the slightly
different view definitions were semantically the same, it was weird to see
the syntax difference.

Our view SQL where 'bar' constant is not decorated:

CREATE VIEW fooview AS SELECT t.a FROM (SELECT 1 AS a, 'foo'::text AS baz
UNION SELECT 0 AS a, 'bar')t;
// view definition from pg_get_viewdef()
SELECT t.a
FROM ( SELECT 1 AS a,
'foo'::text AS baz
UNION
SELECT 0 AS a,
'bar'::text) t;

Note that the type decorator is appended to 'bar' in the normal fashion.

Then taking the above view definition, and creating a view,

CREATE VIEW fooview AS SELECT t.a FROM (SELECT 1 AS a, 'foo'::text AS baz
UNION SELECT 0 AS a, 'bar'::text)t;
// view definition from pg_get_viewdef()
SELECT t.a
FROM ( SELECT 1 AS a,
'foo'::text AS baz
UNION
SELECT 0 AS a,
'bar'::text AS text) t;

results in a view definition that has the alias 'AS text' appended to
'bar'::text.

Contrast this to creating a view without the subquery:

CREATE OR REPLACE VIEW fooview AS SELECT 1 AS a, 'foo'::text AS baz UNION
SELECT 0 AS a, 'bar';
// view definition from pg_get_viewdef()
SELECT 1 AS a,
'foo'::text AS baz
UNION
SELECT 0 AS a,
'bar'::text AS baz;

We see that this view will use the view's tuple descriptor to name the
columns.

Looking at the internal code (mostly get_from_clause_item() function), we
saw that when a subquery is used, there is no tuple descriptor passed to
get_query_def() function. Because of this, get_target_list() uses the
resnames obtained from the pg_rewrite entry's ev_action field. However, it
seems to be fairly simple to construct a dummy tuple descriptor from the
ev_action to pass down the call stack so that the column names will be
consistent when deparsing both T_A_Const and T_TypeCast parse tree nodes
involving a UNION. Attached is a patch that demonstrates this.

Running with the attached patch, it seems to work pretty well:

postgres=# CREATE VIEW fooview AS SELECT t.a FROM (SELECT 1 AS a,
'foo'::text AS baz UNION SELECT 0 AS a, 'bar')t;
postgres=# select pg_get_viewdef('fooview');
pg_get_viewdef
------------------------------------
SELECT t.a
FROM ( SELECT 1 AS a,
'foo'::text AS baz
UNION
SELECT 0 AS a,
'bar'::text AS baz) t;
(1 row)

postgres=# CREATE VIEW fooview AS SELECT t.a FROM (SELECT 1 AS a,
'foo'::text AS baz UNION SELECT 0 AS a, 'bar'::text)t;
postgres=# select pg_get_viewdef('fooview');
pg_get_viewdef
------------------------------------
SELECT t.a
FROM ( SELECT 1 AS a,
'foo'::text AS baz
UNION
SELECT 0 AS a,
'bar'::text AS baz) t;
(1 row)

Nested subqueries also work with the patch. We're not sure how this could
break.

Is this an acceptable change that should be pursued?

Regards,
Jimmy Yih and Jim Doty

Attachment Content-Type Size
view_union_subquery_constant.patch application/octet-stream 1.2 KB

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Stephen Frost 2018-09-27 21:55:56 Re: [PATCH] Include application_name in "connection authorized" log message
Previous Message Thomas Munro 2018-09-27 21:48:40 Re: Collation versioning