Current section
Files
Jump to
Current section
Files
src/parser.yrl
%%====================================================================
%% Nonterminals
%%====================================================================
Nonterminals
query
statement
admin
%show
show_query
%select
select_query projection select_fields
%join
join_clauses join_clause
%where
where_clauses where_clause comparison
%insert
insert_query insert_keys_clause insert_keys insert_values_clause insert_values
%delete
delete_query
%create
create_query create_keys attribute attribute_constraint create_index_keys check_comparator
attribute_name
%update
update_query set_clause set_assignments set_assignment
%txs
begin_transaction commit_transaction rollback_transaction
%utils
value atom number_unwrap
%quit program
quit_program
.
%%====================================================================
%% Terminals
%%====================================================================
Terminals
%show
show tables
%index
index indexes on
%select
select wildcard from
%join
join
%where
where
%comparison
equality notequality greater lesser greatereq lessereq
%insert
insert into values
%delete
delete
%create
create table partition crp primary foreign key references default check
attribute_type attribute_encryption_type cascade
%update
update set
%tx
begin commit rollback transaction
%types
atom_value string number boolean
%expression
plus minus conjunctive disjunctive
%list
sep start_list end_list semi_colon
%quit
quit
.
%%====================================================================
%% Rootsymbol
%%====================================================================
Rootsymbol query.
%%====================================================================
%% Rules
%%====================================================================
query -> statement : '$1'.
statement -> statement semi_colon statement : lists:append('$1', '$3').
statement -> statement semi_colon : '$1'.
statement -> admin : '$1'.
statement -> select_query : ['$1'].
statement -> insert_query : ['$1'].
statement -> delete_query : ['$1'].
statement -> update_query : ['$1'].
statement -> create_query : ['$1'].
statement -> begin_transaction : ['$1'].
statement -> commit_transaction : ['$1'].
statement -> rollback_transaction : ['$1'].
statement -> quit_program : ['$1'].
comparison -> equality : '$1'.
comparison -> notequality : '$1'.
comparison -> greater : '$1'.
comparison -> lesser : '$1'.
comparison -> greatereq : '$1'.
comparison -> lessereq : '$1'.
admin -> show_query : ['$1'].
%%--------------------------------------------------------------------
%% show
%%--------------------------------------------------------------------
show_query ->
show index from atom :
?SHOW_CLAUSE({?INDEX_TOKEN, '$4'}).
show_query ->
show index atom from atom :
?SHOW_CLAUSE({?INDEX_TOKEN, '$3', '$5'}).
show_query ->
show indexes from atom :
?SHOW_CLAUSE({?INDEXES_TOKEN, '$4'}).
show_query ->
show tables :
?SHOW_CLAUSE(?TABLES_TOKEN).
%%--------------------------------------------------------------------
%% select query
%%--------------------------------------------------------------------
select_query ->
select projection from atom :
?SELECT_CLAUSE({'$4', '$2', ?PARSER_WILDCARD}).
select_query ->
select projection from atom where where_clauses:
?SELECT_CLAUSE({'$4', '$2', '$6'}).
projection ->
wildcard :
'$1'.
projection ->
select_fields:
'$1'.
select_fields ->
select_fields sep atom :
lists:append('$1', ['$3']).
select_fields ->
atom :
['$1'].
select_query ->
select projection from atom join join_clauses:
?SELECT_CLAUSE({'$4', '$2', '$6'}).
%%--------------------------------------------------------------------
%% join clause
%%--------------------------------------------------------------------
join_clauses ->
join_clauses conjunctive join_clauses :
lists:append(['$1', ['$2'], '$3']).
join_clauses ->
join_clauses disjunctive join_clauses :
lists:append(['$1', ['$2'], '$3']).
join_clauses ->
start_list join_clauses conjunctive join_clauses end_list :
[lists:append(['$2', ['$3'], '$4'])].
join_clauses ->
start_list join_clauses disjunctive join_clauses end_list :
[lists:append(['$2', ['$3'], '$4'])].
join_clauses ->
join_clause :
['$1'].
join_clause ->
atom comparison value :
{'$1', '$2', '$3'}.
%%--------------------------------------------------------------------
%% where clause
%%--------------------------------------------------------------------
where_clauses ->
where_clauses conjunctive where_clauses :
lists:append(['$1', ['$2'], '$3']).
where_clauses ->
where_clauses disjunctive where_clauses :
lists:append(['$1', ['$2'], '$3']).
where_clauses ->
start_list where_clauses conjunctive where_clauses end_list :
[lists:append(['$2', ['$3'], '$4'])].
where_clauses ->
start_list where_clauses disjunctive where_clauses end_list :
[lists:append(['$2', ['$3'], '$4'])].
where_clauses ->
where_clause :
['$1'].
% Uncomment to support this
%where_clauses ->
% start_list where_clause end_list :
% ['$2'].
where_clause ->
atom comparison value :
{'$1', '$2', '$3'}.
%%--------------------------------------------------------------------
%% insert query
%%--------------------------------------------------------------------
insert_query ->
insert into atom insert_keys_clause
values insert_values_clause :
?INSERT_CLAUSE({'$3', '$4', '$6'}).
insert_query ->
insert into atom
values insert_values_clause :
?INSERT_CLAUSE({'$3', ?PARSER_WILDCARD, '$5'}).
insert_keys_clause ->
start_list insert_keys end_list :
'$2'.
insert_keys ->
insert_keys sep atom :
lists:append('$1', ['$3']).
insert_keys ->
atom :
['$1'].
insert_values_clause ->
start_list insert_values end_list :
'$2'.
insert_values ->
insert_values sep value :
lists:append('$1', ['$3']).
insert_values ->
value :
['$1'].
%%--------------------------------------------------------------------
%% update query
%%--------------------------------------------------------------------
update_query ->
update atom set_clause :
?UPDATE_CLAUSE({'$2', '$3', ?PARSER_WILDCARD}).
update_query ->
update atom set_clause where where_clauses :
?UPDATE_CLAUSE({'$2', '$3', '$5'}).
set_clause ->
set set_assignments :
?SET_CLAUSE('$2').
set_assignments ->
set_assignments conjunctive set_assignment :
lists:append('$1', ['$3']).
set_assignments ->
set_assignment :
['$1'].
%assignment expression for varchar and boolean data types
set_assignment ->
atom equality value :
{'$1', ?ASSIGN_OP('$2'), '$3'}.
%assignment expressions for increments/decrements on counter data types
set_assignment ->
atom equality atom plus number_unwrap :
{counter_update_column('$1', '$3'), ?INCREMENT_OP('$4'), '$5'}.
set_assignment ->
atom equality atom minus number_unwrap :
{counter_update_column('$1', '$3'), ?DECREMENT_OP('$4'), '$5'}.
%%--------------------------------------------------------------------
%% create query
%%--------------------------------------------------------------------
create_query ->
create crp table atom start_list create_keys end_list :
?CREATE_CLAUSE(?T_TABLE('$4', crp:set_table_level(unwrap_type('$2'), crp:new()), '$6', [], [], undefined)).
create_query ->
create crp table atom start_list create_keys end_list partition on start_list attribute_name end_list :
?CREATE_CLAUSE(?T_TABLE('$4', crp:set_table_level(unwrap_type('$2'), crp:new()), '$6', [], [], ['$11'])).
create_query ->
create index atom on atom start_list create_index_keys end_list :
?CREATE_CLAUSE(?T_INDEX('$3', '$5', '$7')).
create_keys ->
create_keys sep attribute :
lists:append('$1', ['$3']).
create_keys ->
attribute :
['$1'].
attribute ->
attribute_name attribute_type attribute_encryption_type attribute_constraint:
?T_COL('$1', unwrap_type('$2'), unwrap_type('$3'), '$4').
attribute ->
attribute_name attribute_type attribute_encryption_type:
?T_COL('$1', unwrap_type('$2'), unwrap_type('$3'), ?NO_CONSTRAINT).
attribute ->
attribute_name attribute_type attribute_constraint :
?T_COL('$1', unwrap_type('$2'), ?NO_ENCRYPTION, '$3').
attribute ->
attribute_name attribute_type :
?T_COL('$1', unwrap_type('$2'), ?NO_ENCRYPTION, ?NO_CONSTRAINT).
attribute_constraint ->
primary key :
?PRIMARY_TOKEN.
attribute_constraint ->
foreign key crp references atom start_list atom end_list :
?FOREIGN_KEY({'$5', '$7', unwrap_type('$3'), ?RESTRICT_TOKEN}).
attribute_constraint ->
foreign key references atom start_list atom end_list :
?FOREIGN_KEY({'$4', '$6', unwrap_type(?NO_CONCURRENCY_KEY), ?RESTRICT_TOKEN}).
attribute_constraint ->
foreign key crp references atom start_list atom end_list on delete cascade :
?FOREIGN_KEY({'$5', '$7', unwrap_type('$3'), ?CASCADE_TOKEN}).
attribute_constraint ->
foreign key references atom start_list atom end_list on delete cascade :
?FOREIGN_KEY({'$4', '$6', unwrap_type(?NO_CONCURRENCY_KEY), ?CASCADE_TOKEN}).
attribute_constraint ->
default value :
?DEFAULT_KEY('$2').
attribute_constraint ->
check start_list attribute_name check_comparator number_unwrap end_list :
?CHECK_KEY({'$3', '$4', '$5'}).
attribute_name ->
atom :
'$1'.
check_comparator -> greater : ?GREATER_KEY.
check_comparator -> lesser : ?LESSER_KEY.
check_comparator -> greatereq : ?GREATEREQ_KEY.
check_comparator -> lessereq : ?LESSEREQ_KEY.
create_index_keys ->
create_index_keys sep atom :
lists:append('$1', ['$3']).
create_index_keys ->
atom :
['$1'].
%%--------------------------------------------------------------------
%% delete
%%--------------------------------------------------------------------
delete_query ->
delete from atom :
?DELETE_CLAUSE({'$3', ?PARSER_WILDCARD}).
delete_query ->
delete from atom where where_clauses :
?DELETE_CLAUSE({'$3', '$5'}).
%%--------------------------------------------------------------------
%% transactions
%%--------------------------------------------------------------------
begin_transaction ->
begin transaction :
?BEGIN_CLAUSE(?TRANSACTION_TOKEN).
commit_transaction ->
commit transaction :
?COMMIT_CLAUSE(?TRANSACTION_TOKEN).
rollback_transaction ->
rollback transaction :
?ROLLBACK_CLAUSE(?TRANSACTION_TOKEN).
%%--------------------------------------------------------------------
%% quit program
%%--------------------------------------------------------------------
quit_program ->
quit :
?QUIT_CLAUSE(?QUIT_TOKEN).
%%--------------------------------------------------------------------
%% utils
%%--------------------------------------------------------------------
atom ->
atom_value :
unwrap_type('$1').
number_unwrap ->
number :
unwrap_type('$1').
value ->
number :
unwrap_type('$1').
value ->
string :
unwrap_type('$1').
value ->
boolean :
unwrap_type('$1').
%%====================================================================
%% Erlang Code
%%====================================================================
Erlang code.
-include("parser.hrl").
-include("types.hrl").
unwrap_type(?PARSER_TYPE(_Type, Value)) -> Value.
counter_update_column(Column, Column) -> Column;
counter_update_column(_, _) ->
throw({error, {1, ?MODULE, "The column in the update must be the same on either side of the equality"}}).
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-endif.
%%====================================================================
%% Eunit tests
%%====================================================================
-ifdef(TEST).
test_parser(String) ->
{ok, Tokens, _} = scanner:string(String),
{ok, _ParserTree} = parse(Tokens).
show_tables_test() ->
test_parser("SHOW TABLES").
show_index_test() ->
test_parser("SHOW INDEX FROM TestTable"),
test_parser("SHOW INDEXES FROM TestTable"),
test_parser("SHOW INDEX TestIndex FROM TestTable").
create_table_simple_test() ->
test_parser("CREATE UPDATE-WINS TABLE Test (a VARCHAR, b INTEGER)"),
test_parser("CREATE UPDATE-WINS TABLE Test (a VARCHAR)"),
test_parser("CREATE DELETE-WINS TABLE TestA (a VARCHAR);CREATE DELETE-WINS TABLE TestB (b INTEGER)").
create_table_pk_test() ->
test_parser("CREATE UPDATE-WINS TABLE Test (a VARCHAR PRIMARY KEY, b INTEGER)"),
test_parser("CREATE UPDATE-WINS TABLE Test (a INTEGER PRIMARY KEY, b INTEGER)"),
test_parser("CREATE UPDATE-WINS TABLE Test (a BOOLEAN PRIMARY KEY, b INTEGER)").
create_table_def_test() ->
test_parser("CREATE UPDATE-WINS TABLE Test (a VARCHAR, b INTEGER DEFAULT 5)"),
test_parser("CREATE UPDATE-WINS TABLE Test (a VARCHAR, b BOOLEAN DEFAULT false)"),
test_parser("CREATE UPDATE-WINS TABLE Test (a VARCHAR, b VARCHAR DEFAULT 'example')").
create_table_check_test() ->
test_parser("CREATE UPDATE-WINS TABLE Test(a INTEGER, b COUNTER_INT CHECK (b > 0))"),
test_parser("CREATE UPDATE-WINS TABLE Test(a INTEGER, b COUNTER_INT CHECK (b >= 0))"),
test_parser("CREATE UPDATE-WINS TABLE Test(a INTEGER, b COUNTER_INT CHECK (b < 0))"),
test_parser("CREATE UPDATE-WINS TABLE Test(a INTEGER, b COUNTER_INT CHECK (b <= 0))").
create_table_fk_test() ->
test_parser("CREATE UPDATE-WINS TABLE Test (a VARCHAR, b INTEGER FOREIGN KEY UPDATE-WINS REFERENCES TestB(b))"),
test_parser("CREATE DELETE-WINS TABLE Test (a VARCHAR, b INTEGER FOREIGN KEY REFERENCES TestB(b))").
create_table_fk_cascade_test() ->
test_parser("CREATE DELETE-WINS TABLE TestA (a VARCHAR, b INTEGER FOREIGN KEY DELETE-WINS REFERENCES TestB(b) ON DELETE CASCADE)"),
test_parser("CREATE DELETE-WINS TABLE TestA (a VARCHAR, b INTEGER FOREIGN KEY REFERENCES TestB(b) ON DELETE CASCADE)").
create_table_partition_test() ->
test_parser("CREATE UPDATE-WINS TABLE Test (a VARCHAR, b INTEGER) PARTITION ON (b)").
create_index_simple_test() ->
test_parser("CREATE INDEX TestIdx ON Table (a)"),
test_parser("CREATE INDEX TestIdx ON Table (a, b)").
update_simple_test() ->
test_parser("UPDATE Test SET name = 'aaa'"),
test_parser("UPDATE Test SET name = 'a'; UPDATE Test SET name = 'b'").
update_multiple_test() ->
test_parser("UPDATE Test SET name = 'aaa' AND age = age + 3"),
test_parser("UPDATE Test SET name = 'aaa' AND age = age + 3 AND loc = 'en' WHERE loc = 'pt'").
update_assign_test() ->
test_parser("UPDATE Test SET name = 'aaa' WHERE name = 'a'"),
test_parser("UPDATE Test SET age = 50 WHERE name = 'aa'").
update_increment_test() ->
test_parser("UPDATE Test SET countCars = countCars + 1 WHERE model = 'b'"),
test_parser("UPDATE Test SET countCars = countCars + 2 WHERE model = 'b'").
update_decrement_test() ->
test_parser("UPDATE Test SET countCars = countCars - 1 WHERE model = 'b'"),
test_parser("UPDATE Test SET countCars = countCars - 2 WHERE model = 'b'").
insert_simple_test() ->
test_parser("INSERT INTO Test VALUES ('a', 5, 'b')"),
test_parser("INSERT INTO Test (a, b, c) VALUES ('a', 5, 'b')"),
test_parser("INSERT INTO Test VALUES ('a')"),
test_parser("INSERT INTO Test (a) VALUES (5)").
delete_simple_test() ->
test_parser("DELETE FROM Test"),
test_parser("DELETE FROM Test WHERE id = 5").
select_simple_test() ->
test_parser("SELECT * FROM Test"),
test_parser("SELECT a, b FROM Test WHERE c = 5").
select_projection_test() ->
test_parser("SELECT a FROM Test"),
test_parser("SELECT a, b FROM Test").
select_where_test() ->
test_parser("SELECT a FROM Test WHERE b = 2"),
test_parser("SELECT a FROM Test WHERE b = 2 AND c = 3 AND d = 4"),
test_parser("SELECT a FROM Test WHERE b >= 2 OR c <= 3 AND d = 4"),
test_parser("SELECT a FROM Test WHERE b > 2 AND c < 3 OR d <> 4"),
test_parser("SELECT a FROM Test WHERE b = 2 AND (c <= 3 OR d = 4)"),
test_parser("SELECT a FROM Test WHERE (b >= 2 AND c = 3 OR d <> 4)"),
test_parser("SELECT a FROM Test WHERE (b <> 2 AND c < 3) OR d > 4").
%%select_join_test() ->
%% test_parser("SELECT a FROM Test JOIN Test2"),
%% test_parser("SELECT a FROM Test JOIN Test2 ON Test2.a = Test.a"),
%% test_parser("SELECT a FROM Test JOIN Test2 ON Test2.a = Test.a JOIN Test3 ON Test3.a = Test2.a").
transaction_test() ->
test_parser("BEGIN TRANSACTION"),
test_parser("COMMIT TRANSACTION"),
test_parser("ROLLBACK TRANSACTION").
quit_test() ->
test_parser("QUIT"),
test_parser("quit").
-endif.