Compare commits

..

No commits in common. "334cd6af9d0df50e4d5b38bed788b0f7cb036954" and "4a42d3496f0843b220215849057918fa6a88b320" have entirely different histories.

6 changed files with 183 additions and 417 deletions

View File

@ -1,4 +1,9 @@
open Ast
open Printf open Printf
let () = let () =
printf "hello" let input = "SELECT aa, ab FROM b1" in
let lexbuf = Lexing.from_string input in
match Parser.main Lexer.read_token lexbuf with
| Query(Select (Column("ab")::Column("aa")::[], [Table "b1"])) -> printf("ok")
| _ -> printf("not ok")

View File

@ -8,48 +8,44 @@ let alpha = ['a'-'z' 'A'-'Z' '_']
let alphanumeric = (alpha|digit) let alphanumeric = (alpha|digit)
rule read_token = parse rule read_token = parse
| "SELECT" { SELECT } | "SELECT" { SELECT }
| "AS" { AS } | "AVG" { AVG }
| "DATE" { DATE } | "MAX" { MAX }
| "TIME" { TIME } | "MIN" { MIN }
| "AVG" { AVG } | "SUM" { SUM }
| "MAX" { MAX } | "COUNT" { COUNT }
| "MIN" { MIN } | "DISTINCT" { DISTINCT }
| "SUM" { SUM } | "FROM" { FROM }
| "COUNT" { COUNT } | "INNER" { INNER }
| "DISTINCT" { DISTINCT } | "LEFT" { LEFT }
| "FROM" { FROM } | "RIGHT" { RIGHT }
| "INNER" { INNER } | "CROSS" { CROSS }
| "LEFT" { LEFT } | "UNION" { UNION }
| "RIGHT" { RIGHT } | "NATURAL" { NATURAL }
| "CROSS" { CROSS } | "JOIN" { JOIN }
| "UNION" { UNION } | "ON" { ON }
| "NATURAL" { NATURAL } | "OR" { OR }
| "JOIN" { JOIN } | "AND" { AND }
| "ON" { ON } | "WHERE" { WHERE }
| "OR" { OR } | "HAVING" { HAVING }
| "AND" { AND } | "BETWEEN" { BETWEEN }
| "WHERE" { WHERE } | "IN" { IN }
| "HAVING" { HAVING } | "LIKE" { LIKE }
| "BETWEEN" { BETWEEN } | "GROUP" { GROUP }
| "IN" { IN } | "BY" { BY }
| "LIKE" { LIKE } | "*" { ASTERISK }
| "GROUP" { GROUP } | "." { DOT }
| "BY" { BY } | "=" { EQUALS_OPERATOR }
| "*" { ASTERISK } | "(" { LEFT_PAREN }
| "." { DOT } | ")" { RIGHT_PAREN }
| "=" { EQUALS_OPERATOR } | "," { COMMA }
| "(" { LEFT_PAREN } | "|" { PIPE }
| ")" { RIGHT_PAREN } | "'" { QUOTE }
| ',' { COMMA } | "+" { PLUS_SIGN }
| "|" { PIPE } | "-" { MINUS_SIGN }
| "'" { QUOTE } | whitespace { read_token lexbuf }
| "+" { PLUS_SIGN } | digit+ { INTEGER }
| "-" { MINUS_SIGN } | digit+"."digit+ { FLOAT }
| ':' { COLON } | '.'digit+ { FLOAT }
| whitespace { read_token lexbuf } | alpha alphanumeric* as ident { IDENT ident }
| digit+ as integer { INTEGER (int_of_string integer) } | eof { EOF }
| digit+"."digit+ { FLOAT }
| '.'digit+ { FLOAT }
| alpha alphanumeric* as ident { IDENT ident }
| eof { EOF }

View File

