This commit is contained in:
simon petit 2024-12-11 16:52:19 +00:00
parent 827a7fd1d3
commit b01c50654c
3 changed files with 348 additions and 226 deletions

View File

@ -1,12 +1,18 @@
type query = Query of select_stmt
and select_stmt =
| Select of column list * table list option * filter option
type query =
(*| Select of column list * table list option * filter option*)
| Select of column list * table_expression
| CreateSchema of string
| CreateTable of table
| DropSchema of string
| DropTable of table
and column =
| Asterisk
(* | Column of string *)
| Column of expression * as_clause option
and as_clause =
| As of string
and table_expression =
| TableExpression of table list option * filter option * group option
and table =
| Table of string
| Join of table * join_type * table * condition option
@ -30,8 +36,8 @@ and predicate =
| NotBetween of predicand * predicand
| In of predicand list
| NotIn of predicand list
| Like of string
| NotLike of string
| Like of predicand
| NotLike of predicand
and operator =
| Equals
| NotEquals
@ -39,8 +45,9 @@ and operator =
| GreaterThan
| LessEquals
| GreaterEquals
and filter =
| Filter of condition
and filter = condition
and group =
| Group of quantifier option * expression list option
and aggregate =
| Aggregate of func * filter option
and func =
@ -62,31 +69,41 @@ and expression =
let rec pp_query fmt ast =
match ast with
| Query(s) -> Format.fprintf fmt "%s" (pp_select s)
and pp_select s =
match s with
| Select(cols, _, _) -> String.cat "SELECT " (pp_columns cols)
| Select(cols, table_exp) -> Format.fprintf fmt "%s" (String.cat "SELECT " (pp_columns cols) ^ pp_table_expression table_exp)
| _ -> failwith "not yet supported"
and pp_columns cols =
match cols with
| [] -> ""
| [col] -> pp_column col
| col::l -> pp_column col ^ ";" ^ pp_columns l
| col::l -> pp_column col ^ ", " ^ pp_columns l
and pp_column col =
match col with
| Column(Ref(name),_) -> name
| Column(StringLiteral(name),_) -> "'"^name^"'"
| Column(DateLiteral(name),_) -> "'"^name^"'"
| Column(exp,_) -> pp_expression exp
| Asterisk -> "*"
| _ -> failwith "Pretty parsing of Column not supported"
and pp_expression exp =
match exp with
| Ref(name) -> name
| StringLiteral(name) -> "'"^name^"'"
| DateLiteral(name) -> "'"^name^"'"
| TimeLiteral(name) -> "'"^name^"'"
and pp_table_expression table_exp =
match table_exp with
| TableExpression(tables, filter, _) -> pp_tables tables ^ pp_filter filter
and pp_tables tables =
match tables with
let rec aux t =
match t with
| [] -> ""
| [table] -> pp_table table
| table::l -> pp_table table ^ ";" ^ pp_tables l
| table::[] -> pp_table table
| table::l -> pp_table table ^ ", " ^ aux l
in
match tables with
| None -> ""
| Some(t) -> " FROM " ^ aux t
and pp_table table =
match table with
@ -103,3 +120,32 @@ and pp_join_type j =
| Union -> "union"
| Natural -> "natural"
and pp_filter filter =
let rec aux f =
match f with
| Condition(exp, pred) -> pp_expression exp ^ " " ^ pp_predicate pred
| And(c1, c2) -> aux c1 ^ " AND " ^ aux c2
| Or(c1, c2) -> aux c1 ^ " OR " ^ aux c2
| Not(c) -> "NOT" ^ aux c
in
match filter with
| None -> ""
| Some(f) -> " WHERE " ^ aux f
and pp_predicate pred =
match pred with
| Comparison(op, exp) -> pp_operator op ^ pp_expression exp
| Between(exp1, exp2) -> "BETWEEN " ^ pp_expression exp1 ^ " AND " ^pp_expression exp2
| NotBetween(exp1, exp2) -> "NOT BETWEEN " ^ pp_expression exp1 ^ " AND " ^pp_expression exp2
| Like(exp) -> "LIKE " ^ pp_expression exp
| NotLike(exp) -> " NOT LIKE " ^ pp_expression exp
| _ -> failwith "Predicate not supported"
and pp_operator op =
match op with
| Equals -> "="
| NotEquals -> "!="
| LessThan -> "<"
| GreaterThan -> ">"
| LessEquals -> "<="
| GreaterEquals -> ">="

View File

