work on order by began
This commit is contained in:
parent
7d91319f0b
commit
34e432d031
|
|
@ -1,7 +1,9 @@
|
||||||
|
|
||||||
### TODO
|
### TODO
|
||||||
- support for *
|
|
||||||
- support for order by, offset, limit
|
- support for order by, offset, limit
|
||||||
|
- support for btree indexes
|
||||||
|
- support for parenthesis
|
||||||
|
- support for *
|
||||||
- add pipe | token
|
- add pipe | token
|
||||||
- add count min and max functions, eg aggregate functions
|
- add count min and max functions, eg aggregate functions
|
||||||
- maybe to create iterator on table
|
- maybe to create iterator on table
|
||||||
|
|
|
||||||
57
lexer.cpp
57
lexer.cpp
|
|
@ -119,115 +119,86 @@ namespace usql {
|
||||||
// TODO, FIXME 'one is evaluated as identifier
|
// TODO, FIXME 'one is evaluated as identifier
|
||||||
if (token == ";")
|
if (token == ";")
|
||||||
return TokenType::semicolon;
|
return TokenType::semicolon;
|
||||||
|
|
||||||
if (token == "+")
|
if (token == "+")
|
||||||
return TokenType::plus;
|
return TokenType::plus;
|
||||||
|
|
||||||
if (token == "-")
|
if (token == "-")
|
||||||
return TokenType::minus;
|
return TokenType::minus;
|
||||||
|
|
||||||
if (token == "*")
|
if (token == "*")
|
||||||
return TokenType::multiply;
|
return TokenType::multiply;
|
||||||
|
|
||||||
if (token == "/")
|
if (token == "/")
|
||||||
return TokenType::divide;
|
return TokenType::divide;
|
||||||
|
|
||||||
if (token == "(")
|
if (token == "(")
|
||||||
return TokenType::open_paren;
|
return TokenType::open_paren;
|
||||||
|
|
||||||
if (token == ")")
|
if (token == ")")
|
||||||
return TokenType::close_paren;
|
return TokenType::close_paren;
|
||||||
|
|
||||||
if (token == "=")
|
if (token == "=")
|
||||||
return TokenType::equal;
|
return TokenType::equal;
|
||||||
|
|
||||||
if (token == "!=")
|
if (token == "!=")
|
||||||
return TokenType::not_equal;
|
return TokenType::not_equal;
|
||||||
|
|
||||||
if (token == ">")
|
if (token == ">")
|
||||||
return TokenType::greater;
|
return TokenType::greater;
|
||||||
|
|
||||||
if (token == ">=")
|
if (token == ">=")
|
||||||
return TokenType::greater_equal;
|
return TokenType::greater_equal;
|
||||||
|
|
||||||
if (token == "<")
|
if (token == "<")
|
||||||
return TokenType::lesser;
|
return TokenType::lesser;
|
||||||
|
|
||||||
if (token == "<=")
|
if (token == "<=")
|
||||||
return TokenType::lesser_equal;
|
return TokenType::lesser_equal;
|
||||||
|
|
||||||
if (token == "as")
|
if (token == "as")
|
||||||
return TokenType::keyword_as;
|
return TokenType::keyword_as;
|
||||||
|
|
||||||
if (token == "create")
|
if (token == "create")
|
||||||
return TokenType::keyword_create;
|
return TokenType::keyword_create;
|
||||||
|
|
||||||
if (token == "drop")
|
if (token == "drop")
|
||||||
return TokenType::keyword_drop;
|
return TokenType::keyword_drop;
|
||||||
|
|
||||||
if (token == "where")
|
if (token == "where")
|
||||||
return TokenType::keyword_where;
|
return TokenType::keyword_where;
|
||||||
|
if (token == "order")
|
||||||
|
return TokenType::keyword_order;
|
||||||
|
if (token == "by")
|
||||||
|
return TokenType::keyword_by;
|
||||||
|
if (token == "asc")
|
||||||
|
return TokenType::keyword_asc;
|
||||||
|
if (token == "desc")
|
||||||
|
return TokenType::keyword_desc;
|
||||||
if (token == "from")
|
if (token == "from")
|
||||||
return TokenType::keyword_from;
|
return TokenType::keyword_from;
|
||||||
|
|
||||||
if (token == "delete")
|
if (token == "delete")
|
||||||
return TokenType::keyword_delete;
|
return TokenType::keyword_delete;
|
||||||
|
|
||||||
if (token == "table")
|
if (token == "table")
|
||||||
return TokenType::keyword_table;
|
return TokenType::keyword_table;
|
||||||
|
|
||||||
if (token == "insert")
|
if (token == "insert")
|
||||||
return TokenType::keyword_insert;
|
return TokenType::keyword_insert;
|
||||||
|
|
||||||
if (token == "into")
|
if (token == "into")
|
||||||
return TokenType::keyword_into;
|
return TokenType::keyword_into;
|
||||||
|
|
||||||
if (token == "values")
|
if (token == "values")
|
||||||
return TokenType::keyword_values;
|
return TokenType::keyword_values;
|
||||||
|
|
||||||
if (token == "select")
|
if (token == "select")
|
||||||
return TokenType::keyword_select;
|
return TokenType::keyword_select;
|
||||||
|
|
||||||
if (token == "set")
|
if (token == "set")
|
||||||
return TokenType::keyword_set;
|
return TokenType::keyword_set;
|
||||||
|
|
||||||
if (token == "copy")
|
if (token == "copy")
|
||||||
return TokenType::keyword_copy;
|
return TokenType::keyword_copy;
|
||||||
|
|
||||||
if (token == "update")
|
if (token == "update")
|
||||||
return TokenType::keyword_update;
|
return TokenType::keyword_update;
|
||||||
|
|
||||||
if (token == "load")
|
if (token == "load")
|
||||||
return TokenType::keyword_load;
|
return TokenType::keyword_load;
|
||||||
|
|
||||||
if (token == "save")
|
if (token == "save")
|
||||||
return TokenType::keyword_save;
|
return TokenType::keyword_save;
|
||||||
|
|
||||||
if (token == "not")
|
if (token == "not")
|
||||||
return TokenType::keyword_not;
|
return TokenType::keyword_not;
|
||||||
|
|
||||||
if (token == "null")
|
if (token == "null")
|
||||||
return TokenType::keyword_null;
|
return TokenType::keyword_null;
|
||||||
|
|
||||||
if (token == "integer")
|
if (token == "integer")
|
||||||
return TokenType::keyword_integer;
|
return TokenType::keyword_integer;
|
||||||
|
|
||||||
if (token == "float")
|
if (token == "float")
|
||||||
return TokenType::keyword_float;
|
return TokenType::keyword_float;
|
||||||
|
|
||||||
if (token == "varchar")
|
if (token == "varchar")
|
||||||
return TokenType::keyword_varchar;
|
return TokenType::keyword_varchar;
|
||||||
|
|
||||||
if (token == "or")
|
if (token == "or")
|
||||||
return TokenType::logical_or;
|
return TokenType::logical_or;
|
||||||
|
|
||||||
if (token == "and")
|
if (token == "and")
|
||||||
return TokenType::logical_and;
|
return TokenType::logical_and;
|
||||||
|
|
||||||
if (token == ",")
|
if (token == ",")
|
||||||
return TokenType::comma;
|
return TokenType::comma;
|
||||||
|
|
||||||
if (token == "\n" || token == "\r\n" || token == "\r")
|
if (token == "\n" || token == "\r\n" || token == "\r")
|
||||||
return TokenType::newline;
|
return TokenType::newline;
|
||||||
|
|
||||||
|
|
@ -347,6 +318,18 @@ namespace usql {
|
||||||
case TokenType::keyword_where:
|
case TokenType::keyword_where:
|
||||||
txt = "where";
|
txt = "where";
|
||||||
break;
|
break;
|
||||||
|
case TokenType::keyword_order:
|
||||||
|
txt = "order";
|
||||||
|
break;
|
||||||
|
case TokenType::keyword_by:
|
||||||
|
txt = "by";
|
||||||
|
break;
|
||||||
|
case TokenType::keyword_asc:
|
||||||
|
txt = "asc";
|
||||||
|
break;
|
||||||
|
case TokenType::keyword_desc:
|
||||||
|
txt = "desc";
|
||||||
|
break;
|
||||||
case TokenType::keyword_table:
|
case TokenType::keyword_table:
|
||||||
txt = "table";
|
txt = "table";
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
4
lexer.h
4
lexer.h
|
|
@ -25,6 +25,10 @@ namespace usql {
|
||||||
keyword_drop,
|
keyword_drop,
|
||||||
keyword_table,
|
keyword_table,
|
||||||
keyword_where,
|
keyword_where,
|
||||||
|
keyword_order,
|
||||||
|
keyword_by,
|
||||||
|
keyword_asc,
|
||||||
|
keyword_desc,
|
||||||
keyword_delete,
|
keyword_delete,
|
||||||
keyword_update,
|
keyword_update,
|
||||||
keyword_load,
|
keyword_load,
|
||||||
|
|
|
||||||
50
main.cpp
50
main.cpp
|
|
@ -9,7 +9,7 @@ int main(int argc, char *argv[]) {
|
||||||
std::vector<std::string> sql_commands{
|
std::vector<std::string> sql_commands{
|
||||||
"create table a (i integer not null, s varchar(64), f float null)",
|
"create table a (i integer not null, s varchar(64), f float null)",
|
||||||
"insert into a (i, s) values(1, upper('one'))",
|
"insert into a (i, s) values(1, upper('one'))",
|
||||||
"update table a set s = 'null string aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'",
|
// "update table a set s = 'null string aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'",
|
||||||
// "update table a set i = null",
|
// "update table a set i = null",
|
||||||
"insert into a (i, s) values(2, 'two')",
|
"insert into a (i, s) values(2, 'two')",
|
||||||
"insert into a (i, s) values(3, 'two')",
|
"insert into a (i, s) values(3, 'two')",
|
||||||
|
|
@ -17,30 +17,30 @@ int main(int argc, char *argv[]) {
|
||||||
"insert into a (i, s) values(5, 'five')",
|
"insert into a (i, s) values(5, 'five')",
|
||||||
"insert into a (i, s) values(to_date('20.12.1973', '%d.%m.%Y'), 'six')",
|
"insert into a (i, s) values(to_date('20.12.1973', '%d.%m.%Y'), 'six')",
|
||||||
"save table a into '/tmp/a.csv'",
|
"save table a into '/tmp/a.csv'",
|
||||||
"select i, s from a where i > 2",
|
"select i, s from a where i > 2 order by 1 desc"
|
||||||
"select i, s from a where i = 1",
|
// "select i, s from a where i = 1",
|
||||||
"select i, s from a where s = 'two'",
|
// "select i, s from a where s = 'two'",
|
||||||
"select i, s from a where i <= 3 and s = 'one'",
|
// "select i, s from a where i <= 3 and s = 'one'",
|
||||||
"select i, s from a where i > 0",
|
// "select i, s from a where i > 0",
|
||||||
"delete from a where i = 4",
|
// "delete from a where i = 4",
|
||||||
"select i, s from a where i > 0",
|
// "select i, s from a where i > 0",
|
||||||
"update a set f = 9.99 where i = 3",
|
// "update a set f = 9.99 where i = 3",
|
||||||
"select i, s, f from a where i = 3",
|
// "select i, s, f from a where i = 3",
|
||||||
"update a set s = 'three', f = f + 0.01 where i = 3",
|
// "update a set s = 'three', f = f + 0.01 where i = 3",
|
||||||
"select i, s, f from a where i = 3",
|
// "select i, s, f from a where i = 3",
|
||||||
"create table data (ticker varchar(8), price float null)",
|
// "create table data (ticker varchar(8), price float null)",
|
||||||
"load data from '/Users/vaclavt/Library/Mobile Documents/com~apple~CloudDocs/Development/usql/data.csv')",
|
// "load data from '/Users/vaclavt/Library/Mobile Documents/com~apple~CloudDocs/Development/usql/data.csv')",
|
||||||
"select ticker, price from data",
|
// "select ticker, price from data",
|
||||||
"select i, s, f from a where i < 300",
|
// "select i, s, f from a where i < 300",
|
||||||
"create table x as select i, s, f from a where i < 300",
|
// "create table x as select i, s, f from a where i < 300",
|
||||||
"select i, s, f from x where i < 300",
|
// "select i, s, f from x where i < 300",
|
||||||
"drop table x",
|
// "drop table x",
|
||||||
"select i, s, f from a where i > 300",
|
// "select i, s, f from a where i > 300",
|
||||||
"select i, to_string(i, '%d.%m.%Y'), s, f from a where i > 300",
|
// "select i, to_string(i, '%d.%m.%Y'), s, f from a where i > 300",
|
||||||
"create table prices (datetime integer, symbol varchar(8), prev_close float, open float, price float, change float, change_prct varchar(16))",
|
// "create table prices (datetime integer, symbol varchar(8), prev_close float, open float, price float, change float, change_prct varchar(16))",
|
||||||
"load prices from '/Users/vaclavt/Library/Mobile Documents/com~apple~CloudDocs/Development/usql/prices.csv'",
|
// "load prices from '/Users/vaclavt/Library/Mobile Documents/com~apple~CloudDocs/Development/usql/prices.csv'",
|
||||||
"insert into prices (datetime, symbol, prev_close, open, price, change, change_prct) values (1626979443, 'MPC', 54.08, 53.82, 53.63, -0.832101, '-0.83 %')",
|
// "insert into prices (datetime, symbol, prev_close, open, price, change, change_prct) values (1626979443, 'MPC', 54.08, 53.82, 53.63, -0.832101, '-0.83 %')",
|
||||||
"select to_string(datetime, '%d.%m.%Y %H:%M:%S'), symbol, prev_close, open, price, change, change_prct from prices where symbol = 'SYF'"
|
// "select to_string(datetime, '%d.%m.%Y %H:%M:%S'), symbol, prev_close, open, price, change, change_prct from prices where symbol = 'SYF'"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
83
parser.cpp
83
parser.cpp
|
|
@ -176,7 +176,7 @@ namespace usql {
|
||||||
return std::make_unique<InsertIntoTableNode>(table_name, column_names, std::move(column_values));
|
return std::make_unique<InsertIntoTableNode>(table_name, column_names, std::move(column_values));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Node> Parser::parse_value() {
|
std::unique_ptr<Node> Parser::parse_value() {
|
||||||
if (m_lexer.tokenType() == TokenType::int_number) {
|
if (m_lexer.tokenType() == TokenType::int_number) {
|
||||||
return std::make_unique<IntValueNode>(std::stoi(m_lexer.consumeCurrentToken().token_string));
|
return std::make_unique<IntValueNode>(std::stoi(m_lexer.consumeCurrentToken().token_string));
|
||||||
}
|
}
|
||||||
|
|
@ -205,9 +205,9 @@ std::unique_ptr<Node> Parser::parse_value() {
|
||||||
}
|
}
|
||||||
|
|
||||||
throw Exception("Syntax error, current token: " + m_lexer.currentToken().token_string);
|
throw Exception("Syntax error, current token: " + m_lexer.currentToken().token_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Node> Parser::parse_select_from_table() {
|
std::unique_ptr<Node> Parser::parse_select_from_table() {
|
||||||
auto cols = std::make_unique<std::vector<SelectColNode>>();
|
auto cols = std::make_unique<std::vector<SelectColNode>>();
|
||||||
|
|
||||||
m_lexer.skipToken(TokenType::keyword_select);
|
m_lexer.skipToken(TokenType::keyword_select);
|
||||||
|
|
@ -235,12 +235,13 @@ std::unique_ptr<Node> Parser::parse_select_from_table() {
|
||||||
|
|
||||||
std::unique_ptr<Node> where_node = parse_where_clause();
|
std::unique_ptr<Node> where_node = parse_where_clause();
|
||||||
|
|
||||||
// if (m_lexer.tokenType() == TokenType::keyword_order_by) {}
|
std::vector<ColOrderNode> orderby_node = parse_orderby_clause();
|
||||||
|
|
||||||
// if (m_lexer.tokenType() == TokenType::keyword_offset) {}
|
// if (m_lexer.tokenType() == TokenType::keyword_offset) {}
|
||||||
// if (m_lexer.tokenType() == TokenType::keyword_limit) {}
|
// if (m_lexer.tokenType() == TokenType::keyword_limit) {}
|
||||||
|
|
||||||
return std::make_unique<SelectFromTableNode>(table_name, std::move(cols), std::move(where_node));
|
return std::make_unique<SelectFromTableNode>(table_name, std::move(cols), std::move(where_node), orderby_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Node> Parser::parse_delete_from_table() {
|
std::unique_ptr<Node> Parser::parse_delete_from_table() {
|
||||||
m_lexer.skipToken(TokenType::keyword_delete);
|
m_lexer.skipToken(TokenType::keyword_delete);
|
||||||
|
|
@ -291,26 +292,62 @@ std::unique_ptr<Node> Parser::parse_select_from_table() {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Node> Parser::parse_where_clause() {
|
std::unique_ptr<Node> Parser::parse_where_clause() {
|
||||||
// TODO add support for multiple filters
|
if (m_lexer.tokenType() != TokenType::keyword_where) {
|
||||||
// TODO add support for parenthesis
|
return std::make_unique<TrueNode>();
|
||||||
|
}
|
||||||
|
|
||||||
if (m_lexer.tokenType() != TokenType::keyword_where) {
|
std::unique_ptr<Node> node;
|
||||||
return std::make_unique<TrueNode>();
|
m_lexer.skipToken(TokenType::keyword_where);
|
||||||
}
|
do {
|
||||||
|
node = parse_relational_expression();
|
||||||
|
|
||||||
std::unique_ptr<Node> node;
|
if (Lexer::isLogicalOperator(m_lexer.tokenType())) {
|
||||||
m_lexer.skipToken(TokenType::keyword_where);
|
auto operation = parse_logical_operator();
|
||||||
do {
|
std::unique_ptr<Node> node2 = parse_relational_expression();
|
||||||
node = parse_relational_expression();
|
node = std::make_unique<LogicalOperatorNode>(operation, std::move(node), std::move(node2));
|
||||||
|
}
|
||||||
|
} while (m_lexer.tokenType() != TokenType::eof && m_lexer.tokenType() != TokenType::keyword_order);
|
||||||
|
|
||||||
if (Lexer::isLogicalOperator(m_lexer.tokenType())) {
|
return node;
|
||||||
auto operation = parse_logical_operator();
|
}
|
||||||
std::unique_ptr<Node> node2 = parse_relational_expression();
|
|
||||||
node = std::make_unique<LogicalOperatorNode>(operation, std::move(node), std::move(node2));
|
|
||||||
}
|
|
||||||
} while (m_lexer.tokenType() != TokenType::eof); // until whole where clause parsed
|
|
||||||
|
|
||||||
return node;
|
|
||||||
|
std::vector<ColOrderNode> Parser::parse_orderby_clause() {
|
||||||
|
std::vector<ColOrderNode> order_cols;
|
||||||
|
|
||||||
|
if (m_lexer.tokenType() == TokenType::keyword_order) {
|
||||||
|
m_lexer.skipToken(TokenType::keyword_order);
|
||||||
|
m_lexer.skipToken(TokenType::keyword_by);
|
||||||
|
|
||||||
|
do {
|
||||||
|
int col_index = -1;
|
||||||
|
bool asc = true;
|
||||||
|
|
||||||
|
auto token_type = m_lexer.tokenType();
|
||||||
|
std::string tokenString = m_lexer.consumeCurrentToken().token_string;
|
||||||
|
switch (token_type) {
|
||||||
|
case TokenType::int_number:
|
||||||
|
col_index = std::stoi(tokenString);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw Exception("column index alloved in order by clause at this moment");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_lexer.tokenType() == TokenType::keyword_asc) {
|
||||||
|
m_lexer.skipToken(TokenType::keyword_asc);
|
||||||
|
} else if (m_lexer.tokenType() == TokenType::keyword_desc) {
|
||||||
|
m_lexer.skipToken(TokenType::keyword_desc);
|
||||||
|
asc = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
order_cols.push_back(ColOrderNode{col_index, asc});
|
||||||
|
|
||||||
|
m_lexer.skipTokenOptional(TokenType::comma);
|
||||||
|
|
||||||
|
} while (m_lexer.tokenType() != TokenType::eof); // && m_lexer.tokenType() != TokenType::keyword_offset && m_lexer.tokenType() != TokenType::keyword_limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
return order_cols;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Node> Parser::parse_relational_expression() {
|
std::unique_ptr<Node> Parser::parse_relational_expression() {
|
||||||
|
|
@ -336,7 +373,7 @@ std::unique_ptr<Node> Parser::parse_select_from_table() {
|
||||||
return std::make_unique<DatabaseValueNode>(tokenString);
|
return std::make_unique<DatabaseValueNode>(tokenString);
|
||||||
case TokenType::keyword_null:
|
case TokenType::keyword_null:
|
||||||
return std::make_unique<NullValueNode>();
|
return std::make_unique<NullValueNode>();
|
||||||
default:;
|
default:
|
||||||
throw Exception("Unknown operand node");
|
throw Exception("Unknown operand node");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
17
parser.h
17
parser.h
|
|
@ -34,6 +34,7 @@ namespace usql {
|
||||||
save_table,
|
save_table,
|
||||||
drop_table,
|
drop_table,
|
||||||
column_name,
|
column_name,
|
||||||
|
column_order,
|
||||||
column_value,
|
column_value,
|
||||||
function,
|
function,
|
||||||
column_def,
|
column_def,
|
||||||
|
|
@ -52,6 +53,15 @@ namespace usql {
|
||||||
ColNameNode(const std::string col_name) : Node(NodeType::column_name), name(col_name) {}
|
ColNameNode(const std::string col_name) : Node(NodeType::column_name), name(col_name) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ColOrderNode : Node {
|
||||||
|
std::string col_name;
|
||||||
|
int col_index;
|
||||||
|
bool ascending;
|
||||||
|
|
||||||
|
ColOrderNode(const std::string name, bool asc) : Node(NodeType::column_order), col_name(name), col_index(-1), ascending(asc) {}
|
||||||
|
ColOrderNode(int index, bool asc) : Node(NodeType::column_name), col_name(""), col_index(index), ascending(asc) {}
|
||||||
|
};
|
||||||
|
|
||||||
struct SelectColNode : Node {
|
struct SelectColNode : Node {
|
||||||
std::unique_ptr<Node> value;
|
std::unique_ptr<Node> value;
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
@ -216,9 +226,10 @@ namespace usql {
|
||||||
std::string table_name;
|
std::string table_name;
|
||||||
std::unique_ptr<std::vector<SelectColNode>> cols_names;
|
std::unique_ptr<std::vector<SelectColNode>> cols_names;
|
||||||
std::unique_ptr<Node> where;
|
std::unique_ptr<Node> where;
|
||||||
|
std::vector<ColOrderNode> order_by;
|
||||||
|
|
||||||
SelectFromTableNode(std::string name, std::unique_ptr<std::vector<SelectColNode>> names, std::unique_ptr<Node> where_clause) :
|
SelectFromTableNode(std::string name, std::unique_ptr<std::vector<SelectColNode>> names, std::unique_ptr<Node> where_clause, std::vector<ColOrderNode> orderby) :
|
||||||
Node(NodeType::select_from), table_name(name), cols_names(std::move(names)), where(std::move(where_clause)) {}
|
Node(NodeType::select_from), table_name(name), cols_names(std::move(names)), where(std::move(where_clause)), order_by(orderby) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CreateTableAsSelectNode : Node {
|
struct CreateTableAsSelectNode : Node {
|
||||||
|
|
@ -292,6 +303,8 @@ namespace usql {
|
||||||
std::unique_ptr<Node> parse_update_table();
|
std::unique_ptr<Node> parse_update_table();
|
||||||
|
|
||||||
std::unique_ptr<Node> parse_where_clause();
|
std::unique_ptr<Node> parse_where_clause();
|
||||||
|
std::vector<ColOrderNode> parse_orderby_clause();
|
||||||
|
|
||||||
std::unique_ptr<Node> parse_operand_node();
|
std::unique_ptr<Node> parse_operand_node();
|
||||||
std::unique_ptr<Node> parse_value();
|
std::unique_ptr<Node> parse_value();
|
||||||
RelationalOperatorType parse_relational_operator();
|
RelationalOperatorType parse_relational_operator();
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,13 @@ ColDefNode Table::get_column_def(const std::string &col_name) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ColDefNode Table::get_column_def(int col_index) {
|
||||||
|
if (col_index >= 0 && col_index < columns_count()) {
|
||||||
|
return m_col_defs[col_index];
|
||||||
|
} else {
|
||||||
|
throw Exception("column with this index does not exists (" + std::to_string(col_index) + ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Row Table::create_empty_row() {
|
Row Table::create_empty_row() {
|
||||||
return Row(columns_count());
|
return Row(columns_count());
|
||||||
|
|
|
||||||
1
table.h
1
table.h
|
|
@ -14,6 +14,7 @@ namespace usql {
|
||||||
Table(const std::string name, const std::vector<ColDefNode> columns);
|
Table(const std::string name, const std::vector<ColDefNode> columns);
|
||||||
|
|
||||||
ColDefNode get_column_def(const std::string &col_name);
|
ColDefNode get_column_def(const std::string &col_name);
|
||||||
|
ColDefNode get_column_def(int col_index);
|
||||||
|
|
||||||
int columns_count() const { return m_col_defs.size(); };
|
int columns_count() const { return m_col_defs.size(); };
|
||||||
|
|
||||||
|
|
|
||||||
48
usql.cpp
48
usql.cpp
|
|
@ -155,8 +155,7 @@ std::unique_ptr<Table> USql::execute_select(SelectFromTableNode &node) {
|
||||||
std::vector<int> source_table_col_index{};
|
std::vector<int> source_table_col_index{};
|
||||||
|
|
||||||
for (int i = 0; i < node.cols_names->size(); i++) {
|
for (int i = 0; i < node.cols_names->size(); i++) {
|
||||||
auto [ src_tbl_col_index, rst_tbl_col_def ] = get_column_definition(table,
|
auto [ src_tbl_col_index, rst_tbl_col_def ] = get_column_definition(table, &node.cols_names->operator[](i), i);
|
||||||
&node.cols_names->operator[](i), i);
|
|
||||||
|
|
||||||
source_table_col_index.push_back(src_tbl_col_index);
|
source_table_col_index.push_back(src_tbl_col_index);
|
||||||
result_tbl_col_defs.push_back(rst_tbl_col_def);
|
result_tbl_col_defs.push_back(rst_tbl_col_def);
|
||||||
|
|
@ -176,8 +175,7 @@ std::unique_ptr<Table> USql::execute_select(SelectFromTableNode &node) {
|
||||||
auto row_col_index = source_table_col_index[idx];
|
auto row_col_index = source_table_col_index[idx];
|
||||||
|
|
||||||
if (row_col_index == -1) { // TODO introduce constant here
|
if (row_col_index == -1) { // TODO introduce constant here
|
||||||
auto evaluated_value = eval_value_node(table, *row, node.cols_names->operator[](
|
auto evaluated_value = eval_value_node(table, *row, node.cols_names->operator[](idx).value.get());
|
||||||
idx).value.get());
|
|
||||||
ValueNode *col_value = evaluated_value.get();
|
ValueNode *col_value = evaluated_value.get();
|
||||||
|
|
||||||
new_row.setColumnValue(&result_tbl_col_defs[idx], col_value);
|
new_row.setColumnValue(&result_tbl_col_defs[idx], col_value);
|
||||||
|
|
@ -192,9 +190,51 @@ std::unique_ptr<Table> USql::execute_select(SelectFromTableNode &node) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// order by
|
||||||
|
execute_order_by(node, table, result);
|
||||||
|
|
||||||
|
|
||||||
return std::move(result);
|
return std::move(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void USql::execute_order_by(SelectFromTableNode &node, Table *table, std::__unique_if<Table>::__unique_single &result) const {
|
||||||
|
if (node.order_by.size() == 0) return;
|
||||||
|
|
||||||
|
auto compare_rows = [&node, &table, this](const Row &a, const Row &b) {
|
||||||
|
for(auto order_by_col_def : node.order_by) {
|
||||||
|
ColDefNode col_def = table->get_column_def(order_by_col_def.col_index - 1); // TODO validate index
|
||||||
|
ColValue *a_val = a.ith_column(col_def.order);
|
||||||
|
ColValue *b_val = b.ith_column(col_def.order);
|
||||||
|
|
||||||
|
if (a_val->isNull() && b_val->isNull()) return true; // both is null so a goes to end
|
||||||
|
if (!a_val->isNull() && b_val->isNull()) return true; // b is null so goes to end
|
||||||
|
if (a_val->isNull() && !b_val->isNull()) return false; // a is null so goes to end
|
||||||
|
|
||||||
|
int compare = compare_col_values(col_def, a_val, b_val);
|
||||||
|
if (compare < 0) return order_by_col_def.ascending ? true : false;
|
||||||
|
if (compare > 0) return order_by_col_def.ascending ? false : true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
result->m_rows.sort(compare_rows);
|
||||||
|
}
|
||||||
|
|
||||||
|
int USql::compare_col_values(const ColDefNode &col_def, ColValue *a_val, ColValue *b_val) const {
|
||||||
|
double c;
|
||||||
|
switch (col_def.type) {
|
||||||
|
case (ColumnType::integer_type):
|
||||||
|
return a_val->getIntValue() - b_val->getIntValue();
|
||||||
|
case (ColumnType::float_type):
|
||||||
|
c = a_val->getDoubleValue() - b_val->getDoubleValue();
|
||||||
|
return c < 0 ? -1 : c==0.0 ? 0 : 1;
|
||||||
|
case (ColumnType::varchar_type):
|
||||||
|
return a_val->getStringValue().compare(b_val->getStringValue());
|
||||||
|
default:
|
||||||
|
throw Exception("Unsupported data type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::tuple<int, ColDefNode> USql::get_column_definition(Table *table, SelectColNode *select_col_node, int col_order ) {
|
std::tuple<int, ColDefNode> USql::get_column_definition(Table *table, SelectColNode *select_col_node, int col_order ) {
|
||||||
std::string new_col_name = select_col_node->name;
|
std::string new_col_name = select_col_node->name;
|
||||||
|
|
||||||
|
|
|
||||||
5
usql.h
5
usql.h
|
|
@ -54,6 +54,11 @@ private:
|
||||||
private:
|
private:
|
||||||
Parser m_parser;
|
Parser m_parser;
|
||||||
std::list<Table> m_tables;
|
std::list<Table> m_tables;
|
||||||
|
|
||||||
|
int compare_col_values(const ColDefNode &col_def, ColValue *a_val, ColValue *b_val) const;
|
||||||
|
|
||||||
|
void
|
||||||
|
execute_order_by(SelectFromTableNode &node, Table *table, std::__unique_if<Table>::__unique_single &result) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
Loading…
Reference in New Issue