bind params too
[sqlgg.git] / sql_parser.mly
blobce16feb03b0414d192b5765bac83aba63c3d4f67
1 /* 
2   Simple SQL parser
3 */
6 %{
7   open Printf
8   open Sql
9   open ListMore
10   open Stmt.Raw
11   open Syntax
12   open Operators
14   let def_param_name name (id,t) = 
15     let name =
16     match id with
17     | Next | Numbered _ -> name
18     | Named x -> x
19     in
20     (Named name,t)
24 %token <int> INTEGER
25 %token <string> IDENT
26 %token <Stmt.Raw.param_id> PARAM
27 %token LPAREN RPAREN COMMA EOF DOT
28 %token IGNORE REPLACE ABORT FAIL ROLLBACK
29 %token SELECT INSERT OR INTO CREATE_TABLE UPDATE TABLE VALUES WHERE FROM ASTERISK DISTINCT ALL 
30        LIMIT ORDER_BY DESC ASC EQUAL DELETE_FROM DEFAULT OFFSET SET JOIN LIKE_OP
31        EXCL TILDE NOT FUNCTION TEST_NULL BETWEEN AND ESCAPE USING COMPOUND_OP AS
32 %token NOT_NULL UNIQUE PRIMARY_KEY AUTOINCREMENT ON CONFLICT
33 %token PLUS MINUS DIVIDE PERCENT
34 %token T_INTEGER T_BLOB T_TEXT
36 %type <Syntax.expr> expr
37 %type <RA.Scheme.t * Stmt.Raw.params> select_core
39 %start <RA.Scheme.t * Stmt.Raw.params> input
43 input: statement EOF { $1 } ;
45 statement: CREATE_TABLE IDENT LPAREN column_defs RPAREN
46               { let () = Tables.add ($2,$4) in ([],[]) }
47          | select_stmt
48               { $1 }
49          /*| insert_cmd IDENT LPAREN columns RPAREN VALUES
50               { Raw.Insert (Raw.Cols (List.rev $4)), $2, [] }
51          | insert_cmd IDENT VALUES
52               { Raw.Insert Raw.All, $2, [] }
53          | UPDATE IDENT SET set_columns maybe_where
54               { Raw.Update $4, $2, List.filter_valid [$5] }
55          | DELETE_FROM IDENT maybe_where
56               { Raw.Delete, $2, List.filter_valid [$3] }*/ ;
58 select_stmt: select_core list(preceded(COMPOUND_OP,select_core)) o=loption(order) p4=loption(limit)
59               { let (s1,p1) = $1
60                 and (s2,p2) = List.split $2
61                 and p3 = Syntax.get_params_l o
62                 in
63                 List.fold_left RA.Scheme.compound s1 s2,(p1@(List.flatten p2)@p3@p4) }
65 select_core: SELECT select_type? r=separated_nonempty_list(COMMA,column1)
66              FROM t=table_list
67              w=option(where)
68               {
69                 let p1 = Syntax.params_of_columns r in
70                 let p3 = Syntax.get_params_opt w in
71                 let (tbls,p2) = t in
72                 (Syntax.get_scheme r tbls, p1 @ p2 @ p3) 
73               }
75 table_list: source join_source* { let (s,p) = List.split $2 in (fst $1::s, List.flatten (snd $1::p)) }
76 join_source: join_op s=source p=loption(join_args) { (fst s,snd s @ Syntax.get_params_l p) }
77 source: IDENT { Tables.get $1,[] }
78       | LPAREN s=select_core RPAREN { let (s,p) = s in ("",s),p }
79 join_op: COMMA | JOIN { } ;
80 join_args: ON e=expr { [e] }
81          | USING LPAREN l=separated_nonempty_list(COMMA,IDENT) RPAREN { List.map (fun name -> Column (name,None)) l }
83 insert_cmd: INSERT OR conflict_algo INTO {}
84           | INSERT INTO {}
85           | REPLACE INTO {} ;
87 update_cmd: UPDATE {}
88           | UPDATE OR conflict_algo {} ;
90 select_type: DISTINCT | ALL { }
92 int_or_param: INTEGER { [] }
93             | PARAM { [($1,Some Sql.Type.Int)] }
95 limit: LIMIT p=int_or_param { p }
96      | LIMIT p1=int_or_param COMMA p2=int_or_param { p1 @ p2 }
97      | LIMIT p1=int_or_param OFFSET p2=int_or_param { p1 @ p2 }
99 order: ORDER_BY l=separated_nonempty_list(COMMA,terminated(expr,order_type?)) { l }
100 order_type: DESC | ASC { }
102 where: WHERE e=expr { e }
104 column1:
105        | IDENT DOT ASTERISK { Syntax.AllOf $1 }
106        | ASTERISK { Syntax.All }
107        | expr maybe_as { let e = $1 in Syntax.Expr (e,$2) }
109 maybe_as: option(AS) name=IDENT { Some name }
110         | { None }
112 column_defs: separated_nonempty_list(COMMA,column_def1) { $1 }
113 column_def1: IDENT sql_type column_def_extra* { RA.attr $1 $2 } ;
114 column_def_extra: PRIMARY_KEY { Some Constraint.PrimaryKey }
115                 | NOT_NULL { Some Constraint.NotNull }
116                 | UNIQUE { Some Constraint.Unique }
117                 | AUTOINCREMENT { Some Constraint.Autoincrement }
118                 | ON CONFLICT conflict_algo { Some (Constraint.OnConflict $3) } ;
119                 | DEFAULT INTEGER { None }
122 set_columns: set_columns1 { Raw.Cols (List.filter_valid (List.rev $1)) } ;
124 set_columns1: set_column { [$1] }
125            | set_columns1 COMMA set_column { $3::$1 } ;
127 set_column: IDENT EQUAL expr { match $3 with | 1 -> Some $1 | x -> assert (0=x); None } ;
130 expr:
131       expr binary_op expr { Sub [$1;$3] }
132 (*     | expr LIKE_OP expr loption(escape) { $1 @ $3 @ $4 } *)
133 (*     | unary_op expr { $2 } *)
134     | LPAREN expr RPAREN { $2 }
135     | IDENT { Column ($1,None) }
136     | t=IDENT DOT c=IDENT
137     | IDENT DOT t=IDENT DOT c=IDENT { Column (c,Some t) }
138     | INTEGER { Value Sql.Type.Int }
139     | PARAM { Param ($1,None) }
140     | FUNCTION LPAREN func_params RPAREN { Sub $3 }
141 (*     | expr TEST_NULL { $1 } *)
142 (*     | expr BETWEEN expr AND expr { $1 @ $3 @ $5 } *)
144 expr_list: separated_nonempty_list(COMMA,expr) { $1 }
145 func_params: expr_list { $1 }
146            | ASTERISK { [] } ;
147 escape: ESCAPE expr { $2 }
148 binary_op: PLUS | MINUS | ASTERISK | DIVIDE | EQUAL { } 
150 unary_op: EXCL { }
151         | PLUS { }
152         | MINUS { }
153         | TILDE { }
154         | NOT { } ;
156 conflict_algo: IGNORE { Constraint.Ignore } 
157              | REPLACE { Constraint.Replace }
158              | ABORT { Constraint.Abort }
159              | FAIL { Constraint.Fail } 
160              | ROLLBACK { Constraint.Rollback } ;
162 sql_type: T_INTEGER  { Type.Int }
163         | T_BLOB { Type.Blob }
164         | T_TEXT { Type.Text } ;