@ -31,7 +31,11 @@ open Ast
%%
main:
| query_specification EOF { Query($1) }
| query_specification EOF { $1 }
| schema_definition EOF { $1 }
| table_definition EOF { $1 }
| drop_schema_statement EOF { $1 }
| drop_table_statement EOF { $1 }
(* 5.2 TOKEN / SEPARATOR *)
@ -146,7 +150,7 @@ table_name :
| IDENT { Table($1) }
schema_name:
| IDENT {}
| IDENT { $1 }
(****************************)
@ -169,7 +173,7 @@ parenthesized_value_expression:
nonparenthesized_value_expression_primary:
| unsigned_value_specification { $1 }
| column_reference { Ref($1) }
(*| set_function_specification { Ref("function") } *)
| set_function_specification { Ref("function") }
(***************************)
@ -279,14 +283,14 @@ truth_value:
boolean_primary :
| predicate { $1 }
(*| boolean_predicand {}*)
| boolean_predicand { $1 }
boolean_predicand:
| parenthesized_boolean_value_expression {}
| nonparenthesized_value_expression_primary {}
| parenthesized_boolean_value_expression { $1 }
(* | nonparenthesized_value_expression_primary { $1 }*)
parenthesized_boolean_value_expression:
| LEFT_PAREN boolean_value_expression RIGHT_PAREN {}
| LEFT_PAREN boolean_value_expression RIGHT_PAREN { $2 }
(****************************)
@ -322,9 +326,15 @@ row_value_special_case :
(* 7.4 TABLE EXPRESSION *)
table_expression:
| { None }
| from_clause { Some($1) }
| from_clause where_clause { Some($1) }
| { TableExpression(None, None, None) }
| from_clause { TableExpression(Some($1), None, None) }
| from_clause where_clause { TableExpression(Some($1), Some($2), None) }
| from_clause where_clause group_by_clause { TableExpression(Some($1), Some($2), Some($3)) }
(* | from_clause where_clause group_by_clause having_clause { Some($1) }
| from_clause group_by_clause { Some($1) }
| from_clause group_by_clause having_clause { Some($1) }
| from_clause having_clause { Some($1) }
*)
(************************)
@ -369,8 +379,8 @@ cross_join:
| table_reference CROSS JOIN table_primary { Join($1, Cross, $4, None) }
qualified_join:
| table_reference JOIN table_reference join_specification { Join($1, Left, $3, $4) }
| table_reference join_type JOIN table_reference join_specification { Join($1, $2, $4, $5) }
| table_reference JOIN table_reference join_specification { Join($1, Left, $3, Some($4)) }
| table_reference join_type JOIN table_reference join_specification { Join($1, $2, $4, Some($5)) }
natural_join:
| table_reference NATURAL JOIN table_primary { Join($1, Natural, $4, None) }
@ -384,7 +394,7 @@ join_specification:
(* | named_columns_join {} *)
join_condition:
| ON search_condition { Some($2) }
| ON search_condition { $2 }
join_type:
| INNER { Inner }
@ -416,23 +426,27 @@ where_clause :
(* 7.9 GROUP BY CLAUSE *)
group_by_clause:
| GROUP BY grouping_element_list {}
| GROUP BY set_quantifier grouping_element_list {}
| GROUP BY grouping_element_list { Group(None, Some($3)) }
| GROUP BY set_quantifier grouping_element_list { Group(Some($3), Some($4)) }
grouping_element_list :
| grouping_element {}
| grouping_element_list COMMA grouping_element_list {}
| grouping_element { [$1] }
| grouping_element_list COMMA grouping_element { $3::$1 }
grouping_element:
| ordinary_grouping_set {}
| ordinary_grouping_set { $1 }
ordinary_grouping_set :
| grouping_column_reference {}
| grouping_column_reference { $1 }
(*| LEFT_PAREN grouping_column_reference_list RIGHT_PAREN { $2 }*)
grouping_column_reference:
| column_reference {}
| column_reference { Ref($1) }
(*| column_reference collate_clause {}*)
(*
grouping_column_reference_list :
| grouping_column_reference { [
*)
(***********************)
(* 7.10 HAVING CLAUSE *)
@ -449,8 +463,8 @@ having_clause :
(* 7.12 QUERY SPECIFICATION *)
query_specification :
| SELECT select_list table_expression { Select($2, $3, None) }
| SELECT set_quantifier select_list table_expression { Select($3, $4, None) }
| SELECT select_list table_expression { Select($2, $3) }
| SELECT set_quantifier select_list table_expression { Select($3, $4) }
select_list :
| ASTERISK { [Asterisk] }
@ -510,8 +524,8 @@ as_clause :
predicate :
| comparison_predicate { $1 }
| in_predicate { $1 }
(* | between_predicate { $1 } *)
(* | like_predicate { $1 }*)
| between_predicate { $1 }
| like_predicate { $1 }
(*****************)
@ -602,14 +616,14 @@ search_condition:
(* 10.9 AGGREGATE FUNCTION *)
aggregate_function:
| COUNT LEFT_PAREN ASTERISK RIGHT_PAREN { Count }
| COUNT LEFT_PAREN ASTERISK RIGHT_PAREN filter_clause { Count }
| general_set_function { Aggregate($1) }
| general_set_function filter_clause { Aggregate($1, $2) }
| COUNT LEFT_PAREN ASTERISK RIGHT_PAREN { Aggregate(Function(Count, None, Ref("*")), None) }
| COUNT LEFT_PAREN ASTERISK RIGHT_PAREN filter_clause { Aggregate(Function(Count, None, Ref("*")), Some($5)) }
| general_set_function { Aggregate($1, None) }
| general_set_function filter_clause { Aggregate($1, Some($2)) }
general_set_function:
| set_function_type LEFT_PAREN value_expression RIGHT_PAREN { Function($1, None, $3) }
| set_function_type LEFT_PAREN set_quantifier value_expression RIGHT_PAREN { Function($1, $3, $4) }
| set_function_type LEFT_PAREN set_quantifier value_expression RIGHT_PAREN { Function($1, Some($3), $4) }
set_function_type:
| computationnal_operation { $1 }
@ -619,7 +633,7 @@ set_quantifier :
| DISTINCT { Distinct }
filter_clause :
| FILTER LEFT_PAREN WHERE search_condition RIGHT_PAREN { Filter($4) }
| FILTER LEFT_PAREN WHERE search_condition RIGHT_PAREN { $4 }
computationnal_operation:
| AVG { Avg }
@ -635,24 +649,24 @@ computationnal_operation:
(* 11.1 SCHEMA DEFINITION *)
schema_definition:
| CREATE SCHEMA schema_name_clause {}
| CREATE SCHEMA schema_name_clause { CreateSchema($3) }
schema_name_clause :
| schema_name {}
| schema_name { $1 }
(**************************)
(* 11.2 DROP SCHEMA STATEMENT *)
drop_schema_statement:
| DROP SCHEMA schema_name {}
| DROP SCHEMA schema_name { DropSchema($3) }
(******************************)
(* 11.3 TABLE DEFINITION *)
table_definition :
| CREATE TABLE table_name {}
| CREATE TABLE table_name { CreateTable($3) }
table_scope :
| global_or_local TEMPORARY {}
@ -674,7 +688,7 @@ drop_column_definition:
(* 11.21 DROP TABLE STATEMENT *)
drop_table_statement:
| DROP TABLE table_name {}
| DROP TABLE table_name { DropTable($3) }
(******************************)

View File

@ -13,7 +13,7 @@ let query_testable =
let test_simple_select () =
let query = "SELECT a, b FROM t" in
let q1 = parse query in
let ast1 = Query(
let ast1 =
Select(
[
Column(
@ -25,36 +25,42 @@ let test_simple_select () =
None
)
],
TableExpression(
Some(
[
Table("t")
]
),
None,
None
)
) in
)
in
Alcotest.(check query_testable) query q1 ast1;
let query = "SELECT * FROM t" in
let q2 = parse query in
let ast2 = Query(
let ast2 =
Select(
[
Asterisk
],
TableExpression(
Some(
[
Table("t")
]
),
None,
None
)
) in
)
in
Alcotest.(check query_testable) query q2 ast2 ;
let query = "SELECT 'b', 'a', DATE '2024-12-25' AS date" in
let q3 = parse query in
let ast3 = Query(
let ast3 =
Select(
[
Column(
@ -72,15 +78,18 @@ let test_simple_select () =
None
)
],
TableExpression(
None,
None,
None
)
) in
)
in
Alcotest.(check query_testable) query q3 ast3
let test_default_join () =
let q1 = parse "SELECT a FROM t1 JOIN t2 ON b = c" in
let ast1 = Query(
let ast1 =
Select(
[
Column(
@ -88,6 +97,7 @@ let test_default_join () =
None
)
],
TableExpression(
Some(
[
Join(
@ -99,21 +109,24 @@ let test_default_join () =
Ref("b"),
Comparison(
Equals,
Ref("c"))
Ref("c")
)
)
)
)
]
),
None,
None
)
) in
)
in
Alcotest.(check query_testable) "Ok" q1 ast1
let test_left_join () =
let query = "SELECT a FROM t1 LEFT JOIN t2 ON a = b" in
let q1 = parse query in
let ast1 = Query(
let ast1 =
Select(
[
Column(
@ -121,6 +134,7 @@ let test_left_join () =
None
)
],
TableExpression(
Some(
[
Join(
@ -136,14 +150,16 @@ let test_left_join () =
)
]
),
None,
None
)
) in
)
in
Alcotest.(check query_testable) query q1 ast1
let test_right_join () =
let q1 = parse "SELECT a FROM t1 RIGHT JOIN t2 ON a = b" in
let ast1 = Query(
let ast1 =
Select(
[
Column(
@ -151,6 +167,7 @@ let test_right_join () =
None
)
],
TableExpression(
Some(
[
Join(
@ -166,14 +183,17 @@ let test_right_join () =
)
]
),
None,
None
)
) in
)
in
Alcotest.(check query_testable) "Ok" q1 ast1
let test_inner_join () =
let q1 = parse "SELECT a FROM t1 INNER JOIN t2 ON a = b" in
let ast1 = Query(
let query = "SELECT a FROM t1 INNER JOIN t2 ON a = b" in
let q1 = parse query in
let ast1 =
Select(
[
Column(
@ -181,6 +201,7 @@ let test_inner_join () =
None
)
],
TableExpression(
Some(
[
Join(
@ -196,14 +217,17 @@ let test_inner_join () =
)
]
),
None,
None
)
) in
Alcotest.(check query_testable) "Ok" q1 ast1
)
in
Alcotest.(check query_testable) query q1 ast1
let test_union_join () =
let q1 = parse "SELECT a FROM t1 UNION JOIN t2" in
let ast1 = Query(
let query = "SELECT a FROM t1 UNION JOIN t2" in
let q1 = parse query in
let ast1 =
Select(
[
Column(
@ -211,6 +235,7 @@ let test_union_join () =
None
)
],
TableExpression(
Some(
[
Join(
@ -221,14 +246,17 @@ let test_union_join () =
)
]
),
None,
None
)
) in
Alcotest.(check query_testable) "Ok" q1 ast1
)
in
Alcotest.(check query_testable) query q1 ast1
let test_cross_join () =
let q1 = parse "SELECT a FROM t1 CROSS JOIN t2" in
let ast1 = Query(
let query = "SELECT a FROM t1 CROSS JOIN t2" in
let q1 = parse query in
let ast1 =
Select(
[
Column(
@ -236,6 +264,7 @@ let test_cross_join () =
None
)
],
TableExpression(
Some(
[
Join(
@ -246,14 +275,17 @@ let test_cross_join () =
)
]
),
None,
None
)
) in
Alcotest.(check query_testable) "Ok" q1 ast1
)
in
Alcotest.(check query_testable) query q1 ast1
let test_natural_join () =
let q1 = parse "SELECT a FROM t1 NATURAL JOIN t2" in
let ast1 = Query(
let query = "SELECT a FROM t1 NATURAL JOIN t2" in
let q1 = parse query in
let ast1 =
Select(
[
Column(
@ -261,6 +293,7 @@ let test_natural_join () =
None
)
],
TableExpression(
Some(
[
Join(
@ -271,14 +304,17 @@ let test_natural_join () =
)
]
),
None,
None
)
) in
Alcotest.(check query_testable) "Ok" q1 ast1
)
in
Alcotest.(check query_testable) query q1 ast1
let test_join_join () =
let q1 = parse "SELECT a FROM t1 JOIN t2 ON a = b JOIN t3 ON a = c" in
let ast1 = Query(
let query = "SELECT a FROM t1 JOIN t2 ON a = b JOIN t3 ON a = c" in
let q1 = parse query in
let ast1 =
Select(
[
Column(
@ -286,7 +322,9 @@ let test_join_join () =
None
)
],
Some([
TableExpression(
Some(
[
Join(
Join(
Table("t1"),
@ -308,15 +346,19 @@ let test_join_join () =
)
)
)
]),
]
),
None,
None
)
) in
Alcotest.(check query_testable) "Ok" q1 ast1
)
in
Alcotest.(check query_testable) query q1 ast1
let test_where_equals () =
let q1 = parse "SELECT a FROM t1 WHERE a = a OR a = b" in
let ast1 = Query(
let query = "SELECT a FROM t1 WHERE a = a OR a = b" in
let q1 = parse query in
let ast1 =
Select(
[
Column(
@ -324,15 +366,35 @@ let test_where_equals () =
None
)
],
TableExpression(
Some(
[
Table("t1")
]
),
Some(
Or(
Condition(
Ref("a"),
Comparison(
Equals,
Ref("a")
)
),
Condition(
Ref("a"),
Comparison(
Equals,
Ref("b")
)
)
)
),
None
)
) in
Alcotest.(check query_testable) "Ok" q1 ast1
)
in
Alcotest.(check query_testable) query q1 ast1
(*
let test_aggregtes () =