Compare commits
16 Commits
c944bf67c9
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4faaf38986 | ||
|
|
17445d0bd6 | ||
|
|
525694fbae | ||
|
|
a063e14f3e | ||
|
|
33f7cba493 | ||
|
|
f3a43fdafc | ||
|
|
4074c541c3 | ||
|
|
a51be01072 | ||
|
|
dadad69958 | ||
|
|
aca52899fb | ||
|
|
320b713eb2 | ||
| 038d891db5 | |||
| 056b45c831 | |||
|
|
1578c9889d | ||
|
|
68504eb090 | ||
|
|
e9b210a456 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -7,3 +7,4 @@ localhost.session.sql
|
|||||||
CMakeFiles
|
CMakeFiles
|
||||||
cmake-build-debug-coverage
|
cmake-build-debug-coverage
|
||||||
.idea
|
.idea
|
||||||
|
.cache
|
||||||
|
|||||||
21
Readme.md
21
Readme.md
@@ -1,22 +1,23 @@
|
|||||||
### WIP
|
### WIP
|
||||||
compare in row.cpp shoud take into account m_visible
|
|
||||||
|
|
||||||
### TODO
|
### TODO
|
||||||
- create local_install.sh
|
- create local_install.sh
|
||||||
|
|
||||||
|
- change float type keyword to double and in code functions too
|
||||||
|
|
||||||
|
- add functions:
|
||||||
|
- coalesce
|
||||||
|
- now
|
||||||
|
- rtrim, ltrim, rpad, lpad
|
||||||
|
- round
|
||||||
|
|
||||||
- set xxx - without value to reset to default value
|
- set xxx - without value to reset to default value
|
||||||
- escape " in save csv
|
|
||||||
- is null | is not null
|
|
||||||
- coalesce, date functions now, add_date; string functions rtrim, ltrim, rpad, lpad; math function round
|
|
||||||
- add pipe | concatenation
|
- add pipe | concatenation
|
||||||
- add support for 1_000_000 numbers
|
- add support for 1_000_000 numbers
|
||||||
- expand_asterix_char should support multiple and everywhere *
|
- expand_asterix_char should support multiple and everywhere *
|
||||||
|
|
||||||
|
- support for reusing space of deleted rows
|
||||||
- support for uniqueue indexes (primary key)
|
- support for uniqueue indexes (primary key)
|
||||||
- support for indexes
|
- add drop m_index
|
||||||
- add drop m_index
|
|
||||||
- support for joining
|
- support for joining
|
||||||
|
|
||||||
- add const wherever should be
|
|
||||||
- use static methods where posible
|
|
||||||
- use references where pointer cannot be nullptr
|
|
||||||
|
|||||||
35
debug.h
35
debug.h
@@ -14,10 +14,15 @@ std::vector<std::string> k_debug_sql_commands {
|
|||||||
"set 'DATE_FORMAT' = '%Y-%m-%d'",
|
"set 'DATE_FORMAT' = '%Y-%m-%d'",
|
||||||
"create index sf1_symbol on sf1(symbol)",
|
"create index sf1_symbol on sf1(symbol)",
|
||||||
"load into sf1 '/srv/SHARADAR_SF1.csv'",
|
"load into sf1 '/srv/SHARADAR_SF1.csv'",
|
||||||
"set 'USE_INDEXSCAN' = 'false'",
|
// "set 'USE_INDEXSCAN' = 'true'",
|
||||||
"select dimension, to_string(calendar_date, '%d.%m.%Y'), pp(eps, \"%.2f\"), pp(shareswadil), pp(revenue), pp(netinc), pp(cashneq), pp(assets), pp(debt), pp(ncfdebt), pp(roe*100), pp(intangibles), calendar_date from sf1 where symbol = 'MU' and dimension = 'ARQ' order by dimension, calendar_date desc limit 5",
|
"select distinct dimension from sf1 where symbol = 'ALLY'",
|
||||||
"set 'USE_INDEXSCAN' = 'true'",
|
"select calendar_date, calendar_date, dimension from sf1 where symbol = 'ALLY' and dimension = 'MRQ' and calendar_date <= 1653487723 order by calendar_date desc limit 10",
|
||||||
"select dimension, to_string(calendar_date, '%d.%m.%Y'), pp(eps, \"%.2f\"), pp(shareswadil), pp(revenue), pp(netinc), pp(cashneq), pp(assets), pp(debt), pp(ncfdebt), pp(roe*100), pp(intangibles), calendar_date from sf1 where symbol = 'MU' and dimension = 'ARQ' order by dimension, calendar_date desc limit 5"
|
// "set 'USE_INDEXSCAN' = 'false'",
|
||||||
|
// "select dimension, to_char(calendar_date, '%d.%m.%Y'), pp(eps, \"%.2f\"), pp(shareswadil), pp(revenue), pp(netinc), pp(cashneq), pp(assets), pp(debt), pp(ncfdebt), pp(roe*100), pp(intangibles), calendar_date from sf1 where symbol = 'MU' and dimension = 'ARQ' order by dimension, calendar_date desc limit 5",
|
||||||
|
// "set 'USE_INDEXSCAN' = 'true'",
|
||||||
|
// "select dimension, to_char(calendar_date, '%d.%m.%Y'), pp(eps, \"%.2f\"), pp(shareswadil), pp(revenue), pp(netinc), pp(cashneq), pp(assets), pp(debt), pp(ncfdebt), pp(roe*100), pp(intangibles), calendar_date from sf1 where symbol = 'MU' and dimension = 'ARQ' order by dimension, calendar_date desc limit 5",
|
||||||
|
// "select max(calendar_date), calendar_date from sf1 where symbol = 'MU' and dimension = 'ARQ'",
|
||||||
|
// "select max(calendar_date), min(calendar_date) from sf1 where symbol = 'MU' and dimension = 'ARQ'"
|
||||||
|
|
||||||
// "create table a (i integer not null, s varchar(64))",
|
// "create table a (i integer not null, s varchar(64))",
|
||||||
// "create index a_i on a(i)",
|
// "create index a_i on a(i)",
|
||||||
@@ -26,6 +31,7 @@ std::vector<std::string> k_debug_sql_commands {
|
|||||||
// "insert into a (i, s) values(2, 'second two')",
|
// "insert into a (i, s) values(2, 'second two')",
|
||||||
// "insert into a (i, s) values(3, 'three')",
|
// "insert into a (i, s) values(3, 'three')",
|
||||||
// "insert into a (i, s) values(4, 'four')",
|
// "insert into a (i, s) values(4, 'four')",
|
||||||
|
// "insert into a (i) values(5)",
|
||||||
// "save a into '/tmp/a.csv'",
|
// "save a into '/tmp/a.csv'",
|
||||||
// "set 'USE_INDEXSCAN' = 'true'",
|
// "set 'USE_INDEXSCAN' = 'true'",
|
||||||
// "select * from a where 1 = i",
|
// "select * from a where 1 = i",
|
||||||
@@ -33,8 +39,25 @@ std::vector<std::string> k_debug_sql_commands {
|
|||||||
// "select * from a where i = 2",
|
// "select * from a where i = 2",
|
||||||
// "update a set i = 5 where i = 2",
|
// "update a set i = 5 where i = 2",
|
||||||
// "select * from a where i = 5",
|
// "select * from a where i = 5",
|
||||||
// "select max(i) from a where s = 'two'"
|
// "select max(i) from a where s = 'two'",
|
||||||
// "select min(i), max(i), count(i) from a",
|
// "select min(i), max(i), count(i) from a",
|
||||||
// "select i + 1000 from a"
|
// "select i + 1000 from a",
|
||||||
|
// "select i, s from a where i = 5",
|
||||||
|
// "select i, s, coalesce(s, i) from a where i = 5",
|
||||||
|
|
||||||
|
// "create table a (i float, j float)",
|
||||||
|
// "insert into a (i, j) values(null, 123456789.12345)",
|
||||||
|
// "select pp(coalesce(i, j)) from a",
|
||||||
|
|
||||||
|
// "create table d (datetime date)",
|
||||||
|
// "insert into d (datetime) values(1648634993)",
|
||||||
|
// "select to_char(datetime, '%Y%m%d') from d",
|
||||||
|
// "select to_int(datetime) from d",
|
||||||
|
// "select max(to_char(datetime, '%Y%m%d')) from d",
|
||||||
|
// "select max(to_int(to_float(to_char(datetime, '%Y%m%d')))) from d",
|
||||||
|
|
||||||
|
// "select * from usql_tables",
|
||||||
|
// "select * from usql_columns",
|
||||||
|
// "select * from usql_indexes",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ TokenType Lexer::type(const std::string &token) {
|
|||||||
if (token == "not") return TokenType::keyword_not;
|
if (token == "not") return TokenType::keyword_not;
|
||||||
if (token == "null") return TokenType::keyword_null;
|
if (token == "null") return TokenType::keyword_null;
|
||||||
if (token == "integer") return TokenType::keyword_integer;
|
if (token == "integer") return TokenType::keyword_integer;
|
||||||
if (token == "float") return TokenType::keyword_float;
|
if (token == "float" || token == "double") return TokenType::keyword_float;
|
||||||
if (token == "varchar") return TokenType::keyword_varchar;
|
if (token == "varchar") return TokenType::keyword_varchar;
|
||||||
if (token == "date") return TokenType::keyword_date;
|
if (token == "date") return TokenType::keyword_date;
|
||||||
if (token == "boolean") return TokenType::keyword_bool;
|
if (token == "boolean") return TokenType::keyword_bool;
|
||||||
|
|||||||
111
parser.cpp
111
parser.cpp
@@ -3,7 +3,18 @@
|
|||||||
|
|
||||||
namespace usql {
|
namespace usql {
|
||||||
|
|
||||||
// TOOD handle premature eof
|
// TOOD handle premature eof
|
||||||
|
|
||||||
|
std::string column_type_name(const ColumnType type) {
|
||||||
|
if (type == ColumnType::integer_type) return "integer_type";
|
||||||
|
if (type == ColumnType::float_type) return "float_type";
|
||||||
|
if (type == ColumnType::varchar_type) return "varchar_type";
|
||||||
|
if (type == ColumnType::date_type) return "date_type";
|
||||||
|
if (type == ColumnType::bool_type) return "bool_type";
|
||||||
|
|
||||||
|
throw Exception("invalid column type: " + std::to_string((int)type));
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
Parser::Parser() {
|
Parser::Parser() {
|
||||||
m_lexer = Lexer{};
|
m_lexer = Lexer{};
|
||||||
@@ -53,11 +64,11 @@ namespace usql {
|
|||||||
|
|
||||||
// create as select
|
// create as select
|
||||||
if (m_lexer.tokenType() == TokenType::keyword_as) {
|
if (m_lexer.tokenType() == TokenType::keyword_as) {
|
||||||
m_lexer.skipToken(TokenType::keyword_as);
|
m_lexer.skipToken(TokenType::keyword_as);
|
||||||
|
|
||||||
std::unique_ptr<Node> select = parse_select_from_table();
|
std::unique_ptr<Node> select = parse_select_from_table();
|
||||||
|
|
||||||
return std::make_unique<CreateTableAsSelectNode>(table_name, std::move(select));
|
return std::make_unique<CreateTableAsSelectNode>(table_name, std::move(select));
|
||||||
} else {
|
} else {
|
||||||
m_lexer.skipToken(TokenType::open_paren);
|
m_lexer.skipToken(TokenType::open_paren);
|
||||||
int column_order = 0;
|
int column_order = 0;
|
||||||
@@ -69,30 +80,30 @@ namespace usql {
|
|||||||
|
|
||||||
// column name
|
// column name
|
||||||
if (m_lexer.tokenType() != TokenType::identifier) {
|
if (m_lexer.tokenType() != TokenType::identifier) {
|
||||||
throw Exception("syntax error, expected identifier");
|
throw Exception("syntax error, expected identifier");
|
||||||
}
|
}
|
||||||
database_value = m_lexer.consumeToken().token_string;
|
database_value = m_lexer.consumeToken().token_string;
|
||||||
|
|
||||||
// column type and optionally len
|
// column type and optionally len
|
||||||
if (m_lexer.tokenType() == TokenType::keyword_integer) {
|
if (m_lexer.tokenType() == TokenType::keyword_integer) {
|
||||||
column_type = ColumnType::integer_type;
|
column_type = ColumnType::integer_type;
|
||||||
m_lexer.nextToken();
|
m_lexer.nextToken();
|
||||||
} else if (m_lexer.tokenType() == TokenType::keyword_float) {
|
} else if (m_lexer.tokenType() == TokenType::keyword_float) {
|
||||||
column_type = ColumnType::float_type;
|
column_type = ColumnType::float_type;
|
||||||
m_lexer.nextToken();
|
m_lexer.nextToken();
|
||||||
} else if (m_lexer.tokenType() == TokenType::keyword_varchar) {
|
} else if (m_lexer.tokenType() == TokenType::keyword_varchar) {
|
||||||
column_type = ColumnType::varchar_type;
|
column_type = ColumnType::varchar_type;
|
||||||
m_lexer.nextToken();
|
m_lexer.nextToken();
|
||||||
m_lexer.skipToken(TokenType::open_paren);
|
m_lexer.skipToken(TokenType::open_paren);
|
||||||
column_len = std::stoi(m_lexer.consumeToken(TokenType::int_number).token_string);
|
column_len = std::stoi(m_lexer.consumeToken(TokenType::int_number).token_string);
|
||||||
m_lexer.skipToken(TokenType::close_paren);
|
m_lexer.skipToken(TokenType::close_paren);
|
||||||
} else if (m_lexer.tokenType() == TokenType::keyword_date) {
|
} else if (m_lexer.tokenType() == TokenType::keyword_date) {
|
||||||
column_type = ColumnType::date_type;
|
column_type = ColumnType::date_type;
|
||||||
m_lexer.nextToken();
|
m_lexer.nextToken();
|
||||||
} else if (m_lexer.tokenType() == TokenType::keyword_bool) {
|
} else if (m_lexer.tokenType() == TokenType::keyword_bool) {
|
||||||
column_type = ColumnType::bool_type;
|
column_type = ColumnType::bool_type;
|
||||||
m_lexer.nextToken();
|
m_lexer.nextToken();
|
||||||
} else {
|
} else {
|
||||||
throw Exception("syntax error, column type expected, found " + m_lexer.currentToken().token_string);
|
throw Exception("syntax error, column type expected, found " + m_lexer.currentToken().token_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,7 +120,7 @@ namespace usql {
|
|||||||
m_lexer.skipTokenOptional(TokenType::comma);
|
m_lexer.skipTokenOptional(TokenType::comma);
|
||||||
|
|
||||||
//constraints
|
//constraints
|
||||||
//defaults
|
//defaults
|
||||||
} while (m_lexer.tokenType() != TokenType::close_paren);
|
} while (m_lexer.tokenType() != TokenType::close_paren);
|
||||||
|
|
||||||
return std::make_unique<CreateTableNode>(table_name, cols_def);
|
return std::make_unique<CreateTableNode>(table_name, cols_def);
|
||||||
@@ -374,19 +385,18 @@ namespace usql {
|
|||||||
|
|
||||||
|
|
||||||
std::unique_ptr<Node> Parser::parse_where_clause() {
|
std::unique_ptr<Node> Parser::parse_where_clause() {
|
||||||
if (m_lexer.tokenType() != TokenType::keyword_where) {
|
if (m_lexer.tokenType() != TokenType::keyword_where) {
|
||||||
return std::make_unique<TrueNode>();
|
return std::make_unique<TrueNode>();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_lexer.skipToken(TokenType::keyword_where);
|
m_lexer.skipToken(TokenType::keyword_where);
|
||||||
|
|
||||||
std::unique_ptr<Node> left = parse_expression();
|
std::unique_ptr<Node> left = parse_expression();
|
||||||
do {
|
do {
|
||||||
left = parse_expression(std::move(left));
|
left = parse_expression(std::move(left));
|
||||||
|
} while (m_lexer.tokenType() != TokenType::eof && m_lexer.tokenType() != TokenType::keyword_order && m_lexer.tokenType() != TokenType::keyword_offset && m_lexer.tokenType() != TokenType::keyword_limit && m_lexer.tokenType() != TokenType::semicolon);
|
||||||
|
|
||||||
} while (m_lexer.tokenType() != TokenType::eof && m_lexer.tokenType() != TokenType::keyword_order && m_lexer.tokenType() != TokenType::keyword_offset && m_lexer.tokenType() != TokenType::keyword_limit);
|
return left;
|
||||||
|
|
||||||
return left;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Node> Parser::parse_expression() {
|
std::unique_ptr<Node> Parser::parse_expression() {
|
||||||
@@ -433,39 +443,39 @@ namespace usql {
|
|||||||
|
|
||||||
// function call
|
// function call
|
||||||
if (token_typcol == TokenType::identifier && m_lexer.nextTokenType() == TokenType::open_paren) {
|
if (token_typcol == TokenType::identifier && m_lexer.nextTokenType() == TokenType::open_paren) {
|
||||||
std::string function_name = m_lexer.consumeToken(TokenType::identifier).token_string;
|
std::string function_name = m_lexer.consumeToken(TokenType::identifier).token_string;
|
||||||
std::vector<std::unique_ptr<Node>> pars;
|
std::vector<std::unique_ptr<Node>> pars;
|
||||||
|
|
||||||
m_lexer.skipToken(TokenType::open_paren);
|
m_lexer.skipToken(TokenType::open_paren);
|
||||||
while (m_lexer.tokenType() != TokenType::close_paren && m_lexer.tokenType() != TokenType::eof) {
|
while (m_lexer.tokenType() != TokenType::close_paren && m_lexer.tokenType() != TokenType::eof) {
|
||||||
pars.push_back(parse_expression());
|
pars.push_back(parse_expression());
|
||||||
m_lexer.skipTokenOptional(TokenType::comma);
|
m_lexer.skipTokenOptional(TokenType::comma);
|
||||||
}
|
}
|
||||||
m_lexer.skipToken(TokenType::close_paren);
|
m_lexer.skipToken(TokenType::close_paren);
|
||||||
return std::make_unique<FunctionNode>(function_name, std::move(pars));
|
return std::make_unique<FunctionNode>(function_name, std::move(pars));
|
||||||
}
|
}
|
||||||
|
|
||||||
// numbers and strings
|
// numbers and strings
|
||||||
std::string tokenString = m_lexer.consumeToken().token_string;
|
std::string tokenString = m_lexer.consumeToken().token_string;
|
||||||
|
|
||||||
if (token_typcol == TokenType::int_number)
|
if (token_typcol == TokenType::int_number)
|
||||||
return std::make_unique<IntValueNode>(std::stoi(tokenString));
|
return std::make_unique<IntValueNode>(std::stoi(tokenString));
|
||||||
if (token_typcol == TokenType::double_number)
|
if (token_typcol == TokenType::double_number)
|
||||||
return std::make_unique<DoubleValueNode>(std::stod(tokenString));
|
return std::make_unique<DoubleValueNode>(std::stod(tokenString));
|
||||||
if (token_typcol == TokenType::string_literal)
|
if (token_typcol == TokenType::string_literal)
|
||||||
return std::make_unique<StringValueNode>(tokenString);
|
return std::make_unique<StringValueNode>(tokenString);
|
||||||
|
|
||||||
// db column
|
// db column
|
||||||
if (token_typcol == TokenType::identifier)
|
if (token_typcol == TokenType::identifier)
|
||||||
return std::make_unique<DatabaseValueNode>(tokenString);
|
return std::make_unique<DatabaseValueNode>(tokenString);
|
||||||
|
|
||||||
// null
|
// null
|
||||||
if (token_typcol == TokenType::keyword_null)
|
if (token_typcol == TokenType::keyword_null)
|
||||||
return std::make_unique<NullValueNode>();
|
return std::make_unique<NullValueNode>();
|
||||||
|
|
||||||
// true / false
|
// true / false
|
||||||
if (token_typcol == TokenType::keyword_true || token_typcol == TokenType::keyword_false)
|
if (token_typcol == TokenType::keyword_true || token_typcol == TokenType::keyword_false)
|
||||||
return std::make_unique<BooleanValueNode>(token_typcol == TokenType::keyword_true);
|
return std::make_unique<BooleanValueNode>(token_typcol == TokenType::keyword_true);
|
||||||
|
|
||||||
// token * for count(*)
|
// token * for count(*)
|
||||||
if (token_typcol == TokenType::multiply)
|
if (token_typcol == TokenType::multiply)
|
||||||
@@ -491,7 +501,7 @@ namespace usql {
|
|||||||
return RelationalOperatorType::lesser_equal;
|
return RelationalOperatorType::lesser_equal;
|
||||||
case TokenType::is:
|
case TokenType::is:
|
||||||
if (m_lexer.tokenType() == TokenType::keyword_not) {
|
if (m_lexer.tokenType() == TokenType::keyword_not) {
|
||||||
m_lexer.skipToken(TokenType::keyword_not);
|
m_lexer.skipToken(TokenType::keyword_not);
|
||||||
return RelationalOperatorType::is_not;
|
return RelationalOperatorType::is_not;
|
||||||
}
|
}
|
||||||
return RelationalOperatorType::is;
|
return RelationalOperatorType::is;
|
||||||
@@ -529,4 +539,3 @@ namespace usql {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|||||||
152
parser.h
152
parser.h
@@ -21,6 +21,9 @@ enum class ColumnType {
|
|||||||
bool_type
|
bool_type
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::string column_type_name(const ColumnType type);
|
||||||
|
|
||||||
|
|
||||||
enum class NodeType {
|
enum class NodeType {
|
||||||
true_node,
|
true_node,
|
||||||
null_value,
|
null_value,
|
||||||
@@ -51,6 +54,7 @@ enum class NodeType {
|
|||||||
error
|
error
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct Node {
|
struct Node {
|
||||||
NodeType node_type;
|
NodeType node_type;
|
||||||
|
|
||||||
@@ -58,7 +62,7 @@ struct Node {
|
|||||||
virtual ~Node() = default;
|
virtual ~Node() = default;
|
||||||
|
|
||||||
virtual void dump() const {
|
virtual void dump() const {
|
||||||
std::cout << "type: Node" << std::endl;
|
std::cout << "type: Node" << (int)node_type << std::endl;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -115,20 +119,86 @@ struct ColDefNode : Node {
|
|||||||
null(nullable) {}
|
null(nullable) {}
|
||||||
|
|
||||||
void dump() const override {
|
void dump() const override {
|
||||||
std::cout << "type: ColDefNode, name: " << name << ", type: " << (int)type << " TODO add more" << std::endl;
|
std::cout << "type: ColDefNode, name: " << name << ", type: " << column_type_name(type) << ", order: " << order << ", length: " << length << ", null: " << null << std::endl;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FunctionNode : Node {
|
struct FunctionNode : Node {
|
||||||
std::string function; // TODO use enum
|
|
||||||
std::vector<std::unique_ptr<Node>> params;
|
enum class Type {
|
||||||
|
to_char,
|
||||||
|
to_date,
|
||||||
|
to_int,
|
||||||
|
to_float,
|
||||||
|
date_add,
|
||||||
|
pp,
|
||||||
|
lower,
|
||||||
|
upper,
|
||||||
|
coalesce,
|
||||||
|
min,
|
||||||
|
max,
|
||||||
|
count
|
||||||
|
};
|
||||||
|
|
||||||
|
static Type get_function(const std::string &str) {
|
||||||
|
if (str=="to_char") return Type::to_char;
|
||||||
|
if (str=="to_date") return Type::to_date;
|
||||||
|
if (str=="to_int") return Type::to_int;
|
||||||
|
if (str=="to_float") return Type::to_float;
|
||||||
|
if (str=="date_add") return Type::date_add;
|
||||||
|
if (str=="pp") return Type::pp;
|
||||||
|
if (str=="lower") return Type::lower;
|
||||||
|
if (str=="upper") return Type::upper;
|
||||||
|
if (str=="coalesce") return Type::coalesce;
|
||||||
|
if (str=="min") return Type::min;
|
||||||
|
if (str=="max") return Type::max;
|
||||||
|
if (str=="count") return Type::count;
|
||||||
|
|
||||||
|
throw Exception("invalid function: " + str);
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::string function_name(const Type type) {
|
||||||
|
if (type == Type::to_char) return "to_char";
|
||||||
|
if (type == Type::to_date) return "to_date";
|
||||||
|
if (type == Type::to_int) return "to_int";
|
||||||
|
if (type == Type::to_float) return "to_float";
|
||||||
|
if (type == Type::date_add) return "date_add";
|
||||||
|
if (type == Type::pp) return "pp";
|
||||||
|
if (type == Type::lower) return "lower";
|
||||||
|
if (type == Type::upper) return "upper";
|
||||||
|
if (type == Type::coalesce) return "coalesce";
|
||||||
|
if (type == Type::min) return "min";
|
||||||
|
if (type == Type::max) return "max";
|
||||||
|
if (type == Type::count) return "count";
|
||||||
|
|
||||||
|
throw Exception("invalid function: " + std::to_string((int)type));
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
FunctionNode(std::string func_name, std::vector<std::unique_ptr<Node>> pars) :
|
FunctionNode(std::string func_name, std::vector<std::unique_ptr<Node>> pars) :
|
||||||
Node(NodeType::function), function(std::move(func_name)), params(std::move(pars)) {}
|
Node(NodeType::function), function(get_function(func_name)), params(std::move(pars)) {}
|
||||||
|
|
||||||
|
bool is_agg_function() {
|
||||||
|
return (function == Type::count || function == Type::min || function == Type::max);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
friend std::ostream &operator<<(std::ostream &output, const Type &t ) {
|
||||||
|
output << function_name(t);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
void dump() const override {
|
void dump() const override {
|
||||||
std::cout << "type: FunctionNode, function: " << function << " TODO add more" << std::endl;
|
std::cout << "type: FunctionNode, function: " << function_name(function) << "(";
|
||||||
|
for(int i = 0; i < params.size(); i++){
|
||||||
|
if (i > 0) std::cout << ",";
|
||||||
|
params[i]->dump();
|
||||||
|
}
|
||||||
|
std::cout << ")" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Type function;
|
||||||
|
std::vector<std::unique_ptr<Node>> params;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TrueNode : Node {
|
struct TrueNode : Node {
|
||||||
@@ -325,12 +395,17 @@ struct CreateTableNode : Node {
|
|||||||
Node(NodeType::create_table), table_name(std::move(name)), cols_defs(std::move(defs)) {}
|
Node(NodeType::create_table), table_name(std::move(name)), cols_defs(std::move(defs)) {}
|
||||||
|
|
||||||
void dump() const override {
|
void dump() const override {
|
||||||
std::cout << "type: CreateTableNode, table_name: " << table_name << "TODO complete me" << std::endl;
|
std::cout << "type: CreateTableNode, table_name: " << table_name << "(";
|
||||||
|
for(int i = 0; i < cols_defs.size(); i++) {
|
||||||
|
if (i > 0) std::cout << ",";
|
||||||
|
cols_defs[i].dump();
|
||||||
|
}
|
||||||
|
std::cout << ")" << std::endl;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct InsertIntoTableNode : Node {
|
struct InsertIntoTableNode : Node {
|
||||||
std::string table_name;
|
std::string table_name;
|
||||||
std::vector<DatabaseValueNode> cols_names;
|
std::vector<DatabaseValueNode> cols_names;
|
||||||
std::vector<std::unique_ptr<Node>> cols_values;
|
std::vector<std::unique_ptr<Node>> cols_values;
|
||||||
|
|
||||||
@@ -338,29 +413,53 @@ struct InsertIntoTableNode : Node {
|
|||||||
Node(NodeType::insert_into), table_name(std::move(name)), cols_names(std::move(names)), cols_values(std::move(values)) {}
|
Node(NodeType::insert_into), table_name(std::move(name)), cols_names(std::move(names)), cols_values(std::move(values)) {}
|
||||||
|
|
||||||
void dump() const override {
|
void dump() const override {
|
||||||
std::cout << "type: InsertIntoTableNode, table_name: " << table_name << "TODO complete me" << std::endl;
|
std::cout << "type: InsertIntoTableNode, table_name: " << table_name << "(";
|
||||||
|
for(int i = 0; i < cols_names.size(); i++) {
|
||||||
|
if (i > 0) std::cout << ",";
|
||||||
|
cols_names[i].dump();
|
||||||
|
}
|
||||||
|
std::cout << ") values (";
|
||||||
|
for(int i = 0; i < cols_values.size(); i++) {
|
||||||
|
if (i > 0) std::cout << ",";
|
||||||
|
cols_values[i]->dump();
|
||||||
|
}
|
||||||
|
std::cout << ")" << std::endl;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SelectFromTableNode : Node {
|
struct SelectFromTableNode : Node {
|
||||||
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;
|
std::vector<ColOrderNode> order_by;
|
||||||
OffsetLimitNode offset_limit;
|
OffsetLimitNode offset_limit;
|
||||||
bool distinct;
|
bool distinct;
|
||||||
|
|
||||||
SelectFromTableNode(std::string name, std::unique_ptr<std::vector<SelectColNode>> names, std::unique_ptr<Node> where_clause, std::vector<ColOrderNode> orderby, OffsetLimitNode offlim, bool distinct_):
|
SelectFromTableNode(std::string name, std::unique_ptr<std::vector<SelectColNode>> names, std::unique_ptr<Node> where_clause, std::vector<ColOrderNode> orderby, OffsetLimitNode offlim, bool distinct_):
|
||||||
Node(NodeType::select_from), table_name(std::move(name)), cols_names(std::move(names)), where(std::move(where_clause)), order_by(std::move(orderby)), offset_limit(std::move(offlim)), distinct(distinct_) {}
|
Node(NodeType::select_from), table_name(std::move(name)), cols_names(std::move(names)), where(std::move(where_clause)), order_by(std::move(orderby)), offset_limit(std::move(offlim)), distinct(distinct_) {}
|
||||||
|
|
||||||
void dump() const override {
|
void dump() const override {
|
||||||
std::cout << "type: SelectFromTableNode, table_name: " << table_name << "TODO complete me" << std::endl;
|
std::cout << "type: SelectFromTableNode, table_name: " << table_name;
|
||||||
|
std::cout << "colums: ";
|
||||||
|
for(int i = 0; i < cols_names->size(); i++) {
|
||||||
|
if (i > 0) std::cout << ",";
|
||||||
|
cols_names->operator[](i).dump();
|
||||||
|
}
|
||||||
|
std::cout << "where: ";
|
||||||
where->dump();
|
where->dump();
|
||||||
|
std::cout << "offset,limit: ";
|
||||||
|
for(int i = 0; i < order_by.size(); i++) {
|
||||||
|
if (i > 0) std::cout << ",";
|
||||||
|
order_by[i].dump();
|
||||||
|
}
|
||||||
|
std::cout << "offset,limit: ";
|
||||||
|
offset_limit.dump();
|
||||||
|
std::cout << std::endl;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CreateTableAsSelectNode : Node {
|
struct CreateTableAsSelectNode : Node {
|
||||||
std::string table_name;
|
std::string table_name;
|
||||||
std::unique_ptr<Node> select_table;
|
std::unique_ptr<Node> select_table;
|
||||||
|
|
||||||
CreateTableAsSelectNode(std::string name, std::unique_ptr<Node> table) :
|
CreateTableAsSelectNode(std::string name, std::unique_ptr<Node> table) :
|
||||||
@@ -373,10 +472,10 @@ struct CreateTableAsSelectNode : Node {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct UpdateTableNode : Node {
|
struct UpdateTableNode : Node {
|
||||||
std::string table_name;
|
std::string table_name;
|
||||||
std::vector<DatabaseValueNode> cols_names;
|
std::vector<DatabaseValueNode> cols_names;
|
||||||
std::vector<std::unique_ptr<Node>> values;
|
std::vector<std::unique_ptr<Node>> values;
|
||||||
std::unique_ptr<Node> where;
|
std::unique_ptr<Node> where;
|
||||||
|
|
||||||
UpdateTableNode(std::string name, std::vector<DatabaseValueNode> names, std::vector<std::unique_ptr<Node>> vals,
|
UpdateTableNode(std::string name, std::vector<DatabaseValueNode> names, std::vector<std::unique_ptr<Node>> vals,
|
||||||
std::unique_ptr<Node> where_clause) :
|
std::unique_ptr<Node> where_clause) :
|
||||||
@@ -384,8 +483,16 @@ struct UpdateTableNode : Node {
|
|||||||
where(std::move(where_clause)) {}
|
where(std::move(where_clause)) {}
|
||||||
|
|
||||||
void dump() const override {
|
void dump() const override {
|
||||||
std::cout << "type: UpdateTableNode, table_name: " << table_name << "TODO complete me" << std::endl;
|
std::cout << "type: UpdateTableNode, table_name: " << table_name << " set ";
|
||||||
|
for(int i = 0; i < cols_names.size(); i++) {
|
||||||
|
if (i > 0) std::cout << ",";
|
||||||
|
cols_names[i].dump();
|
||||||
|
std::cout << " = ";
|
||||||
|
values[i]->dump();
|
||||||
|
}
|
||||||
|
std::cout << " where: ";
|
||||||
where->dump();
|
where->dump();
|
||||||
|
std::cout << std::endl;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -431,8 +538,10 @@ struct DeleteFromTableNode : Node {
|
|||||||
Node(NodeType::delete_from), table_name(std::move(name)), where(std::move(where_clause)) {}
|
Node(NodeType::delete_from), table_name(std::move(name)), where(std::move(where_clause)) {}
|
||||||
|
|
||||||
void dump() const override {
|
void dump() const override {
|
||||||
std::cout << "type: DeleteFromTableNode, table_name: " << table_name << std::endl;
|
std::cout << "type: DeleteFromTableNode, table_name: " << table_name;
|
||||||
|
std::cout << "where: ";
|
||||||
where->dump();
|
where->dump();
|
||||||
|
std::cout << std::endl;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -472,7 +581,6 @@ struct CreateIndexNode : Node {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class Parser {
|
class Parser {
|
||||||
private:
|
|
||||||
public:
|
public:
|
||||||
Parser();
|
Parser();
|
||||||
|
|
||||||
|
|||||||
4
row.h
4
row.h
@@ -171,7 +171,7 @@ public:
|
|||||||
case 5:
|
case 5:
|
||||||
return (ColValue &) *std::get_if<ColBooleanValue>(&m_columns[i]);
|
return (ColValue &) *std::get_if<ColBooleanValue>(&m_columns[i]);
|
||||||
default:
|
default:
|
||||||
throw Exception("should not happen");
|
throw Exception("ColValue &operator[](int i), type index invalid :" + std::to_string(type_index));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,7 +182,7 @@ public:
|
|||||||
|
|
||||||
[[nodiscard]] bool is_visible() const { return m_visible; };
|
[[nodiscard]] bool is_visible() const { return m_visible; };
|
||||||
void set_visible() { m_visible = true; };
|
void set_visible() { m_visible = true; };
|
||||||
void set_deleted() { m_visible = true; };
|
void set_deleted() { m_visible = false; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_visible;
|
bool m_visible;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ std::vector<std::pair<std::string, std::string>> Settings::m_settings =
|
|||||||
std::make_pair("BOOL_TRUE_LITERAL", "Y"),
|
std::make_pair("BOOL_TRUE_LITERAL", "Y"),
|
||||||
std::make_pair("BOOL_FALSE_LITERAL", "N"),
|
std::make_pair("BOOL_FALSE_LITERAL", "N"),
|
||||||
std::make_pair("DOUBLE_FORMAT", "%.2f"),
|
std::make_pair("DOUBLE_FORMAT", "%.2f"),
|
||||||
std::make_pair("USE_INDEXSCAN", "N"),
|
std::make_pair("USE_INDEXSCAN", "Y"),
|
||||||
std::make_pair("MAX_PARALLELISM", "1") }; // values "AUTO" or number of workers; when number negative means std::thread::hardware_concurrency() - number
|
std::make_pair("MAX_PARALLELISM", "1") }; // values "AUTO" or number of workers; when number negative means std::thread::hardware_concurrency() - number
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
56
usql.cpp
56
usql.cpp
@@ -6,9 +6,37 @@
|
|||||||
|
|
||||||
namespace usql {
|
namespace usql {
|
||||||
|
|
||||||
|
USql::USql() {
|
||||||
|
// create catalogue tables first
|
||||||
|
|
||||||
|
std::vector<std::string> k_debug_sql_commands {
|
||||||
|
"create table usql_tables(name varchar(32) not null, modified boolean not null)",
|
||||||
|
"create table usql_columns(table_name varchar(32) not null, column_name varchar(32) not null, column_type varchar(16) not null, column_length integer not null, nullable boolean not null, column_order integer not null)",
|
||||||
|
"create table usql_indexes(index_name varchar(32) not null, table_name varchar(32), column_name varchar(32) not null)"
|
||||||
|
};
|
||||||
|
|
||||||
|
// create cataloque tables
|
||||||
|
for (const auto &command : k_debug_sql_commands) {
|
||||||
|
std::unique_ptr<Node> create_table_node = m_parser.parse(command);
|
||||||
|
const CreateTableNode &node = static_cast<CreateTableNode &>(*create_table_node);
|
||||||
|
|
||||||
|
Table table{node.table_name, node.cols_defs};
|
||||||
|
m_tables.push_back(table);
|
||||||
|
|
||||||
|
}
|
||||||
|
// insert data into cataloque tables
|
||||||
|
for (const auto &command : k_debug_sql_commands) {
|
||||||
|
std::unique_ptr<Node> create_table_node = m_parser.parse(command);
|
||||||
|
const CreateTableNode &node = static_cast<CreateTableNode &>(*create_table_node);
|
||||||
|
|
||||||
|
execute_create_table_sys_catalogue(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<Table> USql::execute(const std::string &command) {
|
std::unique_ptr<Table> USql::execute(const std::string &command) {
|
||||||
try {
|
try {
|
||||||
std::unique_ptr<Node> node = m_parser.parse(command);
|
std::unique_ptr<Node> node = m_parser.parse(command);
|
||||||
|
// node->dump();
|
||||||
return execute(*node);
|
return execute(*node);
|
||||||
|
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
@@ -121,7 +149,7 @@ std::unique_ptr<ValueNode> USql::eval_value_node(Table *table, Row &row, Node *n
|
|||||||
|
|
||||||
std::unique_ptr<ValueNode> USql::eval_database_value_node(Table *table, Row &row, Node *node) {
|
std::unique_ptr<ValueNode> USql::eval_database_value_node(Table *table, Row &row, Node *node) {
|
||||||
auto *dvl = static_cast<DatabaseValueNode *>(node);
|
auto *dvl = static_cast<DatabaseValueNode *>(node);
|
||||||
ColDefNode col_def = table->get_column_def( dvl->col_name); // TODO optimize it to just get this def once
|
ColDefNode col_def = table->get_column_def(dvl->col_name); // TODO optimize it to just get this def once
|
||||||
ColValue &db_value = row[col_def.order];
|
ColValue &db_value = row[col_def.order];
|
||||||
|
|
||||||
if (db_value.isNull())
|
if (db_value.isNull())
|
||||||
@@ -173,21 +201,25 @@ std::unique_ptr<ValueNode> USql::eval_function_value_node(Table *table, Row &row
|
|||||||
evaluatedPars.push_back(eval_value_node(table, row, param.get(), nullptr, nullptr));
|
evaluatedPars.push_back(eval_value_node(table, row, param.get(), nullptr, nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// coalesce function can have first parameter null, so must be calles before following "return null"
|
||||||
|
if (fnc->function == FunctionNode::Type::coalesce) return coalesce_function(evaluatedPars);
|
||||||
|
|
||||||
if (evaluatedPars.empty() || evaluatedPars[0]->isNull())
|
if (evaluatedPars.empty() || evaluatedPars[0]->isNull())
|
||||||
return std::make_unique<NullValueNode>();
|
return std::make_unique<NullValueNode>();
|
||||||
|
|
||||||
// TODO use some enum
|
if (fnc->function == FunctionNode::Type::lower) return lower_function(evaluatedPars);
|
||||||
if (fnc->function == "lower") return lower_function(evaluatedPars);
|
if (fnc->function == FunctionNode::Type::upper) return upper_function(evaluatedPars);
|
||||||
if (fnc->function == "upper") return upper_function(evaluatedPars);
|
if (fnc->function == FunctionNode::Type::to_date) return to_date_function(evaluatedPars);
|
||||||
if (fnc->function == "to_date") return to_date_function(evaluatedPars);
|
if (fnc->function == FunctionNode::Type::to_char) return to_char_function(evaluatedPars);
|
||||||
if (fnc->function == "to_string") return to_string_function(evaluatedPars);
|
if (fnc->function == FunctionNode::Type::to_int) return to_int_function(evaluatedPars);
|
||||||
if (fnc->function == "date_add") return date_add_function(evaluatedPars);
|
if (fnc->function == FunctionNode::Type::to_float) return to_float_function(evaluatedPars);
|
||||||
if (fnc->function == "pp") return pp_function(evaluatedPars);
|
if (fnc->function == FunctionNode::Type::date_add) return date_add_function(evaluatedPars);
|
||||||
if (fnc->function == "count") return count_function(agg_func_value, evaluatedPars);
|
if (fnc->function == FunctionNode::Type::pp) return pp_function(evaluatedPars);
|
||||||
if (fnc->function == "max") return max_function(evaluatedPars, col_def_node, agg_func_value);
|
if (fnc->function == FunctionNode::Type::count) return count_function(agg_func_value, evaluatedPars);
|
||||||
if (fnc->function == "min") return min_function(evaluatedPars, col_def_node, agg_func_value);
|
if (fnc->function == FunctionNode::Type::max) return max_function(evaluatedPars, col_def_node, agg_func_value);
|
||||||
|
if (fnc->function == FunctionNode::Type::min) return min_function(evaluatedPars, col_def_node, agg_func_value);
|
||||||
|
|
||||||
throw Exception("invalid function: " + fnc->function);
|
throw Exception("invalid function: " + FunctionNode::function_name(fnc->function));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
18
usql.h
18
usql.h
@@ -13,15 +13,16 @@ namespace usql {
|
|||||||
class USql {
|
class USql {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
USql() = default;
|
USql();
|
||||||
|
|
||||||
std::unique_ptr<Table> execute(const std::string &command);
|
std::unique_ptr<Table> execute(const std::string &command);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<Table> execute(Node &node);
|
std::unique_ptr<Table> execute(Node &node);
|
||||||
|
|
||||||
std::unique_ptr<Table> execute_create_table(const CreateTableNode &node);
|
std::unique_ptr<Table> execute_create_table(const CreateTableNode &node);
|
||||||
|
bool execute_create_table_sys_catalogue(const CreateTableNode &node);
|
||||||
std::unique_ptr<Table> execute_create_index(const CreateIndexNode &node);
|
std::unique_ptr<Table> execute_create_index(const CreateIndexNode &node);
|
||||||
|
bool execute_create_index_sys_catalogue(const CreateIndexNode &node);
|
||||||
std::unique_ptr<Table> execute_create_table_as_table(const CreateTableAsSelectNode &node);
|
std::unique_ptr<Table> execute_create_table_as_table(const CreateTableAsSelectNode &node);
|
||||||
std::unique_ptr<Table> execute_load(const LoadIntoTableNode &node);
|
std::unique_ptr<Table> execute_load(const LoadIntoTableNode &node);
|
||||||
std::unique_ptr<Table> execute_save(const SaveTableNode &node);
|
std::unique_ptr<Table> execute_save(const SaveTableNode &node);
|
||||||
@@ -59,9 +60,6 @@ private:
|
|||||||
void check_index_not_exists(const std::string &index_name);
|
void check_index_not_exists(const std::string &index_name);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Parser m_parser;
|
|
||||||
std::list<Table> m_tables;
|
|
||||||
|
|
||||||
static void execute_distinct(SelectFromTableNode &node, Table *result);
|
static void execute_distinct(SelectFromTableNode &node, Table *result);
|
||||||
static void execute_order_by(SelectFromTableNode &node, Table *result);
|
static void execute_order_by(SelectFromTableNode &node, Table *result);
|
||||||
static void execute_offset_limit(OffsetLimitNode &node, Table *result);
|
static void execute_offset_limit(OffsetLimitNode &node, Table *result);
|
||||||
@@ -73,8 +71,11 @@ private:
|
|||||||
|
|
||||||
static std::unique_ptr<ValueNode> lower_function(const std::vector<std::unique_ptr<ValueNode>> &evaluatedPars);
|
static std::unique_ptr<ValueNode> lower_function(const std::vector<std::unique_ptr<ValueNode>> &evaluatedPars);
|
||||||
static std::unique_ptr<ValueNode> upper_function(const std::vector<std::unique_ptr<ValueNode>> &evaluatedPars);
|
static std::unique_ptr<ValueNode> upper_function(const std::vector<std::unique_ptr<ValueNode>> &evaluatedPars);
|
||||||
|
static std::unique_ptr<ValueNode> coalesce_function(const std::vector<std::unique_ptr<ValueNode>> &evaluatedPars);
|
||||||
static std::unique_ptr<ValueNode> to_date_function(const std::vector<std::unique_ptr<ValueNode>> &evaluatedPars);
|
static std::unique_ptr<ValueNode> to_date_function(const std::vector<std::unique_ptr<ValueNode>> &evaluatedPars);
|
||||||
static std::unique_ptr<ValueNode> to_string_function(const std::vector<std::unique_ptr<ValueNode>> &evaluatedPars);
|
static std::unique_ptr<ValueNode> to_char_function(const std::vector<std::unique_ptr<ValueNode>> &evaluatedPars);
|
||||||
|
static std::unique_ptr<ValueNode> to_int_function(const std::vector<std::unique_ptr<ValueNode>> &evaluatedPars);
|
||||||
|
static std::unique_ptr<ValueNode> to_float_function(const std::vector<std::unique_ptr<ValueNode>> &evaluatedPars);
|
||||||
static std::unique_ptr<ValueNode> date_add_function(const std::vector<std::unique_ptr<ValueNode>> &evaluatedPars);
|
static std::unique_ptr<ValueNode> date_add_function(const std::vector<std::unique_ptr<ValueNode>> &evaluatedPars);
|
||||||
static std::unique_ptr<ValueNode> pp_function(const std::vector<std::unique_ptr<ValueNode>> &evaluatedPars);
|
static std::unique_ptr<ValueNode> pp_function(const std::vector<std::unique_ptr<ValueNode>> &evaluatedPars);
|
||||||
|
|
||||||
@@ -94,6 +95,11 @@ private:
|
|||||||
bool normalize_where(const Node *node) const;
|
bool normalize_where(const Node *node) const;
|
||||||
|
|
||||||
Table::rows_scanner get_iterator(Table *table, const Node *where) const;
|
Table::rows_scanner get_iterator(Table *table, const Node *where) const;
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
Parser m_parser;
|
||||||
|
std::list<Table> m_tables;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
44
usql_ddl.cpp
44
usql_ddl.cpp
@@ -8,17 +8,41 @@
|
|||||||
namespace usql {
|
namespace usql {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
std::unique_ptr<Table> USql::execute_create_table(const CreateTableNode &node) {
|
std::unique_ptr<Table> USql::execute_create_table(const CreateTableNode &node) {
|
||||||
check_table_not_exists(node.table_name);
|
check_table_not_exists(node.table_name);
|
||||||
|
|
||||||
Table table{node.table_name, node.cols_defs};
|
Table table{node.table_name, node.cols_defs};
|
||||||
m_tables.push_back(table);
|
m_tables.push_back(table);
|
||||||
|
|
||||||
|
execute_create_table_sys_catalogue(node);
|
||||||
|
|
||||||
return create_stmt_result_table(0, "table created", 0);
|
return create_stmt_result_table(0, "table created", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool USql::execute_create_table_sys_catalogue(const CreateTableNode &node) {
|
||||||
|
// usql_tables
|
||||||
|
auto r = execute("insert into usql_tables(name, modified) values('" + node.table_name + "', false)");
|
||||||
|
|
||||||
|
// usql_columns
|
||||||
|
for(const ColDefNode & col_def : node.cols_defs) {
|
||||||
|
std::string i {"insert into usql_columns(table_name, column_name, column_type, column_length, nullable, column_order) values("};
|
||||||
|
i += "'" + node.table_name + "', ";
|
||||||
|
i += "'" + col_def.name + "', ";
|
||||||
|
i += "'" + column_type_name(col_def.type) + "', ";
|
||||||
|
i += std::to_string(col_def.length) + ", ";
|
||||||
|
i += (col_def.null ? "true, " : "false, ");
|
||||||
|
i += std::to_string(col_def.order);
|
||||||
|
i += ")";
|
||||||
|
|
||||||
|
auto r = execute(i);
|
||||||
|
// r->print();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::unique_ptr<Table> USql::execute_create_index(const CreateIndexNode &node) {
|
std::unique_ptr<Table> USql::execute_create_index(const CreateIndexNode &node) {
|
||||||
Table *table_def = find_table(node.table_name); // throws exception if not found
|
Table *table_def = find_table(node.table_name); // throws exception if not found
|
||||||
ColDefNode col_def = table_def->get_column_def(node.column_name); // throws exception if not found
|
ColDefNode col_def = table_def->get_column_def(node.column_name); // throws exception if not found
|
||||||
@@ -31,10 +55,25 @@ std::unique_ptr<Table> USql::execute_create_index(const CreateIndexNode &node) {
|
|||||||
|
|
||||||
table_def->index_rows(node.index_name);
|
table_def->index_rows(node.index_name);
|
||||||
|
|
||||||
|
execute_create_index_sys_catalogue(node);
|
||||||
|
|
||||||
return create_stmt_result_table(0, "index created", 0);
|
return create_stmt_result_table(0, "index created", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool USql::execute_create_index_sys_catalogue(const CreateIndexNode &node) {
|
||||||
|
std::string i {"insert into usql_indexes(index_name, table_name, column_name) values("};
|
||||||
|
i += "'" + node.index_name + "', ";
|
||||||
|
i += "'" + node.table_name + "', ";
|
||||||
|
i += "'" + node.column_name + "')";
|
||||||
|
|
||||||
|
auto r = execute(i);
|
||||||
|
// r->print();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::unique_ptr<Table> USql::execute_create_table_as_table(const CreateTableAsSelectNode &node) {
|
std::unique_ptr<Table> USql::execute_create_table_as_table(const CreateTableAsSelectNode &node) {
|
||||||
check_table_not_exists(node.table_name);
|
check_table_not_exists(node.table_name);
|
||||||
|
|
||||||
@@ -57,7 +96,6 @@ std::unique_ptr<Table> USql::execute_create_table_as_table(const CreateTableAsSe
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
std::unique_ptr<Table> USql::execute_drop(const DropTableNode &node) {
|
std::unique_ptr<Table> USql::execute_drop(const DropTableNode &node) {
|
||||||
auto name_cmp = [node](const Table& t) { return t.m_name == node.table_name; };
|
auto name_cmp = [node](const Table& t) { return t.m_name == node.table_name; };
|
||||||
|
|
||||||
@@ -70,11 +108,13 @@ std::unique_ptr<Table> USql::execute_drop(const DropTableNode &node) {
|
|||||||
throw Exception("table not found (" + node.table_name + ")");
|
throw Exception("table not found (" + node.table_name + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::unique_ptr<Table> USql::execute_set(const SetNode &node) {
|
std::unique_ptr<Table> USql::execute_set(const SetNode &node) {
|
||||||
Settings::set_setting(node.name, node.value);
|
Settings::set_setting(node.name, node.value);
|
||||||
return create_stmt_result_table(0, "set succeeded", 1);
|
return create_stmt_result_table(0, "set succeeded", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::unique_ptr<Table> USql::execute_show(const ShowNode &node) {
|
std::unique_ptr<Table> USql::execute_show(const ShowNode &node) {
|
||||||
std::string value = Settings::get_setting(node.name);
|
std::string value = Settings::get_setting(node.name);
|
||||||
return create_stmt_result_table(0, "show succeeded: " + value, 1);
|
return create_stmt_result_table(0, "show succeeded: " + value, 1);
|
||||||
|
|||||||
73
usql_dml.cpp
73
usql_dml.cpp
@@ -35,7 +35,7 @@ std::pair<bool, std::vector<rowid_t>> USql::look_for_usable_index(const Node *wh
|
|||||||
if (used_index != nullptr) {
|
if (used_index != nullptr) {
|
||||||
std::vector<rowid_t> rowids = used_index->search((ValueNode *)ron->right.get());
|
std::vector<rowid_t> rowids = used_index->search((ValueNode *)ron->right.get());
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
std::cout << "using index " << table->m_name << "(" << used_index->get_column_name() << "), " << rowids.size() << "/" << table->rows_count() << std::endl;
|
std::cerr << "using index " << table->m_name << "(" << used_index->get_column_name() << "), " << rowids.size() << "/" << table->rows_count() << std::endl;
|
||||||
#endif
|
#endif
|
||||||
return std::make_pair(true, rowids);
|
return std::make_pair(true, rowids);
|
||||||
}
|
}
|
||||||
@@ -88,7 +88,7 @@ void USql::select_row(SelectFromTableNode &where_node,
|
|||||||
|
|
||||||
Row *rslt_row = nullptr;
|
Row *rslt_row = nullptr;
|
||||||
|
|
||||||
// when aggregate functions in rslt_table only one row exists
|
// when aggregate functions in rslt_table only one row exists
|
||||||
if (is_aggregated && !rslt_table->empty())
|
if (is_aggregated && !rslt_table->empty())
|
||||||
rslt_row = &rslt_table->m_rows[0];
|
rslt_row = &rslt_table->m_rows[0];
|
||||||
else
|
else
|
||||||
@@ -108,24 +108,21 @@ void USql::select_row(SelectFromTableNode &where_node,
|
|||||||
rslt_row->setColumnValue((ColDefNode *) &rslt_tbl_col_defs[idx], col_value);
|
rslt_row->setColumnValue((ColDefNode *) &rslt_tbl_col_defs[idx], col_value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// for aggregate is validated more than needed
|
||||||
// for aggregate is validated more than needed
|
rslt_table->commit_row(*rslt_row);
|
||||||
rslt_table->commit_row(*rslt_row);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool USql::check_for_aggregate_only_functions(SelectFromTableNode &node, size_t result_cols_cnt) {
|
bool USql::check_for_aggregate_only_functions(SelectFromTableNode &node, size_t result_cols_cnt) {
|
||||||
size_t aggregate_funcs = 0;
|
size_t aggregate_funcs = 0;
|
||||||
|
|
||||||
for (size_t i = 0; i < node.cols_names->size(); i++) {
|
for (size_t i = 0; i < node.cols_names->size(); i++) {
|
||||||
SelectColNode * col_node = &node.cols_names->operator[](i);
|
SelectColNode * col_node = &node.cols_names->operator[](i);
|
||||||
if (col_node->value->node_type == NodeType::function) {
|
if (col_node->value->node_type == NodeType::function && ((FunctionNode *)col_node->value.get())->is_agg_function())
|
||||||
auto func_node = static_cast<FunctionNode *>(col_node->value.get());
|
aggregate_funcs++;
|
||||||
if (func_node->function == "count" || func_node->function == "min" || func_node->function == "max")
|
|
||||||
aggregate_funcs++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// check whether aggregates are not present or all columns are aggregates
|
// check whether aggregates are not present or all columns are aggregates
|
||||||
if (aggregate_funcs > 0 && aggregate_funcs != result_cols_cnt) {
|
if (aggregate_funcs > 0 && aggregate_funcs != result_cols_cnt) {
|
||||||
throw Exception("aggregate functions with no aggregates");
|
throw Exception("aggregate functions mixed with no aggregate functions in select clause");
|
||||||
}
|
}
|
||||||
|
|
||||||
return aggregate_funcs > 0;
|
return aggregate_funcs > 0;
|
||||||
@@ -158,8 +155,7 @@ void USql::setup_order_columns(std::vector<ColOrderNode> &node, Table *table) {
|
|||||||
void USql::execute_distinct(SelectFromTableNode &node, Table *result) {
|
void USql::execute_distinct(SelectFromTableNode &node, Table *result) {
|
||||||
if (!node.distinct) return;
|
if (!node.distinct) return;
|
||||||
|
|
||||||
auto compare_rows = [](const Row &a, const Row &b) { return a.compare(b) >= 0; };
|
std::sort(result->m_rows.begin(), result->m_rows.end(), [](const Row &a, const Row &b) { return a.compare(b) > 0; });
|
||||||
std::sort(result->m_rows.begin(), result->m_rows.end(), compare_rows);
|
|
||||||
|
|
||||||
result->m_rows.erase(std::unique(result->m_rows.begin(), result->m_rows.end()), result->m_rows.end());
|
result->m_rows.erase(std::unique(result->m_rows.begin(), result->m_rows.end()), result->m_rows.end());
|
||||||
}
|
}
|
||||||
@@ -220,7 +216,7 @@ ColDefNode USql::get_db_column_definition(Table *table, Node *node) {
|
|||||||
throw Exception("Undefined table node - get_db_column_definition");
|
throw Exception("Undefined table node - get_db_column_definition");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<int, ColDefNode> USql::get_node_definition(Table *table, Node * node, const std::string & col_name, int col_order ) {
|
std::tuple<int, ColDefNode> USql::get_node_definition(Table *table, Node * node, const std::string &col_name, int col_order ) {
|
||||||
if (node->node_type == NodeType::database_value) {
|
if (node->node_type == NodeType::database_value) {
|
||||||
ColDefNode src_col_def = get_db_column_definition(table, node);
|
ColDefNode src_col_def = get_db_column_definition(table, node);
|
||||||
ColDefNode col_def = ColDefNode{col_name, src_col_def.type, col_order, src_col_def.length, src_col_def.null};
|
ColDefNode col_def = ColDefNode{col_name, src_col_def.type, col_order, src_col_def.length, src_col_def.null};
|
||||||
@@ -229,33 +225,54 @@ std::tuple<int, ColDefNode> USql::get_node_definition(Table *table, Node * node,
|
|||||||
} else if (node->node_type == NodeType::function) {
|
} else if (node->node_type == NodeType::function) {
|
||||||
auto func_node = static_cast<FunctionNode *>(node);
|
auto func_node = static_cast<FunctionNode *>(node);
|
||||||
|
|
||||||
if (func_node->function == "to_string") {
|
if (func_node->function == FunctionNode::Type::to_char) {
|
||||||
ColDefNode col_def = ColDefNode{col_name, ColumnType::varchar_type, col_order, 32, true};
|
ColDefNode col_def = ColDefNode{col_name, ColumnType::varchar_type, col_order, 32, true};
|
||||||
return std::make_tuple(-1, col_def);
|
return std::make_tuple(FUNCTION_CALL, col_def);
|
||||||
} else if (func_node->function == "to_date") {
|
} else if (func_node->function == FunctionNode::Type::to_int) {
|
||||||
ColDefNode col_def = ColDefNode{col_name, ColumnType::integer_type, col_order, 1, true};
|
ColDefNode col_def = ColDefNode{col_name, ColumnType::integer_type, col_order, 1, true};
|
||||||
return std::make_tuple(-1, col_def);
|
return std::make_tuple(FUNCTION_CALL, col_def);
|
||||||
} else if (func_node->function == "pp") {
|
} else if (func_node->function == FunctionNode::Type::to_float) {
|
||||||
|
ColDefNode col_def = ColDefNode{col_name, ColumnType::float_type, col_order, 1, true};
|
||||||
|
return std::make_tuple(FUNCTION_CALL, col_def);
|
||||||
|
} else if (func_node->function == FunctionNode::Type::to_date) {
|
||||||
|
ColDefNode col_def = ColDefNode{col_name, ColumnType::integer_type, col_order, 1, true};
|
||||||
|
return std::make_tuple(FUNCTION_CALL, col_def);
|
||||||
|
} else if (func_node->function == FunctionNode::Type::pp) {
|
||||||
ColDefNode col_def = ColDefNode{col_name, ColumnType::varchar_type, col_order, 10, true};
|
ColDefNode col_def = ColDefNode{col_name, ColumnType::varchar_type, col_order, 10, true};
|
||||||
return std::make_tuple(-1, col_def);
|
return std::make_tuple(FUNCTION_CALL, col_def);
|
||||||
} else if (func_node->function == "lower" || func_node->function == "upper") {
|
} else if (func_node->function == FunctionNode::Type::lower || func_node->function == FunctionNode::Type::upper) {
|
||||||
// TODO get length, use get_db_column_definition
|
// TODO get length, use get_db_column_definition
|
||||||
ColDefNode col_def = ColDefNode{col_name, ColumnType::varchar_type, col_order, 256, true};
|
ColDefNode col_def = ColDefNode{col_name, ColumnType::varchar_type, col_order, 256, true};
|
||||||
return std::make_tuple(-1, col_def);
|
return std::make_tuple(FUNCTION_CALL, col_def);
|
||||||
} else if (func_node->function == "min" || func_node->function == "max") {
|
} else if (func_node->function == FunctionNode::Type::coalesce) {
|
||||||
auto col_type= ColumnType::float_type;
|
// TODO handle cases here
|
||||||
|
if (func_node->params.empty()) throw Exception("Coalesce without parameters");
|
||||||
|
if (func_node->params[0]->node_type != NodeType::database_value) throw Exception("Coalesce first parameter must be database column");
|
||||||
|
|
||||||
|
ColDefNode tbl_col_def = get_db_column_definition(table, func_node->params[0].get());
|
||||||
|
ColDefNode col_def = ColDefNode{col_name, tbl_col_def.type, col_order, tbl_col_def.length, true};
|
||||||
|
return std::make_tuple(FUNCTION_CALL, col_def);
|
||||||
|
} else if (func_node->function == FunctionNode::Type::min || func_node->function == FunctionNode::Type::max) {
|
||||||
|
auto col_type = ColumnType::float_type;
|
||||||
size_t col_len = 1;
|
size_t col_len = 1;
|
||||||
auto & v = func_node->params[0];
|
auto &v = func_node->params[0];
|
||||||
|
|
||||||
if (v->node_type == NodeType::database_value) {
|
if (v->node_type == NodeType::database_value) {
|
||||||
ColDefNode src_col_def = get_db_column_definition(table, v.get());
|
ColDefNode src_col_def = get_db_column_definition(table, v.get());
|
||||||
col_type = src_col_def.type;
|
col_type = src_col_def.type;
|
||||||
col_len = src_col_def.length;
|
col_len = src_col_def.length;
|
||||||
|
|
||||||
|
} else if (node->node_type == NodeType::function) {
|
||||||
|
std::tuple<int, ColDefNode> fun_type = get_node_definition(table, static_cast<Node*>(& *v), "", 0);
|
||||||
|
col_type = std::get<1>(fun_type).type;
|
||||||
|
col_len = std::get<1>(fun_type).length;
|
||||||
}
|
}
|
||||||
|
|
||||||
ColDefNode col_def = ColDefNode{col_name, col_type, col_order, col_len, true};
|
ColDefNode col_def = ColDefNode{col_name, col_type, col_order, col_len, true};
|
||||||
return std::make_tuple(-1, col_def);
|
return std::make_tuple(FUNCTION_CALL, col_def);
|
||||||
} else if (func_node->function == "count") {
|
} else if (func_node->function == FunctionNode::Type::count) {
|
||||||
ColDefNode col_def = ColDefNode{col_name, ColumnType::integer_type, col_order, 1, true};
|
ColDefNode col_def = ColDefNode{col_name, ColumnType::integer_type, col_order, 1, true};
|
||||||
return std::make_tuple(-1, col_def);
|
return std::make_tuple(FUNCTION_CALL, col_def);
|
||||||
}
|
}
|
||||||
throw Exception("Unsupported function");
|
throw Exception("Unsupported function");
|
||||||
|
|
||||||
|
|||||||
@@ -7,17 +7,31 @@
|
|||||||
|
|
||||||
namespace usql {
|
namespace usql {
|
||||||
|
|
||||||
std::unique_ptr<ValueNode> USql::to_string_function(const std::vector<std::unique_ptr<ValueNode>> &evaluatedPars) {
|
std::unique_ptr<ValueNode> USql::to_char_function(const std::vector<std::unique_ptr<ValueNode>> &evaluatedPars) {
|
||||||
long date = evaluatedPars[0]->getDateValue();
|
if (evaluatedPars[0]->node_type == NodeType::int_value && evaluatedPars.size()==2) { // TODO when propper date is introduced
|
||||||
std::string format = evaluatedPars[1]->getStringValue();
|
long date = evaluatedPars[0]->getDateValue();
|
||||||
std::string formatted_date = date_to_string(date, format);
|
std::string format = evaluatedPars[1]->getStringValue();
|
||||||
return std::make_unique<StringValueNode>(formatted_date);
|
std::string formatted_date = date_to_string(date, format);
|
||||||
|
|
||||||
|
return std::make_unique<StringValueNode>(formatted_date);
|
||||||
|
} else {
|
||||||
|
return std::make_unique<StringValueNode>(evaluatedPars[0]->getStringValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<ValueNode> USql::to_int_function(const std::vector<std::unique_ptr<ValueNode>> &evaluatedPars) {
|
||||||
|
return std::make_unique<IntValueNode>(evaluatedPars[0]->getIntegerValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<ValueNode> USql::to_float_function(const std::vector<std::unique_ptr<ValueNode>> &evaluatedPars) {
|
||||||
|
return std::make_unique<DoubleValueNode>(evaluatedPars[0]->getDoubleValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<ValueNode> USql::to_date_function(const std::vector<std::unique_ptr<ValueNode>> &evaluatedPars) {
|
std::unique_ptr<ValueNode> USql::to_date_function(const std::vector<std::unique_ptr<ValueNode>> &evaluatedPars) {
|
||||||
std::string date = evaluatedPars[0]->getStringValue();
|
std::string date = evaluatedPars[0]->getStringValue();
|
||||||
std::string format = evaluatedPars[1]->getStringValue();
|
std::string format = evaluatedPars[1]->getStringValue();
|
||||||
long epoch_time = string_to_date(date, format);
|
long epoch_time = string_to_date(date, format);
|
||||||
|
|
||||||
return std::make_unique<IntValueNode>(epoch_time); // No DateValueNode for now
|
return std::make_unique<IntValueNode>(epoch_time); // No DateValueNode for now
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,58 +41,82 @@ std::unique_ptr<ValueNode> USql::date_add_function(const std::vector<std::unique
|
|||||||
std::string part = evaluatedPars[2]->getStringValue();
|
std::string part = evaluatedPars[2]->getStringValue();
|
||||||
|
|
||||||
long new_date = add_to_date(datetime, quantity, part);
|
long new_date = add_to_date(datetime, quantity, part);
|
||||||
|
|
||||||
return std::make_unique<IntValueNode>(new_date); // No DateValueNode for now
|
return std::make_unique<IntValueNode>(new_date); // No DateValueNode for now
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::unique_ptr<ValueNode> USql::upper_function(const std::vector<std::unique_ptr<ValueNode>> &evaluatedPars) {
|
|
||||||
std::string str = evaluatedPars[0]->getStringValue();
|
|
||||||
std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) -> unsigned char { return toupper(c); });
|
|
||||||
return std::make_unique<StringValueNode>(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<ValueNode> USql::lower_function(const std::vector<std::unique_ptr<ValueNode>> &evaluatedPars) {
|
std::unique_ptr<ValueNode> USql::lower_function(const std::vector<std::unique_ptr<ValueNode>> &evaluatedPars) {
|
||||||
std::string str = evaluatedPars[0]->getStringValue();
|
std::string str = evaluatedPars[0]->getStringValue();
|
||||||
std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) -> unsigned char { return tolower(c); });
|
std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) -> unsigned char { return tolower(c); });
|
||||||
|
|
||||||
return std::make_unique<StringValueNode>(str);
|
return std::make_unique<StringValueNode>(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<ValueNode> USql::upper_function(const std::vector<std::unique_ptr<ValueNode>> &evaluatedPars) {
|
||||||
|
std::string str = evaluatedPars[0]->getStringValue();
|
||||||
|
std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) -> unsigned char { return toupper(c); });
|
||||||
|
|
||||||
|
return std::make_unique<StringValueNode>(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<ValueNode> USql::coalesce_function(const std::vector<std::unique_ptr<ValueNode>> &evaluatedPars) {
|
||||||
|
for(const auto & par : evaluatedPars) {
|
||||||
|
if (!par->isNull()) {
|
||||||
|
// TODO implement rest and take it out as a function
|
||||||
|
if (par->node_type == NodeType::int_value)
|
||||||
|
return std::make_unique<IntValueNode>(par->getIntegerValue());
|
||||||
|
if (par->node_type == NodeType::float_value)
|
||||||
|
return std::make_unique<DoubleValueNode>(par->getDoubleValue());
|
||||||
|
if (par->node_type == NodeType::string_value)
|
||||||
|
return std::make_unique<StringValueNode>(par->getStringValue());
|
||||||
|
if (par->node_type == NodeType::bool_value)
|
||||||
|
return std::make_unique<BooleanValueNode>(par->getBooleanValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::make_unique<NullValueNode>();
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<ValueNode> USql::pp_function(const std::vector<std::unique_ptr<ValueNode>> &evaluatedPars) {
|
std::unique_ptr<ValueNode> USql::pp_function(const std::vector<std::unique_ptr<ValueNode>> &evaluatedPars) {
|
||||||
|
constexpr auto k_num_format_rpad = 10;
|
||||||
|
constexpr auto k_num_format_maxlen = 20;
|
||||||
|
|
||||||
auto &parsed_value = evaluatedPars[0];
|
auto &parsed_value = evaluatedPars[0];
|
||||||
|
|
||||||
if (parsed_value->node_type == NodeType::int_value || parsed_value->node_type == NodeType::float_value) {
|
if (parsed_value->node_type == NodeType::int_value || parsed_value->node_type == NodeType::float_value) {
|
||||||
std::string format = evaluatedPars.size() > 1 ? evaluatedPars[1]->getStringValue() : "";
|
std::string format = evaluatedPars.size() > 1 ? evaluatedPars[1]->getStringValue() : "";
|
||||||
char buf[20] {0}; // TODO constant here
|
char buf[k_num_format_maxlen] {0};
|
||||||
double value = parsed_value->getDoubleValue();
|
double value = parsed_value->getDoubleValue();
|
||||||
|
|
||||||
if (format == "100%")
|
if (format == "100%")
|
||||||
std::snprintf(buf, 20, "%.2f%%", value);
|
std::snprintf(buf, k_num_format_maxlen, "%.2f%%", value);
|
||||||
else if (format == "%.2f")
|
else if (format == "%.2f")
|
||||||
std::snprintf(buf, 20, "%.2f", value);
|
std::snprintf(buf, k_num_format_maxlen, "%.2f", value);
|
||||||
else if (value >= 1000000000000)
|
else if (value >= 1000000000000)
|
||||||
std::snprintf(buf, 20, "%7.2fT", value/1000000000000);
|
std::snprintf(buf, k_num_format_maxlen, "%7.2fT", value/1000000000000);
|
||||||
else if (value >= 1000000000)
|
else if (value >= 1000000000)
|
||||||
std::sprintf(buf, "%7.2fB", value/1000000000);
|
std::snprintf(buf, k_num_format_maxlen, "%7.2fB", value/1000000000);
|
||||||
else if (value >= 1000000)
|
else if (value >= 1000000)
|
||||||
std::snprintf(buf, 20, "%7.2fM", value/1000000);
|
std::snprintf(buf, k_num_format_maxlen, "%7.2fM", value/1000000);
|
||||||
else if (value >= 100000)
|
else if (value >= 100000)
|
||||||
std::snprintf(buf, 20, "%7.2fM", value/100000); // 0.12M
|
std::snprintf(buf, k_num_format_maxlen, "%7.2fM", value/100000); // 0.12M
|
||||||
else if (value <= -1000000000000)
|
else if (value <= -1000000000000)
|
||||||
std::snprintf(buf, 20, "%7.2fT", value/1000000000000);
|
std::snprintf(buf, k_num_format_maxlen, "%7.2fT", value/1000000000000);
|
||||||
else if (value <= -1000000000)
|
else if (value <= -1000000000)
|
||||||
std::snprintf(buf, 20, "%7.2fB", value/1000000000);
|
std::snprintf(buf, k_num_format_maxlen, "%7.2fB", value/1000000000);
|
||||||
else if (value <= -1000000)
|
else if (value <= -1000000)
|
||||||
std::snprintf(buf, 20, "%7.2fM", value/1000000);
|
std::snprintf(buf, k_num_format_maxlen, "%7.2fM", value/1000000);
|
||||||
else if (value <= -100000)
|
else if (value <= -100000)
|
||||||
std::snprintf(buf, 20, "%7.2fM", value/100000); // 0.12M
|
std::snprintf(buf, k_num_format_maxlen, "%7.2fM", value/100000); // 0.12M
|
||||||
else if (value == 0)
|
else if (value == 0)
|
||||||
buf[0]='0';
|
buf[0]='0';
|
||||||
else
|
else
|
||||||
return std::make_unique<StringValueNode>(parsed_value->getStringValue().substr(0, 10));
|
return std::make_unique<StringValueNode>(parsed_value->getStringValue().substr(0, k_num_format_rpad));
|
||||||
// TODO introduce constant for 10
|
|
||||||
std::string s {buf};
|
std::string s {buf};
|
||||||
return std::make_unique<StringValueNode>(string_padd(s.erase(s.find_last_not_of(' ')+1), 10, ' ', false));
|
return std::make_unique<StringValueNode>(string_padd(s.erase(s.find_last_not_of(' ') + 1), k_num_format_rpad, ' ', false));
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_unique<StringValueNode>(parsed_value->getStringValue());
|
return std::make_unique<StringValueNode>(parsed_value->getStringValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user