/* symbolic tokens */
%union {
int intval;
double floatval;
char *strval;
int subtok;
}
%token NAME
%token STRING
%token INTNUM APPROXNUM
/* operators */
%left OR
%left AND
%left NOT
%left <subtok> COMPARISON /* = <> < > <= >= */
%left '+' '-'
%left '*' '/'
%nonassoc UMINUS
/* literal keyword tokens */
%token ALL AMMSC ANY AS ASC AUTHORIZATION BETWEEN BY
%token CHARACTER CHECK CLOSE COMMIT CONTINUE CREATE CURRENT
%token CURSOR DECIMAL DECLARE DEFAULT DELETE DESC DISTINCT DOUBLE
%token ESCAPE EXISTS FETCH FLOAT FOR FOREIGN FOUND FROM GOTO
%token GRANT GROUP HAVING IN INDICATOR INSERT INTEGER INTO
%token IS KEY LANGUAGE LIKE NULLX NUMERIC OF ON OPEN OPTION
%token ORDER PARAMETER PRECISION PRIMARY PRIVILEGES PROCEDURE
%token PUBLIC REAL REFERENCES ROLLBACK SCHEMA SELECT SET
%token SMALLINT SOME SQLCODE SQLERROR TABLE TO UNION
%token UNIQUE UPDATE USER VALUES VIEW WHENEVER WHERE WITH WORK
%%
sql_list:
sql ';' { end_sql(); }
| sql_list sql ';' { end_sql(); }
;
/* schema definition language */
sql: schema
;
schema:
CREATE SCHEMA AUTHORIZATION user opt_schema_element_list
;
opt_schema_element_list:
/* empty */
| schema_element_list
;
schema_element_list:
schema_element
| schema_element_list schema_element
;
schema_element:
base_table_def
| view_def
| privilege_def
;
base_table_def:
CREATE TABLE table '(' base_table_element_commalist ')'
;
base_table_element_commalist:
base_table_element
| base_table_element_commalist ',' base_table_element
;
base_table_element:
column_def
| table_constraint_def
;
column_def:
column data_type column_def_opt_list
;
column_def_opt_list:
/* empty */
| column_def_opt_list column_def_opt
;
column_def_opt:
NOT NULLX
| NOT NULLX UNIQUE
| NOT NULLX PRIMARY KEY
| DEFAULT literal
| DEFAULT NULLX
| DEFAULT USER
| CHECK '(' search_condition ')'
| REFERENCES table
| REFERENCES table '(' column_commalist ')'
;
table_constraint_def:
UNIQUE '(' column_commalist ')'
| PRIMARY KEY '(' column_commalist ')'
| FOREIGN KEY '(' column_commalist ')'
REFERENCES table
| FOREIGN KEY '(' column_commalist ')'
REFERENCES table '(' column_commalist ')'
| CHECK '(' search_condition ')'
;
column_commalist:
column
| column_commalist ',' column
;
view_def:
CREATE VIEW table opt_column_commalist
AS query_spec opt_with_check_option
;
opt_with_check_option:
/* empty */
| WITH CHECK OPTION
;
opt_column_commalist:
/* empty */
| '(' column_commalist ')'
;
privilege_def:
GRANT privileges ON table TO grantee_commalist
opt_with_grant_option
;
opt_with_grant_option:
/* empty */
| WITH GRANT OPTION
;
privileges:
ALL PRIVILEGES
| ALL
| operation_commalist
;
operation_commalist:
operation
| operation_commalist ',' operation
;
operation:
SELECT
| INSERT
| DELETE
| UPDATE opt_column_commalist
| REFERENCES opt_column_commalist
;
grantee_commalist:
grantee
| grantee_commalist ',' grantee
;
grantee:
PUBLIC
| user
;
/* cursor definition */
sql:
cursor_def
;
cursor_def:
DECLARE cursor CURSOR FOR query_exp opt_order_by_clause
;
opt_order_by_clause:
/* empty */
| ORDER BY ordering_spec_commalist
;
ordering_spec_commalist:
ordering_spec
| ordering_spec_commalist ',' ordering_spec
;
ordering_spec:
INTNUM opt_asc_desc
| column_ref opt_asc_desc
;
opt_asc_desc:
/* empty */
| ASC
| DESC
;
/* manipulative statements */
sql: manipulative_statement
;
manipulative_statement:
close_statement
| commit_statement
| delete_statement_positioned
| delete_statement_searched
| fetch_statement
| insert_statement
| open_statement
| rollback_statement
| select_statement
| update_statement_positioned
| update_statement_searched
;
close_statement:
CLOSE cursor
;
commit_statement:
COMMIT WORK
;
delete_statement_positioned:
DELETE FROM table WHERE CURRENT OF cursor
;
delete_statement_searched:
DELETE FROM table opt_where_clause
;
fetch_statement:
FETCH cursor INTO target_commalist
;
insert_statement:
INSERT INTO table opt_column_commalist values_or_query_spec
;
values_or_query_spec:
VALUES '(' insert_atom_commalist ')'
| query_spec
;
insert_atom_commalist:
insert_atom
| insert_atom_commalist ',' insert_atom
;
insert_atom:
atom
| NULLX
;
open_statement:
OPEN cursor
;
rollback_statement:
ROLLBACK WORK
;
select_statement:
SELECT opt_all_distinct selection
INTO target_commalist
table_exp
;
opt_all_distinct:
/* empty */
| ALL
| DISTINCT
;
update_statement_positioned:
UPDATE table SET assignment_commalist
WHERE CURRENT OF cursor
;
assignment_commalist:
| assignment
| assignment_commalist ',' assignment
;
assignment:
column '=' scalar_exp
| column '=' NULLX
;
update_statement_searched:
UPDATE table SET assignment_commalist opt_where_clause
;
target_commalist:
target
| target_commalist ',' target
;
target:
parameter_ref
;
opt_where_clause:
/* empty */
| where_clause
;
/* query expressions */
query_exp:
query_term
| query_exp UNION query_term
| query_exp UNION ALL query_term
;
query_term:
query_spec
| '(' query_exp ')'
;
query_spec:
SELECT opt_all_distinct selection table_exp
;
selection:
scalar_exp_commalist
| '*'
;
table_exp:
from_clause
opt_where_clause
opt_group_by_clause
opt_having_clause
;
from_clause:
FROM table_ref_commalist
;
table_ref_commalist:
table_ref
| table_ref_commalist ',' table_ref
;
table_ref:
table
| table range_variable
;
where_clause:
WHERE search_condition
;
opt_group_by_clause:
/* empty */
| GROUP BY column_ref_commalist
;
column_ref_commalist:
column_ref
| column_ref_commalist ',' column_ref
;
opt_having_clause:
/* empty */
| HAVING search_condition
;
/* search conditions */
search_condition:
| search_condition OR search_condition
| search_condition AND search_condition
| NOT search_condition
| '(' search_condition ')'
| predicate
;
predicate:
comparison_predicate
| between_predicate
| like_predicate
| test_for_null
| in_predicate
| all_or_any_predicate
| existence_test
;
comparison_predicate:
scalar_exp COMPARISON scalar_exp
| scalar_exp COMPARISON subquery
;
between_predicate:
scalar_exp NOT BETWEEN scalar_exp AND scalar_exp
| scalar_exp BETWEEN scalar_exp AND scalar_exp
;
like_predicate:
scalar_exp NOT LIKE atom opt_escape
| scalar_exp LIKE atom opt_escape
;
opt_escape:
/* empty */
| ESCAPE atom
;
test_for_null:
column_ref IS NOT NULLX
| column_ref IS NULLX
;
in_predicate:
scalar_exp NOT IN '(' subquery ')'
| scalar_exp IN '(' subquery ')'
| scalar_exp NOT IN '(' atom_commalist ')'
| scalar_exp IN '(' atom_commalist ')'
;
atom_commalist:
atom
| atom_commalist ',' atom
;
all_or_any_predicate:
scalar_exp COMPARISON any_all_some subquery
;
any_all_some:
ANY
| ALL
| SOME
;
existence_test:
EXISTS subquery
;
subquery:
'(' SELECT opt_all_distinct selection table_exp ')'
;
/* scalar expressions */
scalar_exp:
scalar_exp '+' scalar_exp
| scalar_exp '-' scalar_exp
| scalar_exp '*' scalar_exp
| scalar_exp '/' scalar_exp
| '+' scalar_exp %prec UMINUS
| '-' scalar_exp %prec UMINUS
| atom
| column_ref
| function_ref
| '(' scalar_exp ')'
;
scalar_exp_commalist:
scalar_exp
| scalar_exp_commalist ',' scalar_exp
;
atom:
parameter_ref
| literal
| USER
;
parameter_ref:
parameter
| parameter parameter
| parameter INDICATOR parameter
;
function_ref:
AMMSC '(' '*' ')'
| AMMSC '(' DISTINCT column_ref ')'
| AMMSC '(' ALL scalar_exp ')'
| AMMSC '(' scalar_exp ')'
;
literal:
STRING
| INTNUM
| APPROXNUM
;
/* miscellaneous */
table:
NAME
| NAME '.' NAME
;
column_ref:
NAME
| NAME '.' NAME /* needs semantics */
| NAME '.' NAME '.' NAME
;
/* data types */
data_type:
CHARACTER
| CHARACTER '(' INTNUM ')'
| NUMERIC
| NUMERIC '(' INTNUM ')'
| NUMERIC '(' INTNUM ',' INTNUM ')'
| DECIMAL
| DECIMAL '(' INTNUM ')'
| DECIMAL '(' INTNUM ',' INTNUM ')'
| INTEGER
| SMALLINT
| FLOAT
| FLOAT '(' INTNUM ')'
| REAL
| DOUBLE PRECISION
;
/* the various things you can name */
column: NAME
;
cursor: NAME
;
parameter:
PARAMETER /* :name handled in parser */
;
range_variable: NAME
;
user: NAME
;
/* embedded condition things */
sql: WHENEVER NOT FOUND when_action
| WHENEVER SQLERROR when_action
;
when_action: GOTO NAME
| CONTINUE
;
%%