use menhir
[sqlgg.git] / sql_parser.mly
blob659ab9bddc04045276e4de1f2a15ec87fb0740e4
1 /* 
2   $Id$
4   Simple SQL parser
5   TODO: simplify, it captures many unnecessary details
6 */
9 %{
10   open Printf
11   open Sql
12   open ListMore
13   open Stmt.Raw
14   open Operators
17 %token <int> INTEGER
18 %token <string> IDENT COMMENT
19 %token <Stmt.Raw.parameter> PARAM
20 %token LPAREN RPAREN COMMA EOF DOT
21 %token IGNORE REPLACE ABORT FAIL ROLLBACK
22 %token SELECT INSERT OR INTO CREATE_TABLE UPDATE TABLE VALUES WHERE FROM ASTERISK DISTINCT ALL 
23        LIMIT ORDER_BY DESC ASC EQUAL DELETE_FROM DEFAULT OFFSET SET JOIN LIKE_OP
24        EXCL TILDE NOT FUNCTION TEST_NULL BETWEEN AND ESCAPE
25 %token NOT_NULL UNIQUE PRIMARY_KEY AUTOINCREMENT ON_CONFLICT
26 %token PLUS MINUS DIVIDE PERCENT
27 %token T_INTEGER T_BLOB T_TEXT
29 %start input
30 %type <unit> input
34 input: statement EOF { $1 } ;
37 input: collection EOF { List.rev $1 } ;
39 collection: statement { [$1] }
40           | collection statement { $2::$1 } ;
43 statement: CREATE_TABLE IDENT LPAREN column_defs RPAREN
44               { Tables.add ($2,List.rev $4) }
45          | select_core maybe_order maybe_limit
46               { RA.Scheme.print $1 }
47          /*| insert_cmd IDENT LPAREN columns RPAREN VALUES
48               { Raw.Insert (Raw.Cols (List.rev $4)), $2, [] }
49          | insert_cmd IDENT VALUES
50               { Raw.Insert Raw.All, $2, [] }
51          | UPDATE IDENT SET set_columns maybe_where
52               { Raw.Update $4, $2, List.filter_valid [$5] }
53          | DELETE_FROM IDENT maybe_where
54               { Raw.Delete, $2, List.filter_valid [$3] }*/ ;
56 select_core: SELECT select_type results FROM table_list maybe_where 
57               { Syntax.resolve $3 $5 } ;
59 table_list: table { [$1] }
60           | table_list join_op table join_args { $3::$1 } ;
62 table: IDENT { Tables.get $1 } ;
63 join_op: COMMA { }
64        | JOIN { } ;
65 join_args: { } ;
67 insert_cmd: INSERT OR conflict_algo INTO {}
68           | INSERT INTO {}
69           | REPLACE INTO {} ;
71 update_cmd: UPDATE {}
72           | UPDATE OR conflict_algo {} ;
74 select_type: /* */  { }
75            | DISTINCT { }
76            | ALL { } ;
78 maybe_limit: LIMIT PARAM { [Some ("limit",Type.Int)] }
79            | LIMIT INTEGER { [None] }
80            | LIMIT PARAM COMMA PARAM { [Some ("offset",Type.Int); Some ("limit",Type.Int)] }
81            | LIMIT INTEGER COMMA PARAM { [Some ("limit",Type.Int)] }
82            | LIMIT PARAM COMMA INTEGER { [Some ("offset",Type.Int)] }
83            | LIMIT INTEGER COMMA INTEGER { [None] }
84            | LIMIT PARAM OFFSET PARAM { [Some ("limit",Type.Int); Some ("offset",Type.Int)] }
85            | LIMIT INTEGER OFFSET PARAM { [Some ("offset",Type.Int)] }
86            | LIMIT PARAM OFFSET INTEGER { [Some ("limit",Type.Int)] }
87            | LIMIT INTEGER OFFSET INTEGER { [None] }
88            | /* */ { [None] } ;
90 maybe_order: ORDER_BY IDENT order_type { }
91            | /* */ { } ;
93 order_type: DESC { }
94           | ASC { }
95           | /* */ { } ;
97 maybe_where: WHERE IDENT EQUAL PARAM { Some ($2,Type.Int) }
98            | /* */  { None } ;
100 results: columns { List.rev $1 } ;
102 columns: column1 { [$1] }
103        | columns COMMA column1 { $3::$1 } ;
105 column1: IDENT { One $1 }
106        | IDENT DOT IDENT { OneOf ($3,$1) }
107        | IDENT DOT ASTERISK { AllOf $1 }
108        | ASTERISK { All } ;
109 /*        | IDENT LPAREN IDENT RPAREN { $1 } ; */
111 column_defs: column_def1 { [$1] }
112            | column_defs COMMA column_def1 { $3::$1 } ;
114 column_def1: IDENT sql_type { RA.Scheme.attr $1 $2 }
115            | IDENT sql_type column_def_extra { RA.Scheme.attr $1 $2 } ;
117 column_def_extra: column_def_extra1 { [$1] }
118                 | column_def_extra column_def_extra1 { $2::$1 } ;
120 column_def_extra1: PRIMARY_KEY { Some Constraint.PrimaryKey }
121                  | NOT_NULL { Some Constraint.NotNull }
122                  | UNIQUE { Some Constraint.Unique }
123                  | AUTOINCREMENT { Some Constraint.Autoincrement }
124                  | ON_CONFLICT conflict_algo { Some (Constraint.OnConflict $2) } ;
125                  | DEFAULT INTEGER { None }
127 set_columns: set_columns1 { Raw.Cols (List.filter_valid (List.rev $1)) } ;
129 set_columns1: set_column { [$1] }
130            | set_columns1 COMMA set_column { $3::$1 } ;
132 set_column: IDENT EQUAL expr { match $3 with | 1 -> Some $1 | x -> assert (0=x); None } ;
135 expr:
136       expr binary_op expr { $1 @ $3 }
137     | expr LIKE_OP expr maybe_escape { $1 @ $3 @ $4 }
138     | unary_op expr { $2 }
139     | LPAREN expr RPAREN { $2 }
140     | IDENT { [] } 
141     | IDENT DOT IDENT { [] }
142     | IDENT DOT IDENT DOT IDENT { [] }
143     | INTEGER { [] }
144     | PARAM { [$1] }
145     | FUNCTION LPAREN func_params RPAREN { $3 } 
146     | expr TEST_NULL { $1 }
147     | expr BETWEEN expr AND expr { $1 @ $3 @ $5 }
149 expr_list_rev: expr { [$1] }
150              | expr_list_rev COMMA expr { $3::$1 } ;
151 expr_list: expr_list_rev { $1 >> List.rev >> List.flatten } ;
152 func_params: expr_list { $1 }
153            | ASTERISK { [] } ;
154 maybe_escape: { [] } 
155             | ESCAPE expr { $2 } ; 
156 binary_op: PLUS { }
157          | MINUS { }
158          | ASTERISK { }
159          | DIVIDE { } ;
160 unary_op: EXCL { }
161         | PLUS { }
162         | MINUS { }
163         | TILDE { }
164         | NOT { } ;
166 conflict_algo: IGNORE { Constraint.Ignore } 
167              | REPLACE { Constraint.Replace }
168              | ABORT { Constraint.Abort }
169              | FAIL { Constraint.Fail } 
170              | ROLLBACK { Constraint.Rollback } ;
172 sql_type: T_INTEGER  { Type.Int }
173         | T_BLOB { Type.Blob }
174         | T_TEXT { Type.Text } ;