postgresql/src/backend/parser/gram.y

5057 lines
122 KiB
Plaintext
Raw Normal View History

%{ /* -*-text-*- */
/*#define YYDEBUG 1*/
/*-------------------------------------------------------------------------
*
* gram.y--
1997-09-08 05:20:18 +02:00
* POSTGRES SQL YACC rules/actions
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.6 1998/03/07 06:04:59 thomas Exp $
*
* HISTORY
1997-09-08 05:20:18 +02:00
* AUTHOR DATE MAJOR EVENT
* Andrew Yu Sept, 1994 POSTQUEL to SQL conversion
* Andrew Yu Oct, 1994 lispy code conversion
*
* NOTES
1997-09-08 05:20:18 +02:00
* CAPITALS are used to represent terminal symbols.
* non-capitals are used to represent non-terminals.
* SQL92-specific syntax is separated from plain SQL/Postgres syntax
* to help isolate the non-extensible portions of the parser.
*
1997-09-08 05:20:18 +02:00
* if you use list, make sure the datum is a node so that the printing
* routines work
*
* WARNING
1997-09-08 05:20:18 +02:00
* 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"
#include "nodes/print.h"
1996-11-08 21:46:33 +01:00
#include "parser/gramparse.h"
#include "parser/parse_type.h"
#include "utils/acl.h"
#include "utils/palloc.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 List *saved_In_Expr = NIL;
static Oid *param_type_info;
static int pfunc_num_args;
extern List *parsetree;
/*
1997-09-08 05:20:18 +02:00
* 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 *xlateSqlFunc(char *);
static char *xlateSqlType(char *);
static Node *makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr);
1998-01-17 06:01:34 +01:00
static Node *makeRowExpr(char *opr, List *largs, List *rargs);
void mapTargetColumns(List *source, List *target);
static List *makeConstantList( A_Const *node);
static char *FlattenStringList(List *list);
static char *fmtId(char *rawid);
1997-10-31 01:50:39 +01:00
static Node *makeIndexable(char *opname, Node *lexpr, Node *rexpr);
static void param_type_init(Oid *typev, int nargs);
Oid param_type(int t); /* used in parse_expr.c */
/* old versions of flex define this as a macro */
#if defined(yywrap)
#undef yywrap
#endif /* yywrap */
%}
1997-09-08 05:20:18 +02:00
%union
{
double dval;
int ival;
char chr;
char *str;
bool boolean;
bool* pboolean; /* for pg_shadow privileges */
1997-09-08 05:20:18 +02:00
List *list;
Node *node;
Value *value;
Attr *attr;
TypeName *typnam;
DefElem *defelt;
ParamString *param;
SortGroupBy *sortgroupby;
IndexElem *ielem;
RangeVar *range;
RelExpr *relexp;
A_Indices *aind;
ResTarget *target;
ParamNo *paramno;
VersionStmt *vstmt;
DefineStmt *dstmt;
RuleStmt *rstmt;
1998-01-09 21:06:08 +01:00
InsertStmt *astmt;
}
%type <node> stmt,
1997-09-08 05:20:18 +02:00
AddAttrStmt, ClosePortalStmt,
CopyStmt, CreateStmt, CreateAsStmt, CreateSeqStmt, DefineStmt, DestroyStmt,
1997-09-08 05:20:18 +02:00
ExtendStmt, FetchStmt, GrantStmt, CreateTrigStmt, DropTrigStmt,
CreatePLangStmt, DropPLangStmt,
IndexStmt, ListenStmt, LockStmt, OptimizableStmt,
1997-11-21 19:12:58 +01:00
ProcedureStmt, RecipeStmt, RemoveAggrStmt, RemoveOperStmt,
RemoveFuncStmt, RemoveStmt,
1997-09-08 05:20:18 +02:00
RenameStmt, RevokeStmt, RuleStmt, TransactionStmt, ViewStmt, LoadStmt,
1997-12-24 07:06:58 +01:00
CreatedbStmt, DestroydbStmt, VacuumStmt, CursorStmt, SubSelect,
1998-01-09 21:06:08 +01:00
UpdateStmt, InsertStmt, SelectStmt, NotifyStmt, DeleteStmt, ClusterStmt,
ExplainStmt, VariableSetStmt, VariableShowStmt, VariableResetStmt,
CreateUserStmt, AlterUserStmt, DropUserStmt
1997-09-08 05:20:18 +02:00
%type <str> opt_database, location
%type <pboolean> user_createdb_clause, user_createuser_clause
%type <str> user_passwd_clause
%type <str> user_valid_clause
%type <list> user_group_list, user_group_clause
%type <str> join_expr, join_outer, join_spec
%type <boolean> TriggerActionTime, TriggerForSpec, PLangTrusted
%type <str> TriggerEvents, TriggerFuncArg
1997-09-08 05:20:18 +02:00
%type <str> relation_name, copy_file_name, copy_delimiter, def_name,
database_name, access_method_clause, access_method, attr_name,
class, index_name, name, func_name, file_name, recipe_name, aggr_argtype
1997-08-21 03:34:44 +02:00
1997-09-08 05:20:18 +02:00
%type <str> opt_id, opt_portal_name,
1997-11-21 19:12:58 +01:00
all_Op, MathOp, opt_name, opt_unique,
result, OptUseOp, opt_class, SpecialRuleRelation
1997-09-08 05:20:18 +02:00
%type <str> privileges, operation_commalist, grantee
%type <chr> operation, TriggerOneEvent
%type <list> stmtblock, stmtmulti,
relation_name_list, OptTableElementList,
OptInherit, definition,
opt_with, func_args, func_args_list,
1997-09-08 05:20:18 +02:00
oper_argtypes, OptStmtList, OptStmtBlock, OptStmtMulti,
opt_column_list, columnList, opt_va_list, va_list,
sort_clause, sortby_list, index_params, index_list, name_list,
from_clause, from_list, opt_array_bounds, nest_array_bounds,
expr_list, attrs, res_target_list, res_target_list2,
1997-09-08 05:20:18 +02:00
def_list, opt_indirection, group_clause, groupby_list, TriggerFuncArgs
%type <node> func_return
%type <boolean> set_opt
%type <boolean> TriggerForOpt, TriggerForType
%type <list> union_clause, select_list
%type <list> join_list
%type <sortgroupby>
join_using
%type <boolean> opt_union
%type <node> position_expr
%type <list> extract_list, position_list
%type <list> substr_list, substr_from, substr_for, trim_list
%type <list> opt_interval
%type <boolean> opt_inh_star, opt_binary, opt_instead, opt_with_copy,
index_opt_unique, opt_verbose, opt_analyze
1997-11-21 19:12:58 +01:00
%type <ival> copy_dirn, def_type, opt_direction, remove_type,
opt_column, event
1997-11-21 19:12:58 +01:00
%type <ival> fetch_how_many
%type <list> OptSeqList
%type <defelt> OptSeqElem
%type <dstmt> def_rest
%type <astmt> insert_rest
%type <node> OptTableElement, ConstraintElem
%type <node> columnDef, alter_clause
%type <defelt> def_elem
%type <node> def_arg, columnElem, where_clause,
a_expr, a_expr_or_null, b_expr, AexprConst,
in_expr, in_expr_nodes, not_in_expr, not_in_expr_nodes,
1997-09-08 05:20:18 +02:00
having_clause
%type <list> row_descriptor, row_list
%type <node> row_expr
%type <list> OptCreateAs, CreateAsList
%type <node> CreateAsElement
%type <value> NumConst
%type <attr> event_object, attr
1997-09-08 05:20:18 +02:00
%type <sortgroupby> groupby
%type <sortgroupby> sortby
%type <ielem> index_elem, func_index
%type <range> from_val
%type <relexp> relation_expr
%type <target> res_target_el, res_target_el2
1997-09-08 05:20:18 +02:00
%type <paramno> ParamNo
%type <typnam> Typename, opt_type, Array, Generic, Character, Datetime, Numeric
%type <str> generic, numeric, character, datetime
%type <str> opt_charset, opt_collate
%type <str> opt_float, opt_numeric, opt_decimal
%type <boolean> opt_varying, opt_timezone
%type <ival> Iconst
1997-09-08 05:20:18 +02:00
%type <str> Sconst
%type <str> UserId, var_value, zone_value
%type <str> ColId, ColLabel
%type <str> TypeId
%type <node> TableConstraint
%type <list> constraint_list, constraint_expr
%type <list> default_list, default_expr
%type <list> ColQualList, ColQualifier
%type <node> ColConstraint, ColConstraintElem
%type <list> key_actions, key_action
%type <str> key_match, key_reference
/*
* If you make any token changes, remember to:
1997-09-08 05:20:18 +02:00
* - use "yacc -d" and update parse.h
* - update the keyword table in parser/keywords.c
*/
/* Reserved word tokens
* SQL92 syntax has many type-specific constructs.
* So, go ahead and make these types reserved words,
* and call-out the syntax explicitly.
* This gets annoying when trying to also retain Postgres' nice
* type-extensible features, but we don't really have a choice.
* - thomas 1997-10-11
*/
/* Keywords (in SQL92 reserved words) */
%token ACTION, ADD, ALL, ALTER, AND, ANY AS, ASC,
BEGIN_TRANS, BETWEEN, BOTH, BY,
CASCADE, CAST, CHAR, CHARACTER, CHECK, CLOSE, COLLATE, COLUMN, COMMIT,
CONSTRAINT, CREATE, CROSS, CURRENT, CURRENT_DATE, CURRENT_TIME,
CURRENT_TIMESTAMP, CURRENT_USER, CURSOR,
DAY_P, DECIMAL, DECLARE, DEFAULT, DELETE, DESC, DISTINCT, DOUBLE, DROP,
END_TRANS, EXECUTE, EXISTS, EXTRACT,
FETCH, FLOAT, FOR, FOREIGN, FROM, FULL,
GRANT, GROUP, HAVING, HOUR_P,
IN, INNER_P, INSERT, INTERVAL, INTO, IS,
JOIN, KEY, LANGUAGE, LEADING, LEFT, LIKE, LOCAL,
MATCH, MINUTE_P, MONTH_P,
NATIONAL, NATURAL, NCHAR, NO, NOT, NOTIFY, NULL_P, NUMERIC,
ON, OPTION, OR, ORDER, OUTER_P,
PARTIAL, POSITION, PRECISION, PRIMARY, PRIVILEGES, PROCEDURE, PUBLIC,
REFERENCES, REVOKE, RIGHT, ROLLBACK,
SECOND_P, SELECT, SET, SUBSTRING,
TABLE, TIME, TIMESTAMP, TO, TRAILING, TRANSACTION, TRIM,
UNION, UNIQUE, UPDATE, USING,
VALUES, VARCHAR, VARYING, VIEW,
WHERE, WITH, WORK, YEAR_P, ZONE
/* Keywords (in SQL3 reserved words) */
%token FALSE_P, TRIGGER, TRUE_P
/* Keywords (in SQL92 non-reserved words) */
%token TYPE_P
/* Keywords for Postgres support (not in SQL92 reserved words) */
%token ABORT_TRANS, AFTER, AGGREGATE, ANALYZE,
BACKWARD, BEFORE, BINARY, CLUSTER, COPY,
DATABASE, DELIMITERS, DO, EACH, EXPLAIN, EXTEND,
1997-11-21 19:12:58 +01:00
FORWARD, FUNCTION, HANDLER,
INDEX, INHERITS, INSTEAD, ISNULL,
LANCOMPILER, LISTEN, LOAD, LOCK_P, LOCATION, MOVE,
NEW, NONE, NOTHING, NOTNULL, OIDS, OPERATOR, PROCEDURAL,
RECIPE, RENAME, RESET, RETURNS, ROW, RULE,
SEQUENCE, SETOF, SHOW, STATEMENT, STDIN, STDOUT, TRUSTED,
VACUUM, VERBOSE, VERSION
1998-02-03 17:04:05 +01:00
/* Keywords (obsolete; retain through next version for parser - thomas 1997-12-04) */
%token ARCHIVE
/*
* Tokens for pg_passwd support. The CREATEDB and CREATEUSER tokens should go away
* when some sort of pg_privileges relation is introduced.
*
* Todd A. Brandys
*/
%token USER, PASSWORD, CREATEDB, NOCREATEDB, CREATEUSER, NOCREATEUSER, VALID, UNTIL
/* 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 get generated as #define's*/
1997-09-08 05:20:18 +02:00
%token OP
/* precedence */
%left OR
%left AND
%right NOT
%right '='
%nonassoc '<' '>'
%nonassoc LIKE
%nonassoc BETWEEN
%nonassoc IN
%nonassoc Op /* multi-character ops and user-defined operators */
%nonassoc NOTNULL
%nonassoc ISNULL
%nonassoc IS
%left '+' '-'
%left '*' '/'
%left '|' /* this is the relation union op, not logical or */
/* Unary Operators */
%right ':'
%left ';' /* end of statement or natural log */
%right UMINUS
%left '.'
%left '[' ']'
%nonassoc TYPECAST
%nonassoc REDUCE
%left UNION
%%
stmtblock: stmtmulti
1997-09-08 05:20:18 +02:00
{ parsetree = $1; }
| stmt
1997-09-08 05:20:18 +02:00
{ parsetree = lcons($1,NIL); }
;
stmtmulti: stmtmulti stmt ';'
1997-09-08 05:20:18 +02:00
{ $$ = lappend($1, $2); }
| stmtmulti stmt
1997-09-08 05:20:18 +02:00
{ $$ = lappend($1, $2); }
| stmt ';'
1997-09-08 05:20:18 +02:00
{ $$ = lcons($1,NIL); }
;
stmt : AddAttrStmt
| AlterUserStmt
1997-09-08 05:20:18 +02:00
| ClosePortalStmt
| CopyStmt
| CreateStmt
| CreateAsStmt
1997-09-08 05:20:18 +02:00
| CreateSeqStmt
| CreatePLangStmt
1997-09-08 05:20:18 +02:00
| CreateTrigStmt
| CreateUserStmt
1997-09-08 05:20:18 +02:00
| ClusterStmt
| DefineStmt
| DestroyStmt
| DropPLangStmt
1997-09-08 05:20:18 +02:00
| DropTrigStmt
| DropUserStmt
1997-09-08 05:20:18 +02:00
| ExtendStmt
| ExplainStmt
| FetchStmt
| GrantStmt
| IndexStmt
| ListenStmt
| LockStmt
1997-09-08 05:20:18 +02:00
| ProcedureStmt
| RecipeStmt
| RemoveAggrStmt
| RemoveOperStmt
| RemoveFuncStmt
| RemoveStmt
| RenameStmt
| RevokeStmt
| OptimizableStmt
| RuleStmt
| TransactionStmt
| ViewStmt
| LoadStmt
| CreatedbStmt
| DestroydbStmt
| VacuumStmt
| VariableSetStmt
| VariableShowStmt
| VariableResetStmt
;
/*****************************************************************************
*
* Create a new Postgres DBMS user
*
*
*****************************************************************************/
CreateUserStmt: CREATE USER UserId user_passwd_clause user_createdb_clause
user_createuser_clause user_group_clause user_valid_clause
{
CreateUserStmt *n = makeNode(CreateUserStmt);
n->user = $3;
n->password = $4;
n->createdb = $5;
n->createuser = $6;
n->groupElts = $7;
n->validUntil = $8;
$$ = (Node *)n;
}
;
/*****************************************************************************
*
* Alter a postresql DBMS user
*
*
*****************************************************************************/
AlterUserStmt: ALTER USER UserId user_passwd_clause user_createdb_clause
user_createuser_clause user_group_clause user_valid_clause
{
AlterUserStmt *n = makeNode(AlterUserStmt);
n->user = $3;
n->password = $4;
n->createdb = $5;
n->createuser = $6;
n->groupElts = $7;
n->validUntil = $8;
$$ = (Node *)n;
}
;
/*****************************************************************************
*
* Drop a postresql DBMS user
*
*
*****************************************************************************/
DropUserStmt: DROP USER UserId
{
DropUserStmt *n = makeNode(DropUserStmt);
n->user = $3;
$$ = (Node *)n;
}
;
user_passwd_clause: WITH PASSWORD UserId { $$ = $3; }
| /*EMPTY*/ { $$ = NULL; }
;
user_createdb_clause: CREATEDB
{
bool* b;
$$ = (b = (bool*)palloc(sizeof(bool)));
*b = true;
}
| NOCREATEDB
{
bool* b;
$$ = (b = (bool*)palloc(sizeof(bool)));
*b = false;
}
| /*EMPTY*/ { $$ = NULL; }
;
user_createuser_clause: CREATEUSER
{
bool* b;
$$ = (b = (bool*)palloc(sizeof(bool)));
*b = true;
}
| NOCREATEUSER
{
bool* b;
$$ = (b = (bool*)palloc(sizeof(bool)));
*b = false;
}
| /*EMPTY*/ { $$ = NULL; }
;
user_group_list: user_group_list ',' UserId
{
$$ = lcons((void*)makeString($3), $1);
}
| UserId
{
$$ = lcons((void*)makeString($1), NIL);
}
;
user_group_clause: IN GROUP user_group_list { $$ = $3; }
| /*EMPTY*/ { $$ = NULL; }
;
user_valid_clause: VALID UNTIL SCONST { $$ = $3; }
| /*EMPTY*/ { $$ = NULL; }
;
/*****************************************************************************
*
* Set PG internal variable
* SET name TO 'var_value'
* Include SQL92 syntax (thomas 1997-10-22):
* SET TIME ZONE 'var_value'
*
*****************************************************************************/
VariableSetStmt: SET ColId TO var_value
1997-09-08 05:20:18 +02:00
{
VariableSetStmt *n = makeNode(VariableSetStmt);
n->name = $2;
n->value = $4;
$$ = (Node *) n;
}
| SET ColId '=' var_value
1997-09-08 05:20:18 +02:00
{
VariableSetStmt *n = makeNode(VariableSetStmt);
n->name = $2;
n->value = $4;
$$ = (Node *) n;
}
| SET TIME ZONE zone_value
1997-09-08 05:20:18 +02:00
{
VariableSetStmt *n = makeNode(VariableSetStmt);
n->name = "timezone";
n->value = $4;
$$ = (Node *) n;
}
;
var_value: Sconst { $$ = $1; }
| DEFAULT { $$ = NULL; }
1997-09-08 05:20:18 +02:00
;
zone_value: Sconst { $$ = $1; }
| DEFAULT { $$ = NULL; }
| LOCAL { $$ = "default"; }
1997-09-08 05:20:18 +02:00
;
VariableShowStmt: SHOW ColId
1997-09-08 05:20:18 +02:00
{
VariableShowStmt *n = makeNode(VariableShowStmt);
n->name = $2;
$$ = (Node *) n;
}
| SHOW TIME ZONE
{
VariableShowStmt *n = makeNode(VariableShowStmt);
n->name = "timezone";
$$ = (Node *) n;
}
1997-09-08 05:20:18 +02:00
;
VariableResetStmt: RESET ColId
1997-09-08 05:20:18 +02:00
{
VariableResetStmt *n = makeNode(VariableResetStmt);
n->name = $2;
$$ = (Node *) n;
}
| RESET TIME ZONE
{
VariableResetStmt *n = makeNode(VariableResetStmt);
n->name = "timezone";
$$ = (Node *) n;
}
1997-09-08 05:20:18 +02:00
;
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
/*****************************************************************************
*
1997-09-08 05:20:18 +02:00
* QUERY :
* addattr ( attr1 = type1 .. attrn = typen ) to <relname> [*]
*
*****************************************************************************/
AddAttrStmt: ALTER TABLE relation_name opt_inh_star alter_clause
1997-09-08 05:20:18 +02:00
{
AddAttrStmt *n = makeNode(AddAttrStmt);
n->relname = $3;
n->inh = $4;
n->colDef = $5;
1997-09-08 05:20:18 +02:00
$$ = (Node *)n;
}
;
alter_clause: ADD opt_column columnDef
{
$$ = $3;
}
| ADD '(' OptTableElementList ')'
{
Node *lp = lfirst($3);
if (length($3) != 1)
1998-01-09 21:06:08 +01:00
elog(ERROR,"ALTER TABLE/ADD() allows one column only");
$$ = lp;
}
| DROP opt_column ColId
1998-01-09 21:06:08 +01:00
{ elog(ERROR,"ALTER TABLE/DROP COLUMN not yet implemented"); }
| ALTER opt_column ColId SET DEFAULT default_expr
1998-01-09 21:06:08 +01:00
{ elog(ERROR,"ALTER TABLE/ALTER COLUMN/SET DEFAULT not yet implemented"); }
| ALTER opt_column ColId DROP DEFAULT
1998-01-09 21:06:08 +01:00
{ elog(ERROR,"ALTER TABLE/ALTER COLUMN/DROP DEFAULT not yet implemented"); }
| ADD ConstraintElem
1998-01-09 21:06:08 +01:00
{ elog(ERROR,"ALTER TABLE/ADD CONSTRAINT not yet implemented"); }
;
/*****************************************************************************
*
1997-09-08 05:20:18 +02:00
* QUERY :
* close <optname>
*
*****************************************************************************/
ClosePortalStmt: CLOSE opt_id
1997-09-08 05:20:18 +02:00
{
ClosePortalStmt *n = makeNode(ClosePortalStmt);
n->portalname = $2;
$$ = (Node *)n;
}
;
/*****************************************************************************
*
1997-09-08 05:20:18 +02:00
* 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
1997-09-08 05:20:18 +02:00
{
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
1997-09-08 05:20:18 +02:00
{ $$ = 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
1997-09-08 05:20:18 +02:00
* stdout. We silently correct the "typo". - AY 9/94
*/
1997-09-08 05:20:18 +02:00
copy_file_name: Sconst { $$ = $1; }
| STDIN { $$ = NULL; }
| STDOUT { $$ = NULL; }
;
opt_binary: BINARY { $$ = TRUE; }
| /*EMPTY*/ { $$ = FALSE; }
1997-09-08 05:20:18 +02:00
;
1997-09-08 05:20:18 +02:00
opt_with_copy: WITH OIDS { $$ = TRUE; }
| /*EMPTY*/ { $$ = FALSE; }
1997-09-08 05:20:18 +02:00
;
/*
* the default copy delimiter is tab but the user can configure it
*/
copy_delimiter: USING DELIMITERS Sconst { $$ = $3; }
| /*EMPTY*/ { $$ = "\t"; }
1997-09-08 05:20:18 +02:00
;
/*****************************************************************************
*
1997-09-08 05:20:18 +02:00
* QUERY :
* CREATE relname
*
*****************************************************************************/
CreateStmt: CREATE TABLE relation_name '(' OptTableElementList ')'
OptInherit OptArchiveType
1997-09-08 05:20:18 +02:00
{
CreateStmt *n = makeNode(CreateStmt);
n->relname = $3;
n->tableElts = $5;
n->inhRelnames = $7;
n->constraints = NIL;
1997-09-08 05:20:18 +02:00
$$ = (Node *)n;
}
;
OptTableElementList: OptTableElementList ',' OptTableElement
{ $$ = lappend($1, $3); }
| OptTableElement { $$ = lcons($1, NIL); }
| /*EMPTY*/ { $$ = NULL; }
1997-09-08 05:20:18 +02:00
;
OptTableElement: columnDef { $$ = $1; }
| TableConstraint { $$ = $1; }
1997-09-08 05:20:18 +02:00
;
columnDef: ColId Typename ColQualifier
{
ColumnDef *n = makeNode(ColumnDef);
n->colname = $1;
n->typename = $2;
n->defval = NULL;
n->is_not_null = FALSE;
n->constraints = $3;
$$ = (Node *)n;
}
;
ColQualifier: ColQualList { $$ = $1; }
| /*EMPTY*/ { $$ = NULL; }
1997-09-08 05:20:18 +02:00
;
ColQualList: ColQualList ColConstraint { $$ = lappend($1,$2); }
| ColConstraint { $$ = lcons($1, NIL); }
;
ColConstraint:
CONSTRAINT name ColConstraintElem
{
Constraint *n = (Constraint *)$3;
n->name = fmtId($2);
$$ = $3;
}
| ColConstraintElem
{ $$ = $1; }
1997-09-08 05:20:18 +02:00
;
ColConstraintElem: CHECK '(' constraint_expr ')'
{
Constraint *n = makeNode(Constraint);
n->contype = CONSTR_CHECK;
n->name = NULL;
n->def = FlattenStringList($3);
n->keys = NULL;
$$ = (Node *)n;
}
| DEFAULT default_expr
{
Constraint *n = makeNode(Constraint);
n->contype = CONSTR_DEFAULT;
n->name = NULL;
n->def = FlattenStringList($2);
n->keys = NULL;
$$ = (Node *)n;
}
| NOT NULL_P
{
Constraint *n = makeNode(Constraint);
n->contype = CONSTR_NOTNULL;
n->name = NULL;
n->def = NULL;
n->keys = NULL;
$$ = (Node *)n;
}
| UNIQUE
{
Constraint *n = makeNode(Constraint);
n->contype = CONSTR_UNIQUE;
n->name = NULL;
n->def = NULL;
n->keys = NULL;
$$ = (Node *)n;
}
| PRIMARY KEY
{
Constraint *n = makeNode(Constraint);
n->contype = CONSTR_PRIMARY;
n->name = NULL;
n->def = NULL;
n->keys = NULL;
$$ = (Node *)n;
}
| REFERENCES ColId opt_column_list key_match key_actions
{
1998-01-09 21:06:08 +01:00
elog(NOTICE,"CREATE TABLE/FOREIGN KEY clause ignored; not yet implemented");
$$ = NULL;
}
1997-09-08 05:20:18 +02:00
;
1997-08-20 03:12:38 +02:00
default_list: default_list ',' default_expr
{
$$ = lappend($1,makeString(","));
$$ = nconc($$, $3);
}
| default_expr
{
$$ = $1;
}
;
default_expr: AexprConst
{ $$ = makeConstantList((A_Const *) $1); }
| NULL_P
{ $$ = lcons( makeString("NULL"), NIL); }
| '-' default_expr %prec UMINUS
{ $$ = lcons( makeString( "-"), $2); }
| default_expr '+' default_expr
{ $$ = nconc( $1, lcons( makeString( "+"), $3)); }
| default_expr '-' default_expr
{ $$ = nconc( $1, lcons( makeString( "-"), $3)); }
| default_expr '/' default_expr
{ $$ = nconc( $1, lcons( makeString( "/"), $3)); }
| default_expr '*' default_expr
{ $$ = nconc( $1, lcons( makeString( "*"), $3)); }
| default_expr '=' default_expr
1998-01-09 21:06:08 +01:00
{ elog(ERROR,"boolean expressions not supported in DEFAULT"); }
| default_expr '<' default_expr
1998-01-09 21:06:08 +01:00
{ elog(ERROR,"boolean expressions not supported in DEFAULT"); }
| default_expr '>' default_expr
1998-01-09 21:06:08 +01:00
{ elog(ERROR,"boolean expressions not supported in DEFAULT"); }
| ':' default_expr
{ $$ = lcons( makeString( ":"), $2); }
| ';' default_expr
{ $$ = lcons( makeString( ";"), $2); }
| '|' default_expr
{ $$ = lcons( makeString( "|"), $2); }
| default_expr TYPECAST Typename
{
$3->name = fmtId($3->name);
$$ = nconc( lcons( makeString( "CAST"), $1), makeList( makeString("AS"), $3, -1));
}
| CAST '(' default_expr AS Typename ')'
{
$5->name = fmtId($5->name);
$$ = nconc( lcons( makeString( "CAST"), $3), makeList( makeString("AS"), $5, -1));
}
| '(' default_expr ')'
{ $$ = lappend( lcons( makeString( "("), $2), makeString( ")")); }
| func_name '(' ')'
{
$$ = makeList( makeString($1), makeString("("), -1);
$$ = lappend( $$, makeString(")"));
}
| func_name '(' default_list ')'
{
$$ = makeList( makeString($1), makeString("("), -1);
$$ = nconc( $$, $3);
$$ = lappend( $$, makeString(")"));
}
| default_expr Op default_expr
{
if (!strcmp("<=", $2) || !strcmp(">=", $2))
1998-01-09 21:06:08 +01:00
elog(ERROR,"boolean expressions not supported in DEFAULT");
$$ = nconc( $1, lcons( makeString( $2), $3));
}
| Op default_expr
{ $$ = lcons( makeString( $1), $2); }
| default_expr Op
{ $$ = lappend( $1, makeString( $2)); }
/* XXX - thomas 1997-10-07 v6.2 function-specific code to be changed */
| CURRENT_DATE
{ $$ = lcons( makeString( "date( 'current'::datetime + '0 sec')"), NIL); }
| CURRENT_TIME
{ $$ = lcons( makeString( "'now'::time"), NIL); }
| CURRENT_TIME '(' Iconst ')'
{
if ($3 != 0)
elog(NOTICE,"CURRENT_TIME(%d) precision not implemented; zero used instead",$3);
$$ = lcons( makeString( "'now'::time"), NIL);
}
| CURRENT_TIMESTAMP
{ $$ = lcons( makeString( "now()"), NIL); }
| CURRENT_TIMESTAMP '(' Iconst ')'
{
if ($3 != 0)
elog(NOTICE,"CURRENT_TIMESTAMP(%d) precision not implemented; zero used instead",$3);
$$ = lcons( makeString( "now()"), NIL);
}
| CURRENT_USER
{ $$ = lcons( makeString( "CURRENT_USER"), NIL); }
1997-09-08 05:20:18 +02:00
;
/* ConstraintElem specifies constraint syntax which is not embedded into
* a column definition. ColConstraintElem specifies the embedded form.
* - thomas 1997-12-03
*/
TableConstraint: CONSTRAINT name ConstraintElem
1997-09-08 05:20:18 +02:00
{
Constraint *n = (Constraint *)$3;
n->name = fmtId($2);
1997-09-08 05:20:18 +02:00
$$ = $3;
}
| ConstraintElem
{ $$ = $1; }
1997-09-08 05:20:18 +02:00
;
ConstraintElem: CHECK '(' constraint_expr ')'
1997-09-08 05:20:18 +02:00
{
Constraint *n = makeNode(Constraint);
n->contype = CONSTR_CHECK;
n->name = NULL;
n->def = FlattenStringList($3);
$$ = (Node *)n;
1997-09-08 05:20:18 +02:00
}
| UNIQUE '(' columnList ')'
{
Constraint *n = makeNode(Constraint);
n->contype = CONSTR_UNIQUE;
n->name = NULL;
n->def = NULL;
n->keys = $3;
$$ = (Node *)n;
}
| PRIMARY KEY '(' columnList ')'
{
Constraint *n = makeNode(Constraint);
n->contype = CONSTR_PRIMARY;
n->name = NULL;
n->def = NULL;
n->keys = $4;
$$ = (Node *)n;
}
| FOREIGN KEY '(' columnList ')' REFERENCES ColId opt_column_list key_match key_actions
1998-01-09 21:06:08 +01:00
{ elog(NOTICE,"CREATE TABLE/FOREIGN KEY clause ignored; not yet implemented"); }
1997-09-08 05:20:18 +02:00
;
constraint_list: constraint_list ',' constraint_expr
{
$$ = lappend($1,makeString(","));
$$ = nconc($$, $3);
}
| constraint_expr
{
$$ = $1;
}
;
constraint_expr: AexprConst
{ $$ = makeConstantList((A_Const *) $1); }
| NULL_P
{ $$ = lcons( makeString("NULL"), NIL); }
| ColId
{
$$ = lcons( makeString(fmtId($1)), NIL);
}
| '-' constraint_expr %prec UMINUS
{ $$ = lcons( makeString( "-"), $2); }
| constraint_expr '+' constraint_expr
{ $$ = nconc( $1, lcons( makeString( "+"), $3)); }
| constraint_expr '-' constraint_expr
{ $$ = nconc( $1, lcons( makeString( "-"), $3)); }
| constraint_expr '/' constraint_expr
{ $$ = nconc( $1, lcons( makeString( "/"), $3)); }
| constraint_expr '*' constraint_expr
{ $$ = nconc( $1, lcons( makeString( "*"), $3)); }
| constraint_expr '=' constraint_expr
{ $$ = nconc( $1, lcons( makeString( "="), $3)); }
| constraint_expr '<' constraint_expr
{ $$ = nconc( $1, lcons( makeString( "<"), $3)); }
| constraint_expr '>' constraint_expr
{ $$ = nconc( $1, lcons( makeString( ">"), $3)); }
| ':' constraint_expr
{ $$ = lcons( makeString( ":"), $2); }
| ';' constraint_expr
{ $$ = lcons( makeString( ";"), $2); }
| '|' constraint_expr
{ $$ = lcons( makeString( "|"), $2); }
| constraint_expr TYPECAST Typename
{
$3->name = fmtId($3->name);
$$ = nconc( lcons( makeString( "CAST"), $1), makeList( makeString("AS"), $3, -1));
}
| CAST '(' constraint_expr AS Typename ')'
{
$5->name = fmtId($5->name);
$$ = nconc( lcons( makeString( "CAST"), $3), makeList( makeString("AS"), $5, -1));
}
| '(' constraint_expr ')'
{ $$ = lappend( lcons( makeString( "("), $2), makeString( ")")); }
| func_name '(' ')'
{
$$ = makeList( makeString($1), makeString("("), -1);
$$ = lappend( $$, makeString(")"));
}
| func_name '(' constraint_list ')'
{
$$ = makeList( makeString($1), makeString("("), -1);
$$ = nconc( $$, $3);
$$ = lappend( $$, makeString(")"));
}
| constraint_expr Op constraint_expr
{ $$ = nconc( $1, lcons( makeString( $2), $3)); }
| constraint_expr LIKE constraint_expr
{ $$ = nconc( $1, lcons( makeString( "like"), $3)); }
| constraint_expr AND constraint_expr
{ $$ = nconc( $1, lcons( makeString( "AND"), $3)); }
| constraint_expr OR constraint_expr
{ $$ = nconc( $1, lcons( makeString( "OR"), $3)); }
| NOT constraint_expr
{ $$ = lcons( makeString( "NOT"), $2); }
| Op constraint_expr
{ $$ = lcons( makeString( $1), $2); }
| constraint_expr Op
{ $$ = lappend( $1, makeString( $2)); }
| constraint_expr ISNULL
{ $$ = lappend( $1, makeString( "IS NULL")); }
| constraint_expr IS NULL_P
{ $$ = lappend( $1, makeString( "IS NULL")); }
| constraint_expr NOTNULL
{ $$ = lappend( $1, makeString( "IS NOT NULL")); }
| constraint_expr IS NOT NULL_P
{ $$ = lappend( $1, makeString( "IS NOT NULL")); }
| constraint_expr IS TRUE_P
{ $$ = lappend( $1, makeString( "IS TRUE")); }
| constraint_expr IS FALSE_P
{ $$ = lappend( $1, makeString( "IS FALSE")); }
| constraint_expr IS NOT TRUE_P
{ $$ = lappend( $1, makeString( "IS NOT TRUE")); }
| constraint_expr IS NOT FALSE_P
{ $$ = lappend( $1, makeString( "IS NOT FALSE")); }
;
key_match: MATCH FULL { $$ = NULL; }
| MATCH PARTIAL { $$ = NULL; }
| /*EMPTY*/ { $$ = NULL; }
;
key_actions: key_action key_action { $$ = NIL; }
| key_action { $$ = NIL; }
| /*EMPTY*/ { $$ = NIL; }
;
key_action: ON DELETE key_reference { $$ = NIL; }
| ON UPDATE key_reference { $$ = NIL; }
;
key_reference: NO ACTION { $$ = NULL; }
| CASCADE { $$ = NULL; }
| SET DEFAULT { $$ = NULL; }
| SET NULL_P { $$ = NULL; }
;
OptInherit: INHERITS '(' relation_name_list ')' { $$ = $3; }
| /*EMPTY*/ { $$ = NIL; }
;
/*
* "ARCHIVE" keyword was removed in 6.3, but we keep it for now
* so people can upgrade with old pg_dump scripts. - momjian 1997-11-20(?)
*/
OptArchiveType: ARCHIVE '=' NONE { }
| /*EMPTY*/ { }
;
CreateAsStmt: CREATE TABLE relation_name OptCreateAs AS SubSelect
{
1998-01-09 21:06:08 +01:00
SelectStmt *n = (SelectStmt *)$6;
if ($4 != NIL)
mapTargetColumns($4, n->targetList);
n->into = $3;
$$ = (Node *)n;
}
;
OptCreateAs: '(' CreateAsList ')' { $$ = $2; }
| /*EMPTY*/ { $$ = NULL; }
;
CreateAsList: CreateAsList ',' CreateAsElement { $$ = lappend($1, $3); }
| CreateAsElement { $$ = lcons($1, NIL); }
;
CreateAsElement: ColId
{
ColumnDef *n = makeNode(ColumnDef);
n->colname = $1;
n->typename = NULL;
n->defval = NULL;
n->is_not_null = FALSE;
n->constraints = NULL;
$$ = (Node *)n;
}
;
/*****************************************************************************
*
1997-09-08 05:20:18 +02:00
* QUERY :
* CREATE SEQUENCE seqname
*
*****************************************************************************/
1997-09-08 05:20:18 +02:00
CreateSeqStmt: CREATE SEQUENCE relation_name OptSeqList
{
CreateSeqStmt *n = makeNode(CreateSeqStmt);
n->seqname = $3;
n->options = $4;
$$ = (Node *)n;
}
;
OptSeqList:
1997-09-08 05:20:18 +02:00
OptSeqList OptSeqElem
{ $$ = lappend($1, $2); }
| { $$ = NIL; }
;
OptSeqElem: IDENT NumConst
{
$$ = makeNode(DefElem);
$$->defname = $1;
$$->arg = (Node *)$2;
}
| IDENT
{
$$ = makeNode(DefElem);
$$->defname = $1;
$$->arg = (Node *)NULL;
}
;
/*****************************************************************************
*
* QUERIES :
* CREATE PROCEDURAL LANGUAGE ...
* DROP PROCEDURAL LANGUAGE ...
*
*****************************************************************************/
CreatePLangStmt: CREATE PLangTrusted PROCEDURAL LANGUAGE Sconst
HANDLER def_name LANCOMPILER Sconst
{
CreatePLangStmt *n = makeNode(CreatePLangStmt);
n->plname = $5;
n->plhandler = $7;
n->plcompiler = $9;
n->pltrusted = $2;
$$ = (Node *)n;
}
;
PLangTrusted: TRUSTED { $$ = TRUE; }
| { $$ = FALSE; }
DropPLangStmt: DROP PROCEDURAL LANGUAGE Sconst
{
DropPLangStmt *n = makeNode(DropPLangStmt);
n->plname = $4;
$$ = (Node *)n;
}
;
1997-09-04 15:24:26 +02:00
/*****************************************************************************
*
1997-09-08 05:20:18 +02:00
* QUERIES :
* CREATE TRIGGER ...
* DROP TRIGGER ...
1997-09-04 15:24:26 +02:00
*
*****************************************************************************/
CreateTrigStmt: CREATE TRIGGER name TriggerActionTime TriggerEvents ON
1997-09-08 05:20:18 +02:00
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; }
1997-09-08 05:20:18 +02:00
;
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;
}
1997-09-08 05:20:18 +02:00
;
TriggerOneEvent: INSERT { $$ = 'i'; }
| DELETE { $$ = 'd'; }
| UPDATE { $$ = 'u'; }
1997-09-08 05:20:18 +02:00
;
TriggerForSpec: FOR TriggerForOpt TriggerForType
1997-09-08 05:20:18 +02:00
{
$$ = $3;
1997-09-08 05:20:18 +02:00
}
;
1997-09-04 15:24:26 +02:00
TriggerForOpt: EACH { $$ = TRUE; }
| /*EMPTY*/ { $$ = FALSE; }
;
TriggerForType: ROW { $$ = TRUE; }
| STATEMENT { $$ = FALSE; }
;
TriggerFuncArgs: TriggerFuncArg
1997-09-08 05:20:18 +02:00
{ $$ = lcons($1, NIL); }
| TriggerFuncArgs ',' TriggerFuncArg
1997-09-08 05:20:18 +02:00
{ $$ = lappend($1, $3); }
| /*EMPTY*/
{ $$ = NIL; }
1997-09-08 05:20:18 +02:00
;
TriggerFuncArg: ICONST
{
char *s = (char *) palloc (256);
sprintf (s, "%d", $1);
$$ = s;
}
| FCONST
{
char *s = (char *) palloc (256);
sprintf (s, "%g", $1);
$$ = s;
}
| Sconst { $$ = $1; }
| IDENT { $$ = $1; }
1997-09-08 05:20:18 +02:00
;
1997-09-04 15:24:26 +02:00
DropTrigStmt: DROP TRIGGER name ON relation_name
1997-09-08 05:20:18 +02:00
{
DropTrigStmt *n = makeNode(DropTrigStmt);
n->trigname = $3;
n->relname = $5;
$$ = (Node *) n;
}
;
1997-09-04 15:24:26 +02:00
/*****************************************************************************
*
1997-09-08 05:20:18 +02:00
* QUERY :
* define (type,operator,aggregate)
*
*****************************************************************************/
DefineStmt: CREATE def_type def_rest
1997-09-08 05:20:18 +02:00
{
$3->defType = $2;
$$ = (Node *)$3;
}
;
def_rest: def_name definition
1997-09-08 05:20:18 +02:00
{
$$ = makeNode(DefineStmt);
$$->defname = $1;
$$->definition = $2;
}
;
def_type: OPERATOR { $$ = OPERATOR; }
| TYPE_P { $$ = TYPE_P; }
| AGGREGATE { $$ = AGGREGATE; }
1997-09-08 05:20:18 +02:00
;
def_name: PROCEDURE { $$ = "procedure"; }
| JOIN { $$ = "join"; }
| ColId { $$ = $1; }
| MathOp { $$ = $1; }
| Op { $$ = $1; }
1997-09-08 05:20:18 +02:00
;
definition: '(' def_list ')' { $$ = $2; }
1997-09-08 05:20:18 +02:00
;
def_list: def_elem { $$ = lcons($1, NIL); }
| def_list ',' def_elem { $$ = lappend($1, $3); }
1997-09-08 05:20:18 +02:00
;
def_elem: def_name '=' def_arg
1997-09-08 05:20:18 +02:00
{
$$ = makeNode(DefElem);
$$->defname = $1;
$$->arg = (Node *)$3;
}
| def_name
1997-09-08 05:20:18 +02:00
{
$$ = makeNode(DefElem);
$$->defname = $1;
$$->arg = (Node *)NULL;
}
| DEFAULT '=' def_arg
1997-09-08 05:20:18 +02:00
{
$$ = makeNode(DefElem);
$$->defname = "default";
1997-09-08 05:20:18 +02:00
$$->arg = (Node *)$3;
}
;
def_arg: ColId { $$ = (Node *)makeString($1); }
| all_Op { $$ = (Node *)makeString($1); }
| NumConst { $$ = (Node *)$1; /* already a Value */ }
| Sconst { $$ = (Node *)makeString($1); }
| SETOF ColId
{
TypeName *n = makeNode(TypeName);
n->name = $2;
n->setof = TRUE;
n->arrayBounds = NULL;
n->typmod = -1;
$$ = (Node *)n;
}
1997-09-08 05:20:18 +02:00
;
/*****************************************************************************
*
1997-09-08 05:20:18 +02:00
* QUERY:
* destroy <relname1> [, <relname2> .. <relnameN> ]
*
*****************************************************************************/
DestroyStmt: DROP TABLE relation_name_list
1997-09-08 05:20:18 +02:00
{
DestroyStmt *n = makeNode(DestroyStmt);
n->relNames = $3;
n->sequence = FALSE;
1997-09-08 05:20:18 +02:00
$$ = (Node *)n;
}
| DROP SEQUENCE relation_name_list
1997-09-08 05:20:18 +02:00
{
DestroyStmt *n = makeNode(DestroyStmt);
n->relNames = $3;
n->sequence = TRUE;
1997-09-08 05:20:18 +02:00
$$ = (Node *)n;
}
;
/*****************************************************************************
*
1997-09-08 05:20:18 +02:00
* QUERY:
1997-09-29 07:59:16 +02:00
* fetch/move [forward | backward] [number | all ] [ in <portalname> ]
*
*****************************************************************************/
1997-09-08 05:20:18 +02:00
FetchStmt: FETCH opt_direction fetch_how_many opt_portal_name
{
FetchStmt *n = makeNode(FetchStmt);
n->direction = $2;
n->howMany = $3;
n->portalname = $4;
1997-09-29 07:59:16 +02:00
n->ismove = false;
$$ = (Node *)n;
}
| MOVE opt_direction fetch_how_many opt_portal_name
{
FetchStmt *n = makeNode(FetchStmt);
n->direction = $2;
n->howMany = $3;
n->portalname = $4;
n->ismove = TRUE;
1997-09-08 05:20:18 +02:00
$$ = (Node *)n;
}
;
opt_direction: FORWARD { $$ = FORWARD; }
| BACKWARD { $$ = BACKWARD; }
| /*EMPTY*/ { $$ = FORWARD; /* default */ }
;
fetch_how_many: Iconst
1997-09-08 05:20:18 +02:00
{ $$ = $1;
1998-01-09 21:06:08 +01:00
if ($1 <= 0) elog(ERROR,"Please specify nonnegative count for fetch"); }
| ALL { $$ = 0; /* 0 means fetch all tuples*/ }
| /*EMPTY*/ { $$ = 1; /*default*/ }
1997-09-08 05:20:18 +02:00
;
opt_portal_name: IN name { $$ = $2; }
1997-09-29 07:59:16 +02:00
| /*EMPTY*/ { $$ = NULL; }
;
/*****************************************************************************
*
1997-09-08 05:20:18 +02:00
* QUERY:
* GRANT [privileges] ON [relation_name_list] TO [GROUP] grantee
*
*****************************************************************************/
GrantStmt: GRANT privileges ON relation_name_list TO grantee opt_with_grant
1997-09-08 05:20:18 +02:00
{
$$ = (Node*)makeAclStmt($2,$4,$6,'+');
}
;
privileges: ALL PRIVILEGES
1997-09-08 05:20:18 +02:00
{
$$ = aclmakepriv("rwaR",0);
}
| ALL
{
$$ = aclmakepriv("rwaR",0);
}
| operation_commalist
{
$$ = $1;
}
;
operation_commalist: operation
1997-09-08 05:20:18 +02:00
{
$$ = aclmakepriv("",$1);
}
| operation_commalist ',' operation
{
$$ = aclmakepriv($1,$3);
}
;
operation: SELECT
1997-09-08 05:20:18 +02:00
{
$$ = ACL_MODE_RD_CHR;
}
| INSERT
{
$$ = ACL_MODE_AP_CHR;
}
| UPDATE
{
$$ = ACL_MODE_WR_CHR;
}
| DELETE
{
$$ = ACL_MODE_WR_CHR;
}
| RULE
1997-09-08 05:20:18 +02:00
{
$$ = ACL_MODE_RU_CHR;
}
;
grantee: PUBLIC
{
$$ = aclmakeuser("A","");
}
| GROUP ColId
1997-09-08 05:20:18 +02:00
{
$$ = aclmakeuser("G",$2);
}
| ColId
1997-09-08 05:20:18 +02:00
{
$$ = aclmakeuser("U",$1);
}
;
opt_with_grant: WITH GRANT OPTION
1997-09-08 05:20:18 +02:00
{
yyerror("WITH GRANT OPTION is not supported. Only relation owners can set privileges");
}
| /*EMPTY*/
1997-09-08 05:20:18 +02:00
;
/*****************************************************************************
*
1997-09-08 05:20:18 +02:00
* QUERY:
* REVOKE [privileges] ON [relation_name] FROM [user]
*
*****************************************************************************/
RevokeStmt: REVOKE privileges ON relation_name_list FROM grantee
1997-09-08 05:20:18 +02:00
{
$$ = (Node*)makeAclStmt($2,$4,$6,'-');
}
;
/*****************************************************************************
*
1997-09-08 05:20:18 +02:00
* QUERY:
1997-11-21 19:12:58 +01:00
* create index <indexname> on <relname>
1997-09-08 05:20:18 +02:00
* using <access> "(" (<col> with <op>)+ ")" [with
* <target_list>]
*
1997-09-08 05:20:18 +02:00
* [where <qual>] is not supported anymore
*****************************************************************************/
1997-09-08 05:20:18 +02:00
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;
}
;
index_opt_unique: UNIQUE { $$ = TRUE; }
| /*EMPTY*/ { $$ = FALSE; }
1997-09-08 05:20:18 +02:00
;
access_method_clause: USING access_method { $$ = $2; }
| /*EMPTY*/ { $$ = "btree"; }
1997-09-08 05:20:18 +02:00
;
index_params: index_list { $$ = $1; }
| func_index { $$ = lcons($1,NIL); }
;
index_list: index_list ',' index_elem { $$ = lappend($1, $3); }
| index_elem { $$ = lcons($1, NIL); }
;
func_index: func_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; }
| FOR Typename { $$ = $2; }
| /*EMPTY*/ { $$ = NULL; }
;
/* opt_class "WITH class" conflicts with preceeding opt_type
* for Typename of "TIMESTAMP WITH TIME ZONE"
* So, remove "WITH class" from the syntax. OK??
* - thomas 1997-10-12
* | WITH class { $$ = $2; }
*/
opt_class: class { $$ = $1; }
| USING class { $$ = $2; }
| /*EMPTY*/ { $$ = NULL; }
;
/*****************************************************************************
*
1997-09-08 05:20:18 +02:00
* QUERY:
* extend index <indexname> [where <qual>]
*
*****************************************************************************/
ExtendStmt: EXTEND INDEX index_name where_clause
1997-09-08 05:20:18 +02:00
{
ExtendStmt *n = makeNode(ExtendStmt);
n->idxname = $3;
n->whereClause = $4;
$$ = (Node *)n;
}
;
/*****************************************************************************
*
1997-09-08 05:20:18 +02:00
* QUERY:
* execute recipe <recipeName>
*
*****************************************************************************/
RecipeStmt: EXECUTE RECIPE recipe_name
1997-09-08 05:20:18 +02:00
{
RecipeStmt *n;
if (!IsTransactionBlock())
1998-01-09 21:06:08 +01:00
elog(ERROR,"EXECUTE RECIPE may only be used in begin/end transaction blocks");
1997-09-08 05:20:18 +02:00
n = makeNode(RecipeStmt);
n->recipeName = $3;
$$ = (Node *)n;
}
;
/*****************************************************************************
*
1997-09-08 05:20:18 +02:00
* 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 func_name func_args
RETURNS func_return opt_with AS Sconst LANGUAGE Sconst
1997-09-08 05:20:18 +02:00
{
ProcedureStmt *n = makeNode(ProcedureStmt);
n->funcname = $3;
n->defArgs = $4;
n->returnType = $6;
1997-09-08 05:20:18 +02:00
n->withClause = $7;
n->as = $9;
n->language = $11;
$$ = (Node *)n;
};
opt_with: WITH definition { $$ = $2; }
| /*EMPTY*/ { $$ = NIL; }
1997-09-08 05:20:18 +02:00
;
func_args: '(' func_args_list ')' { $$ = $2; }
| '(' ')' { $$ = NIL; }
1997-09-08 05:20:18 +02:00
;
func_args_list: TypeId
{ $$ = lcons(makeString($1),NIL); }
| func_args_list ',' TypeId
{ $$ = lappend($1,makeString($3)); }
;
func_return: set_opt TypeId
{
TypeName *n = makeNode(TypeName);
n->name = $2;
n->setof = $1;
n->arrayBounds = NULL;
$$ = (Node *)n;
}
;
set_opt: SETOF { $$ = TRUE; }
| /*EMPTY*/ { $$ = FALSE; }
;
/*****************************************************************************
*
1997-09-08 05:20:18 +02:00
* QUERY:
*
1997-09-08 05:20:18 +02:00
* 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
1997-09-08 05:20:18 +02:00
{
RemoveStmt *n = makeNode(RemoveStmt);
n->removeType = $2;
n->name = $3;
$$ = (Node *)n;
}
;
remove_type: TYPE_P { $$ = TYPE_P; }
| INDEX { $$ = INDEX; }
| RULE { $$ = RULE; }
| VIEW { $$ = VIEW; }
1997-09-08 05:20:18 +02:00
;
RemoveAggrStmt: DROP AGGREGATE name aggr_argtype
1997-09-08 05:20:18 +02:00
{
RemoveAggrStmt *n = makeNode(RemoveAggrStmt);
n->aggname = $3;
n->aggtype = $4;
$$ = (Node *)n;
}
;
aggr_argtype: name { $$ = $1; }
| '*' { $$ = NULL; }
1997-09-08 05:20:18 +02:00
;
RemoveFuncStmt: DROP FUNCTION func_name func_args
1997-09-08 05:20:18 +02:00
{
RemoveFuncStmt *n = makeNode(RemoveFuncStmt);
n->funcname = $3;
n->args = $4;
1997-09-08 05:20:18 +02:00
$$ = (Node *)n;
}
;
RemoveOperStmt: DROP OPERATOR all_Op '(' oper_argtypes ')'
1997-09-08 05:20:18 +02:00
{
RemoveOperStmt *n = makeNode(RemoveOperStmt);
n->opname = $3;
n->args = $5;
$$ = (Node *)n;
}
;
all_Op: Op | MathOp;
MathOp: '+' { $$ = "+"; }
| '-' { $$ = "-"; }
| '*' { $$ = "*"; }
| '/' { $$ = "/"; }
| '<' { $$ = "<"; }
| '>' { $$ = ">"; }
| '=' { $$ = "="; }
1997-09-08 05:20:18 +02:00
;
oper_argtypes: name
{
1998-01-09 21:06:08 +01:00
elog(ERROR,"parser: argument type missing (use NONE for unary operators)");
1997-09-08 05:20:18 +02:00
}
| 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); }
;
/*****************************************************************************
*
1997-09-08 05:20:18 +02:00
* QUERY:
* rename <attrname1> in <relname> [*] to <attrname2>
* rename <relname1> to <relname2>
*
*****************************************************************************/
RenameStmt: ALTER TABLE relation_name opt_inh_star
1997-09-08 05:20:18 +02:00
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; }
1997-09-08 05:20:18 +02:00
;
opt_column: COLUMN { $$ = COLUMN; }
| /*EMPTY*/ { $$ = 0; }
;
/*****************************************************************************
*
1997-09-08 05:20:18 +02:00
* QUERY: Define Rewrite Rule , Define Tuple Rule
* Define Rule <old rules >
*
1997-09-08 05:20:18 +02:00
* only rewrite rule is supported -- ay 9/94
*
*****************************************************************************/
RuleStmt: CREATE RULE name AS
1997-09-08 05:20:18 +02:00
{ 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
1997-09-08 05:20:18 +02:00
{ $$ = $1; }
| OptimizableStmt
1997-09-08 05:20:18 +02:00
{ $$ = lcons($1, NIL); }
;
OptStmtMulti: OptStmtMulti OptimizableStmt ';'
1997-09-08 05:20:18 +02:00
{ $$ = lappend($1, $2); }
| OptStmtMulti OptimizableStmt
1997-09-08 05:20:18 +02:00
{ $$ = lappend($1, $2); }
| OptimizableStmt ';'
1997-09-08 05:20:18 +02:00
{ $$ = lcons($1, NIL); }
;
event_object: relation_name '.' attr_name
1997-09-08 05:20:18 +02:00
{
$$ = 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 */
1997-09-08 05:20:18 +02:00
event: SELECT { $$ = CMD_SELECT; }
| UPDATE { $$ = CMD_UPDATE; }
| DELETE { $$ = CMD_DELETE; }
| INSERT { $$ = CMD_INSERT; }
;
1997-09-08 05:20:18 +02:00
opt_instead: INSTEAD { $$ = TRUE; }
| /*EMPTY*/ { $$ = FALSE; }
1997-09-08 05:20:18 +02:00
;
/*****************************************************************************
*
1997-09-08 05:20:18 +02:00
* QUERY:
* NOTIFY <relation_name> can appear both in rule bodies and
* as a query-level command
*
*****************************************************************************/
NotifyStmt: NOTIFY relation_name
1997-09-08 05:20:18 +02:00
{
NotifyStmt *n = makeNode(NotifyStmt);
n->relname = $2;
$$ = (Node *)n;
}
;
ListenStmt: LISTEN relation_name
1997-09-08 05:20:18 +02:00
{
ListenStmt *n = makeNode(ListenStmt);
n->relname = $2;
$$ = (Node *)n;
}
;
/*****************************************************************************
*
1997-09-08 05:20:18 +02:00
* Transactions:
*
1997-09-08 05:20:18 +02:00
* abort transaction
* (ABORT)
* begin transaction
* (BEGIN)
* end transaction
* (END)
*
*****************************************************************************/
TransactionStmt: ABORT_TRANS TRANSACTION
1997-09-08 05:20:18 +02:00
{
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;
}
;
/*****************************************************************************
*
1997-09-08 05:20:18 +02:00
* QUERY:
* define view <viewname> '('target-list ')' [where <quals> ]
*
*****************************************************************************/
1998-01-09 21:06:08 +01:00
ViewStmt: CREATE VIEW name AS SelectStmt
1997-09-08 05:20:18 +02:00
{
ViewStmt *n = makeNode(ViewStmt);
n->viewname = $3;
n->query = (Query *)$5;
1998-01-11 21:02:32 +01:00
if (((SelectStmt *)n->query)->sortClause != NULL)
elog(ERROR,"Order by and Distinct on views is not implemented.");
1998-01-09 22:26:12 +01:00
if (((SelectStmt *)n->query)->unionClause != NULL)
1998-01-09 21:06:08 +01:00
elog(ERROR,"Views on unions not implemented.");
1997-09-08 05:20:18 +02:00
$$ = (Node *)n;
}
;
/*****************************************************************************
*
1997-09-08 05:20:18 +02:00
* QUERY:
* load "filename"
*
*****************************************************************************/
LoadStmt: LOAD file_name
1997-09-08 05:20:18 +02:00
{
LoadStmt *n = makeNode(LoadStmt);
n->filename = $2;
$$ = (Node *)n;
}
;
/*****************************************************************************
*
1997-09-08 05:20:18 +02:00
* QUERY:
* createdb dbname
*
*****************************************************************************/
CreatedbStmt: CREATE DATABASE database_name opt_database
1997-09-08 05:20:18 +02:00
{
CreatedbStmt *n = makeNode(CreatedbStmt);
n->dbname = $3;
n->dbpath = $4;
1997-09-08 05:20:18 +02:00
$$ = (Node *)n;
}
;
opt_database: WITH LOCATION '=' location { $$ = $4; }
| /*EMPTY*/ { $$ = NULL; }
;
location: Sconst { $$ = $1; }
| DEFAULT { $$ = NULL; }
| /*EMPTY*/ { $$ = NULL; }
;
/*****************************************************************************
*
1997-09-08 05:20:18 +02:00
* QUERY:
* destroydb dbname
*
*****************************************************************************/
1997-09-08 05:20:18 +02:00
DestroydbStmt: DROP DATABASE database_name
{
DestroydbStmt *n = makeNode(DestroydbStmt);
n->dbname = $3;
$$ = (Node *)n;
}
;
/*****************************************************************************
*
1997-09-08 05:20:18 +02:00
* QUERY:
* cluster <index_name> on <relation_name>
*
*****************************************************************************/
ClusterStmt: CLUSTER index_name ON relation_name
1997-09-08 05:20:18 +02:00
{
ClusterStmt *n = makeNode(ClusterStmt);
n->relname = $4;
n->indexname = $2;
$$ = (Node*)n;
}
;
/*****************************************************************************
*
1997-09-08 05:20:18 +02:00
* QUERY:
* vacuum
*
*****************************************************************************/
VacuumStmt: VACUUM opt_verbose opt_analyze
1997-09-08 05:20:18 +02:00
{
VacuumStmt *n = makeNode(VacuumStmt);
n->verbose = $2;
n->analyze = $3;
n->vacrel = NULL;
n->va_spec = NIL;
$$ = (Node *)n;
}
1997-12-02 17:09:15 +01:00
| VACUUM opt_verbose opt_analyze relation_name opt_va_list
1997-09-08 05:20:18 +02:00
{
VacuumStmt *n = makeNode(VacuumStmt);
n->verbose = $2;
1997-12-02 17:09:15 +01:00
n->analyze = $3;
n->vacrel = $4;
1997-09-08 05:20:18 +02:00
n->va_spec = $5;
if ( $5 != NIL && !$4 )
1998-01-09 21:06:08 +01:00
elog(ERROR,"parser: syntax error at or near \"(\"");
1997-09-08 05:20:18 +02:00
$$ = (Node *)n;
}
;
opt_verbose: VERBOSE { $$ = TRUE; }
| /*EMPTY*/ { $$ = FALSE; }
1997-09-08 05:20:18 +02:00
;
opt_analyze: ANALYZE { $$ = TRUE; }
| /*EMPTY*/ { $$ = FALSE; }
1997-09-08 05:20:18 +02:00
;
opt_va_list: '(' va_list ')'
1997-09-08 05:20:18 +02:00
{ $$ = $2; }
| /* EMPTY */
{ $$ = NIL; }
;
va_list: name
1997-09-08 05:20:18 +02:00
{ $$=lcons($1,NIL); }
| va_list ',' name
{ $$=lappend($1,$3); }
;
/*****************************************************************************
*
1997-09-08 05:20:18 +02:00
* QUERY:
* EXPLAIN query
*
*****************************************************************************/
ExplainStmt: EXPLAIN opt_verbose OptimizableStmt
1997-09-08 05:20:18 +02:00
{
ExplainStmt *n = makeNode(ExplainStmt);
n->verbose = $2;
n->query = (Query*)$3;
$$ = (Node *)n;
}
;
/*****************************************************************************
1997-09-08 05:20:18 +02:00
* *
* 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 *
* *
*****************************************************************************/
1998-01-09 21:06:08 +01:00
OptimizableStmt: SelectStmt
1997-09-08 05:20:18 +02:00
| CursorStmt
1998-01-09 21:06:08 +01:00
| UpdateStmt
| InsertStmt
1997-09-08 05:20:18 +02:00
| NotifyStmt
| DeleteStmt /* by default all are $$=$1 */
;
/*****************************************************************************
*
1997-09-08 05:20:18 +02:00
* QUERY:
* INSERT STATEMENTS
*
*****************************************************************************/
1998-01-09 21:06:08 +01:00
InsertStmt: INSERT INTO relation_name opt_column_list insert_rest
1997-09-08 05:20:18 +02:00
{
$5->relname = $3;
$5->cols = $4;
$$ = (Node *)$5;
}
;
insert_rest: VALUES '(' res_target_list2 ')'
1997-09-08 05:20:18 +02:00
{
1998-01-09 21:06:08 +01:00
$$ = makeNode(InsertStmt);
1998-01-11 04:41:57 +01:00
$$->unique = NULL;
1997-09-08 05:20:18 +02:00
$$->targetList = $3;
$$->fromClause = NIL;
$$->whereClause = NULL;
1998-01-11 04:41:57 +01:00
$$->groupClause = NIL;
$$->havingClause = NULL;
1998-01-11 04:41:57 +01:00
$$->unionClause = NIL;
1997-09-08 05:20:18 +02:00
}
1998-01-11 04:41:57 +01:00
| SELECT opt_unique res_target_list2
from_clause where_clause
group_clause having_clause
union_clause
1997-09-08 05:20:18 +02:00
{
1998-01-09 21:06:08 +01:00
$$ = makeNode(InsertStmt);
1998-01-11 04:41:57 +01:00
$$->unique = $2;
$$->targetList = $3;
$$->fromClause = $4;
$$->whereClause = $5;
$$->groupClause = $6;
$$->havingClause = $7;
$$->unionClause = $8;
1997-09-08 05:20:18 +02:00
}
;
opt_column_list: '(' columnList ')' { $$ = $2; }
1997-09-08 05:20:18 +02:00
| /*EMPTY*/ { $$ = NIL; }
;
columnList:
1997-09-08 05:20:18 +02:00
columnList ',' columnElem
{ $$ = lappend($1, $3); }
| columnElem
{ $$ = lcons($1, NIL); }
;
columnElem: ColId opt_indirection
1997-09-08 05:20:18 +02:00
{
Ident *id = makeNode(Ident);
id->name = $1;
id->indirection = $2;
$$ = (Node *)id;
}
;
/*****************************************************************************
*
1997-09-08 05:20:18 +02:00
* QUERY:
* DELETE STATEMENTS
*
*****************************************************************************/
DeleteStmt: DELETE FROM relation_name
1997-09-08 05:20:18 +02:00
where_clause
{
DeleteStmt *n = makeNode(DeleteStmt);
n->relname = $3;
n->whereClause = $4;
$$ = (Node *)n;
}
;
/*
* Total hack to just lock a table inside a transaction.
* Is it worth making this a separate command, with
* its own node type and file. I don't think so. bjm 1998/1/22
*/
LockStmt: LOCK_P relation_name
{
DeleteStmt *n = makeNode(DeleteStmt);
A_Const *c = makeNode(A_Const);
c->val.type = T_String;
c->val.val.str = "f";
c->typename = makeNode(TypeName);
c->typename->name = xlateSqlType("bool");
c->typename->typmod = -1;
n->relname = $2;
n->whereClause = (Node *)c;
$$ = (Node *)n;
}
;
/*****************************************************************************
*
1997-09-08 05:20:18 +02:00
* QUERY:
1998-01-09 21:06:08 +01:00
* UpdateStmt (UPDATE)
*
*****************************************************************************/
1998-01-09 21:06:08 +01:00
UpdateStmt: UPDATE relation_name
1997-09-08 05:20:18 +02:00
SET res_target_list
from_clause
where_clause
{
1998-01-09 21:06:08 +01:00
UpdateStmt *n = makeNode(UpdateStmt);
1997-09-08 05:20:18 +02:00
n->relname = $2;
n->targetList = $4;
n->fromClause = $5;
n->whereClause = $6;
$$ = (Node *)n;
}
;
/*****************************************************************************
*
1997-09-08 05:20:18 +02:00
* QUERY:
* CURSOR STATEMENTS
*
*****************************************************************************/
CursorStmt: DECLARE name opt_binary CURSOR FOR
1998-01-10 05:30:11 +01:00
SELECT opt_unique res_target_list2
from_clause where_clause
group_clause having_clause
union_clause sort_clause
1997-09-08 05:20:18 +02:00
{
1998-01-10 05:30:11 +01:00
SelectStmt *n = makeNode(SelectStmt);
1997-09-08 05:20:18 +02:00
/* 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())
1998-01-09 21:06:08 +01:00
elog(ERROR,"Named portals may only be used in begin/end transaction blocks");
1997-09-08 05:20:18 +02:00
n->portalname = $2;
n->binary = $3;
n->unique = $7;
n->targetList = $8;
n->fromClause = $9;
n->whereClause = $10;
n->groupClause = $11;
1998-01-10 05:30:11 +01:00
n->havingClause = $12;
n->unionClause = $13;
n->sortClause = $14;
1997-09-08 05:20:18 +02:00
$$ = (Node *)n;
}
;
/*****************************************************************************
*
1997-09-08 05:20:18 +02:00
* QUERY:
* SELECT STATEMENTS
*
*****************************************************************************/
1998-01-09 21:06:08 +01:00
SelectStmt: SELECT opt_unique res_target_list2
result from_clause where_clause
group_clause having_clause
union_clause sort_clause
1997-09-08 05:20:18 +02:00
{
1998-01-09 21:06:08 +01:00
SelectStmt *n = makeNode(SelectStmt);
1997-09-08 05:20:18 +02:00
n->unique = $2;
n->targetList = $3;
n->into = $4;
n->fromClause = $5;
n->whereClause = $6;
n->groupClause = $7;
n->havingClause = $8;
n->unionClause = $9;
1997-09-08 05:20:18 +02:00
n->sortClause = $10;
$$ = (Node *)n;
}
;
union_clause: UNION opt_union select_list
{
1998-01-09 21:06:08 +01:00
SelectStmt *n = (SelectStmt *)lfirst($3);
n->unionall = $2;
$$ = $3;
}
| /*EMPTY*/
{ $$ = NIL; }
1997-09-08 05:20:18 +02:00
;
select_list: select_list UNION opt_union SubSelect
{
1998-01-09 21:06:08 +01:00
SelectStmt *n = (SelectStmt *)$4;
n->unionall = $3;
$$ = lappend($1, $4);
}
1997-09-08 05:20:18 +02:00
| SubSelect
{ $$ = lcons($1, NIL); }
;
SubSelect: SELECT opt_unique res_target_list2
from_clause where_clause
group_clause having_clause
1997-09-08 05:20:18 +02:00
{
1998-01-09 21:06:08 +01:00
SelectStmt *n = makeNode(SelectStmt);
1997-09-08 05:20:18 +02:00
n->unique = $2;
n->unionall = FALSE;
1997-09-08 05:20:18 +02:00
n->targetList = $3;
n->fromClause = $4;
n->whereClause = $5;
n->groupClause = $6;
n->havingClause = $7;
1997-09-08 05:20:18 +02:00
$$ = (Node *)n;
}
;
result: INTO TABLE relation_name
{ $$= $3; }
1997-09-08 05:20:18 +02:00
| /*EMPTY*/
{ $$ = NULL; }
1997-09-08 05:20:18 +02:00
;
opt_union: ALL { $$ = TRUE; }
| /*EMPTY*/ { $$ = FALSE; }
;
opt_unique: DISTINCT { $$ = "*"; }
| DISTINCT ON ColId { $$ = $3; }
| ALL { $$ = NULL; }
| /*EMPTY*/ { $$ = NULL; }
1997-09-08 05:20:18 +02:00
;
1997-09-08 05:20:18 +02:00
sort_clause: ORDER BY sortby_list { $$ = $3; }
| /*EMPTY*/ { $$ = NIL; }
1997-09-08 05:20:18 +02:00
;
sortby_list: sortby { $$ = lcons($1, NIL); }
| sortby_list ',' sortby { $$ = lappend($1, $3); }
1997-09-08 05:20:18 +02:00
;
sortby: ColId OptUseOp
1997-09-08 05:20:18 +02:00
{
$$ = makeNode(SortGroupBy);
$$->resno = 0;
$$->range = NULL;
$$->name = $1;
$$->useOp = $2;
}
| ColId '.' ColId OptUseOp
1997-09-08 05:20:18 +02:00
{
$$ = 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-09-08 05:20:18 +02:00
;
/*
1997-09-08 05:20:18 +02:00
* jimmy bell-style recursive queries aren't supported in the
* current system.
*
1997-09-08 05:20:18 +02:00
* ...however, recursive addattr and rename supported. make special
* cases for these.
*/
opt_inh_star: '*' { $$ = TRUE; }
| /*EMPTY*/ { $$ = FALSE; }
1997-09-08 05:20:18 +02:00
;
relation_name_list: name_list;
name_list: name
{ $$ = lcons(makeString($1),NIL); }
1997-09-08 05:20:18 +02:00
| name_list ',' name
{ $$ = lappend($1,makeString($3)); }
1997-09-08 05:20:18 +02:00
;
group_clause: GROUP BY groupby_list { $$ = $3; }
1997-09-08 05:20:18 +02:00
| /*EMPTY*/ { $$ = NIL; }
;
groupby_list: groupby { $$ = lcons($1, NIL); }
1997-09-08 05:20:18 +02:00
| groupby_list ',' groupby { $$ = lappend($1, $3); }
;
groupby: ColId
1997-09-08 05:20:18 +02:00
{
$$ = makeNode(SortGroupBy);
$$->resno = 0;
$$->range = NULL;
$$->name = $1;
$$->useOp = NULL;
}
| ColId '.' ColId
1997-09-08 05:20:18 +02:00
{
$$ = makeNode(SortGroupBy);
$$->resno = 0;
$$->range = $1;
$$->name = $3;
$$->useOp = NULL;
}
| Iconst
{
$$ = makeNode(SortGroupBy);
$$->resno = $1;
$$->range = NULL;
$$->name = NULL;
$$->useOp = NULL;
}
;
1998-01-20 06:05:08 +01:00
having_clause: HAVING a_expr
{
elog(NOTICE, "HAVING not yet supported; ignore clause");
$$ = $2;
}
1997-09-08 05:20:18 +02:00
| /*EMPTY*/ { $$ = NULL; }
;
/*****************************************************************************
*
1997-09-08 05:20:18 +02:00
* clauses common to all Optimizable Stmts:
* from_clause -
* where_clause -
*
*****************************************************************************/
from_clause: FROM '(' relation_expr join_expr JOIN relation_expr join_spec ')'
1997-09-08 05:20:18 +02:00
{
$$ = NIL;
1998-01-09 21:06:08 +01:00
elog(ERROR,"JOIN not yet implemented");
1997-09-08 05:20:18 +02:00
}
| FROM from_list { $$ = $2; }
| /*EMPTY*/ { $$ = NIL; }
;
from_list: from_list ',' from_val
{ $$ = lappend($1, $3); }
| from_val CROSS JOIN from_val
1998-01-09 21:06:08 +01:00
{ elog(ERROR,"CROSS JOIN not yet implemented"); }
| from_val
1997-09-08 05:20:18 +02:00
{ $$ = lcons($1, NIL); }
;
from_val: relation_expr AS ColLabel
1997-09-08 05:20:18 +02:00
{
$$ = makeNode(RangeVar);
$$->relExpr = $1;
$$->name = $3;
}
| relation_expr ColId
1997-09-08 05:20:18 +02:00
{
$$ = makeNode(RangeVar);
$$->relExpr = $1;
$$->name = $2;
}
| relation_expr
{
$$ = makeNode(RangeVar);
$$->relExpr = $1;
$$->name = NULL;
}
;
join_expr: NATURAL join_expr { $$ = NULL; }
| FULL join_outer
1998-01-09 21:06:08 +01:00
{ elog(ERROR,"FULL OUTER JOIN not yet implemented"); }
1997-09-08 05:20:18 +02:00
| LEFT join_outer
1998-01-09 21:06:08 +01:00
{ elog(ERROR,"LEFT OUTER JOIN not yet implemented"); }
1997-09-08 05:20:18 +02:00
| RIGHT join_outer
1998-01-09 21:06:08 +01:00
{ elog(ERROR,"RIGHT OUTER JOIN not yet implemented"); }
| OUTER_P
1998-01-09 21:06:08 +01:00
{ elog(ERROR,"OUTER JOIN not yet implemented"); }
| INNER_P
1998-01-09 21:06:08 +01:00
{ elog(ERROR,"INNER JOIN not yet implemented"); }
1997-09-08 05:20:18 +02:00
| UNION
1998-01-09 21:06:08 +01:00
{ elog(ERROR,"UNION JOIN not yet implemented"); }
| /*EMPTY*/
1998-01-09 21:06:08 +01:00
{ elog(ERROR,"INNER JOIN not yet implemented"); }
1997-09-08 05:20:18 +02:00
;
join_outer: OUTER_P { $$ = NULL; }
| /*EMPTY*/ { $$ = NULL; /* no qualifiers */ }
1997-09-08 05:20:18 +02:00
;
join_spec: ON '(' a_expr ')' { $$ = NULL; }
| USING '(' join_list ')' { $$ = NULL; }
| /*EMPTY*/ { $$ = NULL; /* no qualifiers */ }
1997-09-08 05:20:18 +02:00
;
join_list: join_using { $$ = lcons($1, NIL); }
1997-09-08 05:20:18 +02:00
| join_list ',' join_using { $$ = lappend($1, $3); }
;
join_using: ColId
1997-09-08 05:20:18 +02:00
{
$$ = makeNode(SortGroupBy);
$$->resno = 0;
$$->range = NULL;
$$->name = $1;
$$->useOp = NULL;
}
| ColId '.' ColId
1997-09-08 05:20:18 +02:00
{
$$ = 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 */ }
1997-09-08 05:20:18 +02:00
;
relation_expr: relation_name
{
/* normal relations */
$$ = makeNode(RelExpr);
$$->relname = $1;
$$->inh = FALSE;
}
| relation_name '*' %prec '='
{
/* inheritance query */
1997-09-08 05:20:18 +02:00
$$ = makeNode(RelExpr);
$$->relname = $1;
$$->inh = TRUE;
}
opt_array_bounds: '[' ']' nest_array_bounds
1997-09-08 05:20:18 +02:00
{ $$ = 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; }
;
/*****************************************************************************
*
* Type syntax
* SQL92 introduces a large amount of type-specific syntax.
* Define individual clauses to handle these cases, and use
* the generic case to handle regular type-extensible Postgres syntax.
* - thomas 1997-10-10
*
*****************************************************************************/
Typename: Array opt_array_bounds
{
$$ = $1;
$$->arrayBounds = $2;
1997-09-08 05:20:18 +02:00
/* Is this the name of a complex type? If so, implement
* it as a set.
*/
if (!strcmp(saved_relname, $$->name))
1997-09-08 05:20:18 +02:00
/* This attr is the same type as the relation
* being defined. The classic example: create
* emp(name=text,mgr=emp)
*/
$$->setof = TRUE;
else if (typeTypeRelid(typenameType($$->name)) != InvalidOid)
1997-09-08 05:20:18 +02:00
/* (Eventually add in here that the set can only
* contain one element.)
*/
$$->setof = TRUE;
else
$$->setof = FALSE;
}
| Character
| SETOF Array
1997-09-08 05:20:18 +02:00
{
$$ = $2;
1997-09-08 05:20:18 +02:00
$$->setof = TRUE;
}
;
Array: Generic
| Datetime
| Numeric
1997-09-08 05:20:18 +02:00
;
Generic: generic
1997-09-08 05:20:18 +02:00
{
$$ = makeNode(TypeName);
$$->name = xlateSqlType($1);
$$->typmod = -1;
}
;
generic: IDENT { $$ = $1; }
| TYPE_P { $$ = xlateSqlType("type"); }
;
/* SQL92 numeric data types
* Check FLOAT() precision limits assuming IEEE floating types.
* Provide rudimentary DECIMAL() and NUMERIC() implementations
* by checking parameters and making sure they match what is possible with INTEGER.
* - thomas 1997-09-18
*/
Numeric: FLOAT opt_float
{
$$ = makeNode(TypeName);
$$->name = xlateSqlType($2);
$$->typmod = -1;
1997-09-08 05:20:18 +02:00
}
| DOUBLE PRECISION
{
$$ = makeNode(TypeName);
$$->name = xlateSqlType("float");
}
| DECIMAL opt_decimal
1997-09-08 05:20:18 +02:00
{
$$ = makeNode(TypeName);
$$->name = xlateSqlType("integer");
$$->typmod = -1;
}
| NUMERIC opt_numeric
{
$$ = makeNode(TypeName);
$$->name = xlateSqlType("integer");
$$->typmod = -1;
}
;
1997-09-08 05:20:18 +02:00
numeric: FLOAT
{ $$ = xlateSqlType("float8"); }
| DOUBLE PRECISION
{ $$ = xlateSqlType("float8"); }
| DECIMAL
{ $$ = xlateSqlType("decimal"); }
| NUMERIC
{ $$ = xlateSqlType("numeric"); }
;
opt_float: '(' Iconst ')'
{
if ($2 < 1)
1998-01-09 21:06:08 +01:00
elog(ERROR,"precision for FLOAT must be at least 1");
else if ($2 < 7)
$$ = xlateSqlType("float4");
else if ($2 < 16)
$$ = xlateSqlType("float8");
else
1998-01-09 21:06:08 +01:00
elog(ERROR,"precision for FLOAT must be less than 16");
}
| /*EMPTY*/
{
$$ = xlateSqlType("float8");
}
;
opt_numeric: '(' Iconst ',' Iconst ')'
{
if ($2 != 9)
elog(ERROR,"NUMERIC precision %d must be 9",$2);
if ($4 != 0)
elog(ERROR,"NUMERIC scale %d must be zero",$4);
}
| '(' Iconst ')'
{
if ($2 != 9)
elog(ERROR,"NUMERIC precision %d must be 9",$2);
}
| /*EMPTY*/
{
$$ = NULL;
}
;
opt_decimal: '(' Iconst ',' Iconst ')'
{
if ($2 > 9)
elog(ERROR,"DECIMAL precision %d exceeds implementation limit of 9",$2);
if ($4 != 0)
elog(ERROR,"DECIMAL scale %d must be zero",$4);
$$ = NULL;
}
| '(' Iconst ')'
{
if ($2 > 9)
elog(ERROR,"DECIMAL precision %d exceeds implementation limit of 9",$2);
$$ = NULL;
}
| /*EMPTY*/
{
$$ = NULL;
}
;
/* SQL92 character data types
* The following implements CHAR() and VARCHAR().
* We do it here instead of the 'Generic' 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
*/
Character: character '(' Iconst ')'
{
$$ = makeNode(TypeName);
if (!strcasecmp($1, "char"))
$$->name = xlateSqlType("bpchar");
else if (!strcasecmp($1, "varchar"))
$$->name = xlateSqlType("varchar");
else
yyerror("parse error");
if ($3 < 1)
elog(ERROR,"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
1997-09-08 05:20:18 +02:00
*/
elog(ERROR,"length for type '%s' 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
*/
$$->typmod = VARHDRSZ + $3;
1997-09-08 05:20:18 +02:00
}
| character
{
$$ = makeNode(TypeName);
$$->name = xlateSqlType($1);
$$->typmod = -1;
}
;
character: CHARACTER opt_varying opt_charset opt_collate
{
char *type, *c;
if (($3 == NULL) || (strcasecmp($3, "sql_text") == 0)) {
if ($2) type = xlateSqlType("varchar");
else type = xlateSqlType("char");
} else {
if ($2) {
c = palloc(strlen("var") + strlen($3) + 1);
strcpy(c, "var");
strcat(c, $3);
type = xlateSqlType(c);
} else {
type = xlateSqlType($3);
}
};
if ($4 != NULL)
elog(ERROR,"COLLATE %s not yet implemented",$4);
$$ = type;
}
| CHAR opt_varying { $$ = xlateSqlType($2? "varchar": "char"); }
| VARCHAR { $$ = xlateSqlType("varchar"); }
| NATIONAL CHARACTER opt_varying { $$ = xlateSqlType($3? "varchar": "char"); }
| NCHAR opt_varying { $$ = xlateSqlType($2? "varchar": "char"); }
;
opt_varying: VARYING { $$ = TRUE; }
| /*EMPTY*/ { $$ = FALSE; }
;
opt_charset: CHARACTER SET ColId { $$ = $3; }
| /*EMPTY*/ { $$ = NULL; }
;
opt_collate: COLLATE ColId { $$ = $2; }
| /*EMPTY*/ { $$ = NULL; }
;
Datetime: datetime
{
$$ = makeNode(TypeName);
$$->name = xlateSqlType($1);
$$->typmod = -1;
}
| TIMESTAMP opt_timezone
{
$$ = makeNode(TypeName);
$$->name = xlateSqlType("timestamp");
$$->timezone = $2;
$$->typmod = -1;
}
| TIME
{
$$ = makeNode(TypeName);
$$->name = xlateSqlType("time");
$$->typmod = -1;
}
| INTERVAL opt_interval
{
$$ = makeNode(TypeName);
$$->name = xlateSqlType("interval");
$$->typmod = -1;
}
1997-09-08 05:20:18 +02:00
;
datetime: YEAR_P { $$ = "year"; }
| MONTH_P { $$ = "month"; }
| DAY_P { $$ = "day"; }
| HOUR_P { $$ = "hour"; }
| MINUTE_P { $$ = "minute"; }
| SECOND_P { $$ = "second"; }
;
opt_timezone: WITH TIME ZONE { $$ = TRUE; }
| /*EMPTY*/ { $$ = FALSE; }
;
opt_interval: datetime { $$ = lcons($1, NIL); }
| YEAR_P TO MONTH_P { $$ = NIL; }
| DAY_P TO HOUR_P { $$ = NIL; }
| DAY_P TO MINUTE_P { $$ = NIL; }
| DAY_P TO SECOND_P { $$ = NIL; }
| HOUR_P TO MINUTE_P { $$ = NIL; }
| HOUR_P TO SECOND_P { $$ = NIL; }
| /*EMPTY*/ { $$ = NIL; }
;
/*****************************************************************************
*
1997-09-08 05:20:18 +02:00
* expression grammar, still needs some cleanup
*
*****************************************************************************/
a_expr_or_null: a_expr
{ $$ = $1; }
| NULL_P
1997-09-08 05:20:18 +02:00
{
A_Const *n = makeNode(A_Const);
n->val.type = T_Null;
$$ = (Node *)n;
}
;
/* Expressions using row descriptors
* Define row_descriptor to allow yacc to break the reduce/reduce conflict
* with singleton expressions.
*/
row_expr: '(' row_descriptor ')' IN '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = $2;
n->oper = lcons("=",NIL);
n->useor = false;
n->subLinkType = ANY_SUBLINK;
n->subselect = $6;
$$ = (Node *)n;
}
| '(' row_descriptor ')' NOT IN '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = $2;
n->oper = lcons("<>",NIL);
n->useor = true;
n->subLinkType = ALL_SUBLINK;
n->subselect = $7;
$$ = (Node *)n;
}
| '(' row_descriptor ')' Op '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = $2;
n->oper = lcons($4, NIL);
if (strcmp($4,"<>") == 0)
n->useor = true;
else
n->useor = false;
n->subLinkType = EXPR_SUBLINK;
n->subselect = $6;
$$ = (Node *)n;
}
| '(' row_descriptor ')' '+' '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = $2;
n->oper = lcons("+", NIL);
n->useor = false;
n->subLinkType = EXPR_SUBLINK;
n->subselect = $6;
$$ = (Node *)n;
}
| '(' row_descriptor ')' '-' '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = $2;
n->oper = lcons("-", NIL);
n->useor = false;
n->subLinkType = EXPR_SUBLINK;
n->subselect = $6;
$$ = (Node *)n;
}
| '(' row_descriptor ')' '/' '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = $2;
n->oper = lcons("/", NIL);
n->useor = false;
n->subLinkType = EXPR_SUBLINK;
n->subselect = $6;
$$ = (Node *)n;
}
| '(' row_descriptor ')' '*' '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = $2;
n->oper = lcons("*", NIL);
n->useor = false;
n->subLinkType = EXPR_SUBLINK;
n->subselect = $6;
$$ = (Node *)n;
}
| '(' row_descriptor ')' '<' '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = $2;
n->oper = lcons("<", NIL);
n->useor = false;
n->subLinkType = EXPR_SUBLINK;
n->subselect = $6;
$$ = (Node *)n;
}
| '(' row_descriptor ')' '>' '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = $2;
n->oper = lcons(">", NIL);
n->useor = false;
n->subLinkType = EXPR_SUBLINK;
n->subselect = $6;
$$ = (Node *)n;
}
| '(' row_descriptor ')' '=' '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = $2;
n->oper = lcons("=", NIL);
n->useor = false;
n->subLinkType = EXPR_SUBLINK;
n->subselect = $6;
$$ = (Node *)n;
}
| '(' row_descriptor ')' Op ANY '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = $2;
n->oper = lcons($4,NIL);
1998-02-18 04:26:54 +01:00
if (strcmp($4,"<>") == 0)
n->useor = true;
else
n->useor = false;
n->subLinkType = ANY_SUBLINK;
n->subselect = $7;
$$ = (Node *)n;
}
| '(' row_descriptor ')' '+' ANY '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = $2;
n->oper = lcons("+",NIL);
n->useor = false;
n->subLinkType = ANY_SUBLINK;
n->subselect = $7;
$$ = (Node *)n;
}
| '(' row_descriptor ')' '-' ANY '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = $2;
n->oper = lcons("-",NIL);
n->useor = false;
n->subLinkType = ANY_SUBLINK;
n->subselect = $7;
$$ = (Node *)n;
}
| '(' row_descriptor ')' '/' ANY '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = $2;
n->oper = lcons("/",NIL);
n->useor = false;
n->subLinkType = ANY_SUBLINK;
n->subselect = $7;
$$ = (Node *)n;
}
| '(' row_descriptor ')' '*' ANY '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = $2;
n->oper = lcons("*",NIL);
n->useor = false;
n->subLinkType = ANY_SUBLINK;
n->subselect = $7;
$$ = (Node *)n;
}
| '(' row_descriptor ')' '<' ANY '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = $2;
n->oper = lcons("<",NIL);
n->useor = false;
n->subLinkType = ANY_SUBLINK;
n->subselect = $7;
$$ = (Node *)n;
}
| '(' row_descriptor ')' '>' ANY '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = $2;
n->oper = lcons(">",NIL);
n->useor = false;
n->subLinkType = ANY_SUBLINK;
n->subselect = $7;
$$ = (Node *)n;
}
| '(' row_descriptor ')' '=' ANY '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = $2;
n->oper = lcons("=",NIL);
n->useor = false;
n->subLinkType = ANY_SUBLINK;
n->subselect = $7;
$$ = (Node *)n;
}
| '(' row_descriptor ')' Op ALL '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = $2;
n->oper = lcons($4,NIL);
1998-02-18 04:26:54 +01:00
if (strcmp($4,"<>") == 0)
n->useor = true;
else
n->useor = false;
n->subLinkType = ALL_SUBLINK;
n->subselect = $7;
$$ = (Node *)n;
}
| '(' row_descriptor ')' '+' ALL '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = $2;
n->oper = lcons("+",NIL);
n->useor = false;
n->subLinkType = ALL_SUBLINK;
n->subselect = $7;
$$ = (Node *)n;
}
| '(' row_descriptor ')' '-' ALL '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = $2;
n->oper = lcons("-",NIL);
n->useor = false;
n->subLinkType = ALL_SUBLINK;
n->subselect = $7;
$$ = (Node *)n;
}
| '(' row_descriptor ')' '/' ALL '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = $2;
n->oper = lcons("/",NIL);
n->useor = false;
n->subLinkType = ALL_SUBLINK;
n->subselect = $7;
$$ = (Node *)n;
}
| '(' row_descriptor ')' '*' ALL '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = $2;
n->oper = lcons("*",NIL);
n->useor = false;
n->subLinkType = ALL_SUBLINK;
n->subselect = $7;
$$ = (Node *)n;
}
| '(' row_descriptor ')' '<' ALL '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = $2;
n->oper = lcons("<",NIL);
n->useor = false;
n->subLinkType = ALL_SUBLINK;
n->subselect = $7;
$$ = (Node *)n;
}
| '(' row_descriptor ')' '>' ALL '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = $2;
n->oper = lcons(">",NIL);
n->useor = false;
n->subLinkType = ALL_SUBLINK;
n->subselect = $7;
$$ = (Node *)n;
}
| '(' row_descriptor ')' '=' ALL '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = $2;
n->oper = lcons("=",NIL);
n->useor = false;
n->subLinkType = ALL_SUBLINK;
n->subselect = $7;
$$ = (Node *)n;
}
| '(' row_descriptor ')' Op '(' row_descriptor ')'
{
1998-01-17 06:01:34 +01:00
$$ = makeRowExpr($4, $2, $6);
}
| '(' row_descriptor ')' '+' '(' row_descriptor ')'
{
$$ = makeRowExpr("+", $2, $6);
}
| '(' row_descriptor ')' '-' '(' row_descriptor ')'
{
$$ = makeRowExpr("-", $2, $6);
}
| '(' row_descriptor ')' '/' '(' row_descriptor ')'
{
$$ = makeRowExpr("/", $2, $6);
}
| '(' row_descriptor ')' '*' '(' row_descriptor ')'
{
$$ = makeRowExpr("*", $2, $6);
}
| '(' row_descriptor ')' '<' '(' row_descriptor ')'
{
$$ = makeRowExpr("<", $2, $6);
}
| '(' row_descriptor ')' '>' '(' row_descriptor ')'
{
$$ = makeRowExpr(">", $2, $6);
}
| '(' row_descriptor ')' '=' '(' row_descriptor ')'
{
$$ = makeRowExpr("=", $2, $6);
}
;
row_descriptor: row_list ',' a_expr
{
$$ = lappend($1, $3);
}
;
row_list: row_list ',' a_expr
{
$$ = lappend($1, $3);
}
| a_expr
{
$$ = lcons($1, NIL);
}
;
/*
* This is the heart of the expression syntax.
* Note that the BETWEEN clause looks similar to a boolean expression
* and so we must define b_expr which is almost the same as a_expr
* but without the boolean expressions.
* All operations are allowed in a BETWEEN clause if surrounded by parens.
*/
a_expr: attr opt_indirection
1997-09-08 05:20:18 +02:00
{
$1->indirection = $2;
$$ = (Node *)$1;
}
| row_expr
{ $$ = $1; }
1997-09-08 05:20:18 +02:00
| AexprConst
{ $$ = $1; }
| ColId
{
/* could be a column name or a relation_name */
Ident *n = makeNode(Ident);
n->name = $1;
n->indirection = NULL;
$$ = (Node *)n;
}
1997-09-08 05:20:18 +02:00
| '-' 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); }
| a_expr TYPECAST Typename
1997-09-08 05:20:18 +02:00
{
$$ = (Node *)$1;
1997-09-08 05:20:18 +02:00
/* AexprConst can be either A_Const or ParamNo */
if (nodeTag($1) == T_A_Const) {
1997-09-08 05:20:18 +02:00
((A_Const *)$1)->typename = $3;
} else if (nodeTag($1) == T_Param) {
1997-09-08 05:20:18 +02:00
((ParamNo *)$1)->typename = $3;
/* otherwise, try to transform to a function call */
} else {
FuncCall *n = makeNode(FuncCall);
n->funcname = $3->name;
n->args = lcons($1,NIL);
$$ = (Node *)n;
}
1997-09-08 05:20:18 +02:00
}
| CAST '(' a_expr AS Typename ')'
1997-09-08 05:20:18 +02:00
{
$$ = (Node *)$3;
1997-09-08 05:20:18 +02:00
/* AexprConst can be either A_Const or ParamNo */
if (nodeTag($3) == T_A_Const) {
((A_Const *)$3)->typename = $5;
} else if (nodeTag($5) == T_Param) {
((ParamNo *)$3)->typename = $5;
/* otherwise, try to transform to a function call */
} else {
FuncCall *n = makeNode(FuncCall);
n->funcname = $5->name;
n->args = lcons($3,NIL);
$$ = (Node *)n;
}
1997-09-08 05:20:18 +02:00
}
| '(' a_expr_or_null ')'
{ $$ = $2; }
| a_expr Op a_expr
1997-10-31 01:50:39 +01:00
{ $$ = makeIndexable($2,$1,$3); }
1997-09-08 05:20:18 +02:00
| a_expr LIKE a_expr
1997-10-31 01:50:39 +01:00
{ $$ = makeIndexable("~~", $1, $3); }
1997-09-08 05:20:18 +02:00
| 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); }
| func_name '(' '*' ')'
1997-09-08 05:20:18 +02:00
{
/* cheap hack for aggregate (eg. count) */
1997-09-08 05:20:18 +02:00
FuncCall *n = makeNode(FuncCall);
A_Const *star = makeNode(A_Const);
1997-09-08 05:20:18 +02:00
star->val.type = T_String;
star->val.val.str = "";
1997-09-08 05:20:18 +02:00
n->funcname = $1;
n->args = lcons(star, NIL);
$$ = (Node *)n;
}
| func_name '(' ')'
1997-09-08 05:20:18 +02:00
{
FuncCall *n = makeNode(FuncCall);
n->funcname = $1;
n->args = NIL;
$$ = (Node *)n;
}
| func_name '(' expr_list ')'
{
FuncCall *n = makeNode(FuncCall);
n->funcname = $1;
n->args = $3;
$$ = (Node *)n;
}
| CURRENT_DATE
{
A_Const *n = makeNode(A_Const);
TypeName *t = makeNode(TypeName);
n->val.type = T_String;
n->val.val.str = "now";
n->typename = t;
t->name = xlateSqlType("date");
t->setof = FALSE;
t->typmod = -1;
$$ = (Node *)n;
}
| CURRENT_TIME
{
A_Const *n = makeNode(A_Const);
TypeName *t = makeNode(TypeName);
n->val.type = T_String;
n->val.val.str = "now";
n->typename = t;
t->name = xlateSqlType("time");
t->setof = FALSE;
t->typmod = -1;
$$ = (Node *)n;
}
| CURRENT_TIME '(' Iconst ')'
{
FuncCall *n = makeNode(FuncCall);
A_Const *s = makeNode(A_Const);
TypeName *t = makeNode(TypeName);
n->funcname = xlateSqlType("time");
n->args = lcons(s, NIL);
s->val.type = T_String;
s->val.val.str = "now";
s->typename = t;
t->name = xlateSqlType("time");
t->setof = FALSE;
t->typmod = -1;
if ($3 != 0)
elog(NOTICE,"CURRENT_TIME(%d) precision not implemented; zero used instead",$3);
$$ = (Node *)n;
}
| CURRENT_TIMESTAMP
{
A_Const *n = makeNode(A_Const);
TypeName *t = makeNode(TypeName);
n->val.type = T_String;
n->val.val.str = "now";
n->typename = t;
t->name = xlateSqlType("timestamp");
t->setof = FALSE;
t->typmod = -1;
$$ = (Node *)n;
}
| CURRENT_TIMESTAMP '(' Iconst ')'
{
FuncCall *n = makeNode(FuncCall);
A_Const *s = makeNode(A_Const);
TypeName *t = makeNode(TypeName);
n->funcname = xlateSqlType("timestamp");
n->args = lcons(s, NIL);
s->val.type = T_String;
s->val.val.str = "now";
s->typename = t;
t->name = xlateSqlType("timestamp");
t->setof = FALSE;
t->typmod = -1;
if ($3 != 0)
elog(NOTICE,"CURRENT_TIMESTAMP(%d) precision not implemented; zero used instead",$3);
1997-09-08 05:20:18 +02:00
$$ = (Node *)n;
}
| CURRENT_USER
{
FuncCall *n = makeNode(FuncCall);
n->funcname = "getpgusername";
n->args = NIL;
$$ = (Node *)n;
}
1997-09-08 05:20:18 +02:00
| EXISTS '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = NIL;
n->useor = false;
n->oper = NIL;
n->subLinkType = EXISTS_SUBLINK;
n->subselect = $3;
$$ = (Node *)n;
1997-09-08 05:20:18 +02:00
}
| 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;
}
| a_expr ISNULL
{ $$ = makeA_Expr(ISNULL, NULL, $1, NULL); }
| a_expr IS NULL_P
1997-09-08 05:20:18 +02:00
{ $$ = makeA_Expr(ISNULL, NULL, $1, NULL); }
| a_expr NOTNULL
{ $$ = makeA_Expr(NOTNULL, NULL, $1, NULL); }
| a_expr IS NOT NULL_P
1997-09-08 05:20:18 +02:00
{ $$ = makeA_Expr(NOTNULL, NULL, $1, NULL); }
/* IS TRUE, IS FALSE, etc used to be function calls
* but let's make them expressions to allow the optimizer
* a chance to eliminate them if a_expr is a constant string.
* - thomas 1997-12-22
*/
| a_expr IS TRUE_P
{
A_Const *n = makeNode(A_Const);
n->val.type = T_String;
n->val.val.str = "t";
n->typename = makeNode(TypeName);
n->typename->name = xlateSqlType("bool");
n->typename->typmod = -1;
$$ = makeA_Expr(OP, "=", $1,(Node *)n);
}
| a_expr IS NOT FALSE_P
{
A_Const *n = makeNode(A_Const);
n->val.type = T_String;
n->val.val.str = "t";
n->typename = makeNode(TypeName);
n->typename->name = xlateSqlType("bool");
n->typename->typmod = -1;
$$ = makeA_Expr(OP, "=", $1,(Node *)n);
}
| a_expr IS FALSE_P
{
A_Const *n = makeNode(A_Const);
n->val.type = T_String;
n->val.val.str = "f";
n->typename = makeNode(TypeName);
n->typename->name = xlateSqlType("bool");
n->typename->typmod = -1;
$$ = makeA_Expr(OP, "=", $1,(Node *)n);
}
| a_expr IS NOT TRUE_P
{
A_Const *n = makeNode(A_Const);
n->val.type = T_String;
n->val.val.str = "f";
n->typename = makeNode(TypeName);
n->typename->name = xlateSqlType("bool");
n->typename->typmod = -1;
$$ = makeA_Expr(OP, "=", $1,(Node *)n);
}
| a_expr BETWEEN b_expr AND b_expr
1997-09-08 05:20:18 +02:00
{
$$ = makeA_Expr(AND, NULL,
makeA_Expr(OP, ">=", $1, $3),
makeA_Expr(OP, "<=", $1, $5));
}
| a_expr NOT BETWEEN b_expr AND b_expr
1997-09-08 05:20:18 +02:00
{
$$ = makeA_Expr(OR, NULL,
makeA_Expr(OP, "<", $1, $4),
makeA_Expr(OP, ">", $1, $6));
}
| a_expr IN { saved_In_Expr = lcons($1,saved_In_Expr); } '(' in_expr ')'
{
saved_In_Expr = lnext(saved_In_Expr);
if (nodeTag($5) == T_SubLink)
{
SubLink *n = (SubLink *)$5;
n->lefthand = lcons($1, NIL);
n->oper = lcons("=",NIL);
n->useor = false;
n->subLinkType = ANY_SUBLINK;
$$ = (Node *)n;
}
else $$ = $5;
}
| a_expr NOT IN { saved_In_Expr = lcons($1,saved_In_Expr); } '(' not_in_expr ')'
{
saved_In_Expr = lnext(saved_In_Expr);
if (nodeTag($6) == T_SubLink)
{
SubLink *n = (SubLink *)$6;
n->lefthand = lcons($1, NIL);
n->oper = lcons("<>",NIL);
n->useor = false;
n->subLinkType = ALL_SUBLINK;
$$ = (Node *)n;
}
else $$ = $6;
}
| a_expr Op '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = lcons($1, NULL);
n->oper = lcons($2,NIL);
n->useor = false;
n->subLinkType = EXPR_SUBLINK;
n->subselect = $4;
$$ = (Node *)n;
}
| a_expr '+' '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = lcons($1, NULL);
n->oper = lcons("+",NIL);
n->useor = false;
n->subLinkType = EXPR_SUBLINK;
n->subselect = $4;
$$ = (Node *)n;
}
| a_expr '-' '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = lcons($1, NULL);
n->oper = lcons("-",NIL);
n->useor = false;
n->subLinkType = EXPR_SUBLINK;
n->subselect = $4;
$$ = (Node *)n;
}
| a_expr '/' '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = lcons($1, NULL);
n->oper = lcons("/",NIL);
n->useor = false;
n->subLinkType = EXPR_SUBLINK;
n->subselect = $4;
$$ = (Node *)n;
}
| a_expr '*' '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = lcons($1, NULL);
n->oper = lcons("*",NIL);
n->useor = false;
n->subLinkType = EXPR_SUBLINK;
n->subselect = $4;
$$ = (Node *)n;
}
| a_expr '<' '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = lcons($1, NULL);
n->oper = lcons("<",NIL);
n->useor = false;
n->subLinkType = EXPR_SUBLINK;
n->subselect = $4;
$$ = (Node *)n;
}
| a_expr '>' '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = lcons($1, NULL);
n->oper = lcons(">",NIL);
n->useor = false;
n->subLinkType = EXPR_SUBLINK;
n->subselect = $4;
$$ = (Node *)n;
}
| a_expr '=' '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = lcons($1, NULL);
n->oper = lcons("=",NIL);
n->useor = false;
n->subLinkType = EXPR_SUBLINK;
n->subselect = $4;
$$ = (Node *)n;
}
| a_expr Op ANY '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = lcons($1,NIL);
n->oper = lcons($2,NIL);
n->useor = false;
n->subLinkType = ANY_SUBLINK;
n->subselect = $5;
$$ = (Node *)n;
}
| a_expr '+' ANY '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = lcons($1,NIL);
n->oper = lcons("+",NIL);
n->useor = false;
n->subLinkType = ANY_SUBLINK;
n->subselect = $5;
$$ = (Node *)n;
}
| a_expr '-' ANY '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = lcons($1,NIL);
n->oper = lcons("-",NIL);
n->useor = false;
n->subLinkType = ANY_SUBLINK;
n->subselect = $5;
$$ = (Node *)n;
}
| a_expr '/' ANY '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = lcons($1,NIL);
n->oper = lcons("/",NIL);
n->useor = false;
n->subLinkType = ANY_SUBLINK;
n->subselect = $5;
$$ = (Node *)n;
}
| a_expr '*' ANY '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = lcons($1,NIL);
n->oper = lcons("*",NIL);
n->useor = false;
n->subLinkType = ANY_SUBLINK;
n->subselect = $5;
$$ = (Node *)n;
}
| a_expr '<' ANY '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = lcons($1,NIL);
n->oper = lcons("<",NIL);
n->useor = false;
n->subLinkType = ANY_SUBLINK;
n->subselect = $5;
$$ = (Node *)n;
}
| a_expr '>' ANY '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = lcons($1,NIL);
n->oper = lcons(">",NIL);
n->useor = false;
n->subLinkType = ANY_SUBLINK;
n->subselect = $5;
$$ = (Node *)n;
}
| a_expr '=' ANY '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = lcons($1,NIL);
n->oper = lcons("=",NIL);
n->useor = false;
n->subLinkType = ANY_SUBLINK;
n->subselect = $5;
$$ = (Node *)n;
}
| a_expr Op ALL '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = lcons($1, NULL);
n->oper = lcons($2,NIL);
n->useor = false;
n->subLinkType = ALL_SUBLINK;
n->subselect = $5;
$$ = (Node *)n;
}
| a_expr '+' ALL '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = lcons($1, NULL);
n->oper = lcons("+",NIL);
n->useor = false;
n->subLinkType = ALL_SUBLINK;
n->subselect = $5;
$$ = (Node *)n;
}
| a_expr '-' ALL '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = lcons($1, NULL);
n->oper = lcons("-",NIL);
n->useor = false;
n->subLinkType = ALL_SUBLINK;
n->subselect = $5;
$$ = (Node *)n;
}
| a_expr '/' ALL '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = lcons($1, NULL);
n->oper = lcons("/",NIL);
n->useor = false;
n->subLinkType = ALL_SUBLINK;
n->subselect = $5;
$$ = (Node *)n;
}
| a_expr '*' ALL '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = lcons($1, NULL);
n->oper = lcons("*",NIL);
n->useor = false;
n->subLinkType = ALL_SUBLINK;
n->subselect = $5;
$$ = (Node *)n;
}
| a_expr '<' ALL '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = lcons($1, NULL);
n->oper = lcons("<",NIL);
n->useor = false;
n->subLinkType = ALL_SUBLINK;
n->subselect = $5;
$$ = (Node *)n;
}
| a_expr '>' ALL '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = lcons($1, NULL);
n->oper = lcons(">",NIL);
n->useor = false;
n->subLinkType = ALL_SUBLINK;
n->subselect = $5;
$$ = (Node *)n;
}
| a_expr '=' ALL '(' SubSelect ')'
{
SubLink *n = makeNode(SubLink);
n->lefthand = lcons($1, NULL);
n->oper = lcons("=",NIL);
n->useor = false;
n->subLinkType = ALL_SUBLINK;
n->subselect = $5;
$$ = (Node *)n;
}
1997-09-08 05:20:18 +02:00
| 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); }
;
/*
* b_expr is a subset of the complete expression syntax
* defined by a_expr. b_expr is used in BETWEEN clauses
* to eliminate parser ambiguities stemming from the AND keyword.
*/
b_expr: attr opt_indirection
{
$1->indirection = $2;
$$ = (Node *)$1;
}
| AexprConst
{ $$ = $1; }
| ColId
{
/* could be a column name or a relation_name */
Ident *n = makeNode(Ident);
n->name = $1;
n->indirection = NULL;
$$ = (Node *)n;
}
| '-' b_expr %prec UMINUS
{ $$ = makeA_Expr(OP, "-", NULL, $2); }
| b_expr '+' b_expr
{ $$ = makeA_Expr(OP, "+", $1, $3); }
| b_expr '-' b_expr
{ $$ = makeA_Expr(OP, "-", $1, $3); }
| b_expr '/' b_expr
{ $$ = makeA_Expr(OP, "/", $1, $3); }
| b_expr '*' b_expr
{ $$ = makeA_Expr(OP, "*", $1, $3); }
| ':' b_expr
{ $$ = makeA_Expr(OP, ":", NULL, $2); }
| ';' b_expr
{ $$ = makeA_Expr(OP, ";", NULL, $2); }
| '|' b_expr
{ $$ = makeA_Expr(OP, "|", NULL, $2); }
| b_expr TYPECAST Typename
{
$$ = (Node *)$1;
/* AexprConst can be either A_Const or ParamNo */
if (nodeTag($1) == T_A_Const) {
((A_Const *)$1)->typename = $3;
} else if (nodeTag($1) == T_Param) {
((ParamNo *)$1)->typename = $3;
/* otherwise, try to transform to a function call */
} else {
FuncCall *n = makeNode(FuncCall);
n->funcname = $3->name;
n->args = lcons($1,NIL);
$$ = (Node *)n;
}
}
| CAST '(' b_expr AS Typename ')'
{
$$ = (Node *)$3;
/* AexprConst can be either A_Const or ParamNo */
if (nodeTag($3) == T_A_Const) {
((A_Const *)$3)->typename = $5;
} else if (nodeTag($3) == T_Param) {
((ParamNo *)$3)->typename = $5;
/* otherwise, try to transform to a function call */
} else {
FuncCall *n = makeNode(FuncCall);
n->funcname = $5->name;
n->args = lcons($3,NIL);
$$ = (Node *)n;
}
}
| '(' a_expr ')'
{ $$ = $2; }
| b_expr Op b_expr
{ $$ = makeIndexable($2,$1,$3); }
| Op b_expr
{ $$ = makeA_Expr(OP, $1, NULL, $2); }
| b_expr Op
{ $$ = makeA_Expr(OP, $2, $1, NULL); }
| func_name '(' ')'
{
FuncCall *n = makeNode(FuncCall);
n->funcname = $1;
n->args = NIL;
$$ = (Node *)n;
}
| func_name '(' expr_list ')'
{
FuncCall *n = makeNode(FuncCall);
n->funcname = $1;
n->args = $3;
$$ = (Node *)n;
}
| CURRENT_DATE
{
A_Const *n = makeNode(A_Const);
TypeName *t = makeNode(TypeName);
n->val.type = T_String;
n->val.val.str = "now";
n->typename = t;
t->name = xlateSqlType("date");
t->setof = FALSE;
t->typmod = -1;
$$ = (Node *)n;
}
| CURRENT_TIME
{
A_Const *n = makeNode(A_Const);
TypeName *t = makeNode(TypeName);
n->val.type = T_String;
n->val.val.str = "now";
n->typename = t;
t->name = xlateSqlType("time");
t->setof = FALSE;
t->typmod = -1;
$$ = (Node *)n;
}
| CURRENT_TIME '(' Iconst ')'
{
FuncCall *n = makeNode(FuncCall);
A_Const *s = makeNode(A_Const);
TypeName *t = makeNode(TypeName);
n->funcname = xlateSqlType("time");
n->args = lcons(s, NIL);
s->val.type = T_String;
s->val.val.str = "now";
s->typename = t;
t->name = xlateSqlType("time");
t->setof = FALSE;
t->typmod = -1;
if ($3 != 0)
elog(NOTICE,"CURRENT_TIME(%d) precision not implemented; zero used instead",$3);
$$ = (Node *)n;
}
| CURRENT_TIMESTAMP
{
A_Const *n = makeNode(A_Const);
TypeName *t = makeNode(TypeName);
n->val.type = T_String;
n->val.val.str = "now";
n->typename = t;
t->name = xlateSqlType("timestamp");
t->setof = FALSE;
t->typmod = -1;
$$ = (Node *)n;
}
| CURRENT_TIMESTAMP '(' Iconst ')'
{
FuncCall *n = makeNode(FuncCall);
A_Const *s = makeNode(A_Const);
TypeName *t = makeNode(TypeName);
n->funcname = xlateSqlType("timestamp");
n->args = lcons(s, NIL);
s->val.type = T_String;
s->val.val.str = "now";
s->typename = t;
t->name = xlateSqlType("timestamp");
t->setof = FALSE;
t->typmod = -1;
if ($3 != 0)
elog(NOTICE,"CURRENT_TIMESTAMP(%d) precision not implemented; zero used instead",$3);
$$ = (Node *)n;
}
| CURRENT_USER
{
FuncCall *n = makeNode(FuncCall);
n->funcname = "getpgusername";
n->args = NIL;
$$ = (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;
}
;
opt_indirection: '[' a_expr ']' opt_indirection
1997-09-08 05:20:18 +02:00
{
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; }
;
expr_list: a_expr_or_null
1997-09-08 05:20:18 +02:00
{ $$ = lcons($1, NIL); }
| expr_list ',' a_expr_or_null
1997-09-08 05:20:18 +02:00
{ $$ = lappend($1, $3); }
| expr_list USING a_expr
1997-09-08 05:20:18 +02:00
{ $$ = lappend($1, $3); }
;
extract_list: datetime FROM a_expr
1997-09-08 05:20:18 +02:00
{
A_Const *n = makeNode(A_Const);
n->val.type = T_String;
n->val.val.str = $1;
$$ = lappend(lcons((Node *)n,NIL), $3);
}
| /* EMPTY */
{ $$ = NIL; }
;
position_list: position_expr IN position_expr
{ $$ = makeList($3, $1, -1); }
1997-09-08 05:20:18 +02:00
| /* EMPTY */
{ $$ = NIL; }
;
position_expr: attr opt_indirection
{
$1->indirection = $2;
$$ = (Node *)$1;
}
| AexprConst
{ $$ = $1; }
| '-' position_expr %prec UMINUS
{ $$ = makeA_Expr(OP, "-", NULL, $2); }
| position_expr '+' position_expr
{ $$ = makeA_Expr(OP, "+", $1, $3); }
| position_expr '-' position_expr
{ $$ = makeA_Expr(OP, "-", $1, $3); }
| position_expr '/' position_expr
{ $$ = makeA_Expr(OP, "/", $1, $3); }
| position_expr '*' position_expr
{ $$ = makeA_Expr(OP, "*", $1, $3); }
| '|' position_expr
{ $$ = makeA_Expr(OP, "|", NULL, $2); }
| position_expr TYPECAST Typename
{
$$ = (Node *)$1;
/* AexprConst can be either A_Const or ParamNo */
if (nodeTag($1) == T_A_Const) {
((A_Const *)$1)->typename = $3;
} else if (nodeTag($1) == T_Param) {
((ParamNo *)$1)->typename = $3;
/* otherwise, try to transform to a function call */
} else {
FuncCall *n = makeNode(FuncCall);
n->funcname = $3->name;
n->args = lcons($1,NIL);
$$ = (Node *)n;
}
}
| CAST '(' position_expr AS Typename ')'
{
$$ = (Node *)$3;
/* AexprConst can be either A_Const or ParamNo */
if (nodeTag($3) == T_A_Const) {
((A_Const *)$3)->typename = $5;
} else if (nodeTag($3) == T_Param) {
((ParamNo *)$3)->typename = $5;
/* otherwise, try to transform to a function call */
} else {
FuncCall *n = makeNode(FuncCall);
n->funcname = $5->name;
n->args = lcons($3,NIL);
$$ = (Node *)n;
}
}
| '(' position_expr ')'
{ $$ = $2; }
| position_expr Op position_expr
{ $$ = makeA_Expr(OP, $2, $1, $3); }
| Op position_expr
{ $$ = makeA_Expr(OP, $1, NULL, $2); }
| position_expr Op
{ $$ = makeA_Expr(OP, $2, $1, NULL); }
| ColId
{
/* could be a column name or a relation_name */
Ident *n = makeNode(Ident);
n->name = $1;
n->indirection = NULL;
$$ = (Node *)n;
}
| func_name '(' ')'
{
FuncCall *n = makeNode(FuncCall);
n->funcname = $1;
n->args = NIL;
$$ = (Node *)n;
}
| func_name '(' expr_list ')'
{
FuncCall *n = makeNode(FuncCall);
n->funcname = $1;
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;
}
;
substr_list: expr_list substr_from substr_for
1997-09-08 05:20:18 +02:00
{
$$ = nconc(nconc($1,$2),$3);
1997-09-08 05:20:18 +02:00
}
| /* EMPTY */
{ $$ = NIL; }
;
substr_from: FROM expr_list
1997-09-08 05:20:18 +02:00
{ $$ = $2; }
| /* EMPTY */
{
A_Const *n = makeNode(A_Const);
n->val.type = T_Integer;
n->val.val.ival = 1;
$$ = lcons((Node *)n,NIL);
}
1997-09-08 05:20:18 +02:00
;
substr_for: FOR expr_list
1997-09-08 05:20:18 +02:00
{ $$ = $2; }
| /* EMPTY */
{ $$ = NIL; }
;
trim_list: a_expr FROM expr_list
1997-09-08 05:20:18 +02:00
{ $$ = lappend($3, $1); }
| FROM expr_list
1997-09-08 05:20:18 +02:00
{ $$ = $2; }
| expr_list
1997-09-08 05:20:18 +02:00
{ $$ = $1; }
;
in_expr: SubSelect
{
SubLink *n = makeNode(SubLink);
n->subselect = $1;
$$ = (Node *)n;
}
| in_expr_nodes
{ $$ = $1; }
;
in_expr_nodes: AexprConst
{ $$ = makeA_Expr(OP, "=", lfirst(saved_In_Expr), $1); }
| in_expr_nodes ',' AexprConst
1997-09-08 05:20:18 +02:00
{ $$ = makeA_Expr(OR, NULL, $1,
makeA_Expr(OP, "=", lfirst(saved_In_Expr), $3));
1997-09-08 05:20:18 +02:00
}
;
not_in_expr: SubSelect
{
SubLink *n = makeNode(SubLink);
n->subselect = $1;
$$ = (Node *)n;
}
| not_in_expr_nodes
{ $$ = $1; }
;
not_in_expr_nodes: AexprConst
{ $$ = makeA_Expr(OP, "<>", lfirst(saved_In_Expr), $1); }
| not_in_expr_nodes ',' AexprConst
1997-09-08 05:20:18 +02:00
{ $$ = makeA_Expr(AND, NULL, $1,
makeA_Expr(OP, "<>", lfirst(saved_In_Expr), $3));
1997-09-08 05:20:18 +02:00
}
;
attr: relation_name '.' attrs
1997-09-08 05:20:18 +02:00
{
$$ = 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("*")); }
;
/*****************************************************************************
*
1997-09-08 05:20:18 +02:00
* target lists
*
*****************************************************************************/
res_target_list: res_target_list ',' res_target_el
1997-09-08 05:20:18 +02:00
{ $$ = 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);
}
;
res_target_el: ColId opt_indirection '=' a_expr_or_null
1997-09-08 05:20:18 +02:00
{
$$ = 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.
1998-01-20 06:05:08 +01:00
** should get rid of the other but is still needed by the defunct select into
** and update (uses a subset)
*/
res_target_list2: res_target_list2 ',' res_target_el2
1997-09-08 05:20:18 +02:00
{ $$ = 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_or_null AS ColLabel
1997-09-08 05:20:18 +02:00
{
$$ = makeNode(ResTarget);
$$->name = $3;
$$->indirection = NULL;
$$->val = (Node *)$1;
}
| 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: ColId { $$ = $1; }
1997-09-08 05:20:18 +02:00
| /* EMPTY */ { $$ = NULL; }
;
relation_name: SpecialRuleRelation
{
$$ = $1;
StrNCpy(saved_relname, $1, NAMEDATALEN);
1997-09-08 05:20:18 +02:00
}
| ColId
{
/* disallow refs to variable system tables */
1997-09-08 05:20:18 +02:00
if (strcmp(LogRelationName, $1) == 0
|| strcmp(VariableRelationName, $1) == 0)
elog(ERROR,"%s cannot be accessed by users",$1);
1997-09-08 05:20:18 +02:00
else
$$ = $1;
StrNCpy(saved_relname, $1, NAMEDATALEN);
1997-09-08 05:20:18 +02:00
}
;
database_name: ColId { $$ = $1; };
access_method: IDENT { $$ = $1; };
1997-09-08 05:20:18 +02:00
attr_name: ColId { $$ = $1; };
class: IDENT { $$ = $1; };
index_name: ColId { $$ = $1; };
/* Functions
* Include date/time keywords as SQL92 extension.
* Include TYPE as a SQL92 unreserved keyword. - thomas 1997-10-05
*/
name: ColId { $$ = $1; };
func_name: ColId { $$ = xlateSqlFunc($1); };
1997-09-08 05:20:18 +02:00
file_name: Sconst { $$ = $1; };
recipe_name: IDENT { $$ = $1; };
/* Constants
* Include TRUE/FALSE for SQL3 support. - thomas 1997-10-24
*/
AexprConst: Iconst
1997-09-08 05:20:18 +02:00
{
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;
}
| Typename Sconst
{
A_Const *n = makeNode(A_Const);
n->typename = $1;
n->val.type = T_String;
n->val.val.str = $2;
$$ = (Node *)n;
}
1997-09-08 05:20:18 +02:00
| ParamNo
{ $$ = (Node *)$1; }
| TRUE_P
{
A_Const *n = makeNode(A_Const);
n->val.type = T_String;
n->val.val.str = "t";
n->typename = makeNode(TypeName);
n->typename->name = xlateSqlType("bool");
n->typename->typmod = -1;
$$ = (Node *)n;
}
| FALSE_P
{
A_Const *n = makeNode(A_Const);
n->val.type = T_String;
n->val.val.str = "f";
n->typename = makeNode(TypeName);
n->typename->name = xlateSqlType("bool");
n->typename->typmod = -1;
$$ = (Node *)n;
}
1997-09-08 05:20:18 +02:00
;
ParamNo: PARAM
1997-09-08 05:20:18 +02:00
{
$$ = makeNode(ParamNo);
$$->number = $1;
}
;
1997-09-08 05:20:18 +02:00
NumConst: Iconst { $$ = makeInteger($1); }
| FCONST { $$ = makeFloat($1); }
1997-09-08 05:20:18 +02:00
;
1997-09-08 05:20:18 +02:00
Iconst: ICONST { $$ = $1; };
Sconst: SCONST { $$ = $1; };
UserId: IDENT { $$ = $1; };
/* Column and type identifier
* Does not include explicit datetime types
* since these must be decoupled in Typename syntax.
* Use ColId for most identifiers. - thomas 1997-10-21
*/
TypeId: ColId
{ $$ = xlateSqlType($1); }
| numeric
{ $$ = xlateSqlType($1); }
| character
{ $$ = xlateSqlType($1); }
;
/* Column identifier
* Include date/time keywords as SQL92 extension.
* Include TYPE as a SQL92 unreserved keyword. - thomas 1997-10-05
* Add other keywords. Note that as the syntax expands,
* some of these keywords will have to be removed from this
* list due to shift/reduce conflicts in yacc. If so, move
* down to the ColLabel entity. - thomas 1997-11-06
*/
ColId: IDENT { $$ = $1; }
| datetime { $$ = $1; }
| ACTION { $$ = "action"; }
| DATABASE { $$ = "database"; }
| DELIMITERS { $$ = "delimiters"; }
| DOUBLE { $$ = "double"; }
| EACH { $$ = "each"; }
| FUNCTION { $$ = "function"; }
| INDEX { $$ = "index"; }
| KEY { $$ = "key"; }
| LANGUAGE { $$ = "language"; }
| LOCATION { $$ = "location"; }
| MATCH { $$ = "match"; }
| OPERATOR { $$ = "operator"; }
| OPTION { $$ = "option"; }
| PRIVILEGES { $$ = "privileges"; }
| RECIPE { $$ = "recipe"; }
| ROW { $$ = "row"; }
| STATEMENT { $$ = "statement"; }
| TIME { $$ = "time"; }
| TRIGGER { $$ = "trigger"; }
| TYPE_P { $$ = "type"; }
| USER { $$ = "user"; }
| VALID { $$ = "valid"; }
| VERSION { $$ = "version"; }
| ZONE { $$ = "zone"; }
;
/* Column label
* Allowed labels in "AS" clauses.
* Include TRUE/FALSE SQL3 reserved words for Postgres backward
* compatibility. Cannot allow this for column names since the
* syntax would not distinguish between the constant value and
* a column name. - thomas 1997-10-24
* Add other keywords to this list. Note that they appear here
* rather than in ColId if there was a shift/reduce conflict
* when used as a full identifier. - thomas 1997-11-06
*/
ColLabel: ColId { $$ = $1; }
| ARCHIVE { $$ = "archive"; }
| CLUSTER { $$ = "cluster"; }
| CONSTRAINT { $$ = "constraint"; }
| CROSS { $$ = "cross"; }
| FOREIGN { $$ = "foreign"; }
| GROUP { $$ = "group"; }
| LOAD { $$ = "load"; }
| ORDER { $$ = "order"; }
| POSITION { $$ = "position"; }
| PRECISION { $$ = "precision"; }
| TABLE { $$ = "table"; }
| TRANSACTION { $$ = "transaction"; }
| TRUE_P { $$ = "true"; }
| FALSE_P { $$ = "false"; }
1997-09-08 05:20:18 +02:00
;
SpecialRuleRelation: CURRENT
1997-09-08 05:20:18 +02:00
{
if (QueryIsRule)
$$ = "*CURRENT*";
else
1998-01-09 21:06:08 +01:00
elog(ERROR,"CURRENT used in non-rule query");
1997-09-08 05:20:18 +02:00
}
| NEW
{
if (QueryIsRule)
$$ = "*NEW*";
else
1998-01-09 21:06:08 +01:00
elog(ERROR,"NEW used in non-rule query");
1997-09-08 05:20:18 +02:00
}
;
%%
static Node *
makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr)
{
1997-09-08 05:20:18 +02:00
A_Expr *a = makeNode(A_Expr);
a->oper = oper;
a->opname = opname;
a->lexpr = lexpr;
a->rexpr = rexpr;
return (Node *)a;
}
1998-01-17 06:01:34 +01:00
/* makeRowExpr()
* Generate separate operator nodes for a single row descriptor expression.
* Perhaps this should go deeper in the parser someday... - thomas 1997-12-22
*/
static Node *
makeRowExpr(char *opr, List *largs, List *rargs)
{
Node *expr = NULL;
Node *larg, *rarg;
if (length(largs) != length(rargs))
elog(ERROR,"Unequal number of entries in row expression");
if (lnext(largs) != NIL)
expr = makeRowExpr(opr,lnext(largs),lnext(rargs));
larg = lfirst(largs);
rarg = lfirst(rargs);
if ((strcmp(opr, "=") == 0)
|| (strcmp(opr, "<") == 0)
|| (strcmp(opr, "<=") == 0)
|| (strcmp(opr, ">") == 0)
|| (strcmp(opr, ">=") == 0))
{
if (expr == NULL)
expr = makeA_Expr(OP, opr, larg, rarg);
else
expr = makeA_Expr(AND, NULL, expr, makeA_Expr(OP, opr, larg, rarg));
}
else if (strcmp(opr, "<>") == 0)
{
if (expr == NULL)
expr = makeA_Expr(OP, opr, larg, rarg);
else
expr = makeA_Expr(OR, NULL, expr, makeA_Expr(OP, opr, larg, rarg));
}
else
{
elog(ERROR,"Operator '%s' not implemented for row expressions",opr);
}
#if FALSE
while ((largs != NIL) && (rargs != NIL))
{
larg = lfirst(largs);
rarg = lfirst(rargs);
if (expr == NULL)
expr = makeA_Expr(OP, opr, larg, rarg);
else
expr = makeA_Expr(AND, NULL, expr, makeA_Expr(OP, opr, larg, rarg));
largs = lnext(largs);
rargs = lnext(rargs);
}
pprint(expr);
#endif
return expr;
}
void
mapTargetColumns(List *src, List *dst)
{
ColumnDef *s;
ResTarget *d;
if (length(src) != length(dst))
1998-01-09 21:06:08 +01:00
elog(ERROR,"CREATE TABLE/AS SELECT has mismatched column count");
while ((src != NIL) && (dst != NIL))
{
s = (ColumnDef *)lfirst(src);
d = (ResTarget *)lfirst(dst);
d->name = s->colname;
src = lnext(src);
dst = lnext(dst);
}
return;
} /* mapTargetColumns() */
1997-10-31 01:50:39 +01:00
static Node *makeIndexable(char *opname, Node *lexpr, Node *rexpr)
{
Node *result = NULL;
/* we do this so indexes can be used */
if (strcmp(opname,"~") == 0 ||
strcmp(opname,"~*") == 0)
1997-10-31 01:50:39 +01:00
{
if (nodeTag(rexpr) == T_A_Const &&
((A_Const *)rexpr)->val.type == T_String &&
((A_Const *)rexpr)->val.val.str[0] == '^')
{
A_Const *n = (A_Const *)rexpr;
char *match_least = palloc(strlen(n->val.val.str)+2);
char *match_most = palloc(strlen(n->val.val.str)+2);
int pos, match_pos=0;
/* skip leading ^ */
for (pos = 1; n->val.val.str[pos]; pos++)
{
if (n->val.val.str[pos] == '.' ||
n->val.val.str[pos] == '?' ||
n->val.val.str[pos] == '*' ||
n->val.val.str[pos] == '[' ||
n->val.val.str[pos] == '$' ||
(strcmp(opname,"~*") == 0 && isalpha(n->val.val.str[pos])))
1997-10-31 01:50:39 +01:00
break;
if (n->val.val.str[pos] == '\\')
pos++;
match_least[match_pos] = n->val.val.str[pos];
match_most[match_pos++] = n->val.val.str[pos];
}
if (match_pos != 0)
{
A_Const *least = makeNode(A_Const);
A_Const *most = makeNode(A_Const);
/* make strings to be used in index use */
match_least[match_pos] = '\0';
match_most[match_pos] = '\377';
match_most[match_pos+1] = '\0';
least->val.type = T_String;
least->val.val.str = match_least;
most->val.type = T_String;
most->val.val.str = match_most;
result = makeA_Expr(AND, NULL,
makeA_Expr(OP, "~", lexpr, rexpr),
makeA_Expr(AND, NULL,
makeA_Expr(OP, ">=", lexpr, (Node *)least),
makeA_Expr(OP, "<=", lexpr, (Node *)most)));
}
}
}
else if (strcmp(opname,"~~") == 0)
{
if (nodeTag(rexpr) == T_A_Const &&
((A_Const *)rexpr)->val.type == T_String)
{
A_Const *n = (A_Const *)rexpr;
char *match_least = palloc(strlen(n->val.val.str)+2);
char *match_most = palloc(strlen(n->val.val.str)+2);
int pos, match_pos=0;
for (pos = 0; n->val.val.str[pos]; pos++)
{
if (n->val.val.str[pos] == '%' &&
n->val.val.str[pos+1] != '%')
break;
if(n->val.val.str[pos] == '_')
break;
if (n->val.val.str[pos] == '\\' ||
n->val.val.str[pos] == '%')
1997-10-31 01:50:39 +01:00
pos++;
if (n->val.val.str[pos] == '\0')
break;
1997-10-31 01:50:39 +01:00
match_least[match_pos] = n->val.val.str[pos];
match_most[match_pos++] = n->val.val.str[pos];
}
if (match_pos != 0)
{
A_Const *least = makeNode(A_Const);
A_Const *most = makeNode(A_Const);
/* make strings to be used in index use */
match_least[match_pos] = '\0';
match_most[match_pos] = '\377';
match_most[match_pos+1] = '\0';
least->val.type = T_String;
least->val.val.str = match_least;
most->val.type = T_String;
most->val.val.str = match_most;
result = makeA_Expr(AND, NULL,
makeA_Expr(OP, "~~", lexpr, rexpr),
makeA_Expr(AND, NULL,
makeA_Expr(OP, ">=", lexpr, (Node *)least),
makeA_Expr(OP, "<=", lexpr, (Node *)most)));
}
}
}
if (result == NULL)
result = makeA_Expr(OP, opname, lexpr, rexpr);
return result;
} /* makeIndexable() */
1997-10-31 01:50:39 +01:00
/* xlateSqlFunc()
* Convert alternate type names to internal Postgres types.
* Do not convert "float", since that is handled elsewhere
* for FLOAT(p) syntax.
*/
static char *
xlateSqlFunc(char *name)
{
if (!strcasecmp(name,"character_length")
|| !strcasecmp(name,"char_length"))
return "length";
else
return name;
} /* xlateSqlFunc() */
/* xlateSqlType()
* Convert alternate type names to internal Postgres types.
*/
static char *
xlateSqlType(char *name)
{
if (!strcasecmp(name,"int")
|| !strcasecmp(name,"integer"))
return "int4";
1997-09-08 05:20:18 +02:00
else if (!strcasecmp(name, "smallint"))
return "int2";
else if (!strcasecmp(name, "real")
|| !strcasecmp(name, "float"))
1997-09-08 05:20:18 +02:00
return "float8";
else if (!strcasecmp(name, "interval"))
return "timespan";
else if (!strcasecmp(name, "boolean"))
return "bool";
1997-09-08 05:20:18 +02:00
else
return name;
} /* xlateSqlType() */
void parser_init(Oid *typev, int nargs)
{
QueryIsRule = FALSE;
1997-09-08 05:20:18 +02:00
saved_relname[0]= '\0';
saved_In_Expr = NULL;
1997-09-08 05:20:18 +02:00
param_type_init(typev, nargs);
}
/* FlattenStringList()
* Traverse list of string nodes and convert to a single string.
* Used for reconstructing string form of complex expressions.
*
* Allocate at least one byte for terminator.
*/
static char *
FlattenStringList(List *list)
{
List *l;
Value *v;
char *s;
char *sp;
int nlist, len = 0;
nlist = length(list);
l = list;
while(l != NIL) {
v = (Value *)lfirst(l);
sp = v->val.str;
l = lnext(l);
len += strlen(sp);
};
len += nlist;
s = (char*) palloc(len+1);
*s = '\0';
l = list;
while(l != NIL) {
v = (Value *)lfirst(l);
sp = v->val.str;
l = lnext(l);
strcat(s,sp);
if (l != NIL) strcat(s," ");
};
*(s+len) = '\0';
#ifdef PARSEDEBUG
printf( "flattened string is \"%s\"\n", s);
#endif
return(s);
} /* FlattenStringList() */
/* makeConstantList()
* Convert constant value node into string node.
*/
static List *
makeConstantList( A_Const *n)
{
char *defval = NULL;
if (nodeTag(n) != T_A_Const) {
1998-01-09 21:06:08 +01:00
elog(ERROR,"Cannot handle non-constant parameter");
} else if (n->val.type == T_Float) {
defval = (char*) palloc(20+1);
sprintf( defval, "%g", n->val.val.dval);
} else if (n->val.type == T_Integer) {
defval = (char*) palloc(20+1);
sprintf( defval, "%ld", n->val.val.ival);
} else if (n->val.type == T_String) {
defval = (char*) palloc(strlen( ((A_Const *) n)->val.val.str) + 3);
strcpy( defval, "'");
strcat( defval, ((A_Const *) n)->val.val.str);
strcat( defval, "'");
} else {
1998-01-09 21:06:08 +01:00
elog(ERROR,"Internal error in makeConstantList(): cannot encode node");
};
#ifdef PARSEDEBUG
printf( "AexprConst argument is \"%s\"\n", defval);
#endif
return( lcons( makeString(defval), NIL));
} /* makeConstantList() */
/* fmtId()
* Check input string for non-lowercase/non-numeric characters.
* Returns either input string or input surrounded by double quotes.
*/
static char *
fmtId(char *rawid)
{
static char *cp;
for (cp = rawid; *cp != '\0'; cp++)
if (! (islower(*cp) || isdigit(*cp) || (*cp == '_'))) break;
if (*cp != '\0') {
cp = palloc(strlen(rawid)+1);
strcpy(cp,"\"");
strcat(cp,rawid);
strcat(cp,"\"");
} else {
cp = rawid;
};
#ifdef PARSEDEBUG
printf("fmtId- %sconvert %s to %s\n", ((cp == rawid)? "do not ": ""), rawid, cp);
#endif
return(cp);
}
/*
* param_type_init()
*
* keep enough information around fill out the type of param nodes
* used in postquel functions
*/
static void
param_type_init(Oid *typev, int nargs)
{
pfunc_num_args = nargs;
param_type_info = typev;
}
Oid param_type(int t)
{
if ((t > pfunc_num_args) || (t == 0))
return InvalidOid;
return param_type_info[t - 1];
}