@@ -164,10 +164,10 @@ typedef struct
164
164
* since they just inherit column names from their input RTEs, and we can't
165
165
* rename the columns at the join level. Most of the time this isn't an issue
166
166
* because we don't need to reference the join's output columns as such; we
167
- * can reference the input columns instead. That approach fails for merged
168
- * FULL JOIN USING columns, however, so when we have one of those in an
169
- * unnamed join, we have to make that column's alias globally unique across
170
- * the whole query to ensure it can be referenced unambiguously.
167
+ * can reference the input columns instead. That approach can fail for merged
168
+ * JOIN USING columns, however, so when we have one of those in an unnamed
169
+ * join, we have to make that column's alias globally unique across the whole
170
+ * query to ensure it can be referenced unambiguously.
171
171
*
172
172
* Another problem is that a JOIN USING clause requires the columns to be
173
173
* merged to have the same aliases in both input RTEs. To handle that, we do
@@ -301,7 +301,7 @@ static bool refname_is_unique(char *refname, deparse_namespace *dpns,
301
301
static void set_deparse_for_query (deparse_namespace * dpns , Query * query ,
302
302
List * parent_namespaces );
303
303
static void set_simple_column_names (deparse_namespace * dpns );
304
- static bool has_unnamed_full_join_using ( Node * jtnode );
304
+ static bool has_dangerous_join_using ( deparse_namespace * dpns , Node * jtnode );
305
305
static void set_using_names (deparse_namespace * dpns , Node * jtnode );
306
306
static void set_relation_column_names (deparse_namespace * dpns ,
307
307
RangeTblEntry * rte ,
@@ -2570,7 +2570,7 @@ set_deparse_for_query(deparse_namespace *dpns, Query *query,
2570
2570
{
2571
2571
/* Detect whether global uniqueness of USING names is needed */
2572
2572
dpns -> unique_using =
2573
- has_unnamed_full_join_using ( (Node * ) query -> jointree );
2573
+ has_dangerous_join_using ( dpns , (Node * ) query -> jointree );
2574
2574
2575
2575
/*
2576
2576
* Select names for columns merged by USING, via a recursive pass over
@@ -2630,25 +2630,26 @@ set_simple_column_names(deparse_namespace *dpns)
2630
2630
}
2631
2631
2632
2632
/*
2633
- * has_unnamed_full_join_using : search jointree for unnamed FULL JOIN USING
2633
+ * has_dangerous_join_using : search jointree for unnamed JOIN USING
2634
2634
*
2635
- * Merged columns of a FULL JOIN USING act differently from either of the
2636
- * input columns, so they have to be referenced as columns of the JOIN not
2637
- * as columns of either input. And this is problematic if the join is
2638
- * unnamed (alias-less): we cannot qualify the column's name with an RTE
2639
- * name, since there is none. (Forcibly assigning an alias to the join is
2640
- * not a solution, since that will prevent legal references to tables below
2641
- * the join.) To ensure that every column in the query is unambiguously
2642
- * referenceable, we must assign such merged columns names that are globally
2643
- * unique across the whole query, aliasing other columns out of the way as
2644
- * necessary.
2635
+ * Merged columns of a JOIN USING may act differently from either of the input
2636
+ * columns, either because they are merged with COALESCE (in a FULL JOIN) or
2637
+ * because an implicit coercion of the underlying input column is required.
2638
+ * In such a case the column must be referenced as a column of the JOIN not as
2639
+ * a column of either input. And this is problematic if the join is unnamed
2640
+ * (alias-less): we cannot qualify the column's name with an RTE name, since
2641
+ * there is none. (Forcibly assigning an alias to the join is not a solution,
2642
+ * since that will prevent legal references to tables below the join.)
2643
+ * To ensure that every column in the query is unambiguously referenceable,
2644
+ * we must assign such merged columns names that are globally unique across
2645
+ * the whole query, aliasing other columns out of the way as necessary.
2645
2646
*
2646
2647
* Because the ensuing re-aliasing is fairly damaging to the readability of
2647
2648
* the query, we don't do this unless we have to. So, we must pre-scan
2648
2649
* the join tree to see if we have to, before starting set_using_names().
2649
2650
*/
2650
2651
static bool
2651
- has_unnamed_full_join_using ( Node * jtnode )
2652
+ has_dangerous_join_using ( deparse_namespace * dpns , Node * jtnode )
2652
2653
{
2653
2654
if (IsA (jtnode , RangeTblRef ))
2654
2655
{
@@ -2661,24 +2662,38 @@ has_unnamed_full_join_using(Node *jtnode)
2661
2662
2662
2663
foreach (lc , f -> fromlist )
2663
2664
{
2664
- if (has_unnamed_full_join_using ( (Node * ) lfirst (lc )))
2665
+ if (has_dangerous_join_using ( dpns , (Node * ) lfirst (lc )))
2665
2666
return true;
2666
2667
}
2667
2668
}
2668
2669
else if (IsA (jtnode , JoinExpr ))
2669
2670
{
2670
2671
JoinExpr * j = (JoinExpr * ) jtnode ;
2671
2672
2672
- /* Is it an unnamed FULL JOIN with USING? */
2673
- if (j -> alias == NULL &&
2674
- j -> jointype == JOIN_FULL &&
2675
- j -> usingClause )
2676
- return true;
2673
+ /* Is it an unnamed JOIN with USING? */
2674
+ if (j -> alias == NULL && j -> usingClause )
2675
+ {
2676
+ /*
2677
+ * Yes, so check each join alias var to see if any of them are not
2678
+ * simple references to underlying columns. If so, we have a
2679
+ * dangerous situation and must pick unique aliases.
2680
+ */
2681
+ RangeTblEntry * jrte = rt_fetch (j -> rtindex , dpns -> rtable );
2682
+ ListCell * lc ;
2683
+
2684
+ foreach (lc , jrte -> joinaliasvars )
2685
+ {
2686
+ Var * aliasvar = (Var * ) lfirst (lc );
2687
+
2688
+ if (aliasvar != NULL && !IsA (aliasvar , Var ))
2689
+ return true;
2690
+ }
2691
+ }
2677
2692
2678
2693
/* Nope, but inspect children */
2679
- if (has_unnamed_full_join_using ( j -> larg ))
2694
+ if (has_dangerous_join_using ( dpns , j -> larg ))
2680
2695
return true;
2681
- if (has_unnamed_full_join_using ( j -> rarg ))
2696
+ if (has_dangerous_join_using ( dpns , j -> rarg ))
2682
2697
return true;
2683
2698
}
2684
2699
else
@@ -2768,16 +2783,16 @@ set_using_names(deparse_namespace *dpns, Node *jtnode)
2768
2783
*
2769
2784
* If dpns->unique_using is TRUE, we force all USING names to be
2770
2785
* unique across the whole query level. In principle we'd only need
2771
- * the names of USING columns in unnamed full joins to be globally
2772
- * unique, but to safely assign all USING names in a single pass, we
2773
- * have to enforce the same uniqueness rule for all of them. However,
2774
- * if a USING column's name has been pushed down from the parent, we
2775
- * should use it as-is rather than making a uniqueness adjustment.
2776
- * This is necessary when we're at an unnamed join, and it creates no
2777
- * risk of ambiguity. Also, if there's a user-written output alias
2778
- * for a merged column, we prefer to use that rather than the input
2779
- * name; this simplifies the logic and seems likely to lead to less
2780
- * aliasing overall.
2786
+ * the names of dangerous USING columns to be globally unique, but to
2787
+ * safely assign all USING names in a single pass, we have to enforce
2788
+ * the same uniqueness rule for all of them. However, if a USING
2789
+ * column's name has been pushed down from the parent, we should use
2790
+ * it as-is rather than making a uniqueness adjustment. This is
2791
+ * necessary when we're at an unnamed join, and it creates no risk of
2792
+ * ambiguity. Also, if there's a user-written output alias for a
2793
+ * merged column, we prefer to use that rather than the input name;
2794
+ * this simplifies the logic and seems likely to lead to less aliasing
2795
+ * overall.
2781
2796
*
2782
2797
* If dpns->unique_using is FALSE, we only need USING names to be
2783
2798
* unique within their own join RTE. We still need to honor
@@ -5344,9 +5359,8 @@ get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
5344
5359
* If it's a simple reference to one of the input vars, then recursively
5345
5360
* print the name of that var instead. When it's not a simple reference,
5346
5361
* we have to just print the unqualified join column name. (This can only
5347
- * happen with columns that were merged by USING or NATURAL clauses in a
5348
- * FULL JOIN; we took pains previously to make the unqualified column name
5349
- * unique in such cases.)
5362
+ * happen with "dangerous" merged columns in a JOIN USING; we took pains
5363
+ * previously to make the unqualified column name unique in such cases.)
5350
5364
*
5351
5365
* This wouldn't work in decompiling plan trees, because we don't store
5352
5366
* joinaliasvars lists after planning; but a plan tree should never
0 commit comments