@ -1,12 +1,9 @@
type query = Query of select_stmt type query = Query of select_stmt
and select_stmt = and select_stmt =
| Select of column list * table list option * filter option | Select of column list * table list * filter option
and column = and column =
| Asterisk | Asterisk
(* | Column of string *) | Column of string
| Column of expression * as_clause option
and as_clause =
| As of string
and table = and table =
| Table of string | Table of string
| Join of table * join_type * table * condition option | Join of table * join_type * table * condition option
@ -23,7 +20,8 @@ and condition =
| And of condition * condition | And of condition * condition
| Or of condition * condition | Or of condition * condition
| Not of condition | Not of condition
and predicand = expression and predicand =
| Ref of string
and predicate = and predicate =
| Comparison of operator * predicand | Comparison of operator * predicand
| Between of predicand * predicand | Between of predicand * predicand
@ -41,24 +39,8 @@ and operator =
| GreaterEquals | GreaterEquals
and filter = and filter =
| Filter of condition | Filter of condition
and aggregate = and search_condition =
| Aggregate of func * filter option | Search of string
and func =
| Function of function_type * quantifier option * expression
and function_type =
| Avg
| Max
| Min
| Sum
| Count
and quantifier =
| All
| Distinct
and expression =
| Ref of string
| StringLiteral of string
| DateLiteral of string
| TimeLiteral of string
let rec pp_query fmt ast = let rec pp_query fmt ast =
match ast with match ast with
@ -76,9 +58,8 @@ and pp_columns cols =
and pp_column col = and pp_column col =
match col with match col with
| Column(Ref(name),_) -> name | Column(name) -> name
| Asterisk -> "*" | Asterisk -> "*"
| _ -> failwith "not supported"
and pp_tables tables = and pp_tables tables =
match tables with match tables with

View File

