@@ -2687,11 +2687,72 @@ get_select_query_def(Query *query, deparse_context *context,
2687
2687
context -> windowTList = save_windowtlist ;
2688
2688
}
2689
2689
2690
+ /*
2691
+ * Detect whether query looks like SELECT ... FROM VALUES();
2692
+ * if so, return the VALUES RTE. Otherwise return NULL.
2693
+ */
2694
+ static RangeTblEntry *
2695
+ get_simple_values_rte (Query * query )
2696
+ {
2697
+ RangeTblEntry * result = NULL ;
2698
+ ListCell * lc ;
2699
+
2700
+ /*
2701
+ * We want to return TRUE even if the Query also contains OLD or NEW rule
2702
+ * RTEs. So the idea is to scan the rtable and see if there is only one
2703
+ * inFromCl RTE that is a VALUES RTE.
2704
+ */
2705
+ foreach (lc , query -> rtable )
2706
+ {
2707
+ RangeTblEntry * rte = (RangeTblEntry * ) lfirst (lc );
2708
+
2709
+ if (rte -> rtekind == RTE_VALUES && rte -> inFromCl )
2710
+ {
2711
+ if (result )
2712
+ return NULL ; /* multiple VALUES (probably not possible) */
2713
+ result = rte ;
2714
+ }
2715
+ else if (rte -> rtekind == RTE_RELATION && !rte -> inFromCl )
2716
+ continue ; /* ignore rule entries */
2717
+ else
2718
+ return NULL ; /* something else -> not simple VALUES */
2719
+ }
2720
+
2721
+ /*
2722
+ * We don't need to check the targetlist in any great detail, because
2723
+ * parser/analyze.c will never generate a "bare" VALUES RTE --- they only
2724
+ * appear inside auto-generated sub-queries with very restricted
2725
+ * structure. However, DefineView might have modified the tlist by
2726
+ * injecting new column aliases; so compare tlist resnames against the
2727
+ * RTE's names to detect that.
2728
+ */
2729
+ if (result )
2730
+ {
2731
+ ListCell * lcn ;
2732
+
2733
+ if (list_length (query -> targetList ) != list_length (result -> eref -> colnames ))
2734
+ return NULL ; /* this probably cannot happen */
2735
+ forboth (lc , query -> targetList , lcn , result -> eref -> colnames )
2736
+ {
2737
+ TargetEntry * tle = (TargetEntry * ) lfirst (lc );
2738
+ char * cname = strVal (lfirst (lcn ));
2739
+
2740
+ if (tle -> resjunk )
2741
+ return NULL ; /* this probably cannot happen */
2742
+ if (tle -> resname == NULL || strcmp (tle -> resname , cname ) != 0 )
2743
+ return NULL ; /* column name has been changed */
2744
+ }
2745
+ }
2746
+
2747
+ return result ;
2748
+ }
2749
+
2690
2750
static void
2691
2751
get_basic_select_query (Query * query , deparse_context * context ,
2692
2752
TupleDesc resultDesc )
2693
2753
{
2694
2754
StringInfo buf = context -> buf ;
2755
+ RangeTblEntry * values_rte ;
2695
2756
char * sep ;
2696
2757
ListCell * l ;
2697
2758
@@ -2704,23 +2765,13 @@ get_basic_select_query(Query *query, deparse_context *context,
2704
2765
/*
2705
2766
* If the query looks like SELECT * FROM (VALUES ...), then print just the
2706
2767
* VALUES part. This reverses what transformValuesClause() did at parse
2707
- * time. If the jointree contains just a single VALUES RTE, we assume
2708
- * this case applies (without looking at the targetlist...)
2768
+ * time.
2709
2769
*/
2710
- if (list_length (query -> jointree -> fromlist ) == 1 )
2770
+ values_rte = get_simple_values_rte (query );
2771
+ if (values_rte )
2711
2772
{
2712
- RangeTblRef * rtr = (RangeTblRef * ) linitial (query -> jointree -> fromlist );
2713
-
2714
- if (IsA (rtr , RangeTblRef ))
2715
- {
2716
- RangeTblEntry * rte = rt_fetch (rtr -> rtindex , query -> rtable );
2717
-
2718
- if (rte -> rtekind == RTE_VALUES )
2719
- {
2720
- get_values_def (rte -> values_lists , context );
2721
- return ;
2722
- }
2723
- }
2773
+ get_values_def (values_rte -> values_lists , context );
2774
+ return ;
2724
2775
}
2725
2776
2726
2777
/*
@@ -6099,7 +6150,9 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
6099
6150
break ;
6100
6151
case RTE_VALUES :
6101
6152
/* Values list RTE */
6153
+ appendStringInfoChar (buf , '(' );
6102
6154
get_values_def (rte -> values_lists , context );
6155
+ appendStringInfoChar (buf , ')' );
6103
6156
break ;
6104
6157
case RTE_CTE :
6105
6158
appendStringInfoString (buf , quote_identifier (rte -> ctename ));
@@ -6139,6 +6192,13 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
6139
6192
quote_identifier (rte -> eref -> aliasname ));
6140
6193
gavealias = true;
6141
6194
}
6195
+ else if (rte -> rtekind == RTE_VALUES )
6196
+ {
6197
+ /* Alias is syntactically required for VALUES */
6198
+ appendStringInfo (buf , " %s" ,
6199
+ quote_identifier (rte -> eref -> aliasname ));
6200
+ gavealias = true;
6201
+ }
6142
6202
6143
6203
if (rte -> rtekind == RTE_FUNCTION )
6144
6204
{
0 commit comments