14 let def_param_name name (id,t) =
17 | Next | Numbered _ -> name
25 %token <string> IDENT TEXT BLOB
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
33 %token NOT_NULL UNIQUE PRIMARY_KEY AUTOINCREMENT ON CONFLICT
34 %token PLUS MINUS DIVIDE PERCENT
35 %token T_INTEGER T_BLOB T_TEXT
37 %type <Syntax.expr> expr
38 %type <RA.Scheme.t * Stmt.Raw.params> select_core
40 %start <RA.Scheme.t * Stmt.Raw.params * Stmt.Raw.kind> input
44 input: statement EOF { $1 } ;
46 statement: CREATE_TABLE name=IDENT LPAREN scheme=column_defs RPAREN
47 { let () = Tables.add (name,scheme) in ([],[],Create) }
49 { let (s,p) = $1 in s,p,Select }
50 | insert_cmd t=IDENT LPAREN cols=separated_nonempty_list(COMMA,IDENT) RPAREN VALUES
51 { let p = RA.Scheme.project cols (Tables.get_scheme t) >> Syntax.scheme_as_params in
53 | insert_cmd t=IDENT VALUES
54 { let p = Tables.get_scheme t >> Syntax.scheme_as_params in
56 | UPDATE table=IDENT SET assignments=separated_nonempty_list(COMMA,set_column) w=option(where)
58 let p2 = get_params_opt w in
59 let (cols,exprs) = List.split assignments in
60 let _ = RA.Scheme.project cols (Tables.get_scheme table) in (* validates columns *)
61 let p1 = Syntax.get_params_l exprs in
64 /*| DELETE_FROM IDENT maybe_where
65 { Raw.Delete, $2, List.filter_valid [$3] }*/ ;
67 select_stmt: select_core list(preceded(COMPOUND_OP,select_core)) o=loption(order) p4=loption(limit)
69 and (s2,p2) = List.split $2
70 and p3 = Syntax.get_params_l o
72 List.fold_left RA.Scheme.compound s1 s2,(p1@(List.flatten p2)@p3@p4) }
74 select_core: SELECT select_type? r=separated_nonempty_list(COMMA,column1)
78 let p1 = Syntax.params_of_columns r in
79 let p3 = Syntax.get_params_opt w in
81 (Syntax.get_scheme r tbls, p1 @ p2 @ p3)
84 table_list: source join_source* { let (s,p) = List.split $2 in (fst $1::s, List.flatten (snd $1::p)) }
85 join_source: join_op s=source p=loption(join_args) { (fst s,snd s @ Syntax.get_params_l p) }
86 source: IDENT { Tables.get $1,[] }
87 | LPAREN s=select_core RPAREN { let (s,p) = s in ("",s),p }
88 join_op: COMMA | JOIN { } ;
89 join_args: ON e=expr { [e] }
90 | USING LPAREN l=separated_nonempty_list(COMMA,IDENT) RPAREN { List.map (fun name -> Column (name,None)) l }
92 insert_cmd: INSERT OR conflict_algo INTO | INSERT INTO | REPLACE INTO { }
95 | UPDATE OR conflict_algo {} ;
97 select_type: DISTINCT | ALL { }
99 int_or_param: INTEGER { [] }
100 | PARAM { [($1,Some Sql.Type.Int)] }
102 limit: LIMIT p=int_or_param { p }
103 | LIMIT p1=int_or_param COMMA p2=int_or_param { p1 @ p2 }
104 | LIMIT p1=int_or_param OFFSET p2=int_or_param { p1 @ p2 }
106 order: ORDER_BY l=separated_nonempty_list(COMMA,terminated(expr,order_type?)) { l }
107 order_type: DESC | ASC { }
109 where: WHERE e=expr { e }
112 | IDENT DOT ASTERISK { Syntax.AllOf $1 }
113 | ASTERISK { Syntax.All }
114 | expr maybe_as { let e = $1 in Syntax.Expr (e,$2) }
116 maybe_as: option(AS) name=IDENT { Some name }
119 column_defs: separated_nonempty_list(COMMA,column_def1) { $1 }
120 column_def1: IDENT sql_type column_def_extra* { RA.attr $1 $2 } ;
121 column_def_extra: PRIMARY_KEY { Some Constraint.PrimaryKey }
122 | NOT_NULL { Some Constraint.NotNull }
123 | UNIQUE { Some Constraint.Unique }
124 | AUTOINCREMENT { Some Constraint.Autoincrement }
125 | ON CONFLICT conflict_algo { Some (Constraint.OnConflict $3) } ;
126 | DEFAULT INTEGER { None }
128 set_column: name=IDENT EQUAL e=expr { name,e }
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 | TEXT { Value Sql.Type.Text }
140 | BLOB { Value Sql.Type.Blob }
141 | PARAM { Param ($1,None) }
142 | FUNCTION LPAREN func_params RPAREN { Sub $3 }
143 (* | expr TEST_NULL { $1 } *)
144 (* | expr BETWEEN expr AND expr { $1 @ $3 @ $5 } *)
146 expr_list: separated_nonempty_list(COMMA,expr) { $1 }
147 func_params: expr_list { $1 }
149 escape: ESCAPE expr { $2 }
150 binary_op: PLUS | MINUS | ASTERISK | DIVIDE | EQUAL | CONCAT_OP { }
158 conflict_algo: IGNORE { Constraint.Ignore }
159 | REPLACE { Constraint.Replace }
160 | ABORT { Constraint.Abort }
161 | FAIL { Constraint.Fail }
162 | ROLLBACK { Constraint.Rollback } ;
164 sql_type: T_INTEGER { Type.Int }
165 | T_BLOB { Type.Blob }
166 | T_TEXT { Type.Text } ;