@@ -2878,11 +2878,72 @@ get_select_query_def(Query *query, deparse_context *context,
2878
2878
context -> windowTList = save_windowtlist ;
2879
2879
}
2880
2880
2881
+ /*
2882
+ * Detect whether query looks like SELECT ... FROM VALUES();
2883
+ * if so, return the VALUES RTE. Otherwise return NULL.
2884
+ */
2885
+ static RangeTblEntry *
2886
+ get_simple_values_rte (Query * query )
2887
+ {
2888
+ RangeTblEntry * result = NULL ;
2889
+ ListCell * lc ;
2890
+
2891
+ /*
2892
+ * We want to return TRUE even if the Query also contains OLD or NEW rule
2893
+ * RTEs. So the idea is to scan the rtable and see if there is only one
2894
+ * inFromCl RTE that is a VALUES RTE.
2895
+ */
2896
+ foreach (lc , query -> rtable )
2897
+ {
2898
+ RangeTblEntry * rte = (RangeTblEntry * ) lfirst (lc );
2899
+
2900
+ if (rte -> rtekind == RTE_VALUES && rte -> inFromCl )
2901
+ {
2902
+ if (result )
2903
+ return NULL ; /* multiple VALUES (probably not possible) */
2904
+ result = rte ;
2905
+ }
2906
+ else if (rte -> rtekind == RTE_RELATION && !rte -> inFromCl )
2907
+ continue ; /* ignore rule entries */
2908
+ else
2909
+ return NULL ; /* something else -> not simple VALUES */
2910
+ }
2911
+
2912
+ /*
2913
+ * We don't need to check the targetlist in any great detail, because
2914
+ * parser/analyze.c will never generate a "bare" VALUES RTE --- they only
2915
+ * appear inside auto-generated sub-queries with very restricted
2916
+ * structure. However, DefineView might have modified the tlist by
2917
+ * injecting new column aliases; so compare tlist resnames against the
2918
+ * RTE's names to detect that.
2919
+ */
2920
+ if (result )
2921
+ {
2922
+ ListCell * lcn ;
2923
+
2924
+ if (list_length (query -> targetList ) != list_length (result -> eref -> colnames ))
2925
+ return NULL ; /* this probably cannot happen */
2926
+ forboth (lc , query -> targetList , lcn , result -> eref -> colnames )
2927
+ {
2928
+ TargetEntry * tle = (TargetEntry * ) lfirst (lc );
2929
+ char * cname = strVal (lfirst (lcn ));
2930
+
2931
+ if (tle -> resjunk )
2932
+ return NULL ; /* this probably cannot happen */
2933
+ if (tle -> resname == NULL || strcmp (tle -> resname , cname ) != 0 )
2934
+ return NULL ; /* column name has been changed */
2935
+ }
2936
+ }
2937
+
2938
+ return result ;
2939
+ }
2940
+
2881
2941
static void
2882
2942
get_basic_select_query (Query * query , deparse_context * context ,
2883
2943
TupleDesc resultDesc )
2884
2944
{
2885
2945
StringInfo buf = context -> buf ;
2946
+ RangeTblEntry * values_rte ;
2886
2947
char * sep ;
2887
2948
ListCell * l ;
2888
2949
@@ -2895,23 +2956,13 @@ get_basic_select_query(Query *query, deparse_context *context,
2895
2956
/*
2896
2957
* If the query looks like SELECT * FROM (VALUES ...), then print just the
2897
2958
* VALUES part. This reverses what transformValuesClause() did at parse
2898
- * time. If the jointree contains just a single VALUES RTE, we assume
2899
- * this case applies (without looking at the targetlist...)
2959
+ * time.
2900
2960
*/
2901
- if (list_length (query -> jointree -> fromlist ) == 1 )
2961
+ values_rte = get_simple_values_rte (query );
2962
+ if (values_rte )
2902
2963
{
2903
- RangeTblRef * rtr = (RangeTblRef * ) linitial (query -> jointree -> fromlist );
2904
-
2905
- if (IsA (rtr , RangeTblRef ))
2906
- {
2907
- RangeTblEntry * rte = rt_fetch (rtr -> rtindex , query -> rtable );
2908
-
2909
- if (rte -> rtekind == RTE_VALUES )
2910
- {
2911
- get_values_def (rte -> values_lists , context );
2912
- return ;
2913
- }
2914
- }
2964
+ get_values_def (values_rte -> values_lists , context );
2965
+ return ;
2915
2966
}
2916
2967
2917
2968
/*
@@ -6474,7 +6525,9 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
6474
6525
break ;
6475
6526
case RTE_VALUES :
6476
6527
/* Values list RTE */
6528
+ appendStringInfoChar (buf , '(' );
6477
6529
get_values_def (rte -> values_lists , context );
6530
+ appendStringInfoChar (buf , ')' );
6478
6531
break ;
6479
6532
case RTE_CTE :
6480
6533
appendStringInfoString (buf , quote_identifier (rte -> ctename ));
@@ -6514,6 +6567,13 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
6514
6567
quote_identifier (rte -> eref -> aliasname ));
6515
6568
gavealias = true;
6516
6569
}
6570
+ else if (rte -> rtekind == RTE_VALUES )
6571
+ {
6572
+ /* Alias is syntactically required for VALUES */
6573
+ appendStringInfo (buf , " %s" ,
6574
+ quote_identifier (rte -> eref -> aliasname ));
6575
+ gavealias = true;
6576
+ }
6517
6577
6518
6578
if (rte -> rtekind == RTE_FUNCTION )
6519
6579
{
0 commit comments