@ -19,10 +19,9 @@ let rec generate_from_clause tables =
let generate_logical_plan ast = let generate_logical_plan ast =
match ast with match ast with
| Ast.Query(Select(_, Some(tables), _)) -> | Ast.Query(Select(_, tables, _)) ->
let base_plan = generate_from_clause tables in let base_plan = generate_from_clause tables in
base_plan base_plan
| Ast.Query(Select(_, None, _)) -> failwith "not supported"
(*let evaluate_plan plan = (*let evaluate_plan plan =
match plan with match plan with

View File

@ -19,11 +19,8 @@ open Ast
%token AS ON GROUP BY FILTER %token AS ON GROUP BY FILTER
%token OR AND NOT %token OR AND NOT
%token TRUE FALSE UNKNOWN %token TRUE FALSE UNKNOWN
%token PLUS_SIGN MINUS_SIGN %token PLUS_SIGN MINUS_SIGN INTEGER FLOAT
%token DATE TIME TIMESTAMP %token UNDERSCORE QUOTE
%token <int> INTEGER
%token FLOAT
%token UNDERSCORE QUOTE COLON
%token EOF %token EOF
%start main %start main
%type <query> main %type <query> main
@ -51,19 +48,18 @@ greater_than_or_equals_operator:
(* 5.3 LITERAL *) (* 5.3 LITERAL *)
literal : literal :
| signed_numeric_literal { $1 } | signed_numeric_literal {}
| general_literal { $1 } | general_literal {}
unsigned_literal: unsigned_literal:
(* | unsigned_numeric_literal {}*) (* | unsigned_numeric_literal {}*)
| general_literal { $1 } | general_literal {}
general_literal: general_literal:
| character_string_literal { $1 } | character_string_literal {}
| datetime_literal { $1 }
character_string_literal: character_string_literal:
| QUOTE IDENT QUOTE { StringLiteral($2) } | QUOTE IDENT QUOTE {}
introducer: introducer:
| UNDERSCORE { } | UNDERSCORE { }
@ -82,65 +78,12 @@ sign:
| PLUS_SIGN {} | PLUS_SIGN {}
| MINUS_SIGN {} | MINUS_SIGN {}
unsigned_integer:
| INTEGER { $1 }
datetime_literal:
| date_literal { $1 }
| time_literal { $1 }
(*| timestamp_literal {}*)
date_literal:
| DATE date_string { DateLiteral($2) }
time_literal:
| TIME time_string { TimeLiteral($2) }
date_string:
| QUOTE unquoted_date_string QUOTE { $2 }
time_string:
| QUOTE unquoted_time_string QUOTE { $2 }
date_value:
| years_value MINUS_SIGN months_value MINUS_SIGN days_value { String.concat "-" [$1;$3;$5] }
time_value:
| hours_value COLON minutes_value COLON seconds_value { String.concat ":" [$1;$3;$5] }
unquoted_date_string:
| date_value { $1 }
unquoted_time_string:
| time_value { $1 }
years_value :
| datetime_value { $1 }
months_value :
| datetime_value { $1 }
days_value :
| datetime_value { $1 }
hours_value :
| datetime_value { $1 }
minutes_value :
| datetime_value { $1 }
seconds_value:
| datetime_value { $1 }
datetime_value :
| unsigned_integer { string_of_int $1 }
(***********) (***********)
(* 5.4 NAMES AND IDENTIFIER *) (* 5.4 NAMES AND IDENTIFIER *)
column_name : column_name :
| IDENT { $1 } | IDENT {}
table_name : table_name :
| IDENT { Table($1) } | IDENT { Table($1) }
@ -167,7 +110,6 @@ parenthesized_value_expression:
| LEFT_PAREN value_expression RIGHT_PAREN { $2 } | LEFT_PAREN value_expression RIGHT_PAREN { $2 }
nonparenthesized_value_expression_primary: nonparenthesized_value_expression_primary:
| unsigned_value_specification { $1 }
| column_reference { Ref($1) } | column_reference { Ref($1) }
(*| set_function_specification { Ref("function") } *) (*| set_function_specification { Ref("function") } *)
@ -176,8 +118,8 @@ nonparenthesized_value_expression_primary:
(* 6.4 VALUE SPECIFCATION / TARGET SPECIFICATION *) (* 6.4 VALUE SPECIFCATION / TARGET SPECIFICATION *)
unsigned_value_specification: unsigned_value_specification:
| unsigned_literal { $1 } | unsigned_literal {}
(*| general_value_specification {}*) | general_value_specification {}
general_value_specification: general_value_specification:
| {} | {}
@ -213,7 +155,7 @@ set_function_specification:
(* 6.25 VALUE EXPRESSION *) (* 6.25 VALUE EXPRESSION *)
value_expression: value_expression:
| common_value_expression { $1 } | common_value_expression {}
common_value_expression: common_value_expression:
(*| numeric_value_expression {}*) (*| numeric_value_expression {}*)
@ -228,7 +170,7 @@ reference_value_expression:
(* 6.28 STRING VALUE EXPRESSION *) (* 6.28 STRING VALUE EXPRESSION *)
string_value_expression : string_value_expression :
| character_value_expression { $1 } | character_value_expression {}
(* | blob_value_expression {} *) (* | blob_value_expression {} *)
character_primary: character_primary:
@ -322,9 +264,8 @@ row_value_special_case :
(* 7.4 TABLE EXPRESSION *) (* 7.4 TABLE EXPRESSION *)
table_expression: table_expression:
| { None } | from_clause { $1 }
| from_clause { Some($1) } | from_clause where_clause { $1 }
| from_clause where_clause { Some($1) }
(************************) (************************)
@ -454,21 +395,15 @@ query_specification :
select_list : select_list :
| ASTERISK { [Asterisk] } | ASTERISK { [Asterisk] }
| select_sublist { $1 } | select_sublist {$1}
(*
select_sublist : select_sublist :
| IDENT { [Column($1)] } | IDENT { [Column($1)] }
| select_sublist COMMA IDENT { Column($3)::$1 } | select_sublist COMMA IDENT { Column($3)::$1 }
*)
select_sublist :
| select_sublist_element { [$1] }
| select_sublist COMMA select_sublist_element { $3::$1 }
select_sublist_element : select_sublist_element :
| derived_column { $1 } | derived_column {}
(* | qualified_asterisk {} *) | qualified_asterisk {}
qualified_asterisk: qualified_asterisk:
| asterisked_identifier_chain {} | asterisked_identifier_chain {}
@ -481,12 +416,12 @@ asterisked_identifier :
| IDENT {} | IDENT {}
derived_column: derived_column:
| value_expression { Column($1, None) } | value_expression {}
| value_expression as_clause { Column($1, Some($2)) } | value_expression as_clause {}
as_clause : as_clause :
| AS column_name { As($2) } | AS column_name {}
(*| column_name { As($1) }*) | column_name {}
(****************************) (****************************)
@ -602,31 +537,31 @@ search_condition:
(* 10.9 AGGREGATE FUNCTION *) (* 10.9 AGGREGATE FUNCTION *)
aggregate_function: aggregate_function:
| COUNT LEFT_PAREN ASTERISK RIGHT_PAREN { Count } | COUNT LEFT_PAREN ASTERISK RIGHT_PAREN { }
| COUNT LEFT_PAREN ASTERISK RIGHT_PAREN filter_clause { Count } | COUNT LEFT_PAREN ASTERISK RIGHT_PAREN filter_clause { }
| general_set_function { Aggregate($1) } | general_set_function { }
| general_set_function filter_clause { Aggregate($1, $2) } | general_set_function filter_clause { }
general_set_function: general_set_function:
| set_function_type LEFT_PAREN value_expression RIGHT_PAREN { Function($1, None, $3) } | set_function_type LEFT_PAREN value_expression RIGHT_PAREN { }
| 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 { }
set_function_type: set_function_type:
| computationnal_operation { $1 } | computationnal_operation {}
set_quantifier : set_quantifier :
| ALL { All } | ALL {}
| DISTINCT { Distinct } | DISTINCT {}
filter_clause : filter_clause :
| FILTER LEFT_PAREN WHERE search_condition RIGHT_PAREN { Filter($4) } | FILTER LEFT_PAREN WHERE search_condition RIGHT_PAREN {}
computationnal_operation: computationnal_operation:
| AVG { Avg } | AVG {}
| MAX { Max } | MAX {}
| MIN { Min } | MIN {}
| SUM { Sum } | SUM {}
| COUNT { Count } | COUNT {}
(***************************) (***************************)

View File

@ -11,164 +11,70 @@ let query_testable =
Alcotest.testable Ast.pp_query equal_ast Alcotest.testable Ast.pp_query equal_ast
let test_simple_select () = let test_simple_select () =
let query = "SELECT a FROM t" in let q1 = parse "SELECT a FROM t" in
let q1 = parse query in let ast1 = Query(Select([Column("a")], [Table("t")], None)) in
let ast1 = Query( Alcotest.(check query_testable) "Ok" q1 ast1;
Select(
[
Column(
Ref("a"),
None
)
],
Some(
[
Table("t")
]
),
None
)
) in
Alcotest.(check query_testable) query q1 ast1;
let query = "SELECT * FROM t" in
let q2 = parse query in
let ast2 = Query(
Select(
[
Asterisk
],
Some(
[
Table("t")
]
t ),
None
)
) in
Alcotest.(check query_testable) query q2 ast2 ;
let query = "SELECT 'a'" in let q2 = parse "SELECT * FROM t" in
let q3 = parse query in let ast2 = Query(Select([Asterisk], [Table("t")], None)) in
let ast3 = Query( Alcotest.(check query_testable) "Ok2" q2 ast2
Select(
[
Column(
StringLiteral("a"),
None
)
],
None,
None
)
) in
Alcotest.(check query_testable) query q3 ast3;
let q4 = parse "SELECT DATE '2024-12-25' AS date" in
let ast4 = Query(
Select(
[
Column(
DateLiteral("2024-12-25"),
Some(
As("date")
)
)
],
None,
None
)
) in
Alcotest.(check query_testable) "OK" q4 ast4
let test_default_join () = let test_default_join () =
let q1 = parse "SELECT a FROM t1 JOIN t2 ON b = c" in let q1 = parse "SELECT a FROM t1 JOIN t2 ON a = b" in
let ast1 = Query( let ast1 = Query(
Select( Select(
[ [Column("a")],
Column( [Join(
Table("t1"),
Left,
Table("t2"),
Some(
Condition(
Ref("a"), Ref("a"),
None Comparison(Equals, Ref("b"))
)
],
Some(
[
Join(
Table("t1"),
Left,
Table("t2"),
Some(
Condition(
Ref("b"),
Comparison(
Equals,
Ref("c"))
)
)
) )
] )
), )],
None None
) )
) in ) in
Alcotest.(check query_testable) "Ok" q1 ast1 Alcotest.(check query_testable) "Ok" q1 ast1
let test_left_join () = let test_left_join () =
let query = "SELECT a FROM t1 LEFT JOIN t2 ON a = b" in let q1 = parse "SELECT a FROM t1 LEFT JOIN t2 ON a = b" in
let q1 = parse query in
let ast1 = Query( let ast1 = Query(
Select( Select([Column("a")],
[ [Join(
Column( Table("t1"),
Ref("a"), Left,
None Table("t2"),
) Some(
], Condition(
Some( Ref("a"),
[ Comparison(Equals, Ref("b"))
Join(
Table("t1"),
Left,
Table("t2"),
Some(
Condition(
Ref("a"),
Comparison(Equals, Ref("b"))
)
)
) )
] )
), )],
None None
) )
) in ) in
Alcotest.(check query_testable) query q1 ast1 Alcotest.(check query_testable) "Ok" q1 ast1
let test_right_join () = let test_right_join () =
let q1 = parse "SELECT a FROM t1 RIGHT JOIN t2 ON a = b" in let q1 = parse "SELECT a FROM t1 RIGHT JOIN t2 ON a = b" in
let ast1 = Query( let ast1 = Query(
Select( Select([Column("a")],
[ [Join(
Column( Table("t1"),
Ref("a"), Right,
None Table("t2"),
) Some(
], Condition(
Some( Ref("a"),
[ Comparison(Equals, Ref("b"))
Join(
Table("t1"),
Right,
Table("t2"),
Some(
Condition(
Ref("a"),
Comparison(Equals, Ref("b"))
)
)
) )
] )
), )],
None None
) )
) in ) in
@ -177,28 +83,18 @@ let test_right_join () =
let test_inner_join () = let test_inner_join () =
let q1 = parse "SELECT a FROM t1 INNER JOIN t2 ON a = b" in let q1 = parse "SELECT a FROM t1 INNER JOIN t2 ON a = b" in
let ast1 = Query( let ast1 = Query(
Select( Select([Column("a")],
[ [Join(
Column( Table("t1"),
Ref("a"), Inner,
None Table("t2"),
) Some(
], Condition(
Some( Ref("a"),
[ Comparison(Equals, Ref("b"))
Join(
Table("t1"),
Inner,
Table("t2"),
Some(
Condition(
Ref("a"),
Comparison(Equals, Ref("b"))
)
)
) )
] )
), )],
None None
) )
) in ) in
@ -207,23 +103,13 @@ let test_inner_join () =
let test_union_join () = let test_union_join () =
let q1 = parse "SELECT a FROM t1 UNION JOIN t2" in let q1 = parse "SELECT a FROM t1 UNION JOIN t2" in
let ast1 = Query( let ast1 = Query(
Select( Select([Column("a")],
[ [Join(
Column( Table("t1"),
Ref("a"), Union,
None Table("t2"),
) None
], )],
Some(
[
Join(
Table("t1"),
Union,
Table("t2"),
None
)
]
),
None None
) )
) in ) in
@ -232,23 +118,13 @@ let test_union_join () =
let test_cross_join () = let test_cross_join () =
let q1 = parse "SELECT a FROM t1 CROSS JOIN t2" in let q1 = parse "SELECT a FROM t1 CROSS JOIN t2" in
let ast1 = Query( let ast1 = Query(
Select( Select([Column("a")],
[ [Join(
Column( Table("t1"),
Ref("a"), Cross,
None Table("t2"),
) None
], )],
Some(
[
Join(
Table("t1"),
Cross,
Table("t2"),
None
)
]
),
None None
) )
) in ) in
@ -257,23 +133,13 @@ let test_cross_join () =
let test_natural_join () = let test_natural_join () =
let q1 = parse "SELECT a FROM t1 NATURAL JOIN t2" in let q1 = parse "SELECT a FROM t1 NATURAL JOIN t2" in
let ast1 = Query( let ast1 = Query(
Select( Select([Column("a")],
[ [Join(
Column( Table("t1"),
Ref("a"), Natural,
None Table("t2"),
) None
], )],
Some(
[
Join(
Table("t1"),
Natural,
Table("t2"),
None
)
]
),
None None
) )
) in ) in
@ -282,37 +148,30 @@ let test_natural_join () =
let test_join_join () = let test_join_join () =
let q1 = parse "SELECT a FROM t1 JOIN t2 ON a = b JOIN t3 ON a = c" in let q1 = parse "SELECT a FROM t1 JOIN t2 ON a = b JOIN t3 ON a = c" in
let ast1 = Query( let ast1 = Query(
Select( Select([Column("a")], [
[ Join(
Column(
Ref("a"),
None
)
],
Some([
Join( Join(
Join( Table("t1"),
Table("t1"), Left,
Left, Table("t2"),
Table("t2"),
Some(
Condition(
Ref("a"),
Comparison(Equals, Ref("b"))
)
)
),
Left,
Table("t3"),
Some( Some(
Condition( Condition(
Ref("a"), Ref("a"),
Comparison(Equals, Ref("c")) Comparison(Equals, Ref("b"))
) )
)
),
Left,
Table("t3"),
Some(
Condition(
Ref("a"),
Comparison(Equals, Ref("c"))
) )
) )
]), )
None ],
None
) )
) in ) in
Alcotest.(check query_testable) "Ok" q1 ast1 Alcotest.(check query_testable) "Ok" q1 ast1
@ -321,17 +180,8 @@ let test_where_equals () =
let q1 = parse "SELECT a FROM t1 WHERE a = a OR a = b" in let q1 = parse "SELECT a FROM t1 WHERE a = a OR a = b" in
let ast1 = Query( let ast1 = Query(
Select( Select(
[ [Column("a")],
Column( [Table("t1")],
Ref("a"),
None
)
],
Some(
[
Table("t1")
]
),
None None
) )
) in ) in