From 5ec6b7f1b87f0fa006b8e08a11cd4e99bcb67358 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Sat, 1 Oct 2011 14:01:46 -0400
Subject: [PATCH] Improve generated column names for cases involving
 sub-SELECTs.

We'll now use "exists" for EXISTS(SELECT ...), "array" for ARRAY(SELECT
...), or the sub-select's own result column name for a simple expression
sub-select.  Previously, you usually got "?column?" in such cases.

Marti Raudsepp, reviewed by Kyotaro Horiugchi
---
 doc/src/sgml/ref/select.sgml             |  5 +--
 doc/src/sgml/syntax.sgml                 |  6 ++--
 src/backend/parser/parse_target.c        | 42 ++++++++++++++++++++++++
 src/test/regress/expected/aggregates.out |  6 ++--
 src/test/regress/expected/subselect.out  | 12 +++----
 src/test/regress/expected/with.out       |  4 +--
 6 files changed, 59 insertions(+), 16 deletions(-)

diff --git a/doc/src/sgml/ref/select.sgml b/doc/src/sgml/ref/select.sgml
index 7fb52833e8a..636435fe1d8 100644
--- a/doc/src/sgml/ref/select.sgml
+++ b/doc/src/sgml/ref/select.sgml
@@ -758,8 +758,9 @@ UNBOUNDED FOLLOWING
     If you do not specify a column name, a name is chosen automatically
     by <productname>PostgreSQL</productname>.  If the column's expression
     is a simple column reference then the chosen name is the same as that
-    column's name; in more complex cases a generated name looking like
-    <literal>?column<replaceable>N</>?</literal> is usually chosen.
+    column's name.  In more complex cases a function or type name may be
+    used, or the system may fall back on a generated name such as
+    <literal>?column?</literal>.
    </para>
 
    <para>
diff --git a/doc/src/sgml/syntax.sgml b/doc/src/sgml/syntax.sgml
index 9119b60792e..5ea755c5725 100644
--- a/doc/src/sgml/syntax.sgml
+++ b/doc/src/sgml/syntax.sgml
@@ -2109,9 +2109,9 @@ SELECT ARRAY[]::integer[];
    bracketed) subquery. For example:
 <programlisting>
 SELECT ARRAY(SELECT oid FROM pg_proc WHERE proname LIKE 'bytea%');
-                          ?column?
--------------------------------------------------------------
- {2011,1954,1948,1952,1951,1244,1950,2005,1949,1953,2006,31}
+                                 array
+-----------------------------------------------------------------------
+ {2011,1954,1948,1952,1951,1244,1950,2005,1949,1953,2006,31,2412,2413}
 (1 row)
 </programlisting>
    The subquery must return a single column. The resulting
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index 9d4e580e476..2f2e87fd698 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -1610,6 +1610,48 @@ FigureColnameInternal(Node *node, char **name)
 			break;
 		case T_CollateClause:
 			return FigureColnameInternal(((CollateClause *) node)->arg, name);
+		case T_SubLink:
+			switch (((SubLink *) node)->subLinkType)
+			{
+				case EXISTS_SUBLINK:
+					*name = "exists";
+					return 2;
+				case ARRAY_SUBLINK:
+					*name = "array";
+					return 2;
+				case EXPR_SUBLINK:
+					{
+						/* Get column name of the subquery's single target */
+						SubLink	   *sublink = (SubLink *) node;
+						Query	   *query = (Query *) sublink->subselect;
+
+						/*
+						 * The subquery has probably already been transformed,
+						 * but let's be careful and check that.  (The reason
+						 * we can see a transformed subquery here is that
+						 * transformSubLink is lazy and modifies the SubLink
+						 * node in-place.)
+						 */
+						if (IsA(query, Query))
+						{
+							TargetEntry *te = (TargetEntry *) linitial(query->targetList);
+
+							if (te->resname)
+							{
+								*name = te->resname;
+								return 2;
+							}
+						}
+					}
+					break;
+				/* As with other operator-like nodes, these have no names */
+				case ALL_SUBLINK:
+				case ANY_SUBLINK:
+				case ROWCOMPARE_SUBLINK:
+				case CTE_SUBLINK:
+					break;
+			}
+			break;
 		case T_CaseExpr:
 			strength = FigureColnameInternal((Node *) ((CaseExpr *) node)->defresult,
 											 name);
diff --git a/src/test/regress/expected/aggregates.out b/src/test/regress/expected/aggregates.out
index 48610066bbd..69926f7b79e 100644
--- a/src/test/regress/expected/aggregates.out
+++ b/src/test/regress/expected/aggregates.out
@@ -300,9 +300,9 @@ LINE 4:                where sum(distinct a.four + b.four) = b.four)...
 select
   (select max((select i.unique2 from tenk1 i where i.unique1 = o.unique1)))
 from tenk1 o;
- ?column? 
-----------
-     9999
+ max  
+------
+ 9999
 (1 row)
 
 --
diff --git a/src/test/regress/expected/subselect.out b/src/test/regress/expected/subselect.out
index e638f0a60c3..4ea8211c692 100644
--- a/src/test/regress/expected/subselect.out
+++ b/src/test/regress/expected/subselect.out
@@ -490,20 +490,20 @@ select view_a from view_a;
 (1 row)
 
 select (select view_a) from view_a;
- ?column? 
-----------
+ view_a 
+--------
  (42)
 (1 row)
 
 select (select (select view_a)) from view_a;
- ?column? 
-----------
+ view_a 
+--------
  (42)
 (1 row)
 
 select (select (a.*)::text) from view_a a;
- ?column? 
-----------
+  a   
+------
  (42)
 (1 row)
 
diff --git a/src/test/regress/expected/with.out b/src/test/regress/expected/with.out
index a1b089921d3..c4b045604b6 100644
--- a/src/test/regress/expected/with.out
+++ b/src/test/regress/expected/with.out
@@ -1065,7 +1065,7 @@ with cte(foo) as ( select 42 ) select * from ((select foo from cte)) q;
 select ( with cte(foo) as ( values(f1) )
          select (select foo from cte) )
 from int4_tbl;
-  ?column?   
+     foo     
 -------------
            0
       123456
@@ -1077,7 +1077,7 @@ from int4_tbl;
 select ( with cte(foo) as ( values(f1) )
           values((select foo from cte)) )
 from int4_tbl;
-  ?column?   
+   column1   
 -------------
            0
       123456
-- 
GitLab