diff options
Diffstat (limited to 'src/backend/parser/gram.y')
| -rw-r--r-- | src/backend/parser/gram.y | 383 |
1 files changed, 181 insertions, 202 deletions
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 7e970ab187..301be9eb9b 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.188 2000/09/12 05:09:44 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.189 2000/09/12 21:07:01 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -36,6 +36,7 @@ #include <ctype.h> #include "postgres.h" + #include "access/htup.h" #include "access/xact.h" #include "catalog/catname.h" @@ -77,15 +78,10 @@ static Node *makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr); static Node *makeTypeCast(Node *arg, TypeName *typename); static Node *makeRowExpr(char *opr, List *largs, List *rargs); static void mapTargetColumns(List *source, List *target); -static void param_type_init(Oid *typev, int nargs); static bool exprIsNullConstant(Node *arg); static Node *doNegate(Node *n); static void doNegateFloat(Value *v); -/* old versions of flex define this as a macro */ -#if defined(yywrap) -#undef yywrap -#endif /* yywrap */ %} @@ -95,6 +91,7 @@ static void doNegateFloat(Value *v); char chr; char *str; bool boolean; + JoinType jtype; List *list; Node *node; Value *value; @@ -108,7 +105,6 @@ static void doNegateFloat(Value *v); JoinExpr *jexpr; IndexElem *ielem; RangeVar *range; - RelExpr *relexp; A_Indices *aind; ResTarget *target; ParamNo *paramno; @@ -194,19 +190,8 @@ static void doNegateFloat(Value *v); %type <boolean> opt_table %type <boolean> opt_chain, opt_trans -%type <jexpr> from_expr, join_clause, join_expr -%type <jexpr> join_clause_with_union, join_expr_with_union %type <node> join_outer, join_qual -%type <ival> join_type -%type <list> using_list -%type <ident> using_expr -/*** -#ifdef ENABLE_ORACLE_JOIN_SYNTAX -%type <list> oracle_list -%type <jexpr> oracle_expr -%type <boolean> oracle_outer -#endif -***/ +%type <jtype> join_type %type <list> extract_list, position_list %type <list> substr_list, substr_from, substr_for, trim_list @@ -246,8 +231,9 @@ static void doNegateFloat(Value *v); %type <attr> event_object, attr, alias_clause %type <sortgroupby> sortby %type <ielem> index_elem, func_index -%type <range> table_expr -%type <relexp> relation_expr +%type <node> table_ref +%type <jexpr> joined_table +%type <range> relation_expr %type <target> target_el, update_target_el %type <paramno> ParamNo @@ -356,6 +342,12 @@ static void doNegateFloat(Value *v); TEMP, TOAST, TRUNCATE, TRUSTED, UNLISTEN, UNTIL, VACUUM, VALID, VERBOSE, VERSION +/* The grammar thinks these are keywords, but they are not in the keywords.c + * list and so can never be entered directly. The filter in parser.c + * creates these tokens when required. + */ +%token UNIONJOIN + /* Special keywords, not in the query language - see the "lex" file */ %token <str> IDENT, FCONST, SCONST, Op %token <ival> ICONST, PARAM @@ -364,7 +356,9 @@ static void doNegateFloat(Value *v); %token OP /* precedence: lowest to highest */ -%left UNION INTERSECT EXCEPT +%left UNION EXCEPT +%left INTERSECT +%left JOIN UNIONJOIN CROSS LEFT FULL RIGHT INNER_P NATURAL %left OR %left AND %right NOT @@ -800,7 +794,7 @@ VariableSetStmt: SET ColId TO var_value n->value = $3; $$ = (Node *) n; #else - elog(ERROR, "SET NAMES is not supported."); + elog(ERROR, "SET NAMES is not supported"); #endif } ; @@ -1031,7 +1025,6 @@ AlterTableStmt: n->relname = $3; $$ = (Node *)n; } - /* ALTER TABLE <name> OWNER TO UserId */ | ALTER TABLE relation_name OWNER TO UserId { @@ -2956,7 +2949,7 @@ CreatedbStmt: CREATE DATABASE database_name WITH createdb_opt_location createdb CreatedbStmt *n; if ($5 == NULL && $6 == -1) - elog(ERROR, "CREATE DATABASE WITH requires at least one option."); + elog(ERROR, "CREATE DATABASE WITH requires at least one option"); n = makeNode(CreatedbStmt); n->dbname = $3; @@ -3465,7 +3458,7 @@ SelectStmt: select_clause sort_clause for_update_clause opt_select_limit /* This rule parses Select statements that can appear within set operations, * including UNION, INTERSECT and EXCEPT. '(' and ')' can be used to specify * the ordering of the set operations. Without '(' and ')' we want the - * operations to be left associative. + * operations to be ordered per the precedence specs at the head of this file. * * Note that sort clauses cannot be included at this level --- a sort clause * can only appear at the end of the complete Select, and it will be handled @@ -3486,10 +3479,12 @@ select_clause: '(' select_clause ')' { $$ = $1; } - | select_clause EXCEPT select_clause + | select_clause EXCEPT opt_all select_clause { $$ = (Node *)makeA_Expr(AND,NULL,$1, - makeA_Expr(NOT,NULL,NULL,$3)); + makeA_Expr(NOT,NULL,NULL,$4)); + if ($3) + elog(ERROR, "EXCEPT ALL is not implemented yet"); } | select_clause UNION opt_all select_clause { @@ -3506,9 +3501,11 @@ select_clause: '(' select_clause ')' } $$ = (Node *)makeA_Expr(OR,NULL,$1,$4); } - | select_clause INTERSECT select_clause + | select_clause INTERSECT opt_all select_clause { - $$ = (Node *)makeA_Expr(AND,NULL,$1,$3); + $$ = (Node *)makeA_Expr(AND,NULL,$1,$4); + if ($3) + elog(ERROR, "INTERSECT ALL is not implemented yet"); } ; @@ -3741,113 +3738,63 @@ update_list: OF va_list { $$ = $2; } *****************************************************************************/ from_clause: FROM from_list { $$ = $2; } -/*** -#ifdef ENABLE_ORACLE_JOIN_SYNTAX - | FROM oracle_list { $$ = $2; } -#endif -***/ - | FROM from_expr { $$ = lcons($2, NIL); } | /*EMPTY*/ { $$ = NIL; } ; -from_list: from_list ',' table_expr { $$ = lappend($1, $3); } - | table_expr { $$ = lcons($1, NIL); } - ; - -/*********** - * This results in one shift/reduce conflict, presumably due to the trailing "(+)" - * - Thomas 1999-09-20 - * -#ifdef ENABLE_ORACLE_JOIN_SYNTAX -oracle_list: oracle_expr { $$ = lcons($1, NIL); } - ; - -oracle_expr: ColId ',' ColId oracle_outer - { - elog(ERROR,"Oracle OUTER JOIN not yet supported"); - $$ = NULL; - } - | oracle_outer ColId ',' ColId - { - elog(ERROR,"Oracle OUTER JOIN not yet supported"); - $$ = NULL; - } - ; - -oracle_outer: '(' '+' ')' { $$ = TRUE; } - ; -#endif -***********/ - -from_expr: '(' join_clause_with_union ')' alias_clause - { - JoinExpr *j = $2; - j->alias = $4; - $$ = j; - } - | join_clause - { $$ = $1; } - ; - -table_expr: relation_expr alias_clause - { - $$ = makeNode(RangeVar); - $$->relExpr = $1; - $$->name = $2; - -#ifdef DISABLE_JOIN_SYNTAX - if (($2 != NULL) && ($2->attrs != NULL)) - elog(ERROR, "Column aliases in table expressions not yet supported"); -#endif - } +from_list: from_list ',' table_ref { $$ = lappend($1, $3); } + | table_ref { $$ = lcons($1, NIL); } ; -alias_clause: AS ColId '(' name_list ')' - { - $$ = makeNode(Attr); - $$->relname = $2; - $$->attrs = $4; - } - | AS ColId +/* + * table_ref is where an alias clause can be attached. Note we cannot make + * alias_clause have an empty production because that causes parse conflicts + * between table_ref := '(' joined_table ')' alias_clause + * and joined_table := '(' joined_table ')'. So, we must have the + * redundant-looking productions here instead. + */ +table_ref: relation_expr { - $$ = makeNode(Attr); - $$->relname = $2; + $$ = (Node *) $1; } - | ColId '(' name_list ')' + | relation_expr alias_clause { - $$ = makeNode(Attr); - $$->relname = $1; - $$->attrs = $3; + $1->name = $2; + $$ = (Node *) $1; } - | ColId + | '(' select_clause ')' { - $$ = makeNode(Attr); - $$->relname = $1; + RangeSubselect *n = makeNode(RangeSubselect); + n->subquery = $2; + n->name = NULL; + $$ = (Node *) n; } - | /*EMPTY*/ + | '(' select_clause ')' alias_clause { - $$ = NULL; /* no qualifiers */ + RangeSubselect *n = makeNode(RangeSubselect); + n->subquery = $2; + n->name = $4; + $$ = (Node *) n; } - ; - -/* A UNION JOIN is the same as a FULL OUTER JOIN which *omits* - * all result rows which would have matched on an INNER JOIN. - * Syntactically, must enclose the UNION JOIN in parens to avoid - * conflicts with SELECT/UNION. - */ -join_clause: join_clause join_expr + | joined_table { - $2->larg = (Node *)$1; - $$ = $2; + $$ = (Node *) $1; } - | table_expr join_expr + | '(' joined_table ')' alias_clause { - $2->larg = (Node *)$1; - $$ = $2; + $2->alias = $4; + $$ = (Node *) $2; } ; -/* This is everything but the left side of a join. +/* + * It may seem silly to separate joined_table from table_ref, but there is + * method in SQL92's madness: if you don't do it this way you get reduce- + * reduce conflicts, because it's not clear to the parser generator whether + * to expect alias_clause after ')' or not. For the same reason we must + * treat 'JOIN' and 'join_type JOIN' separately, rather than allowing + * join_type to expand to empty; if we try it, the parser generator can't + * figure out when to reduce an empty join_type right after table_ref. + * * Note that a CROSS JOIN is the same as an unqualified * INNER JOIN, and an INNER JOIN/ON has the same shape * but a qualification expression to limit membership. @@ -3855,71 +3802,122 @@ join_clause: join_clause join_expr * tables and the shape is determined by which columns are * in common. We'll collect columns during the later transformations. */ -join_expr: join_type JOIN table_expr join_qual + +joined_table: '(' joined_table ')' + { + $$ = $2; + } + | table_ref CROSS JOIN table_ref { + /* CROSS JOIN is same as unqualified inner join */ JoinExpr *n = makeNode(JoinExpr); - n->jointype = $1; - n->rarg = (Node *)$3; - n->quals = (List *)$4; + n->jointype = JOIN_INNER; + n->isNatural = FALSE; + n->larg = $1; + n->rarg = $4; + n->using = NIL; + n->quals = NULL; $$ = n; } - | NATURAL join_type JOIN table_expr + | table_ref UNIONJOIN table_ref { + /* UNION JOIN is made into 1 token to avoid shift/reduce + * conflict against regular UNION keyword. + */ JoinExpr *n = makeNode(JoinExpr); - n->jointype = $2; - n->isNatural = TRUE; - n->rarg = (Node *)$4; - n->quals = NULL; /* figure out which columns later... */ + n->jointype = JOIN_UNION; + n->isNatural = FALSE; + n->larg = $1; + n->rarg = $3; + n->using = NIL; + n->quals = NULL; $$ = n; } - | CROSS JOIN table_expr + | table_ref join_type JOIN table_ref join_qual { JoinExpr *n = makeNode(JoinExpr); - n->jointype = INNER_P; + n->jointype = $2; n->isNatural = FALSE; - n->rarg = (Node *)$3; - n->quals = NULL; + n->larg = $1; + n->rarg = $4; + if ($5 != NULL && IsA($5, List)) + n->using = (List *) $5; /* USING clause */ + else + n->quals = $5; /* ON clause */ $$ = n; } - ; - -join_clause_with_union: join_clause_with_union join_expr_with_union + | table_ref JOIN table_ref join_qual { - $2->larg = (Node *)$1; - $$ = $2; + /* letting join_type reduce to empty doesn't work */ + JoinExpr *n = makeNode(JoinExpr); + n->jointype = JOIN_INNER; + n->isNatural = FALSE; + n->larg = $1; + n->rarg = $3; + if ($4 != NULL && IsA($4, List)) + n->using = (List *) $4; /* USING clause */ + else + n->quals = $4; /* ON clause */ + $$ = n; } - | table_expr join_expr_with_union + | table_ref NATURAL join_type JOIN table_ref { - $2->larg = (Node *)$1; - $$ = $2; + JoinExpr *n = makeNode(JoinExpr); + n->jointype = $3; + n->isNatural = TRUE; + n->larg = $1; + n->rarg = $5; + n->using = NIL; /* figure out which columns later... */ + n->quals = NULL; /* fill later */ + $$ = n; } - ; - -join_expr_with_union: join_expr - { $$ = $1; } - | UNION JOIN table_expr + | table_ref NATURAL JOIN table_ref { + /* letting join_type reduce to empty doesn't work */ JoinExpr *n = makeNode(JoinExpr); - n->jointype = UNION; - n->rarg = (Node *)$3; - n->quals = NULL; + n->jointype = JOIN_INNER; + n->isNatural = TRUE; + n->larg = $1; + n->rarg = $4; + n->using = NIL; /* figure out which columns later... */ + n->quals = NULL; /* fill later */ $$ = n; + } + ; - elog(ERROR,"UNION JOIN not yet implemented"); +alias_clause: AS ColId '(' name_list ')' + { + $$ = makeNode(Attr); + $$->relname = $2; + $$->attrs = $4; + } + | AS ColId + { + $$ = makeNode(Attr); + $$->relname = $2; + } + | ColId '(' name_list ')' + { + $$ = makeNode(Attr); + $$->relname = $1; + $$->attrs = $3; + } + | ColId + { + $$ = makeNode(Attr); + $$->relname = $1; } ; -/* OUTER is just noise... */ -join_type: FULL join_outer { $$ = FULL; } - | LEFT join_outer { $$ = LEFT; } - | RIGHT join_outer { $$ = RIGHT; } - | OUTER_P { $$ = LEFT; } - | INNER_P { $$ = INNER_P; } - | /*EMPTY*/ { $$ = INNER_P; } +join_type: FULL join_outer { $$ = JOIN_FULL; } + | LEFT join_outer { $$ = JOIN_LEFT; } + | RIGHT join_outer { $$ = JOIN_RIGHT; } + | INNER_P { $$ = JOIN_INNER; } ; +/* OUTER is just noise... */ join_outer: OUTER_P { $$ = NULL; } - | /*EMPTY*/ { $$ = NULL; /* no qualifiers */ } + | /*EMPTY*/ { $$ = NULL; } ; /* JOIN qualification clauses @@ -3927,60 +3925,43 @@ join_outer: OUTER_P { $$ = NULL; } * USING ( column list ) allows only unqualified column names, * which must match between tables. * ON expr allows more general qualifications. - * - thomas 1999-01-07 + * + * We return USING as a List node, while an ON-expr will not be a List. */ -join_qual: USING '(' using_list ')' { $$ = (Node *)$3; } - | ON a_expr { $$ = (Node *)$2; } +join_qual: USING '(' name_list ')' { $$ = (Node *) $3; } + | ON a_expr { $$ = $2; } ; -using_list: using_list ',' using_expr { $$ = lappend($1, $3); } - | using_expr { $$ = lcons($1, NIL); } - ; - -using_expr: ColId - { - /* could be a column name or a relation_name */ - Ident *n = makeNode(Ident); - n->name = $1; - n->indirection = NULL; - $$ = n; - } - ; - -where_clause: WHERE a_expr { $$ = $2; } - | /*EMPTY*/ { $$ = NULL; /* no qualifiers */ } - ; relation_expr: relation_name { /* default inheritance */ - $$ = makeNode(RelExpr); + $$ = makeNode(RangeVar); $$->relname = $1; $$->inh = SQL_inheritance; + $$->name = NULL; } | relation_name '*' %prec '=' { /* inheritance query */ - $$ = makeNode(RelExpr); + $$ = makeNode(RangeVar); $$->relname = $1; $$->inh = TRUE; + $$->name = NULL; } | ONLY relation_name %prec '=' { /* no inheritance */ - $$ = makeNode(RelExpr); + $$ = makeNode(RangeVar); $$->relname = $2; $$->inh = FALSE; + $$->name = NULL; } ; -opt_array_bounds: '[' ']' opt_array_bounds - { $$ = lcons(makeInteger(-1), $3); } - | '[' Iconst ']' opt_array_bounds - { $$ = lcons(makeInteger($2), $4); } - | /*EMPTY*/ - { $$ = NIL; } +where_clause: WHERE a_expr { $$ = $2; } + | /*EMPTY*/ { $$ = NULL; /* no qualifiers */ } ; @@ -4023,6 +4004,14 @@ Typename: SimpleTypename opt_array_bounds } ; +opt_array_bounds: '[' ']' opt_array_bounds + { $$ = lcons(makeInteger(-1), $3); } + | '[' Iconst ']' opt_array_bounds + { $$ = lcons(makeInteger($2), $4); } + | /*EMPTY*/ + { $$ = NIL; } + ; + SimpleTypename: ConstTypename | ConstInterval ; @@ -6024,29 +6013,19 @@ xlateSqlType(char *name) void parser_init(Oid *typev, int nargs) { + saved_relname[0] = '\0'; QueryIsRule = FALSE; - saved_relname[0]= '\0'; - - param_type_init(typev, nargs); -} - - -/* - * param_type_init() - * - * Keep enough information around to fill out the type of param nodes - * used in postquel functions - */ -static void -param_type_init(Oid *typev, int nargs) -{ - pfunc_num_args = nargs; + /* + * Keep enough information around to fill out the type of param nodes + * used in postquel functions + */ param_type_info = typev; + pfunc_num_args = nargs; } Oid param_type(int t) { - if ((t > pfunc_num_args) || (t == 0)) + if ((t > pfunc_num_args) || (t <= 0)) return InvalidOid; return param_type_info[t - 1]; } |
