Fix dumping of views that are just VALUES(...) but have column aliases.
authorTom Lane
Wed, 25 Feb 2015 17:01:12 +0000 (12:01 -0500)
committerTom Lane
Wed, 25 Feb 2015 17:01:12 +0000 (12:01 -0500)
The "simple" path for printing VALUES clauses doesn't work if we need
to attach nondefault column aliases, because there's noplace to do that
in the minimal VALUES() syntax.  So modify get_simple_values_rte() to
detect nondefault aliases and treat that as a non-simple case.  This
further exposes that the "non-simple" path never actually worked;
it didn't produce valid syntax.  Fix that too.  Per bug #12789 from
Curtis McEnroe, and analysis by Andrew Gierth.

Back-patch to all supported branches.  Before 9.3, this also requires
back-patching the part of commit 092d7ded29f36b0539046b23b81b9f0bf2d637f1
that created get_simple_values_rte() to begin with; inserting the extra
test into the old factorization of that logic would've been too messy.

src/backend/utils/adt/ruleutils.c
src/test/regress/expected/rules.out
src/test/regress/sql/rules.sql

index 18256a1bb8248eb684afff6d7246b115fee40379..578972bba254c20db39330fd9acefeae8418e67a 100644 (file)
@@ -4360,10 +4360,7 @@ get_simple_values_rte(Query *query)
    /*
     * We want to return TRUE even if the Query also contains OLD or NEW rule
     * RTEs.  So the idea is to scan the rtable and see if there is only one
-    * inFromCl RTE that is a VALUES RTE.  We don't look at the targetlist at
-    * all.  This is okay because parser/analyze.c will never generate a
-    * "bare" VALUES RTE --- they only appear inside auto-generated
-    * sub-queries with very restricted structure.
+    * inFromCl RTE that is a VALUES RTE.
     */
    foreach(lc, query->rtable)
    {
@@ -4380,6 +4377,33 @@ get_simple_values_rte(Query *query)
        else
            return NULL;        /* something else -> not simple VALUES */
    }
+
+   /*
+    * We don't need to check the targetlist in any great detail, because
+    * parser/analyze.c will never generate a "bare" VALUES RTE --- they only
+    * appear inside auto-generated sub-queries with very restricted
+    * structure.  However, DefineView might have modified the tlist by
+    * injecting new column aliases; so compare tlist resnames against the
+    * RTE's names to detect that.
+    */
+   if (result)
+   {
+       ListCell   *lcn;
+
+       if (list_length(query->targetList) != list_length(result->eref->colnames))
+           return NULL;        /* this probably cannot happen */
+       forboth(lc, query->targetList, lcn, result->eref->colnames)
+       {
+           TargetEntry *tle = (TargetEntry *) lfirst(lc);
+           char       *cname = strVal(lfirst(lcn));
+
+           if (tle->resjunk)
+               return NULL;    /* this probably cannot happen */
+           if (tle->resname == NULL || strcmp(tle->resname, cname) != 0)
+               return NULL;    /* column name has been changed */
+       }
+   }
+
    return result;
 }
 
@@ -8157,7 +8181,9 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
                break;
            case RTE_VALUES:
                /* Values list RTE */
+               appendStringInfoChar(buf, '(');
                get_values_def(rte->values_lists, context);
+               appendStringInfoChar(buf, ')');
                break;
            case RTE_CTE:
                appendStringInfoString(buf, quote_identifier(rte->ctename));
@@ -8199,6 +8225,11 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
             */
            printalias = true;
        }
+       else if (rte->rtekind == RTE_VALUES)
+       {
+           /* Alias is syntactically required for VALUES */
+           printalias = true;
+       }
        else if (rte->rtekind == RTE_CTE)
        {
            /*
index da5b177ae3631edf742e5fab4c8fd715292217bd..7251a289366be0495bb554a96091536cec0bb42e 100644 (file)
@@ -2631,3 +2631,56 @@ ALTER RULE "_RETURN" ON rule_v1 RENAME TO abc; -- ON SELECT rule cannot be renam
 ERROR:  renaming an ON SELECT rule is not allowed
 DROP VIEW rule_v1;
 DROP TABLE rule_t1;
+--
+-- check display of VALUES in view definitions
+--
+create view rule_v1 as values(1,2);
+\d+ rule_v1
+                 View "public.rule_v1"
+ Column  |  Type   | Modifiers | Storage | Description 
+---------+---------+-----------+---------+-------------
+ column1 | integer |           | plain   | 
+ column2 | integer |           | plain   | 
+View definition:
+ VALUES (1,2);
+
+drop view rule_v1;
+create view rule_v1(x) as values(1,2);
+\d+ rule_v1
+                 View "public.rule_v1"
+ Column  |  Type   | Modifiers | Storage | Description 
+---------+---------+-----------+---------+-------------
+ x       | integer |           | plain   | 
+ column2 | integer |           | plain   | 
+View definition:
+ SELECT "*VALUES*".column1 AS x,
+    "*VALUES*".column2
+   FROM (VALUES (1,2)) "*VALUES*";
+
+drop view rule_v1;
+create view rule_v1(x) as select * from (values(1,2)) v;
+\d+ rule_v1
+                 View "public.rule_v1"
+ Column  |  Type   | Modifiers | Storage | Description 
+---------+---------+-----------+---------+-------------
+ x       | integer |           | plain   | 
+ column2 | integer |           | plain   | 
+View definition:
+ SELECT v.column1 AS x,
+    v.column2
+   FROM ( VALUES (1,2)) v;
+
+drop view rule_v1;
+create view rule_v1(x) as select * from (values(1,2)) v(q,w);
+\d+ rule_v1
+                View "public.rule_v1"
+ Column |  Type   | Modifiers | Storage | Description 
+--------+---------+-----------+---------+-------------
+ x      | integer |           | plain   | 
+ w      | integer |           | plain   | 
+View definition:
+ SELECT v.q AS x,
+    v.w
+   FROM ( VALUES (1,2)) v(q, w);
+
+drop view rule_v1;
index d5a357108752b1e39b8963e543041c6eea7c9c3d..68b39ac270c92df89468a77a1ee3e538ba38081c 100644 (file)
@@ -1000,3 +1000,19 @@ ALTER RULE "_RETURN" ON rule_v1 RENAME TO abc; -- ON SELECT rule cannot be renam
 
 DROP VIEW rule_v1;
 DROP TABLE rule_t1;
+
+--
+-- check display of VALUES in view definitions
+--
+create view rule_v1 as values(1,2);
+\d+ rule_v1
+drop view rule_v1;
+create view rule_v1(x) as values(1,2);
+\d+ rule_v1
+drop view rule_v1;
+create view rule_v1(x) as select * from (values(1,2)) v;
+\d+ rule_v1
+drop view rule_v1;
+create view rule_v1(x) as select * from (values(1,2)) v(q,w);
+\d+ rule_v1
+drop view rule_v1;