postgresql/src/backend/parser/gram.y

2917 lines
67 KiB
Plaintext
Raw Normal View History

%{ /* -*-text-*- */
/*#define YYDEBUG 1*/
/*-------------------------------------------------------------------------
*
* gram.y--
* POSTGRES SQL YACC rules/actions
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
1997-09-04 15:24:26 +02:00
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 1.42 1997/09/04 13:24:25 vadim Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
* Andrew Yu Sept, 1994 POSTQUEL to SQL conversion
* Andrew Yu Oct, 1994 lispy code conversion
*
* NOTES
* CAPITALS are used to represent terminal symbols.
* non-capitals are used to represent non-terminals.
*
* if you use list, make sure the datum is a node so that the printing
* routines work
*
* WARNING
* sometimes we assign constants to makeStrings. Make sure we don't free
* those.
*
*-------------------------------------------------------------------------
*/
#include <string.h>
#include <ctype.h>
1996-11-08 21:46:33 +01:00
#include "postgres.h"
#include "nodes/parsenodes.h"
1996-11-08 21:46:33 +01:00
#include "parser/gramparse.h"
#include "parser/catalog_utils.h"
#include "parser/parse_query.h"
1996-11-08 21:46:33 +01:00
#include "storage/smgr.h"
#include "utils/acl.h"
#include "catalog/catname.h"
#include "utils/elog.h"
#include "access/xact.h"
static char saved_relname[NAMEDATALEN]; /* need this for complex attributes */
static bool QueryIsRule = FALSE;
static Node *saved_In_Expr;
extern List *parsetree;
1997-08-20 03:12:38 +02:00
extern int CurScanPosition(void);
extern int DefaultStartPosition;
extern int CheckStartPosition;
extern char *parseString;
/*
* If you need access to certain yacc-generated variables and find that
* they're static by default, uncomment the next line. (this is not a
* problem, yet.)
*/
/*#define __YYSCLASS*/
static char *xlateSqlType(char *);
static Node *makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr);
/* old versions of flex define this as a macro */
#if defined(yywrap)
#undef yywrap
#endif /* yywrap */
%}
%union {
double dval;
int ival;
char chr;
char *str;
bool boolean;
List *list;
Node *node;
Value *value;
Attr *attr;
ColumnDef *coldef;
ConstraintDef *constrdef;
TypeName *typnam;
DefElem *defelt;
ParamString *param;
SortGroupBy *sortgroupby;
IndexElem *ielem;
RangeVar *range;
RelExpr *relexp;
TimeRange *trange;
A_Indices *aind;
ResTarget *target;
ParamNo *paramno;
VersionStmt *vstmt;
DefineStmt *dstmt;
PurgeStmt *pstmt;
RuleStmt *rstmt;
AppendStmt *astmt;
}
%type <node> stmt,
AddAttrStmt, ClosePortalStmt,
CopyStmt, CreateStmt, CreateSeqStmt, DefineStmt, DestroyStmt,
1997-09-04 15:24:26 +02:00
ExtendStmt, FetchStmt, GrantStmt, CreateTrigStmt, DropTrigStmt,
IndexStmt, MoveStmt, ListenStmt, OptimizableStmt,
ProcedureStmt, PurgeStmt,
RecipeStmt, RemoveAggrStmt, RemoveOperStmt, RemoveFuncStmt, RemoveStmt,
RenameStmt, RevokeStmt, RuleStmt, TransactionStmt, ViewStmt, LoadStmt,
CreatedbStmt, DestroydbStmt, VacuumStmt, RetrieveStmt, CursorStmt,
ReplaceStmt, AppendStmt, NotifyStmt, DeleteStmt, ClusterStmt,
To: Thomas Lockhart <Thomas.G.Lockhart@jpl.nasa.gov> Subject: Re: [PATCHES] SET DateStyle patches On Tue, 22 Apr 1997, Thomas Lockhart wrote: > Some more patches! These (try to) finish implementing SET variable TO value > for "DateStyle" (changed the name from simply "date" to be more descriptive). > This is based on code from Martin and Bruce (?), which was easy to modify. > The syntax is > > SET DateStyle TO 'iso' > SET DateStyle TO 'postgres' > SET DateStyle TO 'sql' > SET DateStyle TO 'european' > SET DateStyle TO 'noneuropean' > SET DateStyle TO 'us' (same as "noneuropean") > SET DateStyle TO 'default' (current same as "postgres,us") > > ("european" is just compared for the first 4 characters, and "noneuropean" > is compared for the first 7 to allow less typing). > > Multiple arguments are allowed, so SET datestyle TO 'sql,euro' is valid. > > My mods also try to implement "SHOW variable" and "RESET variable", but > that part just core dumps at the moment. I would guess that my errors > are obvious to someone who knows what they are doing with the parser stuff, > so if someone (Bruce and/or Martin??) could have it do the right thing > we will have a more complete set of what we need. > > Also, I would like to have a floating point precision global variable to > implement "SET precision TO 10" and perhaps "SET precision TO 10,2" for > float8 and float4, but I don't know how to do that for integer types rather > than strings. If someone is fixing the SHOW and RESET code, perhaps they can > add some hooks for me to do the floats while they are at it. > > I've left some remnants of variable structures in the source code which > I did not use in the interests of getting something working for v6.1. > We'll have time to clean things up for the next release...
1997-04-23 05:18:27 +02:00
ExplainStmt, VariableSetStmt, VariableShowStmt, VariableResetStmt
%type <str> txname
%type <node> SubSelect
%type <str> join_clause, join_type, join_outer, join_spec
1997-09-04 15:24:26 +02:00
%type <boolean> join_qual, TriggerActionTime, TriggerForSpec
1997-09-04 15:24:26 +02:00
%type <str> datetime, TriggerEvents, TriggerFuncArg
%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,
1997-08-21 03:34:44 +02:00
var_name, aggr_argtype, OptDefault
%type <constrdef> ConstraintElem, ConstraintDef
%type <str> opt_id, opt_portal_name,
before_clause, after_clause, all_Op, MathOp, opt_name, opt_unique,
result, OptUseOp, opt_class, opt_range_start, opt_range_end,
SpecialRuleRelation
%type <str> privileges, operation_commalist, grantee
1997-09-04 15:24:26 +02:00
%type <chr> operation, TriggerOneEvent
%type <list> stmtblock, stmtmulti,
1997-08-20 03:12:38 +02:00
relation_name_list, OptTableElementList, tableElementList,
1997-08-21 03:34:44 +02:00
OptInherit, OptConstraint, ConstraintList, definition,
opt_with, def_args, def_name_list, func_argtypes,
oper_argtypes, OptStmtList, OptStmtBlock, OptStmtMulti,
opt_column_list, columnList, opt_va_list, va_list,
1997-08-20 03:12:38 +02:00
sort_clause, sortby_list, index_params, index_list, name_list,
from_clause, from_list, opt_array_bounds, nest_array_bounds,
expr_list, default_expr_list, attrs, res_target_list, res_target_list2,
1997-09-04 15:24:26 +02:00
def_list, opt_indirection, group_clause, groupby_list, TriggerFuncArgs
%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,
def_type, opt_direction, remove_type, opt_column, event
%type <ival> OptLocation, opt_move_where, fetch_how_many
%type <list> OptSeqList
%type <defelt> OptSeqElem
%type <dstmt> def_rest
%type <pstmt> purge_quals
%type <astmt> insert_rest
%type <typnam> Typename, typname, opt_type
%type <coldef> columnDef
%type <defelt> def_elem
%type <node> def_arg, columnElem, where_clause,
1997-02-13 16:40:03 +01:00
a_expr, a_expr_or_null, AexprConst,
1997-08-20 03:12:38 +02:00
default_expr, default_expr_or_null,
1997-02-13 16:40:03 +01:00
in_expr_nodes, not_in_expr_nodes,
1997-08-21 03:34:44 +02:00
having_clause
%type <value> NumConst
%type <attr> event_object, attr
%type <sortgroupby> groupby
%type <sortgroupby> sortby
%type <ielem> index_elem, func_index
%type <range> from_val
%type <relexp> relation_expr
%type <trange> time_range
%type <target> res_target_el, res_target_el2
%type <paramno> ParamNo
%type <ival> Iconst
%type <str> Sconst
%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
*/
/* Keywords */
%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,
1997-09-04 15:24:26 +02:00
PNULL, POSITION, PRIVILEGES, PROCEDURE, PUBLIC, PURGE, P_TYPE,
RENAME, REPLACE, RESET, RETRIEVE, RETURNS, REVOKE, RIGHT, ROLLBACK, RULE,
SECONDINTERVAL, SELECT, SET, SETOF, SHOW, STDIN, STDOUT, STORE, SUBSTRING,
1997-09-04 15:24:26 +02:00
TABLE, TIME, TO, TRAILING, TRANSACTION, TRIGGER, 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 <ival> ICONST, PARAM
%token <dval> FCONST
/* these are not real. they are here so that they gets generated as #define's*/
%token OP
/* precedence */
%left OR
%left AND
%right NOT
%right '='
%nonassoc LIKE
%nonassoc BETWEEN
%nonassoc IN
%nonassoc Op
%nonassoc NOTNULL
%nonassoc ISNULL
%nonassoc IS
%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 '[' ']'
%nonassoc TYPECAST
%nonassoc REDUCE
%left UNION
%%
stmtblock: stmtmulti
{ parsetree = $1; }
| stmt
{ parsetree = lcons($1,NIL); }
;
stmtmulti: stmtmulti stmt ';'
{ $$ = lappend($1, $2); }
| stmtmulti stmt
{ $$ = lappend($1, $2); }
| stmt ';'
{ $$ = lcons($1,NIL); }
;
stmt : AddAttrStmt
| ClosePortalStmt
| CopyStmt
| CreateStmt
| CreateSeqStmt
1997-09-04 15:24:26 +02:00
| CreateTrigStmt
| ClusterStmt
| DefineStmt
| DestroyStmt
1997-09-04 15:24:26 +02:00
| DropTrigStmt
| ExtendStmt
| ExplainStmt
| FetchStmt
| GrantStmt
| IndexStmt
| MoveStmt
| ListenStmt
| ProcedureStmt
| PurgeStmt
| RecipeStmt
| RemoveAggrStmt
| RemoveOperStmt
| RemoveFuncStmt
| RemoveStmt
| RenameStmt
| RevokeStmt
| OptimizableStmt
| RuleStmt
| TransactionStmt
| ViewStmt
| LoadStmt
| CreatedbStmt
| DestroydbStmt
| VacuumStmt
| VariableSetStmt
To: Thomas Lockhart <Thomas.G.Lockhart@jpl.nasa.gov> Subject: Re: [PATCHES] SET DateStyle patches On Tue, 22 Apr 1997, Thomas Lockhart wrote: > Some more patches! These (try to) finish implementing SET variable TO value > for "DateStyle" (changed the name from simply "date" to be more descriptive). > This is based on code from Martin and Bruce (?), which was easy to modify. > The syntax is > > SET DateStyle TO 'iso' > SET DateStyle TO 'postgres' > SET DateStyle TO 'sql' > SET DateStyle TO 'european' > SET DateStyle TO 'noneuropean' > SET DateStyle TO 'us' (same as "noneuropean") > SET DateStyle TO 'default' (current same as "postgres,us") > > ("european" is just compared for the first 4 characters, and "noneuropean" > is compared for the first 7 to allow less typing). > > Multiple arguments are allowed, so SET datestyle TO 'sql,euro' is valid. > > My mods also try to implement "SHOW variable" and "RESET variable", but > that part just core dumps at the moment. I would guess that my errors > are obvious to someone who knows what they are doing with the parser stuff, > so if someone (Bruce and/or Martin??) could have it do the right thing > we will have a more complete set of what we need. > > Also, I would like to have a floating point precision global variable to > implement "SET precision TO 10" and perhaps "SET precision TO 10,2" for > float8 and float4, but I don't know how to do that for integer types rather > than strings. If someone is fixing the SHOW and RESET code, perhaps they can > add some hooks for me to do the floats while they are at it. > > I've left some remnants of variable structures in the source code which > I did not use in the interests of getting something working for v6.1. > We'll have time to clean things up for the next release...
1997-04-23 05:18:27 +02:00
| VariableShowStmt
| VariableResetStmt
;
/*****************************************************************************
*
* Set PG internal variable
* 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; }
;
zone_value: Sconst { $$ = $1; }
| LOCAL { $$ = NULL; }
;
VariableShowStmt: SHOW var_name
To: Thomas Lockhart <Thomas.G.Lockhart@jpl.nasa.gov> Subject: Re: [PATCHES] SET DateStyle patches On Tue, 22 Apr 1997, Thomas Lockhart wrote: > Some more patches! These (try to) finish implementing SET variable TO value > for "DateStyle" (changed the name from simply "date" to be more descriptive). > This is based on code from Martin and Bruce (?), which was easy to modify. > The syntax is > > SET DateStyle TO 'iso' > SET DateStyle TO 'postgres' > SET DateStyle TO 'sql' > SET DateStyle TO 'european' > SET DateStyle TO 'noneuropean' > SET DateStyle TO 'us' (same as "noneuropean") > SET DateStyle TO 'default' (current same as "postgres,us") > > ("european" is just compared for the first 4 characters, and "noneuropean" > is compared for the first 7 to allow less typing). > > Multiple arguments are allowed, so SET datestyle TO 'sql,euro' is valid. > > My mods also try to implement "SHOW variable" and "RESET variable", but > that part just core dumps at the moment. I would guess that my errors > are obvious to someone who knows what they are doing with the parser stuff, > so if someone (Bruce and/or Martin??) could have it do the right thing > we will have a more complete set of what we need. > > Also, I would like to have a floating point precision global variable to > implement "SET precision TO 10" and perhaps "SET precision TO 10,2" for > float8 and float4, but I don't know how to do that for integer types rather > than strings. If someone is fixing the SHOW and RESET code, perhaps they can > add some hooks for me to do the floats while they are at it. > > I've left some remnants of variable structures in the source code which > I did not use in the interests of getting something working for v6.1. > We'll have time to clean things up for the next release...
1997-04-23 05:18:27 +02:00
{
VariableShowStmt *n = makeNode(VariableShowStmt);
n->name = $2;
$$ = (Node *) n;
To: Thomas Lockhart <Thomas.G.Lockhart@jpl.nasa.gov> Subject: Re: [PATCHES] SET DateStyle patches On Tue, 22 Apr 1997, Thomas Lockhart wrote: > Some more patches! These (try to) finish implementing SET variable TO value > for "DateStyle" (changed the name from simply "date" to be more descriptive). > This is based on code from Martin and Bruce (?), which was easy to modify. > The syntax is > > SET DateStyle TO 'iso' > SET DateStyle TO 'postgres' > SET DateStyle TO 'sql' > SET DateStyle TO 'european' > SET DateStyle TO 'noneuropean' > SET DateStyle TO 'us' (same as "noneuropean") > SET DateStyle TO 'default' (current same as "postgres,us") > > ("european" is just compared for the first 4 characters, and "noneuropean" > is compared for the first 7 to allow less typing). > > Multiple arguments are allowed, so SET datestyle TO 'sql,euro' is valid. > > My mods also try to implement "SHOW variable" and "RESET variable", but > that part just core dumps at the moment. I would guess that my errors > are obvious to someone who knows what they are doing with the parser stuff, > so if someone (Bruce and/or Martin??) could have it do the right thing > we will have a more complete set of what we need. > > Also, I would like to have a floating point precision global variable to > implement "SET precision TO 10" and perhaps "SET precision TO 10,2" for > float8 and float4, but I don't know how to do that for integer types rather > than strings. If someone is fixing the SHOW and RESET code, perhaps they can > add some hooks for me to do the floats while they are at it. > > I've left some remnants of variable structures in the source code which > I did not use in the interests of getting something working for v6.1. > We'll have time to clean things up for the next release...
1997-04-23 05:18:27 +02:00
}
;
VariableResetStmt: RESET var_name
To: Thomas Lockhart <Thomas.G.Lockhart@jpl.nasa.gov> Subject: Re: [PATCHES] SET DateStyle patches On Tue, 22 Apr 1997, Thomas Lockhart wrote: > Some more patches! These (try to) finish implementing SET variable TO value > for "DateStyle" (changed the name from simply "date" to be more descriptive). > This is based on code from Martin and Bruce (?), which was easy to modify. > The syntax is > > SET DateStyle TO 'iso' > SET DateStyle TO 'postgres' > SET DateStyle TO 'sql' > SET DateStyle TO 'european' > SET DateStyle TO 'noneuropean' > SET DateStyle TO 'us' (same as "noneuropean") > SET DateStyle TO 'default' (current same as "postgres,us") > > ("european" is just compared for the first 4 characters, and "noneuropean" > is compared for the first 7 to allow less typing). > > Multiple arguments are allowed, so SET datestyle TO 'sql,euro' is valid. > > My mods also try to implement "SHOW variable" and "RESET variable", but > that part just core dumps at the moment. I would guess that my errors > are obvious to someone who knows what they are doing with the parser stuff, > so if someone (Bruce and/or Martin??) could have it do the right thing > we will have a more complete set of what we need. > > Also, I would like to have a floating point precision global variable to > implement "SET precision TO 10" and perhaps "SET precision TO 10,2" for > float8 and float4, but I don't know how to do that for integer types rather > than strings. If someone is fixing the SHOW and RESET code, perhaps they can > add some hooks for me to do the floats while they are at it. > > I've left some remnants of variable structures in the source code which > I did not use in the interests of getting something working for v6.1. > We'll have time to clean things up for the next release...
1997-04-23 05:18:27 +02:00
{
VariableResetStmt *n = makeNode(VariableResetStmt);
n->name = $2;
$$ = (Node *) n;
To: Thomas Lockhart <Thomas.G.Lockhart@jpl.nasa.gov> Subject: Re: [PATCHES] SET DateStyle patches On Tue, 22 Apr 1997, Thomas Lockhart wrote: > Some more patches! These (try to) finish implementing SET variable TO value > for "DateStyle" (changed the name from simply "date" to be more descriptive). > This is based on code from Martin and Bruce (?), which was easy to modify. > The syntax is > > SET DateStyle TO 'iso' > SET DateStyle TO 'postgres' > SET DateStyle TO 'sql' > SET DateStyle TO 'european' > SET DateStyle TO 'noneuropean' > SET DateStyle TO 'us' (same as "noneuropean") > SET DateStyle TO 'default' (current same as "postgres,us") > > ("european" is just compared for the first 4 characters, and "noneuropean" > is compared for the first 7 to allow less typing). > > Multiple arguments are allowed, so SET datestyle TO 'sql,euro' is valid. > > My mods also try to implement "SHOW variable" and "RESET variable", but > that part just core dumps at the moment. I would guess that my errors > are obvious to someone who knows what they are doing with the parser stuff, > so if someone (Bruce and/or Martin??) could have it do the right thing > we will have a more complete set of what we need. > > Also, I would like to have a floating point precision global variable to > implement "SET precision TO 10" and perhaps "SET precision TO 10,2" for > float8 and float4, but I don't know how to do that for integer types rather > than strings. If someone is fixing the SHOW and RESET code, perhaps they can > add some hooks for me to do the floats while they are at it. > > I've left some remnants of variable structures in the source code which > I did not use in the interests of getting something working for v6.1. > We'll have time to clean things up for the next release...
1997-04-23 05:18:27 +02:00
}
;
/*****************************************************************************
*
* QUERY :
* addattr ( attr1 = type1 .. attrn = typen ) to <relname> [*]
*
*****************************************************************************/
AddAttrStmt: ALTER TABLE relation_name opt_inh_star ADD COLUMN columnDef
{
AddAttrStmt *n = makeNode(AddAttrStmt);
n->relname = $3;
n->inh = $4;
n->colDef = $7;
$$ = (Node *)n;
}
;
/* 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;
$$->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);
1997-08-20 03:12:38 +02:00
}
;
OptDefault: DEFAULT default_expr
{
1997-08-20 03:12:38 +02:00
int deflen = CurScanPosition() - DefaultStartPosition;
char *defval;
defval = (char*) palloc (deflen + 1);
memcpy (defval,
parseString + DefaultStartPosition,
deflen);
defval[deflen] = 0;
$$ = defval;
}
| /*EMPTY*/ { $$ = NULL; }
;
default_expr_or_null: default_expr
{ $$ = $1;}
| Pnull
{
A_Const *n = makeNode(A_Const);
n->val.type = T_Null;
$$ = (Node *)n;
}
default_expr: AexprConst
{
if (nodeTag($1) != T_A_Const)
elog (WARN, "Cannot handle parameter in DEFAULT");
$$ = $1;
}
| '-' default_expr %prec UMINUS
{ $$ = makeA_Expr(OP, "-", NULL, $2); }
| default_expr '+' default_expr
{ $$ = makeA_Expr(OP, "+", $1, $3); }
| default_expr '-' default_expr
{ $$ = makeA_Expr(OP, "-", $1, $3); }
| default_expr '/' default_expr
{ $$ = makeA_Expr(OP, "/", $1, $3); }
| default_expr '*' default_expr
{ $$ = makeA_Expr(OP, "*", $1, $3); }
| default_expr '<' default_expr
{ $$ = makeA_Expr(OP, "<", $1, $3); }
| default_expr '>' default_expr
{ $$ = makeA_Expr(OP, ">", $1, $3); }
| default_expr '=' default_expr
{ $$ = makeA_Expr(OP, "=", $1, $3); }
| ':' default_expr
{ $$ = makeA_Expr(OP, ":", NULL, $2); }
| ';' default_expr
{ $$ = makeA_Expr(OP, ";", NULL, $2); }
| '|' default_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;
}else {
elog (WARN, "Cannot handle parameter in DEFAULT");
}
$$ = (Node *)$1;
}
| CAST AexprConst AS Typename
{
/* AexprConst can be either A_Const or ParamNo */
if (nodeTag($2) == T_A_Const) {
((A_Const *)$2)->typename = $4;
}else {
elog (WARN, "Cannot handle parameter in DEFAULT");
}
$$ = (Node *)$2;
}
| '(' default_expr ')'
{ $$ = $2; }
| default_expr Op default_expr
{ $$ = makeA_Expr(OP, $2, $1, $3); }
| Op default_expr
{ $$ = makeA_Expr(OP, $1, NULL, $2); }
| default_expr Op
{ $$ = makeA_Expr(OP, $2, $1, NULL); }
| name '(' ')'
{
FuncCall *n = makeNode(FuncCall);
n->funcname = $1;
n->args = NIL;
$$ = (Node *)n;
}
1997-08-20 03:12:38 +02:00
| name '(' default_expr_list ')'
{
FuncCall *n = makeNode(FuncCall);
n->funcname = $1;
n->args = $3;
$$ = (Node *)n;
}
;
default_expr_list: default_expr_or_null
{ $$ = lcons($1, NIL); }
| default_expr_list ',' default_expr_or_null
{ $$ = lappend($1, $3); }
;
opt_null: NOT PNULL { $$ = true; }
1997-08-20 03:12:38 +02:00
| NOTNULL { $$ = true; }
| /* EMPTY */ { $$ = false; }
;
opt_with_col: WITH TIME ZONE { $$ = TRUE; }
| /* EMPTY */ { $$ = FALSE; }
;
/*****************************************************************************
*
* QUERY :
* close <optname>
*
*****************************************************************************/
ClosePortalStmt: CLOSE opt_id
{
ClosePortalStmt *n = makeNode(ClosePortalStmt);
n->portalname = $2;
$$ = (Node *)n;
}
;
/*****************************************************************************
*
* QUERY :
* COPY [BINARY] <relname> FROM/TO
* [USING DELIMITERS <delimiter>]
*
*****************************************************************************/
CopyStmt: COPY opt_binary relation_name opt_with_copy copy_dirn copy_file_name copy_delimiter
{
CopyStmt *n = makeNode(CopyStmt);
n->binary = $2;
n->relname = $3;
n->oids = $4;
n->direction = $5;
n->filename = $6;
n->delimiter = $7;
$$ = (Node *)n;
}
;
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
*/
copy_file_name: Sconst { $$ = $1; }
| STDIN { $$ = NULL; }
| STDOUT { $$ = NULL; }
;
opt_binary: BINARY { $$ = TRUE; }
| /*EMPTY*/ { $$ = FALSE; }
;
opt_with_copy: WITH OIDS { $$ = TRUE; }
| /* EMPTY */ { $$ = FALSE; }
;
/*
* the default copy delimiter is tab but the user can configure it
*/
copy_delimiter: USING DELIMITERS Sconst { $$ = $3;}
| /* EMPTY */ { $$ = "\t"; }
;
/*****************************************************************************
*
* QUERY :
* CREATE relname
*
*****************************************************************************/
CreateStmt: CREATE TABLE relation_name '(' OptTableElementList ')'
1997-08-21 03:34:44 +02:00
OptInherit OptConstraint OptArchiveType OptLocation
1997-08-20 03:12:38 +02:00
OptArchiveLocation
{
CreateStmt *n = makeNode(CreateStmt);
n->relname = $3;
n->tableElts = $5;
n->inhRelnames = $7;
1997-08-21 03:34:44 +02:00
n->constraints = $8;
1997-08-20 03:12:38 +02:00
n->archiveType = $9;
n->location = $10;
n->archiveLoc = $11;
$$ = (Node *)n;
}
;
OptTableElementList: tableElementList { $$ = $1; }
| /* EMPTY */ { $$ = NULL; }
;
tableElementList :
tableElementList ',' columnDef
{ $$ = lappend($1, $3); }
| columnDef
{ $$ = lcons($1, NIL); }
;
OptArchiveType: ARCHIVE '=' archive_type { $$ = $3; }
| /*EMPTY*/ { $$ = ARCH_NONE; }
;
archive_type: HEAVY { $$ = ARCH_HEAVY; }
| LIGHT { $$ = ARCH_LIGHT; }
| NONE { $$ = ARCH_NONE; }
;
OptLocation: STORE '=' Sconst
{ $$ = smgrin($3); }
| /*EMPTY*/
{ $$ = -1; }
;
OptArchiveLocation: ARCH_STORE '=' Sconst
{ $$ = smgrin($3); }
| /*EMPTY*/
{ $$ = -1; }
;
OptInherit: INHERITS '(' relation_name_list ')' { $$ = $3; }
| /*EMPTY*/ { $$ = NIL; }
;
1997-08-21 03:34:44 +02:00
OptConstraint: ConstraintList { $$ = $1; }
1997-08-20 03:12:38 +02:00
| { $$ = NULL; }
;
1997-08-21 03:34:44 +02:00
ConstraintList :
ConstraintList ',' ConstraintElem
1997-08-20 03:12:38 +02:00
{ $$ = lappend($1, $3); }
1997-08-21 03:34:44 +02:00
| ConstraintElem
1997-08-20 03:12:38 +02:00
{ $$ = lcons($1, NIL); }
;
1997-08-21 03:34:44 +02:00
ConstraintElem:
CONSTRAINT name ConstraintDef
{
$3->name = $2;
$$ = $3;
}
| ConstraintDef { $$ = $1; }
;
ConstraintDef: CHECK a_expr {
ConstraintDef *constr = palloc (sizeof(ConstraintDef));
1997-08-20 03:12:38 +02:00
int chklen = CurScanPosition() - CheckStartPosition;
char *check;
check = (char*) palloc (chklen + 1);
memcpy (check,
parseString + CheckStartPosition,
chklen);
check[chklen] = 0;
1997-08-21 03:34:44 +02:00
constr->type = CONSTR_CHECK;
constr->name = NULL;
constr->def = (void*) check;
1997-08-21 03:34:44 +02:00
$$ = constr;
1997-08-20 03:12:38 +02:00
}
;
/*****************************************************************************
*
* QUERY :
* CREATE SEQUENCE seqname
*
*****************************************************************************/
CreateSeqStmt: CREATE SEQUENCE relation_name OptSeqList
{
CreateSeqStmt *n = makeNode(CreateSeqStmt);
n->seqname = $3;
n->options = $4;
$$ = (Node *)n;
}
;
OptSeqList:
OptSeqList OptSeqElem
{ $$ = lappend($1, $2); }
| { $$ = NIL; }
;
OptSeqElem: IDENT NumConst
{
$$ = makeNode(DefElem);
$$->defname = $1;
$$->arg = (Node *)$2;
}
| IDENT
{
$$ = makeNode(DefElem);
$$->defname = $1;
$$->arg = (Node *)NULL;
}
;
1997-09-04 15:24:26 +02:00
/*****************************************************************************
*
* QUERIES :
* CREATE TRIGGER ...
* DROP TRIGGER ...
*
*****************************************************************************/
CreateTrigStmt: CREATE TRIGGER name TriggerActionTime TriggerEvents ON
relation_name TriggerForSpec EXECUTE PROCEDURE
name '(' TriggerFuncArgs ')'
{
CreateTrigStmt *n = makeNode(CreateTrigStmt);
n->trigname = $3;
n->relname = $7;
n->funcname = $11;
n->args = $13;
n->before = $4;
n->row = $8;
memcpy (n->actions, $5, 4);
$$ = (Node *)n;
}
;
TriggerActionTime: BEFORE { $$ = true; }
| AFTER { $$ = false; }
;
TriggerEvents: TriggerOneEvent
{
char *e = palloc (4);
e[0] = $1; e[1] = 0; $$ = e;
}
| TriggerOneEvent OR TriggerOneEvent
{
char *e = palloc (4);
e[0] = $1; e[1] = $3; e[2] = 0; $$ = e;
}
| TriggerOneEvent OR TriggerOneEvent OR TriggerOneEvent
{
char *e = palloc (4);
e[0] = $1; e[1] = $3; e[2] = $5; e[3] = 0;
$$ = e;
}
;
TriggerOneEvent: INSERT { $$ = 'i'; }
| DELETE { $$ = 'd'; }
| UPDATE { $$ = 'u'; }
;
TriggerForSpec: FOR name name
{
if ( strcmp ($2, "each") != 0 )
elog (WARN, "parser: syntax error near %s", $2);
if ( strcmp ($3, "row") == 0 )
$$ = true;
else if ( strcmp ($3, "statement") == 0 )
$$ = false;
else
elog (WARN, "parser: syntax error near %s", $3);
}
;
TriggerFuncArgs: TriggerFuncArg
{ $$ = lcons($1, NIL); }
| TriggerFuncArgs ',' TriggerFuncArg
{ $$ = lappend($1, $3); }
| /* EMPTY */ { $$ = NIL; }
;
TriggerFuncArg: ICONST
{
char *s = (char *) palloc (256);
sprintf (s, "%d", $1);
$$ = s;
}
| Sconst { $$ = $1; }
;
DropTrigStmt: DROP TRIGGER name ON relation_name
{
DropTrigStmt *n = makeNode(DropTrigStmt);
n->trigname = $3;
n->relname = $5;
$$ = (Node *) n;
}
;
/*****************************************************************************
*
* QUERY :
* define (type,operator,aggregate)
*
*****************************************************************************/
DefineStmt: CREATE def_type def_rest
{
$3->defType = $2;
$$ = (Node *)$3;
}
;
def_rest: def_name definition
{
$$ = makeNode(DefineStmt);
$$->defname = $1;
$$->definition = $2;
}
;
def_type: OPERATOR { $$ = OPERATOR; }
| Type { $$ = P_TYPE; }
| AGGREGATE { $$ = AGGREGATE; }
;
def_name: Id | MathOp | Op
;
definition: '(' def_list ')' { $$ = $2; }
;
def_list: def_elem
{ $$ = lcons($1, NIL); }
| def_list ',' def_elem
{ $$ = lappend($1, $3); }
;
def_elem: def_name '=' def_arg
{
$$ = makeNode(DefElem);
$$->defname = $1;
$$->arg = (Node *)$3;
}
| def_name
{
$$ = makeNode(DefElem);
$$->defname = $1;
$$->arg = (Node *)NULL;
}
| DEFAULT '=' def_arg
{
$$ = makeNode(DefElem);
$$->defname = (char*) palloc (8);
strcpy ($$->defname, "default");
$$->arg = (Node *)$3;
}
;
def_arg: Id { $$ = (Node *)makeString($1); }
| all_Op { $$ = (Node *)makeString($1); }
| NumConst { $$ = (Node *)$1; /* already a Value */ }
| Sconst { $$ = (Node *)makeString($1); }
| SETOF Id {
TypeName *n = makeNode(TypeName);
n->name = $2;
n->setof = TRUE;
n->arrayBounds = NULL;
$$ = (Node *)n;
}
;
/*****************************************************************************
*
* 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;
$$ = (Node *)n;
}
;
/*****************************************************************************
*
* QUERY:
* fetch [forward | backward] [number | all ] [ in <portalname> ]
*
*****************************************************************************/
FetchStmt: FETCH opt_direction fetch_how_many opt_portal_name
{
FetchStmt *n = makeNode(FetchStmt);
n->direction = $2;
n->howMany = $3;
n->portalname = $4;
$$ = (Node *)n;
}
;
opt_direction: FORWARD { $$ = FORWARD; }
| BACKWARD { $$ = BACKWARD; }
| /*EMPTY*/ { $$ = FORWARD; /* default */ }
;
fetch_how_many: Iconst
{ $$ = $1;
if ($1 <= 0) elog(WARN,"Please specify nonnegative count for fetch"); }
| ALL { $$ = 0; /* 0 means fetch all tuples*/}
| /*EMPTY*/ { $$ = 1; /*default*/ }
;
/*****************************************************************************
*
* QUERY:
* GRANT [privileges] ON [relation_name_list] TO [GROUP] grantee
*
*****************************************************************************/
GrantStmt: GRANT privileges ON relation_name_list TO grantee opt_with_grant
{
$$ = (Node*)makeAclStmt($2,$4,$6,'+');
free($2);
free($6);
}
;
privileges: ALL PRIVILEGES
{
$$ = aclmakepriv("rwaR",0);
}
| ALL
{
$$ = aclmakepriv("rwaR",0);
}
| operation_commalist {
$$ = $1;
}
;
operation_commalist: operation {
$$ = aclmakepriv("",$1);
}
| operation_commalist ',' operation
{
$$ = aclmakepriv($1,$3);
free($1);
}
;
operation: SELECT {
$$ = ACL_MODE_RD_CHR;
}
| INSERT {
$$ = ACL_MODE_AP_CHR;
}
| UPDATE {
$$ = ACL_MODE_WR_CHR;
}
| DELETE {
$$ = ACL_MODE_WR_CHR;
}
| RULE {
$$ = ACL_MODE_RU_CHR;
}
;
grantee: PUBLIC {
$$ = aclmakeuser("A","");
}
| GROUP Id {
$$ = aclmakeuser("G",$2);
}
| Id {
$$ = aclmakeuser("U",$1);
}
;
opt_with_grant : /* empty */
| WITH GRANT OPTION
{
yyerror("WITH GRANT OPTION is not supported. Only relation owners can set privileges");
}
;
/*****************************************************************************
*
* QUERY:
* REVOKE [privileges] ON [relation_name] FROM [user]
*
*****************************************************************************/
RevokeStmt: REVOKE privileges ON relation_name_list FROM grantee
{
$$ = (Node*)makeAclStmt($2,$4,$6,'-');
free($2);
free($6);
}
;
/*****************************************************************************
*
* QUERY:
* move [<dirn>] [<whereto>] [<portalname>]
*
*****************************************************************************/
MoveStmt: MOVE opt_direction opt_move_where opt_portal_name
{
MoveStmt *n = makeNode(MoveStmt);
n->direction = $2;
n->to = FALSE;
n->where = $3;
n->portalname = $4;
$$ = (Node *)n;
}
| MOVE opt_direction TO Iconst opt_portal_name
{
MoveStmt *n = makeNode(MoveStmt);
n->direction = $2;
n->to = TRUE;
n->where = $4;
n->portalname = $5;
$$ = (Node *)n;
}
;
opt_move_where: Iconst { $$ = $1; }
| /*EMPTY*/ { $$ = 1; /* default */ }
;
opt_portal_name: IN name { $$ = $2;}
| /*EMPTY*/ { $$ = NULL; }
;
/*****************************************************************************
*
* QUERY:
* define [archive] index <indexname> on <relname>
* using <access> "(" (<col> with <op>)+ ")" [with
* <target_list>]
*
* [where <qual>] is not supported anymore
*****************************************************************************/
IndexStmt: CREATE index_opt_unique INDEX index_name ON relation_name
access_method_clause '(' index_params ')' opt_with
{
/* should check that access_method is valid,
etc ... but doesn't */
IndexStmt *n = makeNode(IndexStmt);
n->unique = $2;
n->idxname = $4;
n->relname = $6;
n->accessMethod = $7;
n->indexParams = $9;
n->withClause = $11;
n->whereClause = NULL;
$$ = (Node *)n;
}
;
access_method_clause: USING access_method { $$ = $2; }
| /* empty -- 'btree' is default access method */
{ $$ = "btree"; }
;
index_opt_unique: UNIQUE { $$ = TRUE; }
| /*empty*/ { $$ = FALSE; }
;
/*****************************************************************************
*
* QUERY:
* extend index <indexname> [where <qual>]
*
*****************************************************************************/
ExtendStmt: EXTEND INDEX index_name where_clause
{
ExtendStmt *n = makeNode(ExtendStmt);
n->idxname = $3;
n->whereClause = $4;
$$ = (Node *)n;
}
;
/*****************************************************************************
*
* QUERY:
* execute recipe <recipeName>
*
*****************************************************************************/
RecipeStmt: EXECUTE RECIPE recipe_name
{
RecipeStmt *n;
if (!IsTransactionBlock())
elog(WARN, "EXECUTE RECIPE may only be used in begin/end transaction blocks.");
n = makeNode(RecipeStmt);
n->recipeName = $3;
$$ = (Node *)n;
}
;
/*****************************************************************************
*
* QUERY:
* define function <fname>
* (language = <lang>, returntype = <typename>
* [, arch_pct = <percentage | pre-defined>]
* [, disk_pct = <percentage | pre-defined>]
* [, byte_pct = <percentage | pre-defined>]
* [, perbyte_cpu = <int | pre-defined>]
* [, percall_cpu = <int | pre-defined>]
* [, iscachable])
* [arg is (<type-1> { , <type-n>})]
* as <filename or code in language as appropriate>
*
*****************************************************************************/
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;
n->returnType = (Node *)$6;
n->withClause = $7;
n->as = $9;
n->language = $11;
$$ = (Node *)n;
};
opt_with: WITH definition { $$ = $2; }
| /* EMPTY */ { $$ = NIL; }
;
def_args: '(' def_name_list ')' { $$ = $2; }
| '(' ')' { $$ = NIL; }
;
def_name_list: name_list;
/*****************************************************************************
*
* QUERY:
* purge <relname> [before <date>] [after <date>]
* or
* 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;
}
;
before_clause: BEFORE date { $$ = $2; }
after_clause: AFTER date { $$ = $2; }
/*****************************************************************************
*
* QUERY:
*
* remove function <funcname>
* (REMOVE FUNCTION "funcname" (arg1, arg2, ...))
* remove aggregate <aggname>
* (REMOVE AGGREGATE "aggname" "aggtype")
* remove operator <opname>
* (REMOVE OPERATOR "opname" (leftoperand_typ rightoperand_typ))
* remove type <typename>
* (REMOVE TYPE "typename")
* remove rule <rulename>
* (REMOVE RULE "rulename")
*
*****************************************************************************/
RemoveStmt: DROP remove_type name
{
RemoveStmt *n = makeNode(RemoveStmt);
n->removeType = $2;
n->name = $3;
$$ = (Node *)n;
}
;
remove_type: Type { $$ = P_TYPE; }
| INDEX { $$ = INDEX; }
| RULE { $$ = RULE; }
| VIEW { $$ = VIEW; }
;
RemoveAggrStmt: DROP AGGREGATE name aggr_argtype
{
RemoveAggrStmt *n = makeNode(RemoveAggrStmt);
n->aggname = $3;
n->aggtype = $4;
$$ = (Node *)n;
}
;
aggr_argtype: name { $$ = $1; }
| '*' { $$ = NULL; }
;
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; }
;
RemoveOperStmt: DROP OPERATOR all_Op '(' oper_argtypes ')'
{
RemoveOperStmt *n = makeNode(RemoveOperStmt);
n->opname = $3;
n->args = $5;
$$ = (Node *)n;
}
;
all_Op: Op | MathOp;
MathOp: '+' { $$ = "+"; }
| '-' { $$ = "-"; }
| '*' { $$ = "*"; }
| '/' { $$ = "/"; }
| '<' { $$ = "<"; }
| '>' { $$ = ">"; }
| '=' { $$ = "="; }
;
oper_argtypes: name
{
elog(WARN, "parser: argument type missing (use NONE for unary operators)");
}
| name ',' name
{ $$ = makeList(makeString($1), makeString($3), -1); }
| NONE ',' name /* left unary */
{ $$ = makeList(NULL, makeString($3), -1); }
| name ',' NONE /* right unary */
{ $$ = makeList(makeString($1), NULL, -1); }
;
/*****************************************************************************
*
* QUERY:
* rename <attrname1> in <relname> [*] to <attrname2>
* rename <relname1> to <relname2>
*
*****************************************************************************/
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;
n->column = $7;
n->newname = $9;
$$ = (Node *)n;
}
;
opt_name: name { $$ = $1; }
| /*EMPTY*/ { $$ = NULL; }
;
opt_column: COLUMN { $$ = COLUMN; }
| /*EMPTY*/ { $$ = 0; }
;
/*****************************************************************************
*
* QUERY: Define Rewrite Rule , Define Tuple Rule
* Define Rule <old rules >
*
* only rewrite rule is supported -- ay 9/94
*
*****************************************************************************/
RuleStmt: CREATE RULE name AS
{ QueryIsRule=TRUE; }
ON event TO event_object where_clause
DO opt_instead OptStmtList
{
RuleStmt *n = makeNode(RuleStmt);
n->rulename = $3;
n->event = $7;
n->object = $9;
n->whereClause = $10;
n->instead = $12;
n->actions = $13;
$$ = (Node *)n;
}
;
OptStmtList: NOTHING { $$ = NIL; }
| OptimizableStmt { $$ = lcons($1, NIL); }
| '[' OptStmtBlock ']' { $$ = $2; }
;
OptStmtBlock: OptStmtMulti
{ $$ = $1; }
| OptimizableStmt
{ $$ = lcons($1, NIL); }
;
OptStmtMulti: OptStmtMulti OptimizableStmt ';'
{ $$ = lappend($1, $2); }
| OptStmtMulti OptimizableStmt
{ $$ = lappend($1, $2); }
| OptimizableStmt ';'
{ $$ = lcons($1, NIL); }
;
event_object: relation_name '.' attr_name
{
$$ = makeNode(Attr);
$$->relname = $1;
$$->paramNo = NULL;
$$->attrs = lcons(makeString($3), NIL);
$$->indirection = NIL;
}
| relation_name
{
$$ = makeNode(Attr);
$$->relname = $1;
$$->paramNo = NULL;
$$->attrs = NIL;
$$->indirection = NIL;
}
;
/* change me to select, update, etc. some day */
event: SELECT { $$ = CMD_SELECT; }
| UPDATE { $$ = CMD_UPDATE; }
| DELETE { $$ = CMD_DELETE; }
| INSERT { $$ = CMD_INSERT; }
;
opt_instead: INSTEAD { $$ = TRUE; }
| /* EMPTY */ { $$ = FALSE; }
;
/*****************************************************************************
*
* QUERY:
* NOTIFY <relation_name> can appear both in rule bodies and
* as a query-level command
*
*****************************************************************************/
NotifyStmt: NOTIFY relation_name
{
NotifyStmt *n = makeNode(NotifyStmt);
n->relname = $2;
$$ = (Node *)n;
}
;
ListenStmt: LISTEN relation_name
{
ListenStmt *n = makeNode(ListenStmt);
n->relname = $2;
$$ = (Node *)n;
}
;
/*****************************************************************************
*
* Transactions:
*
* abort transaction
* (ABORT)
* begin transaction
* (BEGIN)
* end transaction
* (END)
*
*****************************************************************************/
TransactionStmt: ABORT_TRANS TRANSACTION
{
TransactionStmt *n = makeNode(TransactionStmt);
n->command = ABORT_TRANS;
$$ = (Node *)n;
}
| BEGIN_TRANS TRANSACTION
{
TransactionStmt *n = makeNode(TransactionStmt);
n->command = BEGIN_TRANS;
$$ = (Node *)n;
}
| BEGIN_TRANS WORK
{
TransactionStmt *n = makeNode(TransactionStmt);
n->command = BEGIN_TRANS;
$$ = (Node *)n;
}
| COMMIT WORK
{
TransactionStmt *n = makeNode(TransactionStmt);
n->command = END_TRANS;
$$ = (Node *)n;
}
| END_TRANS TRANSACTION
{
TransactionStmt *n = makeNode(TransactionStmt);
n->command = END_TRANS;
$$ = (Node *)n;
}
| ROLLBACK WORK
{
TransactionStmt *n = makeNode(TransactionStmt);
n->command = ABORT_TRANS;
$$ = (Node *)n;
}
| ABORT_TRANS
{
TransactionStmt *n = makeNode(TransactionStmt);
n->command = ABORT_TRANS;
$$ = (Node *)n;
}
| BEGIN_TRANS
{
TransactionStmt *n = makeNode(TransactionStmt);
n->command = BEGIN_TRANS;
$$ = (Node *)n;
}
| COMMIT
{
TransactionStmt *n = makeNode(TransactionStmt);
n->command = END_TRANS;
$$ = (Node *)n;
}
| END_TRANS
{
TransactionStmt *n = makeNode(TransactionStmt);
n->command = END_TRANS;
$$ = (Node *)n;
}
| ROLLBACK
{
TransactionStmt *n = makeNode(TransactionStmt);
n->command = ABORT_TRANS;
$$ = (Node *)n;
}
;
/*****************************************************************************
*
* QUERY:
* define view <viewname> '('target-list ')' [where <quals> ]
*
*****************************************************************************/
ViewStmt: CREATE VIEW name AS RetrieveStmt
{
ViewStmt *n = makeNode(ViewStmt);
n->viewname = $3;
n->query = (Query *)$5;
$$ = (Node *)n;
}
;
/*****************************************************************************
*
* QUERY:
* load "filename"
*
*****************************************************************************/
LoadStmt: LOAD file_name
{
LoadStmt *n = makeNode(LoadStmt);
n->filename = $2;
$$ = (Node *)n;
}
;
/*****************************************************************************
*
* QUERY:
* createdb dbname
*
*****************************************************************************/
CreatedbStmt: CREATE DATABASE database_name
{
CreatedbStmt *n = makeNode(CreatedbStmt);
n->dbname = $3;
$$ = (Node *)n;
}
;
/*****************************************************************************
*
* QUERY:
* destroydb dbname
*
*****************************************************************************/
DestroydbStmt: DROP DATABASE database_name
{
DestroydbStmt *n = makeNode(DestroydbStmt);
n->dbname = $3;
$$ = (Node *)n;
}
;
/*****************************************************************************
*
* QUERY:
* cluster <index_name> on <relation_name>
*
*****************************************************************************/
ClusterStmt: CLUSTER index_name ON relation_name
{
ClusterStmt *n = makeNode(ClusterStmt);
n->relname = $4;
n->indexname = $2;
$$ = (Node*)n;
}
;
/*****************************************************************************
*
* QUERY:
* vacuum
*
*****************************************************************************/
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;
}
;
opt_verbose: VERBOSE { $$ = TRUE; }
| /* EMPTY */ { $$ = FALSE; }
;
opt_analyze: ANALYZE { $$ = TRUE; }
| /* EMPTY */ { $$ = FALSE; }
;
opt_va_list: '(' va_list ')'
{ $$ = $2; }
| /* EMPTY */
{ $$ = NIL; }
;
va_list: name
{ $$=lcons($1,NIL); }
| va_list ',' name
{ $$=lappend($1,$3); }
;
/*****************************************************************************
*
* QUERY:
* EXPLAIN query
*
*****************************************************************************/
ExplainStmt: EXPLAIN opt_verbose OptimizableStmt
{
ExplainStmt *n = makeNode(ExplainStmt);
n->verbose = $2;
n->query = (Query*)$3;
$$ = (Node *)n;
}
;
/*****************************************************************************
* *
* Optimizable Stmts: *
* *
* one of the five queries processed by the planner *
* *
* [ultimately] produces query-trees as specified *
* in the query-spec document in ~postgres/ref *
* *
*****************************************************************************/
OptimizableStmt: RetrieveStmt
| CursorStmt
| ReplaceStmt
| AppendStmt
| NotifyStmt
| DeleteStmt /* by default all are $$=$1 */
;
/*****************************************************************************
*
* QUERY:
* INSERT STATEMENTS
*
*****************************************************************************/
AppendStmt: INSERT INTO relation_name opt_column_list insert_rest
{
$5->relname = $3;
$5->cols = $4;
$$ = (Node *)$5;
}
;
1996-10-30 03:02:41 +01:00
insert_rest: VALUES '(' res_target_list2 ')'
{
$$ = makeNode(AppendStmt);
1996-10-30 03:02:41 +01:00
$$->targetList = $3;
$$->fromClause = NIL;
$$->whereClause = NULL;
}
1996-10-30 03:02:41 +01:00
| SELECT res_target_list2 from_clause where_clause
{
$$ = makeNode(AppendStmt);
1996-10-30 03:02:41 +01:00
$$->targetList = $2;
$$->fromClause = $3;
$$->whereClause = $4;
}
;
opt_column_list: '(' columnList ')' { $$ = $2; }
| /*EMPTY*/ { $$ = NIL; }
;
columnList:
columnList ',' columnElem
{ $$ = lappend($1, $3); }
| columnElem
{ $$ = lcons($1, NIL); }
;
columnElem: Id opt_indirection
{
Ident *id = makeNode(Ident);
id->name = $1;
id->indirection = $2;
$$ = (Node *)id;
}
;
/*****************************************************************************
*
* QUERY:
* DELETE STATEMENTS
*
*****************************************************************************/
DeleteStmt: DELETE FROM relation_name
where_clause
{
DeleteStmt *n = makeNode(DeleteStmt);
n->relname = $3;
n->whereClause = $4;
$$ = (Node *)n;
}
;
/*****************************************************************************
*
* QUERY:
* ReplaceStmt (UPDATE)
*
*****************************************************************************/
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;
}
;
/*****************************************************************************
*
* QUERY:
* CURSOR STATEMENTS
*
*****************************************************************************/
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);
/* from PORTAL name */
/*
* 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.
* -- mao
*/
if (!IsTransactionBlock())
elog(WARN, "Named portals may only be used in begin/end transaction blocks.");
n->portalname = $2;
n->binary = $3;
n->unique = $7;
n->targetList = $8;
n->fromClause = $9;
n->whereClause = $10;
n->groupClause = $11;
n->sortClause = $12;
$$ = (Node *)n;
}
;
/*****************************************************************************
*
* QUERY:
* SELECT STATEMENTS
*
*****************************************************************************/
/******************************************************************************
RetrieveStmt: SELECT opt_unique res_target_list2
result from_clause where_clause
group_clause having_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->sortClause = $9;
$$ = (Node *)n;
}
;
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*/
{ $$ = NULL; }
;
opt_unique: DISTINCT { $$ = "*"; }
| DISTINCT ON Id { $$ = $3; }
| /*EMPTY*/ { $$ = NULL;}
;
sort_clause: ORDER BY sortby_list { $$ = $3; }
| /*EMPTY*/ { $$ = NIL; }
;
sortby_list: sortby
{ $$ = lcons($1, NIL); }
| sortby_list ',' sortby
{ $$ = lappend($1, $3); }
;
sortby: Id OptUseOp
{
$$ = makeNode(SortGroupBy);
$$->resno = 0;
$$->range = NULL;
$$->name = $1;
$$->useOp = $2;
}
| Id '.' Id OptUseOp
{
$$ = makeNode(SortGroupBy);
$$->resno = 0;
$$->range = $1;
$$->name = $3;
$$->useOp = $4;
}
| Iconst OptUseOp
{
$$ = makeNode(SortGroupBy);
$$->resno = $1;
$$->range = NULL;
$$->name = NULL;
$$->useOp = $2;
}
;
OptUseOp: USING Op { $$ = $2; }
| USING '<' { $$ = "<"; }
| USING '>' { $$ = ">"; }
| ASC { $$ = "<"; }
| DESC { $$ = ">"; }
| /*EMPTY*/ { $$ = "<"; /*default*/ }
;
1997-03-26 03:52:49 +01:00
index_params: index_list { $$ = $1; }
| func_index { $$ = lcons($1,NIL); }
;
1997-03-26 03:52:49 +01:00
index_list:
index_list ',' index_elem
{ $$ = lappend($1, $3); }
| index_elem
{ $$ = lcons($1, NIL); }
1997-03-26 03:52:49 +01:00
;
func_index: name '(' name_list ')' opt_type opt_class
{
$$ = makeNode(IndexElem);
$$->name = $1;
$$->args = $3;
$$->class = $6;
$$->tname = $5;
}
;
index_elem: attr_name opt_type opt_class
{
$$ = makeNode(IndexElem);
$$->name = $1;
$$->args = NIL;
$$->class = $3;
$$->tname = $2;
}
;
opt_type: ':' Typename { $$ = $2;}
| /*EMPTY*/ { $$ = NULL;}
;
opt_class: class
| WITH class { $$ = $2; }
| /*EMPTY*/ { $$ = NULL; }
;
/*
* jimmy bell-style recursive queries aren't supported in the
* current system.
*
* ...however, recursive addattr and rename supported. make special
* cases for these.
*
* XXX i believe '*' should be the default behavior, but...
*/
opt_inh_star: '*' { $$ = TRUE; }
| /*EMPTY*/ { $$ = FALSE; }
;
relation_name_list: name_list ;
name_list: name
{ $$=lcons(makeString($1),NIL); }
| name_list ',' name
{ $$=lappend($1,makeString($3)); }
;
group_clause: GROUP BY groupby_list { $$ = $3; }
| /*EMPTY*/ { $$ = NIL; }
;
groupby_list: groupby { $$ = lcons($1, NIL); }
| groupby_list ',' groupby { $$ = lappend($1, $3); }
;
groupby: 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;
}
;
having_clause: HAVING a_expr { $$ = $2; }
| /*EMPTY*/ { $$ = NULL; }
;
/*****************************************************************************
*
* clauses common to all Optimizable Stmts:
* from_clause -
* where_clause -
*
*****************************************************************************/
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); }
;
from_val: relation_expr AS var_name
{
$$ = makeNode(RangeVar);
$$->relExpr = $1;
$$->name = $3;
}
| relation_expr var_name
{
$$ = makeNode(RangeVar);
$$->relExpr = $1;
$$->name = $2;
}
| relation_expr
{
$$ = makeNode(RangeVar);
$$->relExpr = $1;
$$->name = NULL;
}
;
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 */ }
;
relation_expr: relation_name
{
/* normal relations */
$$ = makeNode(RelExpr);
$$->relname = $1;
$$->inh = FALSE;
$$->timeRange = NULL;
}
| relation_name '*' %prec '='
{
/* inheiritance query */
$$ = makeNode(RelExpr);
$$->relname = $1;
$$->inh = TRUE;
$$->timeRange = NULL;
}
| relation_name time_range
{
/* time-qualified query */
$$ = makeNode(RelExpr);
$$->relname = $1;
$$->inh = FALSE;
$$->timeRange = $2;
}
;
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"; }
;
opt_range_end: date
| /*EMPTY*/ { $$ = "now"; }
;
opt_array_bounds: '[' ']' nest_array_bounds
{ $$ = lcons(makeInteger(-1), $3); }
| '[' Iconst ']' nest_array_bounds
{ $$ = lcons(makeInteger($2), $4); }
| /* EMPTY */
{ $$ = NIL; }
;
nest_array_bounds: '[' ']' nest_array_bounds
{ $$ = lcons(makeInteger(-1), $3); }
| '[' Iconst ']' nest_array_bounds
{ $$ = lcons(makeInteger($2), $4); }
| /*EMPTY*/
{ $$ = NIL; }
;
typname: txname
{
char *tname = xlateSqlType($1);
$$ = makeNode(TypeName);
$$->name = tname;
/* Is this the name of a complex type? If so, implement
* it as a set.
*/
if (!strcmp(saved_relname, tname)) {
/* 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
* contain one element.)
*/
$$->setof = TRUE;
} else {
$$->setof = FALSE;
}
}
| SETOF txname
{
char *tname = xlateSqlType($2);
$$ = makeNode(TypeName);
$$->name = tname;
$$->setof = TRUE;
}
;
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;
}
| txname '(' Iconst ')'
{
/*
* 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
*/
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;
}
}
;
/*****************************************************************************
*
* expression grammar, still needs some cleanup
*
*****************************************************************************/
1997-02-13 16:40:03 +01:00
a_expr_or_null: a_expr
{ $$ = $1;}
| Pnull
{
1997-02-13 16:40:03 +01:00
A_Const *n = makeNode(A_Const);
n->val.type = T_Null;
$$ = (Node *)n;
}
a_expr: attr opt_indirection
{
$1->indirection = $2;
$$ = (Node *)$1;
}
| AexprConst
{ $$ = $1; }
| '-' a_expr %prec UMINUS
{ $$ = makeA_Expr(OP, "-", NULL, $2); }
| a_expr '+' a_expr
{ $$ = makeA_Expr(OP, "+", $1, $3); }
| a_expr '-' a_expr
{ $$ = makeA_Expr(OP, "-", $1, $3); }
| a_expr '/' a_expr
{ $$ = makeA_Expr(OP, "/", $1, $3); }
| a_expr '*' a_expr
{ $$ = makeA_Expr(OP, "*", $1, $3); }
| a_expr '<' a_expr
{ $$ = makeA_Expr(OP, "<", $1, $3); }
| a_expr '>' a_expr
{ $$ = makeA_Expr(OP, ">", $1, $3); }
| a_expr '=' a_expr
{ $$ = makeA_Expr(OP, "=", $1, $3); }
| ':' a_expr
{ $$ = makeA_Expr(OP, ":", NULL, $2); }
| ';' a_expr
{ $$ = makeA_Expr(OP, ";", NULL, $2); }
| '|' 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;
}else {
((ParamNo *)$1)->typename = $3;
}
$$ = (Node *)$1;
}
| CAST AexprConst AS Typename
{
/* AexprConst can be either A_Const or ParamNo */
if (nodeTag($2) == T_A_Const) {
((A_Const *)$2)->typename = $4;
}else {
((ParamNo *)$2)->typename = $4;
}
$$ = (Node *)$2;
}
1997-02-13 16:40:03 +01:00
| '(' a_expr_or_null ')'
{ $$ = $2; }
| a_expr Op a_expr
{ $$ = makeA_Expr(OP, $2, $1, $3); }
| a_expr LIKE a_expr
{ $$ = makeA_Expr(OP, "~~", $1, $3); }
| a_expr NOT LIKE a_expr
{ $$ = makeA_Expr(OP, "!~~", $1, $4); }
| Op a_expr
{ $$ = makeA_Expr(OP, $1, NULL, $2); }
| a_expr Op
{ $$ = makeA_Expr(OP, $2, $1, NULL); }
| Id
{ /* could be a column name or a relation_name */
Ident *n = makeNode(Ident);
n->name = $1;
n->indirection = NULL;
$$ = (Node *)n;
}
| name '(' '*' ')'
{
FuncCall *n = makeNode(FuncCall);
Ident *star = makeNode(Ident);
/* cheap hack for aggregate (eg. count) */
star->name = "oid";
n->funcname = $1;
n->args = lcons(star, NIL);
$$ = (Node *)n;
}
| name '(' ')'
{
FuncCall *n = makeNode(FuncCall);
n->funcname = $1;
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);
n->funcname = $1;
n->args = $3;
$$ = (Node *)n;
}
| a_expr ISNULL
{ $$ = makeA_Expr(ISNULL, NULL, $1, NULL); }
| a_expr IS PNULL
{ $$ = makeA_Expr(ISNULL, NULL, $1, NULL); }
| a_expr NOTNULL
{ $$ = makeA_Expr(NOTNULL, NULL, $1, NULL); }
| a_expr IS NOT PNULL
{ $$ = makeA_Expr(NOTNULL, NULL, $1, NULL); }
| a_expr BETWEEN AexprConst AND AexprConst
{ $$ = makeA_Expr(AND, NULL,
makeA_Expr(OP, ">=", $1, $3),
makeA_Expr(OP, "<=", $1, $5));
}
| a_expr NOT BETWEEN AexprConst AND AexprConst
{ $$ = makeA_Expr(OR, NULL,
makeA_Expr(OP, "<", $1, $4),
makeA_Expr(OP, ">", $1, $6));
}
| a_expr IN { saved_In_Expr = $1; } '(' in_expr_nodes ')'
{ $$ = $5; }
| a_expr NOT IN { saved_In_Expr = $1; } '(' not_in_expr_nodes ')'
{ $$ = $6; }
| a_expr AND a_expr
{ $$ = makeA_Expr(AND, NULL, $1, $3); }
| a_expr OR a_expr
{ $$ = makeA_Expr(OR, NULL, $1, $3); }
| NOT a_expr
{ $$ = makeA_Expr(NOT, NULL, NULL, $2); }
;
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_Indices *ai = makeNode(A_Indices);
ai->lidx = $2;
ai->uidx = $4;
$$ = lcons(ai, $6);
}
| /* EMPTY */
{ $$ = NIL; }
;
1997-02-13 16:40:03 +01:00
expr_list: a_expr_or_null
{ $$ = lcons($1, NIL); }
1997-02-13 16:40:03 +01:00
| 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
{ $$ = makeA_Expr(OP, "=", saved_In_Expr, $1); }
| in_expr_nodes ',' AexprConst
{ $$ = makeA_Expr(OR, NULL, $1,
makeA_Expr(OP, "=", saved_In_Expr, $3));
}
;
not_in_expr_nodes: AexprConst
{ $$ = makeA_Expr(OP, "<>", saved_In_Expr, $1); }
| not_in_expr_nodes ',' AexprConst
{ $$ = makeA_Expr(AND, NULL, $1,
makeA_Expr(OP, "<>", saved_In_Expr, $3));
}
;
attr: relation_name '.' attrs
{
$$ = makeNode(Attr);
$$->relname = $1;
$$->paramNo = NULL;
$$->attrs = $3;
$$->indirection = NULL;
}
| ParamNo '.' attrs
{
$$ = makeNode(Attr);
$$->relname = NULL;
$$->paramNo = $1;
$$->attrs = $3;
$$->indirection = NULL;
}
;
attrs: attr_name
{ $$ = lcons(makeString($1), NIL); }
| attrs '.' attr_name
{ $$ = lappend($1, makeString($3)); }
| attrs '.' '*'
{ $$ = lappend($1, makeString("*")); }
;
datetime: YEARINTERVAL { $$ = "year"; }
| MONTHINTERVAL { $$ = "month"; }
| DAYINTERVAL { $$ = "day"; }
| HOURINTERVAL { $$ = "hour"; }
| MINUTEINTERVAL { $$ = "minute"; }
| SECONDINTERVAL { $$ = "second"; }
;
/*****************************************************************************
*
* target lists
*
*****************************************************************************/
res_target_list: res_target_list ',' res_target_el
{ $$ = lappend($1,$3); }
| res_target_el
{ $$ = lcons($1, NIL); }
| '*'
{
ResTarget *rt = makeNode(ResTarget);
Attr *att = makeNode(Attr);
att->relname = "*";
att->paramNo = NULL;
att->attrs = NULL;
att->indirection = NIL;
rt->name = NULL;
rt->indirection = NULL;
rt->val = (Node *)att;
$$ = lcons(rt, NIL);
}
;
1997-02-13 16:40:03 +01:00
res_target_el: Id opt_indirection '=' a_expr_or_null
{
$$ = makeNode(ResTarget);
$$->name = $1;
$$->indirection = $2;
$$->val = (Node *)$4;
}
| attr opt_indirection
{
$$ = makeNode(ResTarget);
$$->name = NULL;
$$->indirection = $2;
$$->val = (Node *)$1;
}
| relation_name '.' '*'
{
Attr *att = makeNode(Attr);
att->relname = $1;
att->paramNo = NULL;
att->attrs = lcons(makeString("*"), NIL);
att->indirection = NIL;
$$ = makeNode(ResTarget);
$$->name = 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
{ $$ = lappend($1, $3); }
| res_target_el2
{ $$ = lcons($1, NIL); }
;
/* AS is not optional because shift/red conflict with unary ops */
res_target_el2: a_expr AS ColId
{
$$ = makeNode(ResTarget);
$$->name = $3;
$$->indirection = NULL;
$$->val = (Node *)$1;
}
1997-02-13 16:40:03 +01:00
| a_expr_or_null
{
$$ = makeNode(ResTarget);
$$->name = NULL;
$$->indirection = NULL;
$$->val = (Node *)$1;
}
| relation_name '.' '*'
{
Attr *att = makeNode(Attr);
att->relname = $1;
att->paramNo = NULL;
att->attrs = lcons(makeString("*"), NIL);
att->indirection = NIL;
$$ = makeNode(ResTarget);
$$->name = NULL;
$$->indirection = NULL;
$$->val = (Node *)att;
}
| '*'
{
Attr *att = makeNode(Attr);
att->relname = "*";
att->paramNo = NULL;
att->attrs = NULL;
att->indirection = NIL;
$$ = makeNode(ResTarget);
$$->name = NULL;
$$->indirection = NULL;
$$->val = (Node *)att;
}
;
opt_id: Id { $$ = $1; }
| /* EMPTY */ { $$ = NULL; }
;
relation_name: SpecialRuleRelation
{
$$ = $1;
strNcpy(saved_relname, $1, NAMEDATALEN-1);
}
| ColId
{
/* disallow refs to magic system tables */
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);
}
;
database_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; };
date: Sconst { $$ = $1; };
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;
$$ = (Node *)n;
}
| ParamNo
{ $$ = (Node *)$1; }
;
ParamNo: PARAM
{
$$ = makeNode(ParamNo);
$$->number = $1;
}
;
NumConst: Iconst { $$ = makeInteger($1); }
| FCONST { $$ = makeFloat($1); }
;
Iconst: ICONST { $$ = $1; };
Sconst: SCONST { $$ = $1; };
Id: IDENT { $$ = $1; };
ColId: Id { $$ = $1; }
| datetime { $$ = $1; }
;
SpecialRuleRelation: CURRENT
{
if (QueryIsRule)
$$ = "*CURRENT*";
else
elog(WARN,"CURRENT used in non-rule query");
}
| NEW
{
if (QueryIsRule)
$$ = "*NEW*";
else
elog(WARN,"NEW used in non-rule query");
}
;
Type: P_TYPE;
Pnull: PNULL;
%%
static Node *makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr)
{
A_Expr *a = makeNode(A_Expr);
a->oper = oper;
a->opname = opname;
a->lexpr = lexpr;
a->rexpr = rexpr;
return (Node *)a;
}
static char *
xlateSqlType(char *name)
{
if (!strcasecmp(name,"int") ||
!strcasecmp(name,"integer"))
return "int4"; /* strdup("int4") -- strdup leaks memory here */
else if (!strcasecmp(name, "smallint"))
return "int2";
else if (!strcasecmp(name, "float") ||
!strcasecmp(name, "real"))
return "float8";
else if (!strcasecmp(name, "interval"))
return "timespan";
else
return name;
}
void parser_init(Oid *typev, int nargs)
{
QueryIsRule = false;
saved_relname[0]= '\0';
saved_In_Expr = NULL;
param_type_init(typev, nargs);
}