@ -509,7 +509,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <ival> sub_type opt_materialized
%type <value> NumericOnly
%type <list> NumericOnly_list
%type <alias> alias_clause opt_alias_clause
%type <alias> alias_clause opt_alias_clause opt_alias_clause_for_join_using
%type <list> func_alias_clause
%type <sortby> sortby
%type <ielem> index_elem index_elem_options
@ -12144,6 +12144,7 @@ joined_table:
n->larg = $1;
n->rarg = $4;
n->usingClause = NIL;
n->join_using_alias = NULL;
n->quals = NULL;
$$ = n;
}
@ -12155,9 +12156,16 @@ joined_table:
n->larg = $1;
n->rarg = $4;
if ($5 != NULL && IsA($5, List))
n->usingClause = (List *) $5; /* USING clause */
{
/* USING clause */
n->usingClause = linitial_node(List, castNode(List, $5));
n->join_using_alias = lsecond_node(Alias, castNode(List, $5));
}
else
n->quals = $5; /* ON clause */
{
/* ON clause */
n->quals = $5;
}
$$ = n;
}
| table_ref JOIN table_ref join_qual
@ -12169,9 +12177,16 @@ joined_table:
n->larg = $1;
n->rarg = $3;
if ($4 != NULL && IsA($4, List))
n->usingClause = (List *) $4; /* USING clause */
{
/* USING clause */
n->usingClause = linitial_node(List, castNode(List, $4));
n->join_using_alias = lsecond_node(Alias, castNode(List, $4));
}
else
n->quals = $4; /* ON clause */
{
/* ON clause */
n->quals = $4;
}
$$ = n;
}
| table_ref NATURAL join_type JOIN table_ref
@ -12182,6 +12197,7 @@ joined_table:
n->larg = $1;
n->rarg = $5;
n->usingClause = NIL; /* figure out which columns later... */
n->join_using_alias = NULL;
n->quals = NULL; /* fill later */
$$ = n;
}
@ -12194,6 +12210,7 @@ joined_table:
n->larg = $1;
n->rarg = $4;
n->usingClause = NIL; /* figure out which columns later... */
n->join_using_alias = NULL;
n->quals = NULL; /* fill later */
$$ = n;
}
@ -12228,6 +12245,22 @@ opt_alias_clause: alias_clause { $$ = $1; }
| /*EMPTY*/ { $$ = NULL; }
;
/*
* The alias clause after JOIN ... USING only accepts the AS ColId spelling,
* per SQL standard. (The grammar could parse the other variants, but they
* don't seem to be useful, and it might lead to parser problems in the
* future.)
*/
opt_alias_clause_for_join_using:
AS ColId
{
$$ = makeNode(Alias);
$$->aliasname = $2;
/* the column name list will be inserted later */
}
| /*EMPTY*/ { $$ = NULL; }
;
/*
* func_alias_clause can include both an Alias and a coldeflist, so we make it
* return a 2-element list that gets disassembled by calling production.
@ -12272,15 +12305,24 @@ opt_outer: OUTER_P
/* JOIN qualification clauses
* Possibilities are:
* USING ( column list ) allows only unqualified column names,
* USING ( column list ) [ AS alias ]
* allows only unqualified column names,
* which must match between tables.
* ON expr allows more general qualifications.
*
* We return USING as a List node, while an ON-expr will not be a List.
* We return USING as a two-element List (the first item being a sub-List
* of the common column names, and the second either an Alias item or NULL).
* An ON-expr will not be a List, so it can be told apart that way.
*/
join_qual: USING '(' name_list ')' { $$ = (Node *) $3; }
| ON a_expr { $$ = $2; }
join_qual: USING '(' name_list ')' opt_alias_clause_for_join_using
{
$$ = (Node *) list_make2($3, $5);
}
| ON a_expr
{
$$ = $2;
}
;