diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 61a81a41a261c1f827a84df5a2f57d93f03c998a..f9709ebdac1183d6235a57bc03e3f0254737585d 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -2,15 +2,15 @@ /*#define YYDEBUG 1*/ /*------------------------------------------------------------------------- - * + * * gram.y-- * POSTGRES SQL YACC rules/actions - * + * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 1.40 1997/08/28 05:02:01 vadim Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 1.41 1997/09/01 06:00:35 thomas Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -72,7 +72,7 @@ static Node *makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr); %union { - double dval; + double dval; int ival; char chr; char *str; @@ -96,7 +96,7 @@ static Node *makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr); A_Indices *aind; ResTarget *target; ParamNo *paramno; - + VersionStmt *vstmt; DefineStmt *dstmt; PurgeStmt *pstmt; @@ -104,11 +104,11 @@ static Node *makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr); AppendStmt *astmt; } -%type <node> stmt, +%type <node> stmt, AddAttrStmt, ClosePortalStmt, - CopyStmt, CreateStmt, CreateSeqStmt, DefineStmt, DestroyStmt, + CopyStmt, CreateStmt, CreateSeqStmt, DefineStmt, DestroyStmt, ExtendStmt, FetchStmt, GrantStmt, - IndexStmt, MoveStmt, ListenStmt, OptimizableStmt, + IndexStmt, MoveStmt, ListenStmt, OptimizableStmt, ProcedureStmt, PurgeStmt, RecipeStmt, RemoveAggrStmt, RemoveOperStmt, RemoveFuncStmt, RemoveStmt, RenameStmt, RevokeStmt, RuleStmt, TransactionStmt, ViewStmt, LoadStmt, @@ -116,6 +116,13 @@ static Node *makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr); ReplaceStmt, AppendStmt, NotifyStmt, DeleteStmt, ClusterStmt, ExplainStmt, VariableSetStmt, VariableShowStmt, VariableResetStmt +%type <str> txname +%type <node> SubSelect +%type <str> join_clause, join_type, join_outer, join_spec +%type <boolean> join_qual + +%type <str> datetime + %type <str> relation_name, copy_file_name, copy_delimiter, def_name, database_name, access_method_clause, access_method, attr_name, class, index_name, name, file_name, recipe_name, @@ -142,13 +149,21 @@ static Node *makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr); expr_list, default_expr_list, attrs, res_target_list, res_target_list2, def_list, opt_indirection, group_clause, groupby_list -%type <boolean> opt_inh_star, opt_binary, opt_instead, opt_with_copy, +%type <list> union_clause, select_list +%type <list> join_list +%type <sortgroupby> join_using + +%type <list> extract_list, position_list +%type <list> substr_list, substr_from, substr_for, trim_list +%type <list> interval_opts + +%type <boolean> opt_inh_star, opt_binary, opt_instead, opt_with_col, opt_with_copy, index_opt_unique, opt_verbose, opt_analyze, opt_null -%type <ival> copy_dirn, archive_type, OptArchiveType, OptArchiveLocation, +%type <ival> copy_dirn, archive_type, OptArchiveType, OptArchiveLocation, def_type, opt_direction, remove_type, opt_column, event -%type <ival> OptLocation, opt_move_where, fetch_how_many +%type <ival> OptLocation, opt_move_where, fetch_how_many %type <list> OptSeqList %type <defelt> OptSeqElem @@ -160,7 +175,7 @@ static Node *makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr); %type <typnam> Typename, typname, opt_type %type <coldef> columnDef %type <defelt> def_elem -%type <node> def_arg, columnElem, where_clause, +%type <node> def_arg, columnElem, where_clause, a_expr, a_expr_or_null, AexprConst, default_expr, default_expr_or_null, in_expr_nodes, not_in_expr_nodes, @@ -178,36 +193,40 @@ static Node *makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr); %type <ival> Iconst %type <str> Sconst -%type <str> Id, date, var_value +%type <str> Id, date, var_value, zone_value +%type <str> ColId /* * If you make any token changes, remember to: * - use "yacc -d" and update parse.h - * - update the keyword table in parser/keywords.c + * - update the keyword table in parser/keywords.c */ /* Keywords */ -%token ABORT_TRANS, ACL, ADD, AFTER, AGGREGATE, ALL, ALTER, ANALYZE, - AND, APPEND, ARCHIVE, ARCH_STORE, AS, ASC, - BACKWARD, BEFORE, BEGIN_TRANS, BETWEEN, BINARY, BY, - CAST, CHANGE, CHECK, CLOSE, CLUSTER, COLUMN, COMMIT, CONSTRAINT, - COPY, CREATE, CURRENT, CURSOR, DATABASE, DECLARE, DEFAULT, DELETE, - DELIMITERS, DESC, DISTINCT, DO, DROP, END_TRANS, - EXTEND, FETCH, FOR, FORWARD, FROM, FUNCTION, GRANT, GROUP, - HAVING, HEAVY, IN, INDEX, INHERITS, INSERT, INSTEAD, INTO, IS, - ISNULL, LANGUAGE, LIGHT, LISTEN, LOAD, MERGE, MOVE, NEW, - NONE, NOT, NOTHING, NOTIFY, NOTNULL, - OIDS, ON, OPERATOR, OPTION, OR, ORDER, - PNULL, PRIVILEGES, PUBLIC, PURGE, P_TYPE, - RENAME, REPLACE, RESET, RETRIEVE, RETURNS, REVOKE, ROLLBACK, RULE, - SELECT, SET, SETOF, SHOW, STDIN, STDOUT, STORE, - TABLE, TO, TRANSACTION, UNIQUE, UPDATE, USING, VACUUM, VALUES - VERBOSE, VERSION, VIEW, WHERE, WITH, WORK +%token ABORT_TRANS, ACL, ADD, AFTER, AGGREGATE, ALL, ALTER, ANALYZE, + AND, APPEND, ARCHIVE, ARCH_STORE, AS, ASC, + BACKWARD, BEFORE, BEGIN_TRANS, BETWEEN, BINARY, BOTH, BY, + CAST, CHANGE, CHECK, CLOSE, CLUSTER, COLUMN, COMMIT, CONSTRAINT, COPY, CREATE, CROSS, + CURRENT, CURSOR, DATABASE, DAYINTERVAL, DECLARE, DEFAULT, DELETE, DELIMITERS, DESC, + DISTINCT, DO, DROP, END_TRANS, EXISTS, EXTEND, EXTRACT, + FETCH, FOR, FORWARD, FROM, FULL, FUNCTION, GRANT, GROUP, + HAVING, HEAVY, HOURINTERVAL, + IN, INDEX, INHERITS, INNERJOIN, INSERT, INSTEAD, INTERVAL, INTO, IS, ISNULL, + JOIN, LANGUAGE, LEADING, LEFT, LIGHT, LISTEN, LOAD, LOCAL, + MERGE, MINUTEINTERVAL, MONTHINTERVAL, MOVE, + NATURAL, NEW, NONE, NOT, NOTHING, NOTIFY, NOTNULL, + OIDS, ON, OPERATOR, OPTION, OR, ORDER, OUTERJOIN, + PNULL, POSITION, PRIVILEGES, PUBLIC, PURGE, P_TYPE, + RENAME, REPLACE, RESET, RETRIEVE, RETURNS, REVOKE, RIGHT, ROLLBACK, RULE, + SECONDINTERVAL, SELECT, SET, SETOF, SHOW, STDIN, STDOUT, STORE, SUBSTRING, + TABLE, TIME, TO, TRAILING, TRANSACTION, TRIM, + UNION, UNIQUE, UPDATE, USING, VACUUM, VALUES, + VERBOSE, VERSION, VIEW, WHERE, WITH, WORK, YEARINTERVAL, ZONE %token EXECUTE, RECIPE, EXPLAIN, LIKE, SEQUENCE /* Special keywords, not in the query language - see the "lex" file */ -%token <str> IDENT, SCONST, Op +%token <str> IDENT, SCONST, Op %token <ival> ICONST, PARAM %token <dval> FCONST @@ -218,7 +237,7 @@ static Node *makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr); %left OR %left AND %right NOT -%right '=' +%right '=' %nonassoc LIKE %nonassoc BETWEEN %nonassoc IN @@ -226,17 +245,18 @@ static Node *makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr); %nonassoc NOTNULL %nonassoc ISNULL %nonassoc IS -%left '+' '-' -%left '*' '/' +%left '+' '-' +%left '*' '/' %left '|' /* this is the relation union op, not logical or */ %right ':' /* Unary Operators */ %left ';' /* end of statement or natural log */ %nonassoc '<' '>' %right UMINUS %left '.' -%left '[' ']' +%left '[' ']' %nonassoc TYPECAST %nonassoc REDUCE +%left UNION %% stmtblock: stmtmulti @@ -264,23 +284,23 @@ stmt : AddAttrStmt | ExtendStmt | ExplainStmt | FetchStmt - | GrantStmt + | GrantStmt | IndexStmt | MoveStmt - | ListenStmt + | ListenStmt | ProcedureStmt - | PurgeStmt + | PurgeStmt | RecipeStmt | RemoveAggrStmt | RemoveOperStmt | RemoveFuncStmt | RemoveStmt | RenameStmt - | RevokeStmt - | OptimizableStmt - | RuleStmt + | RevokeStmt + | OptimizableStmt + | RuleStmt | TransactionStmt - | ViewStmt + | ViewStmt | LoadStmt | CreatedbStmt | DestroydbStmt @@ -291,25 +311,43 @@ stmt : AddAttrStmt ; /***************************************************************************** - * + * * Set PG internal variable * SET var_name TO 'var_value' - * + * *****************************************************************************/ -VariableSetStmt: SET var_name TO var_value +VariableSetStmt: SET var_name TO var_value { VariableSetStmt *n = makeNode(VariableSetStmt); n->name = $2; n->value = $4; $$ = (Node *) n; } + | SET var_name '=' var_value + { + VariableSetStmt *n = makeNode(VariableSetStmt); + n->name = $2; + n->value = $4; + $$ = (Node *) n; + } + | SET TIME ZONE zone_value + { + VariableSetStmt *n = makeNode(VariableSetStmt); + n->name = "timezone"; + n->value = $4; + $$ = (Node *) n; + } ; var_value: Sconst { $$ = $1; } ; -VariableShowStmt: SHOW var_name +zone_value: Sconst { $$ = $1; } + | LOCAL { $$ = NULL; } + ; + +VariableShowStmt: SHOW var_name { VariableShowStmt *n = makeNode(VariableShowStmt); n->name = $2; @@ -317,7 +355,7 @@ VariableShowStmt: SHOW var_name } ; -VariableResetStmt: RESET var_name +VariableResetStmt: RESET var_name { VariableResetStmt *n = makeNode(VariableResetStmt); n->name = $2; @@ -342,13 +380,22 @@ AddAttrStmt: ALTER TABLE relation_name opt_inh_star ADD COLUMN columnDef } ; -columnDef: Id Typename OptDefault opt_null +/* Column definition might include WITH TIME ZONE, but only for the data types + * called out in SQL92 date/time definitions. So, check explicitly for "timestamp" + * and "time". - thomas 1997-07-14 + */ +columnDef: Id Typename opt_with_col OptDefault opt_null { $$ = makeNode(ColumnDef); $$->colname = $1; $$->typename = $2; - $$->defval = $3; - $$->is_not_null = $4; + $$->typename->timezone = $3; + $$->defval = $4; + $$->is_not_null = $5; + if ($$->typename->timezone + && (strcasecmp($$->typename->name, "timestamp") + && strcasecmp($$->typename->name, "time"))) + elog(NOTICE,"%s does not use WITH TIME ZONE",$$->typename->name); } ; @@ -457,18 +504,21 @@ default_expr_list: default_expr_or_null opt_null: NOT PNULL { $$ = true; } | NOTNULL { $$ = true; } | /* EMPTY */ { $$ = false; } + ; + +opt_with_col: WITH TIME ZONE { $$ = TRUE; } + | /* EMPTY */ { $$ = FALSE; } ; - /***************************************************************************** - * + * * QUERY : * close <optname> - * + * *****************************************************************************/ -ClosePortalStmt: CLOSE opt_id - { +ClosePortalStmt: CLOSE opt_id + { ClosePortalStmt *n = makeNode(ClosePortalStmt); n->portalname = $2; $$ = (Node *)n; @@ -479,7 +529,7 @@ ClosePortalStmt: CLOSE opt_id /***************************************************************************** * * QUERY : - * COPY [BINARY] <relname> FROM/TO + * COPY [BINARY] <relname> FROM/TO * [USING DELIMITERS <delimiter>] * *****************************************************************************/ @@ -497,13 +547,13 @@ CopyStmt: COPY opt_binary relation_name opt_with_copy copy_dirn copy_file_name } ; -copy_dirn: TO +copy_dirn: TO { $$ = TO; } | FROM { $$ = FROM; } ; -/* +/* * copy_file_name NULL indicates stdio is used. Whether stdin or stdout is * used depends on the direction. (It really doesn't make sense to copy from * stdout. We silently correct the "typo". - AY 9/94 @@ -557,9 +607,9 @@ OptTableElementList: tableElementList { $$ = $1; } ; tableElementList : - tableElementList ',' columnDef + tableElementList ',' columnDef { $$ = lappend($1, $3); } - | columnDef + | columnDef { $$ = lcons($1, NIL); } ; @@ -568,20 +618,20 @@ OptArchiveType: ARCHIVE '=' archive_type { $$ = $3; } | /*EMPTY*/ { $$ = ARCH_NONE; } ; -archive_type: HEAVY { $$ = ARCH_HEAVY; } - | LIGHT { $$ = ARCH_LIGHT; } +archive_type: HEAVY { $$ = ARCH_HEAVY; } + | LIGHT { $$ = ARCH_LIGHT; } | NONE { $$ = ARCH_NONE; } ; OptLocation: STORE '=' Sconst { $$ = smgrin($3); } - | /*EMPTY*/ + | /*EMPTY*/ { $$ = -1; } ; OptArchiveLocation: ARCH_STORE '=' Sconst { $$ = smgrin($3); } - | /*EMPTY*/ + | /*EMPTY*/ { $$ = -1; } ; @@ -642,14 +692,14 @@ CreateSeqStmt: CREATE SEQUENCE relation_name OptSeqList } ; -OptSeqList: +OptSeqList: OptSeqList OptSeqElem { $$ = lappend($1, $2); } - | { $$ = NIL; } + | { $$ = NIL; } ; OptSeqElem: IDENT NumConst - { + { $$ = makeNode(DefElem); $$->defname = $1; $$->arg = (Node *)$2; @@ -665,7 +715,7 @@ OptSeqElem: IDENT NumConst /***************************************************************************** * - * QUERY : + * QUERY : * define (type,operator,aggregate) * *****************************************************************************/ @@ -677,7 +727,7 @@ DefineStmt: CREATE def_type def_rest } ; -def_rest: def_name definition +def_rest: def_name definition { $$ = makeNode(DefineStmt); $$->defname = $1; @@ -685,12 +735,12 @@ def_rest: def_name definition } ; -def_type: OPERATOR { $$ = OPERATOR; } - | Type { $$ = P_TYPE; } +def_type: OPERATOR { $$ = OPERATOR; } + | Type { $$ = P_TYPE; } | AGGREGATE { $$ = AGGREGATE; } ; -def_name: Id | MathOp | Op +def_name: Id | MathOp | Op ; @@ -705,7 +755,7 @@ def_list: def_elem ; def_elem: def_name '=' def_arg - { + { $$ = makeNode(DefElem); $$->defname = $1; $$->arg = (Node *)$3; @@ -728,33 +778,33 @@ def_elem: def_name '=' def_arg def_arg: Id { $$ = (Node *)makeString($1); } | all_Op { $$ = (Node *)makeString($1); } | NumConst { $$ = (Node *)$1; /* already a Value */ } - | Sconst { $$ = (Node *)makeString($1); } - | SETOF Id { + | Sconst { $$ = (Node *)makeString($1); } + | SETOF Id { TypeName *n = makeNode(TypeName); n->name = $2; n->setof = TRUE; n->arrayBounds = NULL; $$ = (Node *)n; - } + } ; /***************************************************************************** * - * QUERY: + * QUERY: * destroy <relname1> [, <relname2> .. <relnameN> ] * *****************************************************************************/ DestroyStmt: DROP TABLE relation_name_list - { + { DestroyStmt *n = makeNode(DestroyStmt); n->relNames = $3; n->sequence = false; $$ = (Node *)n; } | DROP SEQUENCE relation_name_list - { + { DestroyStmt *n = makeNode(DestroyStmt); n->relNames = $3; n->sequence = true; @@ -785,7 +835,7 @@ opt_direction: FORWARD { $$ = FORWARD; } | /*EMPTY*/ { $$ = FORWARD; /* default */ } ; -fetch_how_many: Iconst +fetch_how_many: Iconst { $$ = $1; if ($1 <= 0) elog(WARN,"Please specify nonnegative count for fetch"); } | ALL { $$ = 0; /* 0 means fetch all tuples*/} @@ -800,70 +850,70 @@ fetch_how_many: Iconst *****************************************************************************/ GrantStmt: GRANT privileges ON relation_name_list TO grantee opt_with_grant - { - $$ = (Node*)makeAclStmt($2,$4,$6,'+'); - free($2); - free($6); - } - ; + { + $$ = (Node*)makeAclStmt($2,$4,$6,'+'); + free($2); + free($6); + } + ; privileges: ALL PRIVILEGES { $$ = aclmakepriv("rwaR",0); } - | ALL + | ALL { $$ = aclmakepriv("rwaR",0); } - | operation_commalist { + | operation_commalist { $$ = $1; } - ; + ; operation_commalist: operation { $$ = aclmakepriv("",$1); } - | operation_commalist ',' operation + | operation_commalist ',' operation { $$ = aclmakepriv($1,$3); free($1); } - ; + ; operation: SELECT { $$ = ACL_MODE_RD_CHR; } - | INSERT { + | INSERT { $$ = ACL_MODE_AP_CHR; } - | UPDATE { + | UPDATE { $$ = ACL_MODE_WR_CHR; } - | DELETE { + | DELETE { $$ = ACL_MODE_WR_CHR; } | RULE { $$ = ACL_MODE_RU_CHR; } - ; + ; -grantee: PUBLIC { +grantee: PUBLIC { $$ = aclmakeuser("A",""); } - | GROUP Id { + | GROUP Id { $$ = aclmakeuser("G",$2); } - | Id { + | Id { $$ = aclmakeuser("U",$1); - } - ; + } + ; opt_with_grant : /* empty */ - | WITH GRANT OPTION - { - yyerror("WITH GRANT OPTION is not supported. Only relation owners can set privileges"); - } - ; + | WITH GRANT OPTION + { + yyerror("WITH GRANT OPTION is not supported. Only relation owners can set privileges"); + } + ; /***************************************************************************** * * QUERY: @@ -872,12 +922,12 @@ opt_with_grant : /* empty */ *****************************************************************************/ RevokeStmt: REVOKE privileges ON relation_name_list FROM grantee - { - $$ = (Node*)makeAclStmt($2,$4,$6,'-'); - free($2); - free($6); - } - ; + { + $$ = (Node*)makeAclStmt($2,$4,$6,'-'); + free($2); + free($6); + } + ; /***************************************************************************** * @@ -887,7 +937,7 @@ RevokeStmt: REVOKE privileges ON relation_name_list FROM grantee *****************************************************************************/ MoveStmt: MOVE opt_direction opt_move_where opt_portal_name - { + { MoveStmt *n = makeNode(MoveStmt); n->direction = $2; n->to = FALSE; @@ -896,7 +946,7 @@ MoveStmt: MOVE opt_direction opt_move_where opt_portal_name $$ = (Node *)n; } | MOVE opt_direction TO Iconst opt_portal_name - { + { MoveStmt *n = makeNode(MoveStmt); n->direction = $2; n->to = TRUE; @@ -970,11 +1020,11 @@ ExtendStmt: EXTEND INDEX index_name where_clause /***************************************************************************** * * QUERY: - * execute recipe <recipeName> + * execute recipe <recipeName> * *****************************************************************************/ -RecipeStmt: EXECUTE RECIPE recipe_name +RecipeStmt: EXECUTE RECIPE recipe_name { RecipeStmt *n; if (!IsTransactionBlock()) @@ -991,7 +1041,7 @@ RecipeStmt: EXECUTE RECIPE recipe_name * * QUERY: * define function <fname> - * (language = <lang>, returntype = <typename> + * (language = <lang>, returntype = <typename> * [, arch_pct = <percentage | pre-defined>] * [, disk_pct = <percentage | pre-defined>] * [, byte_pct = <percentage | pre-defined>] @@ -1003,9 +1053,9 @@ RecipeStmt: EXECUTE RECIPE recipe_name * *****************************************************************************/ -ProcedureStmt: CREATE FUNCTION def_name def_args +ProcedureStmt: CREATE FUNCTION def_name def_args RETURNS def_arg opt_with AS Sconst LANGUAGE Sconst - { + { ProcedureStmt *n = makeNode(ProcedureStmt); n->funcname = $3; n->defArgs = $4; @@ -1021,10 +1071,10 @@ opt_with: WITH definition { $$ = $2; } ; def_args: '(' def_name_list ')' { $$ = $2; } - | '(' ')' { $$ = NIL; } + | '(' ')' { $$ = NIL; } ; -def_name_list: name_list; +def_name_list: name_list; /***************************************************************************** @@ -1032,43 +1082,43 @@ def_name_list: name_list; * QUERY: * purge <relname> [before <date>] [after <date>] * or - * purge <relname> [after<date>][before <date>] - * + * purge <relname> [after <date>] [before <date>] + * *****************************************************************************/ PurgeStmt: PURGE relation_name purge_quals - { + { $3->relname = $2; $$ = (Node *)$3; } ; purge_quals: before_clause - { + { $$ = makeNode(PurgeStmt); $$->beforeDate = $1; $$->afterDate = NULL; } | after_clause - { + { $$ = makeNode(PurgeStmt); $$->beforeDate = NULL; $$->afterDate = $1; } | before_clause after_clause - { + { $$ = makeNode(PurgeStmt); $$->beforeDate = $1; $$->afterDate = $2; } | after_clause before_clause - { + { $$ = makeNode(PurgeStmt); $$->beforeDate = $2; $$->afterDate = $1; } | /*EMPTY*/ - { + { $$ = makeNode(PurgeStmt); $$->beforeDate = NULL; $$->afterDate = NULL; @@ -1105,11 +1155,11 @@ RemoveStmt: DROP remove_type name } ; -remove_type: Type { $$ = P_TYPE; } - | INDEX { $$ = INDEX; } - | RULE { $$ = RULE; } +remove_type: Type { $$ = P_TYPE; } + | INDEX { $$ = INDEX; } + | RULE { $$ = RULE; } | VIEW { $$ = VIEW; } - ; + ; RemoveAggrStmt: DROP AGGREGATE name aggr_argtype { @@ -1125,16 +1175,16 @@ aggr_argtype: name { $$ = $1; } ; RemoveFuncStmt: DROP FUNCTION name '(' func_argtypes ')' - { + { RemoveFuncStmt *n = makeNode(RemoveFuncStmt); n->funcname = $3; n->args = $5; $$ = (Node *)n; } - ; + ; func_argtypes: name_list { $$ = $1; } - | /*EMPTY*/ { $$ = NIL; } + | /*EMPTY*/ { $$ = NIL; } ; RemoveOperStmt: DROP OPERATOR all_Op '(' oper_argtypes ')' @@ -1144,21 +1194,21 @@ RemoveOperStmt: DROP OPERATOR all_Op '(' oper_argtypes ')' n->args = $5; $$ = (Node *)n; } - ; + ; all_Op: Op | MathOp; -MathOp: '+' { $$ = "+"; } - | '-' { $$ = "-"; } - | '*' { $$ = "*"; } - | '/' { $$ = "/"; } - | '<' { $$ = "<"; } - | '>' { $$ = ">"; } - | '=' { $$ = "="; } +MathOp: '+' { $$ = "+"; } + | '-' { $$ = "-"; } + | '*' { $$ = "*"; } + | '/' { $$ = "/"; } + | '<' { $$ = "<"; } + | '>' { $$ = ">"; } + | '=' { $$ = "="; } ; -oper_argtypes: name - { +oper_argtypes: name + { elog(WARN, "parser: argument type missing (use NONE for unary operators)"); } | name ',' name @@ -1171,15 +1221,15 @@ oper_argtypes: name /***************************************************************************** * - * QUERY: + * QUERY: * rename <attrname1> in <relname> [*] to <attrname2> * rename <relname1> to <relname2> - * + * *****************************************************************************/ -RenameStmt: ALTER TABLE relation_name opt_inh_star +RenameStmt: ALTER TABLE relation_name opt_inh_star RENAME opt_column opt_name TO name - { + { RenameStmt *n = makeNode(RenameStmt); n->relname = $3; n->inh = $4; @@ -1199,15 +1249,15 @@ opt_column: COLUMN { $$ = COLUMN; } /***************************************************************************** - * - * QUERY: Define Rewrite Rule , Define Tuple Rule + * + * QUERY: Define Rewrite Rule , Define Tuple Rule * Define Rule <old rules > * * only rewrite rule is supported -- ay 9/94 - * + * *****************************************************************************/ -RuleStmt: CREATE RULE name AS +RuleStmt: CREATE RULE name AS { QueryIsRule=TRUE; } ON event TO event_object where_clause DO opt_instead OptStmtList @@ -1224,26 +1274,26 @@ RuleStmt: CREATE RULE name AS ; OptStmtList: NOTHING { $$ = NIL; } - | OptimizableStmt { $$ = lcons($1, NIL); } + | OptimizableStmt { $$ = lcons($1, NIL); } | '[' OptStmtBlock ']' { $$ = $2; } - ; + ; OptStmtBlock: OptStmtMulti - { $$ = $1; } + { $$ = $1; } | OptimizableStmt { $$ = lcons($1, NIL); } ; - + OptStmtMulti: OptStmtMulti OptimizableStmt ';' - { $$ = lappend($1, $2); } + { $$ = lappend($1, $2); } | OptStmtMulti OptimizableStmt - { $$ = lappend($1, $2); } + { $$ = lappend($1, $2); } | OptimizableStmt ';' { $$ = lcons($1, NIL); } ; - + event_object: relation_name '.' attr_name - { + { $$ = makeNode(Attr); $$->relname = $1; $$->paramNo = NULL; @@ -1258,12 +1308,12 @@ event_object: relation_name '.' attr_name $$->attrs = NIL; $$->indirection = NIL; } - ; + ; /* change me to select, update, etc. some day */ -event: SELECT { $$ = CMD_SELECT; } - | UPDATE { $$ = CMD_UPDATE; } - | DELETE { $$ = CMD_DELETE; } +event: SELECT { $$ = CMD_SELECT; } + | UPDATE { $$ = CMD_UPDATE; } + | DELETE { $$ = CMD_DELETE; } | INSERT { $$ = CMD_INSERT; } ; @@ -1280,7 +1330,7 @@ opt_instead: INSTEAD { $$ = TRUE; } * *****************************************************************************/ -NotifyStmt: NOTIFY relation_name +NotifyStmt: NOTIFY relation_name { NotifyStmt *n = makeNode(NotifyStmt); n->relname = $2; @@ -1288,7 +1338,7 @@ NotifyStmt: NOTIFY relation_name } ; -ListenStmt: LISTEN relation_name +ListenStmt: LISTEN relation_name { ListenStmt *n = makeNode(ListenStmt); n->relname = $2; @@ -1307,74 +1357,74 @@ ListenStmt: LISTEN relation_name * (BEGIN) * end transaction * (END) - * + * *****************************************************************************/ TransactionStmt: ABORT_TRANS TRANSACTION - { - TransactionStmt *n = makeNode(TransactionStmt); - n->command = ABORT_TRANS; + { + TransactionStmt *n = makeNode(TransactionStmt); + n->command = ABORT_TRANS; $$ = (Node *)n; } | BEGIN_TRANS TRANSACTION - { - TransactionStmt *n = makeNode(TransactionStmt); + { + TransactionStmt *n = makeNode(TransactionStmt); n->command = BEGIN_TRANS; $$ = (Node *)n; } | BEGIN_TRANS WORK { - TransactionStmt *n = makeNode(TransactionStmt); + TransactionStmt *n = makeNode(TransactionStmt); n->command = BEGIN_TRANS; $$ = (Node *)n; } | COMMIT WORK { - TransactionStmt *n = makeNode(TransactionStmt); + TransactionStmt *n = makeNode(TransactionStmt); n->command = END_TRANS; $$ = (Node *)n; } | END_TRANS TRANSACTION - { - TransactionStmt *n = makeNode(TransactionStmt); + { + TransactionStmt *n = makeNode(TransactionStmt); n->command = END_TRANS; $$ = (Node *)n; } | ROLLBACK WORK { - TransactionStmt *n = makeNode(TransactionStmt); + TransactionStmt *n = makeNode(TransactionStmt); n->command = ABORT_TRANS; $$ = (Node *)n; } | ABORT_TRANS - { - TransactionStmt *n = makeNode(TransactionStmt); - n->command = ABORT_TRANS; + { + TransactionStmt *n = makeNode(TransactionStmt); + n->command = ABORT_TRANS; $$ = (Node *)n; } | BEGIN_TRANS - { - TransactionStmt *n = makeNode(TransactionStmt); + { + TransactionStmt *n = makeNode(TransactionStmt); n->command = BEGIN_TRANS; $$ = (Node *)n; } | COMMIT { - TransactionStmt *n = makeNode(TransactionStmt); + TransactionStmt *n = makeNode(TransactionStmt); n->command = END_TRANS; $$ = (Node *)n; } | END_TRANS - { - TransactionStmt *n = makeNode(TransactionStmt); + { + TransactionStmt *n = makeNode(TransactionStmt); n->command = END_TRANS; $$ = (Node *)n; } | ROLLBACK { - TransactionStmt *n = makeNode(TransactionStmt); + TransactionStmt *n = makeNode(TransactionStmt); n->command = ABORT_TRANS; $$ = (Node *)n; } @@ -1389,7 +1439,7 @@ TransactionStmt: ABORT_TRANS TRANSACTION *****************************************************************************/ ViewStmt: CREATE VIEW name AS RetrieveStmt - { + { ViewStmt *n = makeNode(ViewStmt); n->viewname = $3; n->query = (Query *)$5; @@ -1406,12 +1456,12 @@ ViewStmt: CREATE VIEW name AS RetrieveStmt *****************************************************************************/ LoadStmt: LOAD file_name - { + { LoadStmt *n = makeNode(LoadStmt); n->filename = $2; $$ = (Node *)n; } - ; + ; /***************************************************************************** @@ -1422,12 +1472,12 @@ LoadStmt: LOAD file_name *****************************************************************************/ CreatedbStmt: CREATE DATABASE database_name - { + { CreatedbStmt *n = makeNode(CreatedbStmt); n->dbname = $3; $$ = (Node *)n; } - ; + ; /***************************************************************************** @@ -1438,12 +1488,12 @@ CreatedbStmt: CREATE DATABASE database_name *****************************************************************************/ DestroydbStmt: DROP DATABASE database_name - { + { DestroydbStmt *n = makeNode(DestroydbStmt); n->dbname = $3; $$ = (Node *)n; } - ; + ; /***************************************************************************** @@ -1453,7 +1503,7 @@ DestroydbStmt: DROP DATABASE database_name * *****************************************************************************/ -ClusterStmt: CLUSTER index_name ON relation_name +ClusterStmt: CLUSTER index_name ON relation_name { ClusterStmt *n = makeNode(ClusterStmt); n->relname = $4; @@ -1470,26 +1520,26 @@ ClusterStmt: CLUSTER index_name ON relation_name *****************************************************************************/ VacuumStmt: VACUUM opt_verbose opt_analyze - { - VacuumStmt *n = makeNode(VacuumStmt); - n->verbose = $2; - n->analyze = $3; - n->vacrel = NULL; - n->va_spec = NIL; - $$ = (Node *)n; - } - | VACUUM opt_verbose relation_name opt_analyze opt_va_list - { - VacuumStmt *n = makeNode(VacuumStmt); - n->verbose = $2; - n->analyze = $4; - n->vacrel = $3; - n->va_spec = $5; - if ( $5 != NIL && !$4 ) - elog (WARN, "parser: syntax error at or near \"(\""); - $$ = (Node *)n; - } - ; + { + VacuumStmt *n = makeNode(VacuumStmt); + n->verbose = $2; + n->analyze = $3; + n->vacrel = NULL; + n->va_spec = NIL; + $$ = (Node *)n; + } + | VACUUM opt_verbose relation_name opt_analyze opt_va_list + { + VacuumStmt *n = makeNode(VacuumStmt); + n->verbose = $2; + n->analyze = $4; + n->vacrel = $3; + n->va_spec = $5; + if ( $5 != NIL && !$4 ) + elog (WARN, "parser: syntax error at or near \"(\""); + $$ = (Node *)n; + } + ; opt_verbose: VERBOSE { $$ = TRUE; } | /* EMPTY */ { $$ = FALSE; } @@ -1503,14 +1553,14 @@ opt_va_list: '(' va_list ')' { $$ = $2; } | /* EMPTY */ { $$ = NIL; } - ; + ; va_list: name { $$=lcons($1,NIL); } | va_list ',' name { $$=lappend($1,$3); } - ; - + ; + /***************************************************************************** * * QUERY: @@ -1539,11 +1589,11 @@ ExplainStmt: EXPLAIN opt_verbose OptimizableStmt *****************************************************************************/ OptimizableStmt: RetrieveStmt - | CursorStmt + | CursorStmt | ReplaceStmt | AppendStmt - | NotifyStmt - | DeleteStmt /* by default all are $$=$1 */ + | NotifyStmt + | DeleteStmt /* by default all are $$=$1 */ ; @@ -1551,7 +1601,7 @@ OptimizableStmt: RetrieveStmt * * QUERY: * INSERT STATEMENTS - * + * *****************************************************************************/ AppendStmt: INSERT INTO relation_name opt_column_list insert_rest @@ -1559,7 +1609,7 @@ AppendStmt: INSERT INTO relation_name opt_column_list insert_rest $5->relname = $3; $5->cols = $4; $$ = (Node *)$5; - } + } ; insert_rest: VALUES '(' res_target_list2 ')' @@ -1582,7 +1632,7 @@ opt_column_list: '(' columnList ')' { $$ = $2; } | /*EMPTY*/ { $$ = NIL; } ; -columnList: +columnList: columnList ',' columnElem { $$ = lappend($1, $3); } | columnElem @@ -1590,7 +1640,7 @@ columnList: ; columnElem: Id opt_indirection - { + { Ident *id = makeNode(Ident); id->name = $1; id->indirection = $2; @@ -1604,16 +1654,16 @@ columnElem: Id opt_indirection * DELETE STATEMENTS * *****************************************************************************/ - + DeleteStmt: DELETE FROM relation_name where_clause - { + { DeleteStmt *n = makeNode(DeleteStmt); n->relname = $3; n->whereClause = $4; $$ = (Node *)n; } - ; + ; /***************************************************************************** @@ -1623,20 +1673,20 @@ DeleteStmt: DELETE FROM relation_name * *****************************************************************************/ -ReplaceStmt: UPDATE relation_name +ReplaceStmt: UPDATE relation_name SET res_target_list from_clause where_clause - { + { ReplaceStmt *n = makeNode(ReplaceStmt); n->relname = $2; n->targetList = $4; n->fromClause = $5; n->whereClause = $6; $$ = (Node *)n; - } - ; - + } + ; + /***************************************************************************** * @@ -1645,8 +1695,8 @@ ReplaceStmt: UPDATE relation_name * *****************************************************************************/ -CursorStmt: DECLARE name opt_binary CURSOR FOR - SELECT opt_unique res_target_list2 +CursorStmt: DECLARE name opt_binary CURSOR FOR + SELECT opt_unique res_target_list2 from_clause where_clause group_clause sort_clause { CursorStmt *n = makeNode(CursorStmt); @@ -1656,7 +1706,7 @@ CursorStmt: DECLARE name opt_binary CURSOR FOR * 15 august 1991 -- since 3.0 postgres does locking * right, we discovered that portals were violating * locking protocol. portal locks cannot span xacts. - * as a short-term fix, we installed the check here. + * as a short-term fix, we installed the check here. * -- mao */ if (!IsTransactionBlock()) @@ -1682,11 +1732,12 @@ CursorStmt: DECLARE name opt_binary CURSOR FOR * *****************************************************************************/ +/****************************************************************************** RetrieveStmt: SELECT opt_unique res_target_list2 - result from_clause where_clause + result from_clause where_clause group_clause having_clause sort_clause - { + { RetrieveStmt *n = makeNode(RetrieveStmt); n->unique = $2; n->targetList = $3; @@ -1700,6 +1751,69 @@ RetrieveStmt: SELECT opt_unique res_target_list2 } ; +RetrieveStmt: Select UNION select_list sort_clause + | Select sort_clause +Select: SELECT opt_unique res_target_list2 + result from_clause where_clause + group_clause having_clause + { + Select *n = makeNode(Select); + n->unique = $2; + n->targetList = $3; + n->into = $4; + n->fromClause = $5; + n->whereClause = $6; + n->groupClause = $7; + n->havingClause = $8; + $$ = (Node *)n; + } + ; +******************************************************************************/ + +RetrieveStmt: SELECT opt_unique res_target_list2 + result from_clause where_clause + group_clause having_clause + union_clause sort_clause + { + RetrieveStmt *n = makeNode(RetrieveStmt); + n->unique = $2; + n->targetList = $3; + n->into = $4; + n->fromClause = $5; + n->whereClause = $6; + n->groupClause = $7; + n->havingClause = $8; + n->selectClause = $9; + n->sortClause = $10; + $$ = (Node *)n; + } + ; + +union_clause: UNION select_list { $$ = $2; } + | /*EMPTY*/ { $$ = NIL; } + ; + +select_list: select_list UNION SubSelect + { $$ = lappend($1, $3); } + | SubSelect + { $$ = lcons($1, NIL); } + ; + +SubSelect: SELECT opt_unique res_target_list2 + result from_clause where_clause + group_clause having_clause + { + SubSelect *n = makeNode(SubSelect); + n->unique = $2; + n->targetList = $3; + n->fromClause = $5; + n->whereClause = $6; + n->groupClause = $7; + n->havingClause = $8; + $$ = (Node *)n; + } + ; + result: INTO TABLE relation_name { $$= $3; /* should check for archive level */ } | /*EMPTY*/ @@ -1711,7 +1825,7 @@ opt_unique: DISTINCT { $$ = "*"; } | /*EMPTY*/ { $$ = NULL;} ; -sort_clause: ORDER BY sortby_list { $$ = $3; } +sort_clause: ORDER BY sortby_list { $$ = $3; } | /*EMPTY*/ { $$ = NIL; } ; @@ -1722,7 +1836,7 @@ sortby_list: sortby ; sortby: Id OptUseOp - { + { $$ = makeNode(SortGroupBy); $$->resno = 0; $$->range = NULL; @@ -1782,13 +1896,13 @@ index_elem: attr_name opt_type opt_class $$->name = $1; $$->args = NIL; $$->class = $3; - $$->tname = $2; + $$->tname = $2; } ; opt_type: ':' Typename { $$ = $2;} - | /*EMPTY*/ { $$ = NULL;} - ; + | /*EMPTY*/ { $$ = NULL;} + ; opt_class: class | WITH class { $$ = $2; } @@ -1799,9 +1913,9 @@ opt_class: class * jimmy bell-style recursive queries aren't supported in the * current system. * - * ...however, recursive addattr and rename supported. make special + * ...however, recursive addattr and rename supported. make special * cases for these. - * + * * XXX i believe '*' should be the default behavior, but... */ opt_inh_star: '*' { $$ = TRUE; } @@ -1810,11 +1924,11 @@ opt_inh_star: '*' { $$ = TRUE; } relation_name_list: name_list ; -name_list: name +name_list: name { $$=lcons(makeString($1),NIL); } - | name_list ',' name + | name_list ',' name { $$=lappend($1,makeString($3)); } - ; + ; group_clause: GROUP BY groupby_list { $$ = $3; } | /*EMPTY*/ { $$ = NIL; } @@ -1855,19 +1969,26 @@ having_clause: HAVING a_expr { $$ = $2; } ; /***************************************************************************** - * + * * clauses common to all Optimizable Stmts: - * from_clause - - * where_clause - - * + * from_clause - + * where_clause - + * *****************************************************************************/ -from_clause: FROM from_list { $$ = $2; } +from_clause: FROM '(' relation_expr join_clause relation_expr join_spec ')' + { + $$ = NIL; + elog(WARN,"JOIN not yet implemented",NULL); + } + | FROM from_list { $$ = $2; } | /*EMPTY*/ { $$ = NIL; } ; from_list: from_list ',' from_val { $$ = lappend($1, $3); } + | from_val CROSS JOIN from_val + { elog(WARN,"CROSS JOIN not yet implemented",NULL); } | from_val { $$ = lcons($1, NIL); } ; @@ -1877,7 +1998,7 @@ from_val: relation_expr AS var_name $$ = makeNode(RangeVar); $$->relExpr = $1; $$->name = $3; - } + } | relation_expr var_name { $$ = makeNode(RangeVar); @@ -1892,12 +2013,76 @@ from_val: relation_expr AS var_name } ; +join_clause: join_qual join_type JOIN + { + $$ = NULL; + } + ; + +join_qual: NATURAL { $$ = TRUE; } + | /*EMPTY*/ { $$ = FALSE; } + ; + +join_type: FULL join_outer + { elog(WARN,"FULL OUTER JOIN not yet implemented",NULL); } + | LEFT join_outer + { elog(WARN,"LEFT OUTER JOIN not yet implemented",NULL); } + | RIGHT join_outer + { elog(WARN,"RIGHT OUTER JOIN not yet implemented",NULL); } + | join_outer + { elog(WARN,"OUTER JOIN not yet implemented",NULL); } + | INNERJOIN + { elog(WARN,"INNER JOIN not yet implemented",NULL); } + | UNION + { elog(WARN,"UNION JOIN not yet implemented",NULL); } + | /*EMPTY*/ { $$ = NULL; /* no qualifiers */ } + ; + +join_outer: OUTERJOIN { $$ = NULL; } + | /*EMPTY*/ { $$ = NULL; /* no qualifiers */ } + ; + +join_spec: ON '(' a_expr ')' { $$ = NULL; } + | USING '(' join_list ')' { $$ = NULL; } + | /*EMPTY*/ { $$ = NULL; /* no qualifiers */ } + ; + +join_list: join_using { $$ = lcons($1, NIL); } + | join_list ',' join_using { $$ = lappend($1, $3); } + ; + +join_using: Id + { + $$ = makeNode(SortGroupBy); + $$->resno = 0; + $$->range = NULL; + $$->name = $1; + $$->useOp = NULL; + } + | Id '.' Id + { + $$ = makeNode(SortGroupBy); + $$->resno = 0; + $$->range = $1; + $$->name = $3; + $$->useOp = NULL; + } + | Iconst + { + $$ = makeNode(SortGroupBy); + $$->resno = $1; + $$->range = NULL; + $$->name = NULL; + $$->useOp = NULL; + } + ; + where_clause: WHERE a_expr { $$ = $2; } - | /*EMPTY*/ { $$ = NULL; /* no qualifiers */ } + | /*EMPTY*/ { $$ = NULL; /* no qualifiers */ } ; relation_expr: relation_name - { + { /* normal relations */ $$ = makeNode(RelExpr); $$->relname = $1; @@ -1905,15 +2090,15 @@ relation_expr: relation_name $$->timeRange = NULL; } | relation_name '*' %prec '=' - { + { /* inheiritance query */ $$ = makeNode(RelExpr); $$->relname = $1; $$->inh = TRUE; $$->timeRange = NULL; } - | relation_name time_range - { + | relation_name time_range + { /* time-qualified query */ $$ = makeNode(RelExpr); $$->relname = $1; @@ -1922,20 +2107,20 @@ relation_expr: relation_name } ; - + time_range: '[' opt_range_start ',' opt_range_end ']' - { + { $$ = makeNode(TimeRange); $$->startDate = $2; $$->endDate = $4; } | '[' date ']' - { + { $$ = makeNode(TimeRange); $$->startDate = $2; $$->endDate = NULL; } - ; + ; opt_range_start: date | /*EMPTY*/ { $$ = "epoch"; } @@ -1949,19 +2134,19 @@ opt_array_bounds: '[' ']' nest_array_bounds { $$ = lcons(makeInteger(-1), $3); } | '[' Iconst ']' nest_array_bounds { $$ = lcons(makeInteger($2), $4); } - | /* EMPTY */ + | /* EMPTY */ { $$ = NIL; } ; nest_array_bounds: '[' ']' nest_array_bounds { $$ = lcons(makeInteger(-1), $3); } - | '[' Iconst ']' nest_array_bounds + | '[' Iconst ']' nest_array_bounds { $$ = lcons(makeInteger($2), $4); } | /*EMPTY*/ { $$ = NIL; } ; -typname: name +typname: txname { char *tname = xlateSqlType($1); $$ = makeNode(TypeName); @@ -1971,66 +2156,101 @@ typname: name * it as a set. */ if (!strcmp(saved_relname, tname)) { - /* This attr is the same type as the relation + /* This attr is the same type as the relation * being defined. The classic example: create * emp(name=text,mgr=emp) */ $$->setof = TRUE; }else if (get_typrelid((Type)type(tname)) != InvalidOid) { - /* (Eventually add in here that the set can only + /* (Eventually add in here that the set can only * contain one element.) */ $$->setof = TRUE; - } else { + } else { $$->setof = FALSE; } } - | SETOF name + | SETOF txname { + char *tname = xlateSqlType($2); $$ = makeNode(TypeName); - $$->name = $2; + $$->name = tname; $$->setof = TRUE; } - ; + ; -Typename: typname opt_array_bounds - { +txname: Id { $$ = $1; } + | TIME { $$ = "time"; } + | INTERVAL interval_opts { $$ = "interval"; } + ; + +interval_opts: YEARINTERVAL { $$ = lcons("year", NIL); } + | MONTHINTERVAL { $$ = NIL; } + | DAYINTERVAL { $$ = NIL; } + | HOURINTERVAL { $$ = NIL; } + | MINUTEINTERVAL { $$ = NIL; } + | SECONDINTERVAL { $$ = NIL; } + | YEARINTERVAL TO MONTHINTERVAL { $$ = NIL; } + | DAYINTERVAL TO HOURINTERVAL { $$ = NIL; } + | DAYINTERVAL TO MINUTEINTERVAL { $$ = NIL; } + | DAYINTERVAL TO SECONDINTERVAL { $$ = NIL; } + | HOURINTERVAL TO MINUTEINTERVAL { $$ = NIL; } + | HOURINTERVAL TO SECONDINTERVAL { $$ = NIL; } + | /* EMPTY */ { $$ = NIL; } + ; + +Typename: typname opt_array_bounds + { $$ = $1; $$->arrayBounds = $2; } - | name '(' Iconst ')' + | txname '(' Iconst ')' { /* - * The following implements char() and varchar(). - * We do it here instead of the 'typname:' production - * because we don't want to allow arrays of varchar(). - * I haven't thought about whether that will work or not. - * - ay 6/95 + * This block gets hit when the parser is passed a query + * which contains only spaces (e.g. from psql type " \g"). + * Let's check explicitly for a zero-length argument + * here, and do nothing if so. This seems to fix the problem. + * - thomas 1997-07-13 */ - $$ = makeNode(TypeName); - if (!strcasecmp($1, "char")) { - $$->name = "bpchar"; /* strdup("bpchar"); */ - } else if (!strcasecmp($1, "varchar")) { - $$->name = "varchar"; /* strdup("varchar"); */ - } else { - yyerror("parse error"); - } - if ($3 < 1) { - elog(WARN, "length for '%s' type must be at least 1", - $1); - } else if ($3 > 4096) { - /* we can store a char() of length up to the size - of a page (8KB) - page headers and friends but - just to be safe here... - ay 6/95 */ - elog(WARN, "length for '%s' type cannot exceed 4096", + if (strlen($1) > 0) { + + /* + * The following implements char() and varchar(). + * We do it here instead of the 'typname:' production + * because we don't want to allow arrays of varchar(). + * I haven't thought about whether that will work or not. + * - ay 6/95 + */ + $$ = makeNode(TypeName); + if (!strcasecmp($1, "char")) { + $$->name = "bpchar"; /* strdup("bpchar"); */ + } else if (!strcasecmp($1, "varchar")) { + $$->name = "varchar"; /* strdup("varchar"); */ + } else { + yyerror("parse error"); + } + if ($3 < 1) { + elog(WARN, "length for '%s' type must be at least 1", + $1); + } else if ($3 > 4096) { + /* we can store a char() of length up to the size + * of a page (8KB) - page headers and friends but + * just to be safe here... - ay 6/95 + * XXX note this hardcoded limit - thomas 1997-07-13 + */ + elog(WARN, "length for '%s' type cannot exceed 4096", $1); + } + /* we actually implement this sort of like a varlen, so + * the first 4 bytes is the length. (the difference + * between this and "text" is that we blank-pad and + * truncate where necessary + */ + $$->typlen = 4 + $3; + } - /* we actually implement this sort of like a varlen, so - the first 4 bytes is the length. (the difference - between this and "text" is that we blank-pad and - truncate where necessary */ - $$->typlen = 4 + $3; } ; @@ -2044,12 +2264,12 @@ Typename: typname opt_array_bounds a_expr_or_null: a_expr { $$ = $1;} | Pnull - { + { A_Const *n = makeNode(A_Const); n->val.type = T_Null; $$ = (Node *)n; } - + a_expr: attr opt_indirection { $1->indirection = $2; @@ -2080,7 +2300,7 @@ a_expr: attr opt_indirection | '|' a_expr { $$ = makeA_Expr(OP, "|", NULL, $2); } | AexprConst TYPECAST Typename - { + { /* AexprConst can be either A_Const or ParamNo */ if (nodeTag($1) == T_A_Const) { ((A_Const *)$1)->typename = $3; @@ -2124,7 +2344,7 @@ a_expr: attr opt_indirection Ident *star = makeNode(Ident); /* cheap hack for aggregate (eg. count) */ - star->name = "oid"; + star->name = "oid"; n->funcname = $1; n->args = lcons(star, NIL); $$ = (Node *)n; @@ -2136,6 +2356,66 @@ a_expr: attr opt_indirection n->args = NIL; $$ = (Node *)n; } + /* We probably need to define an "exists" node, + * since the optimizer could choose to find only one match. + * Perhaps the first implementation could just check for + * count(*) > 0? - thomas 1997-07-19 + */ + | EXISTS '(' SubSelect ')' + { + elog(WARN,"EXISTS not yet supported",NULL); + $$ = $3; + } + | EXTRACT '(' extract_list ')' + { + FuncCall *n = makeNode(FuncCall); + n->funcname = "date_part"; + n->args = $3; + $$ = (Node *)n; + } + | POSITION '(' position_list ')' + { + FuncCall *n = makeNode(FuncCall); + n->funcname = "strpos"; + n->args = $3; + $$ = (Node *)n; + } + | SUBSTRING '(' substr_list ')' + { + FuncCall *n = makeNode(FuncCall); + n->funcname = "substr"; + n->args = $3; + $$ = (Node *)n; + } + /* various trim expressions are defined in SQL92 - thomas 1997-07-19 */ + | TRIM '(' BOTH trim_list ')' + { + FuncCall *n = makeNode(FuncCall); + n->funcname = "btrim"; + n->args = $4; + $$ = (Node *)n; + } + | TRIM '(' LEADING trim_list ')' + { + FuncCall *n = makeNode(FuncCall); + n->funcname = "ltrim"; + n->args = $4; + $$ = (Node *)n; + } + | TRIM '(' TRAILING trim_list ')' + { + FuncCall *n = makeNode(FuncCall); + n->funcname = "rtrim"; + n->args = $4; + $$ = (Node *)n; + } + | TRIM '(' trim_list ')' + { + FuncCall *n = makeNode(FuncCall); + n->funcname = "btrim"; + n->args = $3; + $$ = (Node *)n; + } | name '(' expr_list ')' { FuncCall *n = makeNode(FuncCall); @@ -2154,7 +2434,7 @@ a_expr: attr opt_indirection | a_expr BETWEEN AexprConst AND AexprConst { $$ = makeA_Expr(AND, NULL, makeA_Expr(OP, ">=", $1, $3), - makeA_Expr(OP, "<=", $1,$5)); + makeA_Expr(OP, "<=", $1, $5)); } | a_expr NOT BETWEEN AexprConst AND AexprConst { $$ = makeA_Expr(OR, NULL, @@ -2173,28 +2453,80 @@ a_expr: attr opt_indirection { $$ = makeA_Expr(NOT, NULL, NULL, $2); } ; -opt_indirection: '[' a_expr ']' opt_indirection +opt_indirection: '[' a_expr ']' opt_indirection { A_Indices *ai = makeNode(A_Indices); ai->lidx = NULL; ai->uidx = $2; $$ = lcons(ai, $4); } - | '[' a_expr ':' a_expr ']' opt_indirection + | '[' a_expr ':' a_expr ']' opt_indirection { A_Indices *ai = makeNode(A_Indices); ai->lidx = $2; ai->uidx = $4; $$ = lcons(ai, $6); } - | /* EMPTY */ + | /* EMPTY */ { $$ = NIL; } ; - + expr_list: a_expr_or_null { $$ = lcons($1, NIL); } | expr_list ',' a_expr_or_null { $$ = lappend($1, $3); } + | expr_list USING a_expr + { $$ = lappend($1, $3); } + ; + +extract_list: datetime FROM a_expr + { + A_Const *n = makeNode(A_Const); + n->val.type = T_String; + n->val.val.str = $1; +printf( "string is %s\n", $1); + $$ = lappend(lcons((Node *)n,NIL), $3); + } + | /* EMPTY */ + { $$ = NIL; } + ; + +position_list: a_expr IN expr_list + { + $$ = lappend($3, $1); + } + | /* EMPTY */ + { $$ = NIL; } + ; + +substr_list: expr_list substr_from substr_for + { + $$ = $1; + if ($2 != NULL) $$ = lappend($$, $2); + if ($3 != NULL) $$ = lappend($$, $3); + } + | /* EMPTY */ + { $$ = NIL; } + ; + +substr_from: FROM expr_list + { $$ = $2; } + | /* EMPTY */ + { $$ = NIL; } + ; + +substr_for: FOR expr_list + { $$ = $2; } + | /* EMPTY */ + { $$ = NIL; } + ; + +trim_list: a_expr FROM expr_list + { $$ = lappend($3, $1); } + | FROM expr_list + { $$ = $2; } + | expr_list + { $$ = $1; } ; in_expr_nodes: AexprConst @@ -2214,7 +2546,7 @@ not_in_expr_nodes: AexprConst ; attr: relation_name '.' attrs - { + { $$ = makeNode(Attr); $$->relname = $1; $$->paramNo = NULL; @@ -2231,14 +2563,21 @@ attr: relation_name '.' attrs } ; -attrs: attr_name +attrs: attr_name { $$ = lcons(makeString($1), NIL); } - | attrs '.' attr_name + | attrs '.' attr_name { $$ = lappend($1, makeString($3)); } | attrs '.' '*' { $$ = lappend($1, makeString("*")); } ; +datetime: YEARINTERVAL { $$ = "year"; } + | MONTHINTERVAL { $$ = "month"; } + | DAYINTERVAL { $$ = "day"; } + | HOURINTERVAL { $$ = "hour"; } + | MINUTEINTERVAL { $$ = "minute"; } + | SECONDINTERVAL { $$ = "second"; } + ; /***************************************************************************** * @@ -2246,9 +2585,9 @@ attrs: attr_name * *****************************************************************************/ -res_target_list: res_target_list ',' res_target_el +res_target_list: res_target_list ',' res_target_el { $$ = lappend($1,$3); } - | res_target_el + | res_target_el { $$ = lcons($1, NIL); } | '*' { @@ -2280,7 +2619,7 @@ res_target_el: Id opt_indirection '=' a_expr_or_null $$->val = (Node *)$1; } | relation_name '.' '*' - { + { Attr *att = makeNode(Attr); att->relname = $1; att->paramNo = NULL; @@ -2291,23 +2630,22 @@ res_target_el: Id opt_indirection '=' a_expr_or_null $$->indirection = NULL; $$->val = (Node *)att; } - ; + ; /* ** target list for select. ** should get rid of the other but is still needed by the defunct retrieve into ** and update (uses a subset) */ -res_target_list2: - res_target_list2 ',' res_target_el2 +res_target_list2: res_target_list2 ',' res_target_el2 { $$ = lappend($1, $3); } - | res_target_el2 + | res_target_el2 { $$ = lcons($1, NIL); } ; /* AS is not optional because shift/red conflict with unary ops */ -res_target_el2: a_expr AS Id - { +res_target_el2: a_expr AS ColId + { $$ = makeNode(ResTarget); $$->name = $3; $$->indirection = NULL; @@ -2351,30 +2689,30 @@ opt_id: Id { $$ = $1; } ; relation_name: SpecialRuleRelation - { - $$ = $1; - strNcpy(saved_relname, $1, NAMEDATALEN-1); + { + $$ = $1; + strNcpy(saved_relname, $1, NAMEDATALEN-1); } - | Id - { + | ColId + { /* disallow refs to magic system tables */ - if (strcmp(LogRelationName, $1) == 0 - || strcmp(VariableRelationName, $1) == 0 - || strcmp(TimeRelationName, $1) == 0 - || strcmp(MagicRelationName, $1) == 0) { + if (strcmp(LogRelationName, $1) == 0 + || strcmp(VariableRelationName, $1) == 0 + || strcmp(TimeRelationName, $1) == 0 + || strcmp(MagicRelationName, $1) == 0) { elog(WARN, "%s cannot be accessed by users", $1); } else { $$ = $1; } - strNcpy(saved_relname, $1, NAMEDATALEN-1); + strNcpy(saved_relname, $1, NAMEDATALEN-1); } ; database_name: Id { $$ = $1; }; -access_method: Id { $$ = $1; }; -attr_name: Id { $$ = $1; }; -class: Id { $$ = $1; }; -index_name: Id { $$ = $1; }; +access_method: Id { $$ = $1; }; +attr_name: ColId { $$ = $1; }; +class: Id { $$ = $1; }; +index_name: Id { $$ = $1; }; var_name: Id { $$ = $1; }; name: Id { $$ = $1; }; @@ -2383,21 +2721,21 @@ file_name: Sconst { $$ = $1; }; recipe_name: Id { $$ = $1; }; AexprConst: Iconst - { + { A_Const *n = makeNode(A_Const); n->val.type = T_Integer; n->val.val.ival = $1; $$ = (Node *)n; } | FCONST - { + { A_Const *n = makeNode(A_Const); n->val.type = T_Float; n->val.val.dval = $1; $$ = (Node *)n; } | Sconst - { + { A_Const *n = makeNode(A_Const); n->val.type = T_String; n->val.val.str = $1; @@ -2415,27 +2753,31 @@ ParamNo: PARAM ; NumConst: Iconst { $$ = makeInteger($1); } - | FCONST { $$ = makeFloat($1); } + | FCONST { $$ = makeFloat($1); } ; Iconst: ICONST { $$ = $1; }; Sconst: SCONST { $$ = $1; }; -Id: IDENT { $$ = $1; }; +Id: IDENT { $$ = $1; }; + +ColId: Id { $$ = $1; } + | datetime { $$ = $1; } + ; SpecialRuleRelation: CURRENT - { + { if (QueryIsRule) $$ = "*CURRENT*"; - else + else elog(WARN,"CURRENT used in non-rule query"); } | NEW - { + { if (QueryIsRule) $$ = "*NEW*"; - else - elog(WARN,"NEW used in non-rule query"); + else + elog(WARN,"NEW used in non-rule query"); } ; @@ -2466,6 +2808,8 @@ xlateSqlType(char *name) else if (!strcasecmp(name, "float") || !strcasecmp(name, "real")) return "float8"; + else if (!strcasecmp(name, "interval")) + return "timespan"; else return name; } @@ -2475,7 +2819,7 @@ void parser_init(Oid *typev, int nargs) QueryIsRule = false; saved_relname[0]= '\0'; saved_In_Expr = NULL; - + param_type_init(typev, nargs); }