context->windowTList = save_windowtlist;
}
+/*
+ * Detect whether query looks like SELECT ... FROM VALUES();
+ * if so, return the VALUES RTE. Otherwise return NULL.
+ */
+static RangeTblEntry *
+get_simple_values_rte(Query *query)
+{
+ RangeTblEntry *result = NULL;
+ ListCell *lc;
+
+ /*
+ * 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.
+ */
+ foreach(lc, query->rtable)
+ {
+ RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
+
+ if (rte->rtekind == RTE_VALUES && rte->inFromCl)
+ {
+ if (result)
+ return NULL; /* multiple VALUES (probably not possible) */
+ result = rte;
+ }
+ else if (rte->rtekind == RTE_RELATION && !rte->inFromCl)
+ continue; /* ignore rule entries */
+ 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;
+}
+
static void
get_basic_select_query(Query *query, deparse_context *context,
TupleDesc resultDesc)
{
StringInfo buf = context->buf;
+ RangeTblEntry *values_rte;
char *sep;
ListCell *l;
/*
* If the query looks like SELECT * FROM (VALUES ...), then print just the
* VALUES part. This reverses what transformValuesClause() did at parse
- * time. If the jointree contains just a single VALUES RTE, we assume
- * this case applies (without looking at the targetlist...)
+ * time.
*/
- if (list_length(query->jointree->fromlist) == 1)
+ values_rte = get_simple_values_rte(query);
+ if (values_rte)
{
- RangeTblRef *rtr = (RangeTblRef *) linitial(query->jointree->fromlist);
-
- if (IsA(rtr, RangeTblRef))
- {
- RangeTblEntry *rte = rt_fetch(rtr->rtindex, query->rtable);
-
- if (rte->rtekind == RTE_VALUES)
- {
- get_values_def(rte->values_lists, context);
- return;
- }
- }
+ get_values_def(values_rte->values_lists, context);
+ return;
}
/*
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));
quote_identifier(rte->eref->aliasname));
gavealias = true;
}
+ else if (rte->rtekind == RTE_VALUES)
+ {
+ /* Alias is syntactically required for VALUES */
+ appendStringInfo(buf, " %s",
+ quote_identifier(rte->eref->aliasname));
+ gavealias = true;
+ }
if (rte->rtekind == RTE_FUNCTION)
{
WHERE sh.slunit = un.un_name;
(1 row)
+--
+-- 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;