@@ -172,11 +172,14 @@ typedef struct
172
172
* query to ensure it can be referenced unambiguously.
173
173
*
174
174
* Another problem is that a JOIN USING clause requires the columns to be
175
- * merged to have the same aliases in both input RTEs. To handle that, we do
176
- * USING-column alias assignment in a recursive traversal of the query's
177
- * jointree. When descending through a JOIN with USING, we preassign the
178
- * USING column names to the child columns, overriding other rules for column
179
- * alias assignment.
175
+ * merged to have the same aliases in both input RTEs, and that no other
176
+ * columns in those RTEs or their children conflict with the USING names.
177
+ * To handle that, we do USING-column alias assignment in a recursive
178
+ * traversal of the query's jointree. When descending through a JOIN with
179
+ * USING, we preassign the USING column names to the child columns, overriding
180
+ * other rules for column alias assignment. We also mark each RTE with a list
181
+ * of all USING column names selected for joins containing that RTE, so that
182
+ * when we assign other columns' aliases later, we can avoid conflicts.
180
183
*
181
184
* Another problem is that if a JOIN's input tables have had columns added or
182
185
* deleted since the query was parsed, we must generate a column alias list
@@ -227,6 +230,9 @@ typedef struct
227
230
/* This flag tells whether we should actually print a column alias list */
228
231
bool printaliases ;
229
232
233
+ /* This list has all names used as USING names in joins above this RTE */
234
+ List * parentUsing ; /* names assigned to parent merged columns */
235
+
230
236
/*
231
237
* If this struct is for a JOIN RTE, we fill these fields during the
232
238
* set_using_names() pass to describe its relationship to its child RTEs.
@@ -304,7 +310,8 @@ static void set_deparse_for_query(deparse_namespace *dpns, Query *query,
304
310
List * parent_namespaces );
305
311
static void set_simple_column_names (deparse_namespace * dpns );
306
312
static bool has_dangerous_join_using (deparse_namespace * dpns , Node * jtnode );
307
- static void set_using_names (deparse_namespace * dpns , Node * jtnode );
313
+ static void set_using_names (deparse_namespace * dpns , Node * jtnode ,
314
+ List * parentUsing );
308
315
static void set_relation_column_names (deparse_namespace * dpns ,
309
316
RangeTblEntry * rte ,
310
317
deparse_columns * colinfo );
@@ -2579,7 +2586,7 @@ set_deparse_for_query(deparse_namespace *dpns, Query *query,
2579
2586
* Select names for columns merged by USING, via a recursive pass over
2580
2587
* the query jointree.
2581
2588
*/
2582
- set_using_names (dpns , (Node * ) query -> jointree );
2589
+ set_using_names (dpns , (Node * ) query -> jointree , NIL );
2583
2590
}
2584
2591
2585
2592
/*
@@ -2713,9 +2720,12 @@ has_dangerous_join_using(deparse_namespace *dpns, Node *jtnode)
2713
2720
*
2714
2721
* Column alias info is saved in the dpns->rtable_columns list, which is
2715
2722
* assumed to be filled with pre-zeroed deparse_columns structs.
2723
+ *
2724
+ * parentUsing is a list of all USING aliases assigned in parent joins of
2725
+ * the current jointree node. (The passed-in list must not be modified.)
2716
2726
*/
2717
2727
static void
2718
- set_using_names (deparse_namespace * dpns , Node * jtnode )
2728
+ set_using_names (deparse_namespace * dpns , Node * jtnode , List * parentUsing )
2719
2729
{
2720
2730
if (IsA (jtnode , RangeTblRef ))
2721
2731
{
@@ -2727,7 +2737,7 @@ set_using_names(deparse_namespace *dpns, Node *jtnode)
2727
2737
ListCell * lc ;
2728
2738
2729
2739
foreach (lc , f -> fromlist )
2730
- set_using_names (dpns , (Node * ) lfirst (lc ));
2740
+ set_using_names (dpns , (Node * ) lfirst (lc ), parentUsing );
2731
2741
}
2732
2742
else if (IsA (jtnode , JoinExpr ))
2733
2743
{
@@ -2807,6 +2817,9 @@ set_using_names(deparse_namespace *dpns, Node *jtnode)
2807
2817
*/
2808
2818
if (j -> usingClause )
2809
2819
{
2820
+ /* Copy the input parentUsing list so we don't modify it */
2821
+ parentUsing = list_copy (parentUsing );
2822
+
2810
2823
/* USING names must correspond to the first join output columns */
2811
2824
expand_colnames_array_to (colinfo , list_length (j -> usingClause ));
2812
2825
i = 0 ;
@@ -2836,6 +2849,7 @@ set_using_names(deparse_namespace *dpns, Node *jtnode)
2836
2849
2837
2850
/* Remember selected names for use later */
2838
2851
colinfo -> usingNames = lappend (colinfo -> usingNames , colname );
2852
+ parentUsing = lappend (parentUsing , colname );
2839
2853
2840
2854
/* Push down to left column, unless it's a system column */
2841
2855
if (leftattnos [i ] > 0 )
@@ -2855,9 +2869,13 @@ set_using_names(deparse_namespace *dpns, Node *jtnode)
2855
2869
}
2856
2870
}
2857
2871
2872
+ /* Mark child deparse_columns structs with correct parentUsing info */
2873
+ leftcolinfo -> parentUsing = parentUsing ;
2874
+ rightcolinfo -> parentUsing = parentUsing ;
2875
+
2858
2876
/* Now recursively assign USING column names in children */
2859
- set_using_names (dpns , j -> larg );
2860
- set_using_names (dpns , j -> rarg );
2877
+ set_using_names (dpns , j -> larg , parentUsing );
2878
+ set_using_names (dpns , j -> rarg , parentUsing );
2861
2879
}
2862
2880
else
2863
2881
elog (ERROR , "unrecognized node type: %d" ,
@@ -3324,6 +3342,15 @@ colname_is_unique(char *colname, deparse_namespace *dpns,
3324
3342
return false;
3325
3343
}
3326
3344
3345
+ /* Also check against names already assigned for parent-join USING cols */
3346
+ foreach (lc , colinfo -> parentUsing )
3347
+ {
3348
+ char * oldname = (char * ) lfirst (lc );
3349
+
3350
+ if (strcmp (oldname , colname ) == 0 )
3351
+ return false;
3352
+ }
3353
+
3327
3354
return true;
3328
3355
}
3329
3356
0 commit comments