*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.56 1999/02/21 03:49:00 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.57 1999/02/23 07:42:41 thomas Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
DefElem *defelt;
ParamString *param;
SortGroupBy *sortgroupby;
- JoinUsing *joinusing;
+ JoinExpr *joinexpr;
IndexElem *ielem;
RangeVar *range;
RelExpr *relexp;
RemoveFuncStmt, RemoveStmt,
RenameStmt, RevokeStmt, RuleStmt, TransactionStmt, ViewStmt, LoadStmt,
CreatedbStmt, DestroydbStmt, VacuumStmt, CursorStmt, SubSelect,
- UpdateStmt, InsertStmt, select_w_o_sort, SelectStmt, NotifyStmt, DeleteStmt,
+ UpdateStmt, InsertStmt, select_clause, SelectStmt, NotifyStmt, DeleteStmt,
ClusterStmt, ExplainStmt, VariableSetStmt, VariableShowStmt, VariableResetStmt,
CreateUserStmt, AlterUserStmt, DropUserStmt, RuleActionStmt
%type <str> user_valid_clause
%type <list> user_group_list, user_group_clause
-%type <str> join_expr, join_outer, join_spec
%type <boolean> TriggerActionTime, TriggerForSpec, PLangTrusted
%type <str> TriggerEvents, TriggerFuncArg
oper_argtypes, RuleActionList, RuleActionBlock, RuleActionMulti,
opt_column_list, columnList, opt_va_list, va_list,
sort_clause, sortby_list, index_params, index_list, name_list,
- from_clause, from_list, opt_array_bounds, nest_array_bounds,
+ from_clause, from_expr, table_list, opt_array_bounds, nest_array_bounds,
expr_list, attrs, res_target_list, res_target_list2,
def_list, opt_indirection, group_clause, TriggerFuncArgs,
opt_select_limit
%type <boolean> TriggerForOpt, TriggerForType, OptTemp
-%type <list> for_update_clause
-%type <list> join_list
-%type <joinusing>
- join_using
+%type <list> for_update_clause, update_list
%type <boolean> opt_union
%type <boolean> opt_table
%type <boolean> opt_trans
+%type <list> join_clause_with_union, join_clause, join_list, join_qual, using_list
+%type <node> join_expr, using_expr
+%type <str> join_outer
+%type <ival> join_type
+
%type <node> position_expr
%type <list> extract_list, position_list
%type <list> substr_list, substr_from, substr_for, trim_list
%type <attr> event_object, attr
%type <sortgroupby> sortby
%type <ielem> index_elem, func_index
-%type <range> from_val
+%type <range> table_expr
%type <relexp> relation_expr
%type <target> res_target_el, res_target_el2
%type <paramno> ParamNo
{ $$ = $1; }
;
-/* The column constraint WITH NULL gives a shift/reduce error
- * because it requires yacc to look more than one token ahead to
- * resolve WITH TIME ZONE and WITH NULL.
- * So, leave it out of the syntax for now.
- | WITH NULL_P
- {
- $$ = NULL;
- }
- * - thomas 1998-09-12
- *
- * DEFAULT NULL is already the default for Postgres.
+/* DEFAULT NULL is already the default for Postgres.
* Bue define it here and carry it forward into the system
* to make it explicit.
* - thomas 1998-09-13
+ * WITH NULL and NULL are not SQL92-standard syntax elements,
+ * so leave them out. Use DEFAULT NULL to explicitly indicate
+ * that a column may have that value. WITH NULL leads to
+ * shift/reduce conflicts with WITH TIME ZONE anyway.
+ * - thomas 1999-01-08
*/
ColConstraintElem: CHECK '(' constraint_expr ')'
{
* accepts the use of '(' and ')' to select an order of set operations.
*
* The rule returns a SelectStmt Node having the set operations attached to
- * unionClause and intersectClause (NIL if no set operations were present) */
-SelectStmt: select_w_o_sort sort_clause for_update_clause opt_select_limit
+ * unionClause and intersectClause (NIL if no set operations were present)
+ */
+
+SelectStmt: select_clause sort_clause for_update_clause opt_select_limit
{
/* There were no set operations, so just attach the sortClause */
if IsA($1, SelectStmt)
* the A_Expr Nodes.
* If no set operations show up in the query the tree consists only of one
* SelectStmt Node */
-select_w_o_sort: '(' select_w_o_sort ')'
+select_clause: '(' select_clause ')'
{
$$ = $2;
}
{
$$ = $1;
}
- | select_w_o_sort EXCEPT select_w_o_sort
+ | select_clause EXCEPT select_clause
{
$$ = (Node *)makeA_Expr(AND,NULL,$1,
makeA_Expr(NOT,NULL,NULL,$3));
}
- | select_w_o_sort UNION opt_union select_w_o_sort
+ | select_clause UNION opt_union select_clause
{
if (IsA($4, SelectStmt))
{
}
$$ = (Node *)makeA_Expr(OR,NULL,$1,$4);
}
- | select_w_o_sort INTERSECT select_w_o_sort
+ | select_clause INTERSECT select_clause
{
$$ = (Node *)makeA_Expr(AND,NULL,$1,$3);
}
{ $$ = lappend($1,makeString($3)); }
;
-group_clause: GROUP BY expr_list { $$ = $3; }
+group_clause: GROUP BY expr_list { $$ = $3; }
| /*EMPTY*/ { $$ = NIL; }
;
| /*EMPTY*/ { $$ = NULL; }
;
-for_update_clause:
- FOR UPDATE
- {
- $$ = lcons(NULL, NULL);
- }
- | FOR UPDATE OF va_list
- {
- $$ = $4;
- }
- | /* EMPTY */
- {
- $$ = NULL;
- }
+for_update_clause: FOR UPDATE update_list { $$ = $3; }
+ | /* EMPTY */ { $$ = NULL; }
+ ;
+
+update_list: OF va_list { $$ = $2; }
+ | /* EMPTY */ { $$ = lcons(NULL, NULL); }
;
/*****************************************************************************
*
*****************************************************************************/
-from_clause: FROM '(' relation_expr join_expr JOIN relation_expr join_spec ')'
- {
- $$ = NIL;
- elog(ERROR,"JOIN not yet implemented");
- }
- | FROM from_list { $$ = $2; }
+from_clause: FROM from_expr { $$ = $2; }
| /*EMPTY*/ { $$ = NIL; }
;
-from_list: from_list ',' from_val
+from_expr: '(' join_clause_with_union ')'
+ { $$ = $2; }
+ | join_clause
+ { $$ = $1; }
+ | table_list
+ { $$ = $1; }
+ ;
+
+table_list: table_list ',' table_expr
{ $$ = lappend($1, $3); }
- | from_val CROSS JOIN from_val
- { elog(ERROR,"CROSS JOIN not yet implemented"); }
- | from_val
+ | table_expr
{ $$ = lcons($1, NIL); }
;
-from_val: relation_expr AS ColLabel
+table_expr: relation_expr AS ColLabel
{
$$ = makeNode(RangeVar);
$$->relExpr = $1;
}
;
-join_expr: NATURAL join_expr { $$ = NULL; }
- | FULL join_outer
- { elog(ERROR,"FULL OUTER JOIN not yet implemented"); }
+/* A UNION JOIN is the same as a FULL OUTER JOIN which *omits*
+ * all result rows which would have matched on an INNER JOIN.
+ * Let's reject this for now. - thomas 1999-01-08
+ */
+join_clause_with_union: join_clause
+ { $$ = $1; }
+ | table_expr UNION JOIN table_expr
+ { elog(ERROR,"UNION JOIN not yet implemented"); }
+ ;
+
+join_clause: table_expr join_list
+ {
+ Node *n = lfirst($2);
+
+ /* JoinExpr came back? then it is a join of some sort...
+ */
+ if (IsA(n, JoinExpr))
+ {
+ JoinExpr *j = (JoinExpr *)n;
+ j->larg = $1;
+ $$ = $2;
+ }
+ /* otherwise, it was a cross join,
+ * which we just represent as an inner join...
+ */
+ else
+ $$ = lcons($1, $2);
+ }
+ ;
+
+join_list: join_list join_expr
+ {
+ $$ = lappend($1, $2);
+ }
+ | join_expr
+ {
+ $$ = lcons($1, NIL);
+ }
+ ;
+
+/* This is everything but the left side of a join.
+ * Note that a CROSS JOIN is the same as an unqualified
+ * inner join, so just pass back the right-side table.
+ * A NATURAL JOIN implicitly matches column names between
+ * tables, so we'll collect those during the later transformation.
+ */
+join_expr: join_type JOIN table_expr join_qual
+ {
+ JoinExpr *n = makeNode(JoinExpr);
+ n->jointype = $1;
+ n->rarg = (Node *)$3;
+ n->quals = $4;
+ $$ = (Node *)n;
+ }
+ | NATURAL join_type JOIN table_expr
+ {
+ JoinExpr *n = makeNode(JoinExpr);
+ n->jointype = $2;
+ n->rarg = (Node *)$4;
+ n->quals = NULL; /* figure out which columns later... */
+ $$ = (Node *)n;
+ }
+ | CROSS JOIN table_expr
+ { $$ = (Node *)$3; }
+ ;
+
+/* OUTER is just noise... */
+join_type: FULL join_outer
+ {
+ $$ = FULL;
+ elog(NOTICE,"FULL OUTER JOIN not yet implemented");
+ }
| LEFT join_outer
- { elog(ERROR,"LEFT OUTER JOIN not yet implemented"); }
+ {
+ $$ = LEFT;
+ elog(NOTICE,"LEFT OUTER JOIN not yet implemented");
+ }
| RIGHT join_outer
- { elog(ERROR,"RIGHT OUTER JOIN not yet implemented"); }
+ {
+ $$ = RIGHT;
+ elog(NOTICE,"RIGHT OUTER JOIN not yet implemented");
+ }
| OUTER_P
- { elog(ERROR,"OUTER JOIN not yet implemented"); }
+ {
+ $$ = LEFT;
+ elog(NOTICE,"OUTER JOIN not yet implemented");
+ }
| INNER_P
- { elog(ERROR,"INNER JOIN not yet implemented"); }
- | UNION
- { elog(ERROR,"UNION JOIN not yet implemented"); }
+ {
+ $$ = INNER_P;
+ }
| /*EMPTY*/
- { elog(ERROR,"INNER JOIN not yet implemented"); }
+ {
+ $$ = INNER_P;
+ }
;
join_outer: OUTER_P { $$ = NULL; }
| /*EMPTY*/ { $$ = NULL; /* no qualifiers */ }
;
-join_spec: ON '(' a_expr ')' { $$ = NULL; }
- | USING '(' join_list ')' { $$ = NULL; }
- | /*EMPTY*/ { $$ = NULL; /* no qualifiers */ }
+/* JOIN qualification clauses
+ * Possibilities are:
+ * USING ( column list ) allows only unqualified column names,
+ * which must match between tables.
+ * ON expr allows more general qualifications.
+ * - thomas 1999-01-07
+ */
+
+join_qual: USING '(' using_list ')' { $$ = $3; }
+ | ON a_expr { $$ = lcons($2, NIL); }
;
-join_list: join_using { $$ = lcons($1, NIL); }
- | join_list ',' join_using { $$ = lappend($1, $3); }
+using_list: using_list ',' using_expr { $$ = lappend($1, $3); }
+ | using_expr { $$ = lcons($1, NIL); }
;
-join_using: ColId
- /* Changed from SortGroupBy parse node to new JoinUsing node.
- * SortGroupBy no longer needs these structure members.
- *
- * Once, acknowledged, this comment can be removed by the
- * developer(s) working on the JOIN clause.
- *
- * - daveh@insightdist.com 1998-07-31
- */
- {
- $$ = makeNode(JoinUsing);
- $$->resno = 0;
- $$->range = NULL;
- $$->name = $1;
- }
- | ColId '.' ColId
- {
- $$ = makeNode(JoinUsing);
- $$->resno = 0;
- $$->range = $1;
- $$->name = $3;
- }
- | Iconst
+using_expr: ColId
{
- $$ = makeNode(JoinUsing);
- $$->resno = $1;
- $$->range = NULL;
- $$->name = NULL;
+ /* could be a column name or a relation_name */
+ Ident *n = makeNode(Ident);
+ n->name = $1;
+ n->indirection = NULL;
+ $$ = (Node *)n;
}
;
{
CaseExpr *c = makeNode(CaseExpr);
CaseWhen *w = makeNode(CaseWhen);
+/*
+ A_Const *n = makeNode(A_Const);
+ n->val.type = T_Null;
+ w->result = (Node *)n;
+*/
+ w->expr = makeA_Expr(OP, "=", $3, $5);
c->args = lcons(w, NIL);
c->defresult = $3;
- w->expr = makeA_Expr(OP, "=", $3, $5);
$$ = (Node *)c;
-
- elog(NOTICE,"NULLIF() not yet fully implemented");
}
| COALESCE '(' expr_list ')'
{
c->args = lappend(c->args, w);
}
$$ = (Node *)c;
-
- elog(NOTICE,"COALESCE() not yet fully implemented");
}
;
| COALESCE { $$ = "coalesce"; }
| CONSTRAINT { $$ = "constraint"; }
| COPY { $$ = "copy"; }
- | CROSS { $$ = "cross"; }
| CURRENT { $$ = "current"; }
| DO { $$ = "do"; }
| ELSE { $$ = "else"; }
/* makeRowExpr()
* Generate separate operator nodes for a single row descriptor expression.
- * Perhaps this should go deeper in the parser someday... - thomas 1997-12-22
+ * Perhaps this should go deeper in the parser someday...
+ * - thomas 1997-12-22
*/
static Node *
makeRowExpr(char *opr, List *largs, List *rargs)
elog(ERROR,"Operator '%s' not implemented for row expressions",opr);
}
-#ifdef NOT_USED
- while ((largs != NIL) && (rargs != NIL))
- {
- larg = lfirst(largs);
- rarg = lfirst(rargs);
-
- if (expr == NULL)
- expr = makeA_Expr(OP, opr, larg, rarg);
- else
- expr = makeA_Expr(AND, NULL, expr, makeA_Expr(OP, opr, larg, rarg));
-
- largs = lnext(largs);
- rargs = lnext(rargs);
- }
- pprint(expr);
-#endif
-
return expr;
}