indexes WIP

This commit is contained in:
2021-11-17 15:35:57 +01:00
parent cc639ee891
commit 411f0fd48c
25 changed files with 609 additions and 807 deletions

View File

@@ -1,4 +1,6 @@
### TODO
- create local_install.sh
- set xxx - without value to reset to default value
- escape " in save csv
- is null | is not null
@@ -8,7 +10,8 @@
- expand_asterix_char should support multiple and everywhere *
- support for uniqueue indexes (primary key)
- support for btree indexes
- support for indexes
- add drop m_index
- support for joining
- use string_to_double and string_to_long (from Table) everywhere

View File

@@ -1942,7 +1942,7 @@ operator<<(std::basic_ostream<CharT, Traits>& os, const weekday_indexed& wdi)
{
os << wdi.weekday() << '[' << wdi.index();
if (!(1 <= wdi.index() && wdi.index() <= 5))
os << " is not a valid index";
os << " is not a valid m_index";
os << ']';
return os;
}

View File

@@ -148,7 +148,7 @@ struct linenoiseState {
size_t len; /* Current edited line length. */
size_t cols; /* Number of columns in terminal. */
size_t maxrows; /* Maximum num of rows used so far (multiline mode) */
int history_index; /* The history index we are currently editing. */
int history_index; /* The history m_index we are currently editing. */
};
enum KEY_ACTION{

View File

@@ -2,6 +2,6 @@
namespace usql {
Exception::Exception(const std::string msg) : std::runtime_error(msg) {}
Exception::Exception(std::string msg) : std::runtime_error(msg) {}
} // namespace

View File

@@ -8,7 +8,7 @@ namespace usql {
class Exception : public std::runtime_error {
public:
Exception(const std::string msg);
explicit Exception(std::string msg);
};
} // namespace

96
index.h Normal file
View File

@@ -0,0 +1,96 @@
#pragma once
#include <iostream>
#include <utility>
#include <vector>
#include <map>
enum class IndexedDataType {
integer,
string
};
template <typename K>
class Index {
public:
Index(std::string index_name, std::string col_name, IndexedDataType type) :
m_index_name(std::move(index_name)), m_column_name(std::move(col_name)),
m_data_type(type), m_uniq(false) {}
void insert(K key, int rowid) {
// std::cout << "inserting key: " << key << " val: " << rowid << std::endl;
// TODO handle uniqueness
auto search = m_index.find(key);
if (search != m_index.end()) {
search->second.push_back(rowid);
} else {
std::vector<int> rowids{rowid};
m_index[key] = rowids;
}
}
void update(K old_key, K new_key, int rowid) {
// std::cout << "updating key: " << old_key << " to: " << new_key << " val: " << rowid << std::endl;
// TODO handle uniqueness
}
void remove(K key, int rowid) {
// std::cout << "removing key: " << key << " val: " << rowid << std::endl;
auto search = m_index.find(key);
if (search != m_index.end()) {
search->second.erase(find(search->second.begin(), search->second.end(), rowid));
}
}
std::vector<int> search(K key) {
// std::cout << "returning rowids for key: " << key << std::endl;
auto search = m_index.find(key);
if (search != m_index.end()) {
return search->second;
} else {
return std::vector<int>{};
}
}
void truncate() {
// std::cout << "truncating" << std::endl;
m_index.clear();
}
void dump() {
std::for_each(m_index.begin(), m_index.end(),
[](std::pair<K, std::vector<int>> element){
K key = element.first;
std::vector<int> rowids = element.second;
std::cout << "key: " << key << ", rowids count:" << rowids.size() << std::endl;
});
}
[[nodiscard]] const std::string &get_column_name() const {
return m_column_name;
}
[[nodiscard]] const std::string &get_index_name() const {
return m_index_name;
}
[[nodiscard]] IndexedDataType get_data_type() const {
return m_data_type;
}
private:
bool m_uniq;
std::string m_index_name;
std::string m_column_name;
IndexedDataType m_data_type;
// DEBUG for debug it is public
public:
std::map<K, std::vector<int> > m_index;
};

View File

@@ -147,6 +147,8 @@ namespace usql {
if (token == "from") return TokenType::keyword_from;
if (token == "delete") return TokenType::keyword_delete;
if (token == "table") return TokenType::keyword_table;
if (token == "index") return TokenType::keyword_index;
if (token == "on") return TokenType::keyword_on;
if (token == "insert") return TokenType::keyword_insert;
if (token == "into") return TokenType::keyword_into;
if (token == "values") return TokenType::keyword_values;
@@ -252,6 +254,8 @@ namespace usql {
case TokenType::keyword_asc: return "asc";
case TokenType::keyword_desc: return "desc";
case TokenType::keyword_table: return "table";
case TokenType::keyword_index: return "index";
case TokenType::keyword_on: return "on";
case TokenType::keyword_into: return "into";
case TokenType::keyword_values: return "values";
case TokenType::keyword_select: return "select";

View File

@@ -25,6 +25,8 @@ namespace usql {
keyword_create,
keyword_drop,
keyword_table,
keyword_index,
keyword_on,
keyword_where,
keyword_order,
keyword_by,

View File

@@ -127,13 +127,34 @@ void repl() {
void debug() {
std::vector<std::string> sql_commands {
"create table history_earnings_dates (datetime date, symbol varchar(8), time varchar(18), title varchar(256))",
"set 'DATE_FORMAT' = '%Y-%m-%d' ",
"load into history_earnings_dates '/Users/vaclavt/Development/mlisp_fin/data/history_earnings_dates.csv'"
"insert into history_earnings_dates (symbol,time,datetime,title) values ('BABA', '07:00:00', '2021-11-04', 'Alibaba Group Holding')",
"insert into history_earnings_dates (symbol,time,datetime,title) values ('BABA', '07:00:00', '2021-11-04', 'Alibaba Group Holding')",
"delete from history_earnings_dates where symbol='BABA' and datetime=to_date('2021-11-04', '%Y-%m-%d')",
"select * from history_earnings_dates"
// "create table history_earnings_dates (datetime date, symbol varchar(8), time varchar(18), title varchar(256))",
// "set 'DATE_FORMAT' = '%Y-%m-%d'",
// "load into history_earnings_dates '/Users/vaclavt/Development/mlisp_fin/data/history_earnings_dates.csv'"
// "insert into history_earnings_dates (symbol,time,datetime,title) values ('BABA', '07:00:00', '2021-11-04', 'Alibaba Group Holding')",
// "insert into history_earnings_dates (symbol,time,datetime,title) values ('BABA', '07:00:00', '2021-11-04', 'Alibaba Group Holding')",
// "delete from history_earnings_dates where symbol='BABA' and datetime=to_date('2021-11-04', '%Y-%m-%d')",
// "select * from history_earnings_dates"
// "create table sf1 (symbol varchar(8), dimension varchar(3), calendar_date date, date_key date, report_period date, last_updated date, accoci float, assets float, assetsavg float, assetsc float, assetsnc float, assetturnover float, bvps float, capex float, cashneq float, cashnequsd float, cor float, consolinc float, currentratio float, de float, debt float, debtc float, debtnc float, debtusd float, deferredrev float, depamor float, deposits float, divyield float, dps float, ebit float, ebitda float, ebitdamargin float, ebitdausd float, ebitusd float, ebt float, eps float, epsdil float, epsusd float, equity float, equityavg float, equityusd float, ev float, evebit float, evebitda float, fcf float, fcfps float, fxusd float, gp float, grossmargin float, intangibles float, intexp float, invcap float, invcapavg float, inventory float, investments float, investmentsc float, investmentsnc float, liabilities float, liabilitiesc float, liabilitiesnc float, marketcap float, ncf float, ncfbus float, ncfcommon float, ncfdebt float, ncfdiv float, ncff float, ncfi float, ncfinv float, ncfo float, ncfx float, netinc float, netinccmn float, netinccmnusd float, netincdis float, netincnci float, netmargin float, opex float, opinc float, payables float, payoutratio float, pb float, pe float, pe1 float, ppnenet float, prefdivis float, price float, ps float, ps1 float, receivables float, retearn float, revenue float, revenueusd float, rnd float, roa float, roe float, roic float, ros float, sbcomp float, sgna float, sharefactor float, sharesbas float, shareswa float, shareswadil float, sps float, tangibles float, taxassets float, taxexp float, taxliabilities float, tbvps float, workingcapital float)",
// "set 'DATE_FORMAT' = '%Y-%m-%d'",
// "load into sf1 '/srv/SHARADAR_SF1.csv'",
// "create index sf1_symbol on sf1(symbol)",
// "set 'USE_INDEXSCAN' = 'false'",
// "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' = '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"
"create table a (i integer not null, s varchar(64))",
"insert into a (i, s) values(1, 'one')",
"insert into a (i, s) values(2, 'two')",
"insert into a (i, s) values(2, 'second two')",
"insert into a (i, s) values(3, 'three')",
"create index a_i on a(i)",
"create index a_s on a(s)",
"set 'USE_INDEXSCAN' = 'true'",
"select * from a where 1 = i",
"select * from a where i = 2",
"select max(i) from a where s = 'two'"
};
usql::USql uSql{};
@@ -156,11 +177,11 @@ void debug() {
int main(int argc, char *argv[]) {
#ifdef NDEBUG
repl();
#else
//#ifdef NDEBUG
// repl();
//#else
debug();
#endif
//#endif
return 0;
}

View File

@@ -10,7 +10,6 @@ long now() { // get-universal-time
std::string date_to_string(const long datetime, const std::string format) {
// std::locale::global(std::locale("en-US.UTF8"));
time_t timestamp = datetime;
char mbstr[128];

View File

@@ -15,6 +15,8 @@ namespace usql {
if (m_lexer.tokenType() == TokenType::keyword_create && m_lexer.nextTokenType() == TokenType::keyword_table)
return parse_create_table();
if (m_lexer.tokenType() == TokenType::keyword_create && m_lexer.nextTokenType() == TokenType::keyword_index)
return parse_create_index();
if (m_lexer.tokenType() == TokenType::keyword_drop)
return parse_drop_table();
@@ -302,6 +304,18 @@ namespace usql {
return std::make_unique<UpdateTableNode>(table_name, cols_names, std::move(values), std::move(where_node));
}
std::unique_ptr<Node> Parser::parse_create_index() {
m_lexer.skipToken(TokenType::keyword_create);
m_lexer.skipToken(TokenType::keyword_index);
std::string index_name = m_lexer.consumeToken(TokenType::identifier).token_string;
m_lexer.skipToken(TokenType::keyword_on);
std::string table_name = m_lexer.consumeToken(TokenType::identifier).token_string;
m_lexer.skipToken(TokenType::open_paren);
std::string column_name = m_lexer.consumeToken(TokenType::identifier).token_string;
m_lexer.skipToken(TokenType::close_paren);
return std::make_unique<CreateIndexNode>(index_name, table_name, column_name);
}
std::vector<ColOrderNode> Parser::parse_order_by_clause() {
std::vector<ColOrderNode> order_cols;
@@ -331,7 +345,7 @@ namespace usql {
order_cols.emplace_back(cspec_token, asc);
break;
default:
throw Exception("order by column can be either column index or identifier");
throw Exception("order by column can be either column m_index or identifier");
}
m_lexer.skipTokenOptional(TokenType::comma);

198
parser.h
View File

@@ -6,6 +6,7 @@
#include "settings.h"
#include <string>
#include <utility>
#include <vector>
static const int FUNCTION_CALL = -1;
@@ -39,12 +40,12 @@ namespace usql {
load_table,
save_table,
drop_table,
create_index,
set,
show,
database_value,
offset_limit,
column_order,
column_value,
function,
column_def,
error
@@ -55,6 +56,10 @@ namespace usql {
explicit Node(const NodeType type) : node_type(type) {}
virtual ~Node() = default;
virtual void dump() const {
std::cout << "type: Node" << std::endl;
}
};
@@ -63,8 +68,12 @@ namespace usql {
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::database_value), col_name(""), col_index(index), ascending(asc) {}
ColOrderNode(std::string name, bool asc) : Node(NodeType::column_order), col_name(std::move(name)), col_index(-1), ascending(asc) {}
ColOrderNode(int index, bool asc) : Node(NodeType::database_value), col_index(index), ascending(asc) {}
void dump() const override {
std::cout << "type: ColOrderNode, col_name: " << col_name << ", col_index: " << col_index << ", asc: " << ascending << std::endl;
}
};
@@ -74,6 +83,10 @@ namespace usql {
int limit;
OffsetLimitNode(int off, int lim) : Node(NodeType::offset_limit), offset(off), limit(lim) {}
void dump() const override {
std::cout << "type: OffsetLimitNode, offset: " << offset << ", limit: " << limit << std::endl;
}
};
@@ -81,8 +94,13 @@ namespace usql {
std::unique_ptr<Node> value;
std::string name;
SelectColNode(std::unique_ptr<Node> column, const std::string &alias) :
Node(NodeType::database_value), value(std::move(column)), name(alias) {}
SelectColNode(std::unique_ptr<Node> column, std::string alias) :
Node(NodeType::database_value), value(std::move(column)), name(std::move(alias)) {}
void dump() const override {
std::cout << "type: SelectColNode, name:" << name << "value:" << std::endl;
value->dump();
}
};
struct ColDefNode : Node {
@@ -92,21 +110,33 @@ namespace usql {
int length;
bool null;
ColDefNode(const std::string& col_name, ColumnType col_type, int col_order, int col_len, bool nullable) :
Node(NodeType::column_def), name(col_name), type(col_type), order(col_order), length(col_len),
ColDefNode(std::string col_name, ColumnType col_type, int col_order, int col_len, bool nullable) :
Node(NodeType::column_def), name(std::move(col_name)), type(col_type), order(col_order), length(col_len),
null(nullable) {}
void dump() const override {
std::cout << "type: ColDefNode, name: " << name << ", type: " << (int)type << " TODO add more" << std::endl;
}
};
struct FunctionNode : Node {
std::string function; // TODO use enum
std::vector<std::unique_ptr<Node>> params;
FunctionNode(const std::string& func_name, std::vector<std::unique_ptr<Node>> pars) :
Node(NodeType::function), function(func_name), params(std::move(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)) {}
void dump() const override {
std::cout << "type: FunctionNode, function: " << function << " TODO add more" << std::endl;
}
};
struct TrueNode : Node {
TrueNode() : Node(NodeType::true_node) {}
void dump() const override {
std::cout << "type: TrueNode," << std::endl;
}
};
struct ValueNode : Node {
@@ -119,7 +149,7 @@ namespace usql {
virtual long getDateValue() = 0;
virtual bool getBooleanValue() = 0;
virtual ~ValueNode() = default;
~ValueNode() override = default;
};
struct NullValueNode : ValueNode {
@@ -133,6 +163,10 @@ namespace usql {
std::string getStringValue() override { throw Exception("getStringValue not supported on NullValueNode"); };
long getDateValue() override { throw Exception("getDateValue not supported on NullValueNode"); };
bool getBooleanValue() override { throw Exception("getBooleanValue not supported on NullValueNode"); };
void dump() const override {
std::cout << "type: NullValueNode," << std::endl;
}
};
struct IntValueNode : ValueNode {
@@ -145,6 +179,10 @@ namespace usql {
std::string getStringValue() override { return Settings::int_to_string(value); }
long getDateValue() override { return value; };
bool getBooleanValue() override { return value != 0; };
void dump() const override {
std::cout << "type: IntValueNode, value: " << value << std::endl;
}
};
struct DoubleValueNode : ValueNode {
@@ -157,18 +195,26 @@ namespace usql {
std::string getStringValue() override { return Settings::double_to_string(value); }
long getDateValue() override { return (long) value; };
bool getBooleanValue() override { return value != 0.0; };
void dump() const override {
std::cout << "type: DoubleValueNode, value: " << value << std::endl;
}
};
struct StringValueNode : ValueNode {
std::string value;
explicit StringValueNode(const std::string &value) : ValueNode(NodeType::string_value), value(value) {}
explicit StringValueNode(std::string value) : ValueNode(NodeType::string_value), value(std::move(value)) {}
long getIntegerValue() override { return Settings::string_to_int(value); };
double getDoubleValue() override { return Settings::string_to_double(value); };
std::string getStringValue() override { return value; };
long getDateValue() override { return Settings::string_to_date(value); };
bool getBooleanValue() override { return Settings::string_to_bool(value); };
void dump() const override {
std::cout << "type: StringValueNode, value: " << value << std::endl;
}
};
struct BooleanValueNode : ValueNode {
@@ -181,19 +227,27 @@ namespace usql {
std::string getStringValue() override { return Settings::bool_to_string(value); }
long getDateValue() override { return (long) value; };
bool getBooleanValue() override { return value; };
void dump() const override {
std::cout << "type: BooleanValueNode, value: " << value << std::endl;
}
};
struct DatabaseValueNode : Node {
std::string col_name;
explicit DatabaseValueNode(const std::string &name) : Node(NodeType::database_value), col_name(name) {}
explicit DatabaseValueNode(std::string name) : Node(NodeType::database_value), col_name(std::move(name)) {}
void dump() const override {
std::cout << "type: DatabaseValueNode, col_name: " << col_name << std::endl;
}
};
enum class LogicalOperatorType {
and_operator,
or_operator,
not_operator
or_operator
// not_operator
};
struct LogicalOperatorNode : Node {
@@ -203,6 +257,12 @@ namespace usql {
LogicalOperatorNode(LogicalOperatorType op, std::unique_ptr<Node> left, std::unique_ptr<Node> right) :
Node(NodeType::logical_operator), op(op), left(std::move(left)), right(std::move(right)) {};
void dump() const override {
std::cout << "type: LogicalOperatorNode, op: " << (int)op << std::endl;
left->dump();
right->dump();
}
};
enum class RelationalOperatorType {
@@ -225,6 +285,12 @@ namespace usql {
RelationalOperatorNode(RelationalOperatorType op, std::unique_ptr<Node> left, std::unique_ptr<Node> right) :
Node(NodeType::relational_operator), op(op), left(std::move(left)), right(std::move(right)) {};
void dump() const override {
std::cout << "type: RelationalOperatorNode, op: " << (int)op << std::endl;
left->dump();
right->dump();
}
};
enum class ArithmeticalOperatorType {
@@ -243,14 +309,24 @@ namespace usql {
ArithmeticalOperatorNode(ArithmeticalOperatorType op, std::unique_ptr<Node> left, std::unique_ptr<Node> right) :
Node(NodeType::arithmetical_operator), op(op), left(std::move(left)), right(std::move(right)) {};
void dump() const override {
std::cout << "type: ArithmeticalOperatorNode, op: " << (int)op << std::endl;
left->dump();
right->dump();
}
};
struct CreateTableNode : Node {
std::string table_name;
std::vector<ColDefNode> cols_defs;
CreateTableNode(const std::string& name, std::vector<ColDefNode> defs) :
Node(NodeType::create_table), table_name(name), cols_defs(std::move(defs)) {}
CreateTableNode(std::string name, std::vector<ColDefNode> defs) :
Node(NodeType::create_table), table_name(std::move(name)), cols_defs(std::move(defs)) {}
void dump() const override {
std::cout << "type: CreateTableNode, table_name: " << table_name << "TODO complete me" << std::endl;
}
};
struct InsertIntoTableNode : Node {
@@ -258,8 +334,12 @@ namespace usql {
std::vector<DatabaseValueNode> cols_names;
std::vector<std::unique_ptr<Node>> cols_values;
InsertIntoTableNode(const std::string& name, std::vector<DatabaseValueNode> names, std::vector<std::unique_ptr<Node>> values) :
Node(NodeType::insert_into), table_name(name), cols_names(std::move(names)), cols_values(std::move(values)) {}
InsertIntoTableNode(std::string name, std::vector<DatabaseValueNode> names, std::vector<std::unique_ptr<Node>> values) :
Node(NodeType::insert_into), table_name(std::move(name)), cols_names(std::move(names)), cols_values(std::move(values)) {}
void dump() const override {
std::cout << "type: InsertIntoTableNode, table_name: " << table_name << "TODO complete me" << std::endl;
}
};
struct SelectFromTableNode : Node {
@@ -271,15 +351,25 @@ namespace usql {
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(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 {
std::cout << "type: SelectFromTableNode, table_name: " << table_name << "TODO complete me" << std::endl;
where->dump();
}
};
struct CreateTableAsSelectNode : Node {
std::string table_name;
std::unique_ptr<Node> select_table;
CreateTableAsSelectNode(const std::string& name, std::unique_ptr<Node> table) :
Node(NodeType::create_table_as_select), table_name(name), select_table(std::move(table)) {}
CreateTableAsSelectNode(std::string name, std::unique_ptr<Node> table) :
Node(NodeType::create_table_as_select), table_name(std::move(name)), select_table(std::move(table)) {}
void dump() const override {
std::cout << "type: CreateTableAsSelectNode, table_name: " << table_name << std::endl;
select_table->dump();
}
};
struct UpdateTableNode : Node {
@@ -288,57 +378,98 @@ namespace usql {
std::vector<std::unique_ptr<Node>> values;
std::unique_ptr<Node> where;
UpdateTableNode(const 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) :
Node(NodeType::update_table), table_name(name), cols_names(names), values(std::move(vals)),
Node(NodeType::update_table), table_name(std::move(name)), cols_names(std::move(names)), values(std::move(vals)),
where(std::move(where_clause)) {}
void dump() const override {
std::cout << "type: UpdateTableNode, table_name: " << table_name << "TODO complete me" << std::endl;
where->dump();
}
};
struct LoadIntoTableNode : Node {
std::string table_name;
std::string filename;
LoadIntoTableNode(const std::string& name, const std::string &file) :
Node(NodeType::load_table), table_name(name), filename(file) {}
LoadIntoTableNode(std::string name, std::string file) :
Node(NodeType::load_table), table_name(std::move(name)), filename(std::move(file)) {}
void dump() const override {
std::cout << "type: LoadIntoTableNode, table_name: " << table_name << ", filename" << filename << std::endl;
}
};
struct SaveTableNode : Node {
std::string table_name;
std::string filename;
SaveTableNode(const std::string& name, const std::string &file) :
Node(NodeType::save_table), table_name(name), filename(file) {}
SaveTableNode(std::string name, std::string file) :
Node(NodeType::save_table), table_name(std::move(name)), filename(std::move(file)) {}
void dump() const override {
std::cout << "type: SaveTableNode, table_name: " << table_name << ", filename" << filename << std::endl;
}
};
struct DropTableNode : Node {
std::string table_name;
explicit DropTableNode(const std::string& name) : Node(NodeType::drop_table), table_name(name) {}
explicit DropTableNode(std::string name) : Node(NodeType::drop_table), table_name(std::move(name)) {}
void dump() const override {
std::cout << "type: SelectFromTableNode, table_name: " << table_name << std::endl;
}
};
struct DeleteFromTableNode : Node {
std::string table_name;
std::unique_ptr<Node> where;
DeleteFromTableNode(const std::string& name, std::unique_ptr<Node> where_clause) :
Node(NodeType::delete_from), table_name(name), where(std::move(where_clause)) {}
DeleteFromTableNode(std::string name, std::unique_ptr<Node> where_clause) :
Node(NodeType::delete_from), table_name(std::move(name)), where(std::move(where_clause)) {}
void dump() const override {
std::cout << "type: DeleteFromTableNode, table_name: " << table_name << std::endl;
where->dump();
}
};
struct SetNode : Node {
std::string name;
std::string value;
SetNode(const std::string& name_, const std::string& value_) :
Node(NodeType::set), name(name_), value(value_) {}
SetNode(std::string node_name, std::string node_value) :
Node(NodeType::set), name(std::move(node_name)), value(std::move(node_value)) {}
void dump() const override {
std::cout << "type: SetNode, name: " << name << ", value: " << value << std::endl;
}
};
struct ShowNode : Node {
std::string name;
explicit ShowNode(const std::string& name_) : Node(NodeType::show), name(name_) {}
explicit ShowNode(std::string node_name) : Node(NodeType::show), name(std::move(node_name)) {}
void dump() const override {
std::cout << "type: ShowNode, name: " << name << std::endl;
}
};
struct CreateIndexNode : Node {
std::string index_name;
std::string table_name;
std::string column_name;
CreateIndexNode(std::string idx_name, std::string tbl_name, std::string col_name) :
Node(NodeType::create_index), index_name(std::move(idx_name)), table_name(std::move(tbl_name)), column_name(std::move(col_name)) {}
void dump() const override {
std::cout << "type: CreateIndexNode, table_name: " << table_name << ", index_name: " << index_name << ", column_name: " << column_name << std::endl;
}
};
class Parser {
private:
@@ -360,6 +491,7 @@ namespace usql {
std::unique_ptr<Node> parse_select_from_table();
std::unique_ptr<Node> parse_delete_from_table();
std::unique_ptr<Node> parse_update_table();
std::unique_ptr<Node> parse_create_index();
std::vector<ColOrderNode> parse_order_by_clause();
OffsetLimitNode parse_offset_limit_clause();

View File

@@ -9,7 +9,8 @@ std::vector<std::pair<std::string, std::string>> Settings::m_settings =
{ std::make_pair("DATE_FORMAT", "%Y-%m-%d %H:%M:%S"),
std::make_pair("BOOL_TRUE_LITERAL", "Y"),
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") };
@@ -47,23 +48,20 @@ std::string Settings::date_to_string(long date) {
}
bool Settings::string_to_bool(const std::string &boolstr) {
if (boolstr=="true" || boolstr == get_setting("BOOL_TRUE_LITERAL"))
bool Settings::string_to_bool(const std::string &value) {
if (value == "true" || value == get_setting("BOOL_TRUE_LITERAL"))
return true;
if (boolstr=="false" || boolstr == get_setting("BOOL_FALSE_LITERAL"))
if (value == "false" || value == get_setting("BOOL_FALSE_LITERAL"))
return false;
throw Exception("string_to_bool, unrecognized value: " + boolstr);
throw Exception("string_to_bool, unrecognized value: " + value);
}
std::string Settings::bool_to_string(bool boolval) {
return boolval ? "true" : "false";
std::string Settings::bool_to_string(bool value) {
return value ? "true" : "false";
}
std::string Settings::get_setting(const std::string &name) {
for(const auto& pair : m_settings) {
if (pair.first == name) return pair.second;
@@ -71,6 +69,10 @@ std::string Settings::get_setting(const std::string &name) {
throw Exception("unsupported setting name: " + name);
}
bool Settings::get_bool_setting(const std::string &name) {
return string_to_bool(get_setting(name));
}
void Settings::set_setting(const std::string &name, const std::string &value) {
for (auto it = begin(m_settings); it != end(m_settings); ++it) {
if (it->first == name) {

View File

@@ -10,6 +10,7 @@ class Settings {
public:
static void set_setting(const std::string &name, const std::string &value);
static std::string get_setting(const std::string &name);
static bool get_bool_setting(const std::string &name);
static long string_to_int(const std::string &intstr);
static std::string int_to_string(long intval);
@@ -20,8 +21,8 @@ public:
static long string_to_date(const std::string &datestr);
static std::string date_to_string(long dateval);
static bool string_to_bool(const std::string &boolstr);
static std::string bool_to_string(bool boolval);
static bool string_to_bool(const std::string &value);
static std::string bool_to_string(bool value);
private:
static std::vector<std::pair<std::string, std::string>> m_settings;

View File

@@ -27,7 +27,7 @@ Table::Table(const Table &other) {
ColDefNode Table::get_column_def(const std::string &col_name) {
auto name_cmp = [col_name](const ColDefNode& cd) { return cd.name == col_name; };
auto col_def = std::find_if(begin(m_col_defs), end(m_col_defs), name_cmp);
auto col_def = std::find_if(std::begin(m_col_defs), std::end(m_col_defs), name_cmp);
if (col_def != std::end(m_col_defs)) {
return *col_def;
} else {
@@ -39,7 +39,7 @@ 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) + ")");
throw Exception("column with this m_index does not exists (" + std::to_string(col_index) + ")");
}
}
@@ -244,4 +244,63 @@ void Table::validate_row(const Row &row) {
}
}
void Table::create_index(const Index<IndexValue>& index) {
m_indexes.push_back(index);
}
void Table::drop_index(const std::string &column) {
throw Exception("implement me! Table::drop_index(const std::string &column)");
}
void Table::index_row(Index<IndexValue> &index, const Row &row, const size_t rowid) {
ColDefNode col_def = get_column_def(index.get_column_name());
if (col_def.type==ColumnType::integer_type) {
index.insert(row[col_def.order].getIntValue(), rowid);
} else if (col_def.type==ColumnType::varchar_type) {
index.insert(row[col_def.order].getStringValue(), rowid);
} else {
throw Exception("implement me! Table::index_row(const Row &row)");
}
}
void Table::index_row(const Row &row, const size_t rowid) {
for (auto &i : m_indexes) {
index_row(i, row, rowid);
}
}
void Table::index_rows(const std::string &index_name) {
auto index = get_index(index_name);
// TODO handle null pointer
size_t rowid = 0;
for(const Row& r : m_rows) {
index_row(*index, r, rowid);
rowid++;
}
}
Index<IndexValue> * Table::get_index(const std::string &index_name) {
auto it = std::find_if(m_indexes.begin(), m_indexes.end(),
[&index_name](const Index<IndexValue> &idx) {
return idx.get_index_name() == index_name;
});
if (it != m_indexes.end()) return &(*it);
return nullptr;
}
Index<IndexValue> * Table::get_index_for_column(const std::string &col_name) {
auto it = std::find_if(m_indexes.begin(), m_indexes.end(),
[&col_name](const Index<IndexValue> &idx) {
return idx.get_column_name() == col_name;
});
if (it != m_indexes.end()) return &(*it);
return nullptr;
}
} // namespace

35
table.h
View File

@@ -1,13 +1,21 @@
#pragma once
#include "index.h"
#include "parser.h"
#include "row.h"
#include <vector>
#include <iterator> // For std::forward_iterator_tag
#include <cstddef> // For std::ptrdiff_t
namespace usql {
struct Table {
//using IndexValue=std::variant<ColNullValue, ColIntegerValue, ColStringValue>;
using IndexValue=std::variant<long, std::string>;
struct Table {
Table(const Table &other);
Table(const std::string& name, const std::vector<ColDefNode>& columns);
@@ -21,6 +29,7 @@ namespace usql {
Row& create_empty_row();
void commit_row(const Row &row);
void commit_copy_of_row(const Row &row);
Row& get_row(int rowid) { return m_rows[rowid]; };
static void validate_column(const ColDefNode *col_def, ValueNode *col_val);
static void validate_column(const ColDefNode *col_def, ColValue &col_val);
@@ -35,11 +44,27 @@ namespace usql {
std::string m_name;
std::vector<ColDefNode> m_col_defs;
std::vector<Row> m_rows;
std::vector<Index<IndexValue>> m_indexes;
static long string_to_long(const std::string &s) ;
static double string_to_double(const std::string &s) ;
static long string_to_long(const std::string &s);
static double string_to_double(const std::string &s);
void create_row_from_vector(const std::vector<ColDefNode> &colDefs, const std::vector<std::string> &csv_line);
};
}
void create_index(const Index<IndexValue>& index);
void drop_index(const std::string &column);
void index_row(Index<IndexValue> &index, const Row &row, const size_t rowid);
void index_row(const Row &row, const size_t rowid);
void index_rows(const std::string &index_name);
Index<IndexValue> * get_index(const std::string &index_name);
Index<IndexValue> * get_index_for_column(const std::string &col_name);
std::vector<int> index_search(const std::string &col_name, IndexValue key);
typedef std::vector<Row>::iterator iterator;
iterator fs_begin() { return m_rows.begin(); }
iterator fs_end() { return m_rows.end(); }
};
} // namespace

View File

@@ -1,23 +0,0 @@
cmake_minimum_required(VERSION 3.0)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14")
project(main)
set(PROJECT_NAME main)
include_directories(${CMAKE_SOURCE_DIR}})
set(SOURCE
main.cpp)
add_executable(${PROJECT_NAME} ${SOURCE})
target_link_libraries(${PROJECT_NAME} stdc++ m)
target_compile_options(main PRIVATE -g)

View File

@@ -1,431 +0,0 @@
/* B-Tree
* Author: Caleb Baker
* Date: 10/8/17
* Summary: A B-Tree data structure. Supports lg(n) time search, insert, and delete.
*/
#include <stdlib.h>
#include <utility>
#include <stdio.h>
using namespace std;
#define NEW_ROOT 2
#define MODIFIED_NOT_ROOT 1
#define NOT_MODIFIED 0
// Constructor for b tree.
// t is the minimum degree of the tree.
// compare is the comparison function used for managing elements within the tree.
// printK is a function that prints keys.
template <typename T>
BTree<T>::BTree(unsigned t, bool (*compare)(T, T), void (*printK)(T)) {
minDegree = t;
lessThan = compare;
root = (BNode<T>*) malloc(sizeof(BNode<T>));
initializeNode(root);
root->leaf = true;
printKey = printK;
}
// Destructor.
template <typename T>
BTree<T>::~BTree<T>() {
freeNode(root);
}
// Inserts the key k into the tree.
template <typename T>
void BTree<T>::insert(T k) {
// Grow upwards if the root is full.
if (root->size == 2 * minDegree - 1) {
BNode<T> *newRoot = (BNode<T>*) malloc(sizeof(BNode<T>));
initializeNode(newRoot);
newRoot->leaf = false;
newRoot->child[0] = root;
root = newRoot;
splitChild(newRoot, 0);
}
// Work down the tree.
BNode<T> *curr = root;
while (!curr->leaf) {
// Find the proper child to go to.
int index = curr->size - 1;
while (index >= 0 && lessThan(k, curr->key[index])) {
index--;
}
index++;
// Split child if full.
if (curr->child[index]->size == 2 * minDegree - 1) {
splitChild(curr, index);
if (lessThan(curr->key[index], k)) {
index++;
}
}
curr = curr->child[index];
}
nodeInsert(curr, k);
}
// Removes k from the tree. Returns the removed key.
// Throws a BTREE_EXCEPTION if key is not found.
template <typename T>
T BTree<T>::remove(T k) {
BNode<T> *curr = root;
while (true) {
unsigned i = findIndex(curr, k);
// If the item to be deleted has been found.
if (i < curr->size && !(lessThan(curr->key[i], k) || lessThan(k, curr->key[i]))) {
T toReturn = curr->key[i];
// If at a leaf, just delete it.
if (curr->leaf) {
nodeDelete(curr, i);
}
// Otherwise replace with predecessor/successor or merge children.
else {
BNode<T> *leftKid = curr->child[i];
BNode<T> *rightKid = curr->child[i + 1];
// Replace with predecessor.
if (leftKid->size >= minDegree) {
while (!(leftKid->leaf)) {
fixChildSize(leftKid, leftKid->size);
leftKid = leftKid->child[leftKid->size];
}
curr->key[i] = nodeDelete(leftKid, leftKid->size - 1);
}
// Replace with successor
else if (rightKid->size >= minDegree) {
while (!(rightKid->leaf)) {
fixChildSize(rightKid, 0);
rightKid = rightKid->child[0];
}
curr->key[i] = nodeDelete(rightKid, 0);
}
// Merge children and move down the tree.
else {
mergeChildren(curr, i);
curr = leftKid;
continue;
}
}
return toReturn;
}
// If the item has not been found, move down the tree.
else {
// If at a leaf, then the item isn't present.
if (curr->leaf) {
throw (BTREE_EXCEPTION) REMOVE_KEY_NOT_FOUND;
}
// Adjust curr and move down the tree.
char result = fixChildSize(curr, i);
if (result == NEW_ROOT) {
curr = root;
}
else {
curr = curr->child[findIndex(curr, k)];
}
}
}
}
// Function to find a key in the tree.
// returnValue.first is the node the item is in.
// returnValue.second is the correct index in that node's key array
template <typename T>
pair<BNode<T>*, unsigned> BTree<T>::search(T k) {
// Start at root.
BNode<T> *x = root;
// Work down the tree.
while (true) {
// Find the proper index in the current node's array.
unsigned i = findIndex(x, k);
// Found it!
if (i < x->size && !(lessThan(k, x->key[i]) || lessThan(x->key[i], k))) {
return pair<BNode<T>*, unsigned>(x, i);
}
// Hit the bottom of the tree.
else if (x->leaf) {
return pair<BNode<T>*, unsigned>(NULL, 0);
}
// Keep going.
else {
x = x->child[i];
}
}
}
// Function to find a key in the tree.
// Returns the key.
// If the item was not found an exception is thrown.
template <typename T>
T BTree<T>::searchKey(T k) {
pair<BNode<T>*, unsigned> node = search(k);
if (node.first == NULL) {
throw (BTREE_EXCEPTION) SEARCH_KEY_NOT_FOUND;
}
return node.first->key[node.second];
}
// Function for printing a tree.
template <typename T>
void BTree<T>::print() {
if (printKey != NULL && root != NULL) {
printf("\n");
printNode(root, 0);
printf("\n");
}
}
// Initialize a b tree node.
// x is a pointer to the node
// t is the minimum degree of the tree.
template <typename T>
void BTree<T>::initializeNode(BNode<T> *x) {
x->size = 0;
x->key = (T*) malloc((2 * minDegree - 1) * sizeof(T));
x->child = (BNode<T>**) malloc(2 * minDegree * sizeof(BNode<T>*));
}
// Recursively deletes the subtree rooted at x.
// Does the dirty work for the destructor.
template <typename T>
void BTree<T>::freeNode(BNode<T> *x) {
if (!x->leaf) {
for (unsigned i = 0; i <= x->size; i++) {
freeNode(x->child[i]);
}
}
free(x->child);
free(x->key);
free(x);
}
// Finds the index of k in x->key.
// If k is not present, returns the index of the subtree
// that could contain k in x->child.
template <typename T>
unsigned BTree<T>::findIndex(BNode<T> *x, T k) {
unsigned i = 0;
while (i < x->size && lessThan(x->key[i], k)) {
i++;
}
return i;
}
// Inserts k into x.
// Returns the index of k in x->key.
template <typename T>
unsigned BTree<T>::nodeInsert(BNode<T> *x, T k) {
int index;
// Make room for k.
for (index = x->size; index > 0 && lessThan(k, x->key[index - 1]); index--) {
x->key[index] = x->key[index - 1];
x->child[index + 1] = x->child[index];
}
// Insert k.
x->child[index + 1] = x->child[index];
x->key[index] = k;
x->size++;
return index;
}
// Deletes the indexth element from x->key.
// Returns deleted key.
template <typename T>
T BTree<T>::nodeDelete(BNode<T> *x, unsigned index) {
T toReturn = x->key[index];
x->size--;
while (index < x->size) {
x->key[index] = x->key[index + 1];
x->child[index + 1] = x->child[index + 2];
index++;
}
return toReturn;
}
// Function for splitting nodes that are too full.
// x points to the parent of the node to splits.
// i is the index in x's child array of the node to split.
template <typename T>
void BTree<T>::splitChild(BNode<T> *x, int i) {
// z is the new node and y is the node to split.
BNode<T> *toSplit = x->child[i];
BNode<T>* newNode = (BNode<T>*) malloc(sizeof(BNode<T>));;
initializeNode(newNode);
newNode->leaf = toSplit->leaf;
newNode->size = minDegree - 1;
// Copy the second half of y's keys and children into z.
for (unsigned j = 0; j < minDegree - 1; j++) {
newNode->key[j] = toSplit->key[j + minDegree];
}
if (!toSplit->leaf) {
for (unsigned j = 0; j < minDegree; j++) {
newNode->child[j] = toSplit->child[j + minDegree];
}
}
toSplit->size = minDegree - 1;
nodeInsert(x, toSplit->key[minDegree - 1]);
x->child[i + 1] = newNode;
}
// Merges the (i + 1)th child of parent with the ith child of parent.
// Returns an indicator of whether the change affected the root.
template <typename T>
char BTree<T>::mergeChildren(BNode<T> *parent, unsigned i) {
BNode<T> *leftKid = parent->child[i];
BNode<T> *rightKid = parent->child[i + 1];
// Move item from parent to left child.
leftKid->key[leftKid->size] = nodeDelete(parent, i);
unsigned j = ++(leftKid->size);
// Move everything from rightKid into leftKid
for (unsigned k = 0; k < rightKid->size; k++) {
leftKid->key[j + k] = rightKid->key[k];
leftKid->child[j + k] = rightKid->child[k];
}
leftKid->size += rightKid->size;
leftKid->child[leftKid->size] = rightKid->child[rightKid->size];
// Free the memory used by rightChild
free(rightKid->child);
free(rightKid->key);
free(rightKid);
// If parent is empty, than it must have been the root.
if (parent->size == 0) {
root = leftKid;
free(parent->child);
free(parent->key);
free(parent);
return NEW_ROOT;
}
return MODIFIED_NOT_ROOT;
}
// Makes sure parent->child[index] has at least minDegree items.
// If it doesn't, then things are changed to make sure it does.
// Returns a code indicating what action was taken.
template <typename T>
char BTree<T>::fixChildSize(BNode<T> *parent, unsigned index) {
BNode<T> *kid = parent->child[index];
// If things need fixed.
if (kid->size < minDegree) {
// Borrow from left sibling if possible.
if (index != 0 && parent->child[index - 1]->size >= minDegree) {
BNode<T> *leftKid = parent->child[index - 1];
// When there are numerous equivalent keys,
// nodeInsert can insert into an index other than 0.
// The for loop fixed child pointers if that happens.
for (unsigned i = nodeInsert(kid, parent->key[index - 1]); i != 0; i--) {
kid->child[i] = kid->child[i - 1];
}
kid->child[0] = leftKid->child[leftKid->size];
parent->key[index - 1] = nodeDelete(leftKid, leftKid->size - 1);
}
// Borrow from right sibling if possible
else if (index != parent->size && parent->child[index + 1]->size >= minDegree) {
BNode<T> *rightKid = parent->child[index + 1];
// Move curr->key[i] into kid->key
nodeInsert(kid, parent->key[index]);
kid->child[kid->size] = rightKid->child[0];
rightKid->child[0] = rightKid->child[1];
// Move rightKid->key[0] into curr->key
parent->key[index] = nodeDelete(rightKid, 0);
}
// If borrowing is not possible, then merge.
else if (index != 0) {
return mergeChildren(parent, index - 1);
}
else {
return mergeChildren(parent, index);
}
return MODIFIED_NOT_ROOT;
}
// If things don't need fixed.
return NOT_MODIFIED;
}
// Recursize function for printing a tree or subtree.
// node is the root of the subtree to be printed.
// tab is how far to indent the subtree.
template <typename T>
void BTree<T>::printNode(BNode<T> *node, unsigned tab) {
// Indent
for (unsigned i = 0; i < tab; i++) {
printf("\t");
}
// Print the current node.
for (unsigned i = 0; i < node->size; i++) {
printKey(node->key[i]);
printf(" ");
}
printf("\n");
// Print all child nodes.
if (!node->leaf) {
tab++;
for (unsigned i = 0; i <= node->size; i++) {
printNode(node->child[i], tab);
}
}
}

View File

@@ -1,116 +0,0 @@
/* B-Tree
* Author: Caleb Baker
* Date: 10/8/17
* Summary: A B-Tree data structure.
* Most standard operations run in O(lg(n)) time.
* Uses O(n) memory.
* Where n is the number of items in the tree.
*/
#pragma once
#include <utility>
// #define NULL 0
#define SEARCH_KEY_NOT_FOUND 's'
#define REMOVE_KEY_NOT_FOUND 'r'
// struct for representing nodes of a b tree
template <typename T>
struct BNode {
BNode<T> **child; // Array of pointers to children.
T *key; // Array of keys.
unsigned size; // Number of keys.
bool leaf; // Whether the node is a leaf.
};
typedef char BTREE_EXCEPTION;
// class for representing b trees.
template <typename T>
class BTree {
public:
// Constructor
// First parameter is the minimum degree of the tree.
// Second parameter is the tree's key-comparison function.
// Third parameter is a function that prints keys.
// Constant time.
BTree(unsigned, bool (*)(T, T), void (*)(T) = NULL);
// Destructor.
// Linear time.
~BTree<T>();
// Inserts a key into the tree.
// Logorithmic time.
void insert(T);
// Removes a key from the tree.
// Throws a BTREE_EXCEPTION if no item was found to remove.
// Logorithmic time.
T remove(T);
// Function to find a key in the tree.
// returnValue.first is the node the item is in.
// returnValue.second is the correct index in that node's key array
// Logorithmic time.
std::pair<BNode<T>*, unsigned> search(T);
// Uses search but just returns the key rather than the whole node.
// Useful when T is a key value pair and lessThan only looks at the key.
// Throws a BTREE_EXCEPTION if no item matching the parameter is found
// Logorithmic time.
T searchKey(T);
// Prints the tree.
// Linear time
void print();
private:
// Used for initializing nodes.
void initializeNode(BNode<T>*);
// Recursive function called by destructor.
void freeNode(BNode<T>*);
// Finds the index of a key in a node.
unsigned findIndex(BNode<T>*, T);
// Inserts a key into a node.
unsigned nodeInsert(BNode<T>*, T);
// Deletes the key at a given index from a node.
T nodeDelete(BNode<T>*, unsigned);
// Function for splitting nodes that are too full.
void splitChild(BNode<T>*, int);
// Merges two children of a node at a given index into one child.
char mergeChildren(BNode<T>*, unsigned);
// Makes sure the child of a node at a specified index has >= minDegree items.
char fixChildSize(BNode<T>*, unsigned);
// Recursively prints a subtree.
void printNode(BNode<T>*, unsigned);
// Root node.
BNode<T> *root;
// Comparison function used for managing element placement.
bool (*lessThan)(T, T);
// Function used to print items in the tree.
void (*printKey)(T);
// Minimum degree of the tree.
unsigned minDegree;
};
#include "bTree.cpp"

View File

@@ -1,45 +0,0 @@
#include <iostream>
#include "bTree.h"
bool compare(int a, int b) {
return a < b;
};
void print(int a) {
std::cout << a << std::endl;
};
int main(int argc, char *argv[]) {
BTree<int> bt(4, compare, print);
bt.insert(1);
bt.insert(2);
bt.insert(3);
bt.insert(3);
bt.insert(3);
bt.insert(3);
bt.insert(3);
bt.insert(3);
bt.insert(3);
bt.insert(3);
bt.insert(4);
bt.insert(5);
bt.insert(6);
bt.insert(7);
bt.insert(7);
bt.insert(7);
bt.insert(7);
bt.insert(7);
bt.print();
auto r = bt.search(7);
auto r1 = bt.searchKey(3);
auto r2 = bt.remove(2);
auto r3 = bt.search(2);
return 0;
}

View File

@@ -1,66 +0,0 @@
// "create table history_dividends (symbol varchar(8), ex_date date, pay_date date, div_rate float)",
// "set 'DATE_FORMAT' = '%m/%d/%Y' ",
// "insert into history_dividends (symbol,ex_date,pay_date,div_rate) values ('symbol', 'ex-date', 'pay-date', 0.1)",
// "insert into history_dividends (symbol,ex_date,pay_date,div_rate) values ('symbol', ex-date, pay-date)"
// "create table ticker ( tablee varchar(5) not null, permaticker integer, ticker varchar(10) not null, name varchar(256) not null, exchange varchar(32), isdelisted boolean, category varchar(32), cusips varchar(256), siccode integer, sicsector varchar(256), sicindustry varchar(256), famasector varchar(256), famaindustry varchar(256), sector varchar(128), industry varchar(128), scalemarketcap varchar(64), scalerevenue varchar(64), relatedtickers varchar(128), currency varchar(3), location varchar(64), lastupdated date, firstadded date, firstpricedate date, lastpricedate date, firstquarter date, lastquarter date, secfilings varchar(256), companysite varchar(256))",
// "load ticker from '/Users/vaclavt/Library/Mobile Documents/com~apple~CloudDocs/Development/usql/tickers.csv')",
// "select * from ticker where ticker = 'WFC' and tablee = 'SF1'",
// "set 'DATE_FORMAT' = '%Y-%m-%d'",
// "show 'DATE_FORMAT'",
// "create table prices (datetime date, symbol varchar(8), prev_close float, open float, price float, change float, change_prct varchar(16))",
// "load into prices from \"/Users/vaclavt/Development/mlisp_fin/tmp/prices.csv\"",
// "select * from prices where symbol = 'AIG' limit 5",
// "create table sf1 ( ticker varchar(8), dimension varchar(3), calendar_date date, date_key date, report_period date, last_updated date, accoci float, assets float, assetsavg float, assetsc float, assetsnc float, assetturnover float, bvps float, capex float, cashneq float, cashnequsd float, cor float, consolinc float, currentratio float, de float, debt float, debtc float, debtnc float, debtusd float, deferredrev float, depamor float, deposits float, divyield float, dps float, ebit float, ebitda float, ebitdamargin float, ebitdausd float, ebitusd float, ebt float, eps float, epsdil float, epsusd float, equity float, equityavg float, equityusd float, ev float, evebit float, evebitda float, fcf float, fcfps float, fxusd float, gp float, grossmargin float, intangibles float, intexp float, invcap float, invcapavg float, inventory float, investments float, investmentsc float, investmentsnc float, liabilities float, liabilitiesc float, liabilitiesnc float, marketcap float, ncf float, ncfbus float, ncfcommon float, ncfdebt float, ncfdiv float, ncff float, ncfi float, ncfinv float, ncfo float, ncfx float, netinc float, netinccmn float, netinccmnusd float, netincdis float, netincnci float, netmargin float, opex float, opinc float, payables float, payoutratio float, pb float, pe float, pe1 float, ppnenet float, prefdivis float, price float, ps float, ps1 float, receivables float, retearn float, revenue float, revenueusd float, rnd float, roa float, roe float, roic float, ros float, sbcomp float, sgna float, sharefactor float, sharesbas float, shareswa float, shareswadil float, sps float, tangibles float, taxassets float, taxexp float, taxliabilities float, tbvps float, workingcapital float)",
// "load sf1 from '/tmp/sf1.csv'",
// "select ticker, calendar_date from sf1 where calendar_date > to_date('2019-01-01', '%Y-%m-%d') limit 1",
// "select ticker, dimension, calendar_date, eps, dps, roa*100 as roa, roe*100 as roe, pp(revenue), netinc from sf1 where (ticker = 'AIG' or ticker = 'WFC') and dimension = 'MRY' and calendar_date > to_date('2019-01-01', '%Y-%m-%d') order by 3 desc
// "select ticker, dimension, calendar_date, eps, dps, roa*100 as roa, roe*100 as roe, pp(revenue) as revenue, pp(netinc) as netinc from sf1 where (ticker = 'AIG' or ticker = 'WFC') and dimension = 'MRY' and calendar_date > to_date('2019-01-01', '%Y-%m-%d') order by 3 desc",
// "create table a (i integer not null, s varchar(64), f float null, d date null, b boolean)",
// "insert into a (i, s, b) values(1, upper('zero'), 'Y')",
// "insert into a (i, s, b, f) values(1 + 10000, upper('one'), 'N', 3.1415)",
// "insert into a (i, s, f) values(2 + 10000, upper('two'), 9.1415)",
// "select pp(f * 100, \"%.2f\"), i from a order by i",
// "select min(i), max(f), count(*) from a where b is not null",
// "select * from a where b is null",
// "select * from a where b is not null",
// "select * from a where b='N'",
// "update a set i = i * 100, f = f + 0.01 where i > 1",
// "select to_string(i, '%d.%m.%Y %H:%M:%S'), i, s from a where i < to_date('20.12.2019', '%d.%m.%Y')",
// "select i + 2 as first, i, s, b, f from a where i >=1 order by 1 desc offset 0 limit 1",
// "update table a set s = 'null string aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'",
// "update table a set i = null",
// "insert into a (i, s) values(2, 'two')",
// "insert into a (i, s) values(3, 'two')",
// "insert into a (i, s) values(4, lower('FOUR'))",
// "insert into a (i, s) values(5, 'five')",
// "insert into a (i, s) values(to_date('20.12.1973', '%d.%m.%Y'), 'six')",
// tohle zpusobi kresh "insert into a (i, d) values(6', '2006-10-04')",
// "insert into a (i, d) values(6, '2006-10-04')",
// "save table a into '/tmp/a.csv'",
// "select i, s from a where i > 2 order by 1 desc offset 1 limit 1",
// "select distinct s, d from a",
// "select i, s from a where i = 1",
// "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 > 0",
// "delete from a where i = 4",
// "select i, s from a where i > 0",
// "update a set f = 9.99 where i = 3",
// "select i, s, f from a where i = 3",
// "update a set s = 'three', f = f + 0.01 where i = 3",
// "select i, s, f from a where i = 3",
// "create table data (ticker varchar(8), price float null)",
// "load data from '/Users/vaclavt/Library/Mobile Documents/com~apple~CloudDocs/Development/usql/data.csv')",
// "select ticker, price from data",
// "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",
// "drop table x",
// "select i, 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))",
// "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 %')",
// "select to_string(datetime, '%d.%m.%Y %H:%M:%S'), symbol, prev_close, open, price, change, change_prct, datetime from prices where symbol = 'SYF' order by 8 desc limit 10"

View File

@@ -4,7 +4,6 @@
#include "ml_string.h"
#include <algorithm>
#include <fstream>
namespace usql {
@@ -24,6 +23,8 @@ std::unique_ptr<Table> USql::execute(Node &node) {
switch (node.node_type) {
case NodeType::create_table:
return execute_create_table(static_cast<CreateTableNode &>(node));
case NodeType::create_index:
return execute_create_index(static_cast<CreateIndexNode &>(node));
case NodeType::create_table_as_select:
return execute_create_table_as_table(static_cast<CreateTableAsSelectNode &>(node));
case NodeType::drop_table:
@@ -108,7 +109,7 @@ std::unique_ptr<ValueNode> USql::eval_value_node(Table *table, Row &row, Node *n
if (node->node_type == NodeType::database_value) {
return eval_database_value_node(table, row, node);
} else if (node->node_type == NodeType::int_value || node->node_type == NodeType::float_value || node->node_type == NodeType::string_value || node->node_type == NodeType::bool_value) {
return eval_literal_value_node(table, row, node);
return eval_literal_value_node(row, node);
} else if (node->node_type == NodeType::function) {
return eval_function_value_node(table, row, node, col_def_node, agg_func_value);
} else if (node->node_type == NodeType::null_value) {
@@ -143,7 +144,7 @@ std::unique_ptr<ValueNode> USql::eval_database_value_node(Table *table, Row &row
}
std::unique_ptr<ValueNode> USql::eval_literal_value_node(Table *table, Row &row, Node *node) {
std::unique_ptr<ValueNode> USql::eval_literal_value_node(Row &row, Node *node) {
if (node->node_type == NodeType::int_value) {
auto *ivl = static_cast<IntValueNode *>(node);
return std::make_unique<IntValueNode>(ivl->value);
@@ -344,7 +345,7 @@ std::unique_ptr<ValueNode> USql::pp_function(const std::vector<std::unique_ptr<V
return std::make_unique<StringValueNode>(parsed_value->getStringValue().substr(0, 10));
// TODO introduce constant for 10
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), 10, ' ', false));
}
return std::make_unique<StringValueNode>(parsed_value->getStringValue());
}
@@ -411,17 +412,17 @@ USql::min_function(const std::vector<std::unique_ptr<ValueNode>> &evaluatedPars,
throw Exception("unsupported data type for min function");
}
Table *USql::find_table(const std::string &name) {
Table *USql::find_table(const std::string &name) const {
auto name_cmp = [name](const Table& t) { return t.m_name == name; };
auto table_def = std::find_if(begin(m_tables), end(m_tables), name_cmp);
if (table_def != std::end(m_tables)) {
return table_def.operator->();
return const_cast<Table *>(table_def.operator->());
} else {
throw Exception("table not found (" + name + ")");
}
}
void USql::check_table_not_exists(const std::string &name) {
void USql::check_table_not_exists(const std::string &name) const {
auto name_cmp = [name](const Table& t) { return t.m_name == name; };
auto table_def = std::find_if(begin(m_tables), end(m_tables), name_cmp);
if (table_def != std::end(m_tables)) {
@@ -429,5 +430,4 @@ void USql::check_table_not_exists(const std::string &name) {
}
}
} // namespace

36
usql.h
View File

@@ -1,7 +1,9 @@
#pragma once
#include "settings.h"
#include "parser.h"
#include "table.h"
#include "index.h"
#include <string>
#include <list>
@@ -19,6 +21,7 @@ private:
std::unique_ptr<Table> execute(Node &node);
std::unique_ptr<Table> execute_create_table(CreateTableNode &node);
std::unique_ptr<Table> execute_create_index(CreateIndexNode &node);
std::unique_ptr<Table> execute_create_table_as_table(CreateTableAsSelectNode &node);
std::unique_ptr<Table> execute_load(LoadIntoTableNode &node);
std::unique_ptr<Table> execute_save(SaveTableNode &node);
@@ -27,7 +30,7 @@ private:
static std::unique_ptr<Table> execute_show(ShowNode &node);
std::unique_ptr<Table> execute_insert_into_table(InsertIntoTableNode &node);
std::unique_ptr<Table> execute_select(SelectFromTableNode &node);
std::unique_ptr<Table> execute_select(SelectFromTableNode &node) const;
std::unique_ptr<Table> execute_delete(DeleteFromTableNode &node);
std::unique_ptr<Table> execute_update(UpdateTableNode &node);
@@ -37,7 +40,7 @@ private:
static std::unique_ptr<ValueNode> eval_value_node(Table *table, Row &row, Node *node, ColDefNode *col_def_node, ColValue *agg_func_value);
static std::unique_ptr<ValueNode> eval_database_value_node(Table *table, Row &row, Node *node);
static std::unique_ptr<ValueNode> eval_literal_value_node(Table *table, Row &row, Node *node);
static std::unique_ptr<ValueNode> eval_literal_value_node(Row &row, Node *node);
static std::unique_ptr<ValueNode> eval_function_value_node(Table *table, Row &row, Node *node, ColDefNode *col_def_node, ColValue *agg_func_value);
@@ -50,22 +53,22 @@ private:
static std::tuple<int, ColDefNode> get_column_definition(Table *table, SelectColNode *select_col_node, int col_order);
static ColDefNode get_db_column_definition(Table *table, Node *node);
static std::tuple<int, ColDefNode> get_node_definition(Table *table, Node *select_col_node, const std::string & col_name, int col_order);
Table *find_table(const std::string &name);
[[nodiscard]] Table *find_table(const std::string &name) const;
void check_table_not_exists(const std::string &name);
void check_table_not_exists(const std::string &name) const;
private:
Parser m_parser;
std::list<Table> m_tables;
static void execute_distinct(SelectFromTableNode &node, Table *result) ;
static void execute_order_by(SelectFromTableNode &node, Table *table, Table *result) ;
static void execute_offset_limit(OffsetLimitNode &node, Table *result) ;
static void execute_distinct(SelectFromTableNode &node, Table *result);
static void execute_order_by(SelectFromTableNode &node, Table *table, Table *result);
static void execute_offset_limit(OffsetLimitNode &node, Table *result);
void expand_asterix_char(SelectFromTableNode &node, Table *table) const;
void setup_order_columns(std::vector<ColOrderNode> &node, Table *table) const;
static void expand_asterix_char(SelectFromTableNode &node, Table *table) ;
static void setup_order_columns(std::vector<ColOrderNode> &node, Table *table) ;
bool check_for_aggregate_only_functions(SelectFromTableNode &node, int result_cols_cnt) const;
static bool check_for_aggregate_only_functions(SelectFromTableNode &node, size_t result_cols_cnt) ;
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);
@@ -77,8 +80,17 @@ private:
static std::unique_ptr<ValueNode> max_function(const std::vector<std::unique_ptr<ValueNode>> &evaluatedPars, const ColDefNode *col_def_node, ColValue *agg_func_value);
static std::unique_ptr<ValueNode> min_function(const std::vector<std::unique_ptr<ValueNode>> &evaluatedPars, const ColDefNode *col_def_node, ColValue *agg_func_value);
static std::unique_ptr<ValueNode>
count_function(ColValue *agg_func_value, const std::vector<std::unique_ptr<ValueNode>> &evaluatedPars);
static std::unique_ptr<ValueNode> count_function(ColValue *agg_func_value, const std::vector<std::unique_ptr<ValueNode>> &evaluatedPars);
static void evalRowWhere(SelectFromTableNode &where_node,
Table *src_table, Row *src_row,
Table *rslt_table, Row *rslt_row,
const std::vector<ColDefNode> &rslt_tbl_col_defs, const std::vector<int> &src_table_col_index,
bool is_aggregated) ;
std::pair<bool, std::vector<int>> probe_index_scan(const Node *where, Table *table) const;
std::pair<bool, std::vector<int>> look_for_usable_index(const Node *where, Table *table) const;
bool normalize_where(const Node *node) const;
};
} // namespace

View File

@@ -1,6 +1,5 @@
#include "usql.h"
#include "exception.h"
#include "ml_date.h"
#include "ml_string.h"
#include <algorithm>
@@ -20,6 +19,28 @@ std::unique_ptr<Table> USql::execute_create_table(CreateTableNode &node) {
}
std::unique_ptr<Table> USql::execute_create_index(CreateIndexNode &node) {
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
if (table_def->get_index(node.index_name) != nullptr) throw Exception("index already exists");
if (col_def.null) throw Exception("index on not null supported only");
if (table_def->get_index_for_column(node.column_name) != nullptr) throw Exception("column is already indexed");
IndexedDataType type;
if (col_def.type == ColumnType::integer_type) type = IndexedDataType::integer;
else if (col_def.type == ColumnType::varchar_type) type = IndexedDataType::string;
else throw Exception("creating index on unsupported type");
Index<IndexValue> i{node.index_name, node.column_name, type};
table_def->create_index(i);
table_def->index_rows(node.index_name);
return create_stmt_result_table(0, "index created", 0);
}
std::unique_ptr<Table> USql::execute_create_table_as_table(CreateTableAsSelectNode &node) {
check_table_not_exists(node.table_name);

View File

@@ -1,15 +1,13 @@
#include "usql.h"
#include "exception.h"
#include "ml_date.h"
#include "ml_string.h"
#include <algorithm>
#include <fstream>
namespace usql {
std::unique_ptr<Table> USql::execute_select(SelectFromTableNode &node) {
std::unique_ptr<Table> USql::execute_select(SelectFromTableNode &node) const {
// find source table
Table *table = find_table(node.table_name);
@@ -28,7 +26,7 @@ std::unique_ptr<Table> USql::execute_select(SelectFromTableNode &node) {
}
// check for aggregate function
bool aggregate_funcs = check_for_aggregate_only_functions(node, result_tbl_col_defs.size());
bool is_aggregated = check_for_aggregate_only_functions(node, result_tbl_col_defs.size());
// prepare result table structure
auto result = std::make_unique<Table>("result", result_tbl_col_defs);
@@ -36,41 +34,26 @@ std::unique_ptr<Table> USql::execute_select(SelectFromTableNode &node) {
// replace possible order by col names to col indexes and validate
setup_order_columns(node.order_by, result.get());
// execute access plan
Row* new_row = nullptr;
for (auto row = begin(table->m_rows); row != end(table->m_rows); ++row) {
// eval where for row
if (eval_where(node.where.get(), table, *row)) {
// prepare empty row and copy column values
// when agregate functions in result only one row for table
if (!aggregate_funcs || result->rows_count()==0) {
new_row = &result->create_empty_row();
}
for (auto idx = 0; idx < result->columns_count(); idx++) {
auto src_table_col_idx = source_table_col_index[idx];
// look for index to use
auto [use_index, rowids] = probe_index_scan(node.where.get(), table);
if (src_table_col_idx == FUNCTION_CALL) {
auto evaluated_value = eval_value_node(table, *row, node.cols_names->operator[](idx).value.get(), &result_tbl_col_defs[idx], &new_row->operator[](idx));
ValueNode *col_value = evaluated_value.get();
// index scan
if (use_index) {
for (int & rowid : rowids) {
evalRowWhere(node, table, (Row *) &table->get_row(rowid), result.get(), new_row, result_tbl_col_defs, source_table_col_index, is_aggregated);
}
new_row->setColumnValue(&result_tbl_col_defs[idx], col_value);
} else {
ColValue &col_value = row->operator[](src_table_col_idx);
new_row->setColumnValue(&result_tbl_col_defs[idx], col_value);
}
}
// add row to result
if (aggregate_funcs == 0) {
result->commit_row(*new_row);
}
// full scan
} else {
for (auto row = table->fs_begin(); row != table->fs_end(); ++row) {
evalRowWhere(node, table, &(*row), result.get(), new_row, result_tbl_col_defs, source_table_col_index, is_aggregated);
}
}
// when aggregates commit this one row
if (aggregate_funcs && new_row != nullptr) {
result->commit_row(*new_row);
}
execute_distinct(node, result.get());
@@ -81,7 +64,116 @@ std::unique_ptr<Table> USql::execute_select(SelectFromTableNode &node) {
return result;
}
bool USql::check_for_aggregate_only_functions(SelectFromTableNode &node, int result_cols_cnt) const {
std::pair<bool, std::vector<int>> USql::probe_index_scan(const Node *where, Table *table) const {
bool indexscan_possible = normalize_where(where);
if (indexscan_possible && Settings::get_bool_setting("USE_INDEXSCAN")) {
// where->dump();
return look_for_usable_index(where, table);
}
// no index scan
return std::make_pair(false, std::vector<int>{});
}
std::pair<bool, std::vector<int>> USql::look_for_usable_index(const Node *where, Table *table) const {
if (where->node_type == NodeType::relational_operator) {
auto * ron = (RelationalOperatorNode *)where;
if (ron->op == RelationalOperatorType::equal) {
if (ron->left->node_type == NodeType::database_value &&
((ron->right->node_type == NodeType::int_value) || (ron->right->node_type == NodeType::string_value))
) {
auto col_name = ((DatabaseValueNode *)ron->left.get())->col_name;
Index<IndexValue> * used_index = table->get_index_for_column(col_name);
if (used_index != nullptr) {
std::vector<int> rowids;
if (used_index->get_data_type() == IndexedDataType::integer)
rowids = used_index->search(((ValueNode *) ron->right.get())->getIntegerValue());
else if (used_index->get_data_type() == IndexedDataType::string)
rowids = used_index->search(((ValueNode *) ron->right.get())->getStringValue());
std::cout << "using index " << table->m_name << "(" << used_index->get_column_name() << "), " << rowids.size() << "/" << table->rows_count() << std::endl;
return std::make_pair(true, rowids);
}
}
}
} else if (where->node_type == NodeType::logical_operator) {
auto * operatorNode = (LogicalOperatorNode *)where;
if (operatorNode->op == LogicalOperatorType::and_operator) {
auto [use_index, rowids] = look_for_usable_index(operatorNode->left.get(), table);
if (use_index) {
return std::make_pair(true, rowids);
}
return look_for_usable_index(operatorNode->right.get(), table);
}
}
// no index available
return std::make_pair(false, std::vector<int>{});
}
bool USql::normalize_where(const Node *node) const {
// normalize relational operators "layout" and check whether index scan even possible
// unify relational operators tha left node is always database value
if (node->node_type == NodeType::relational_operator) {
// TODO more optimizations here, for example node 1 = 2 etc
auto * ron = (RelationalOperatorNode *)node;
if (ron->right->node_type == NodeType::database_value && ((ron->left->node_type == NodeType::int_value) || (ron->left->node_type == NodeType::string_value)) ) {
std::swap(ron->left, ron->right);
}
return true;
} else if (node->node_type == NodeType::logical_operator) {
auto * operatorNode = (LogicalOperatorNode *)node;
if (operatorNode->op == LogicalOperatorType::or_operator) {
return false;
}
bool left_subnode = normalize_where(operatorNode->left.get());
bool right_subnode = normalize_where(operatorNode->left.get());
return left_subnode && right_subnode;
}
return true;
}
void USql::evalRowWhere(SelectFromTableNode &where_node,
Table *src_table, Row *src_row,
Table *rslt_table, Row *rslt_row,
const std::vector<ColDefNode> &rslt_tbl_col_defs,
const std::vector<int> &src_table_col_index,
bool is_aggregated) {
if (eval_where(where_node.where.get(), src_table, *src_row)) {
// prepare empty src_row and copy column values
// when aggregate functions in rslt_table only one src_row for src_table
if (!is_aggregated || rslt_table->rows_count() == 0) {
rslt_row = &rslt_table->create_empty_row();
}
for (auto idx = 0; idx < rslt_table->columns_count(); idx++) {
auto src_table_col_idx = src_table_col_index[idx];
if (src_table_col_idx == FUNCTION_CALL) {
auto evaluated_value = eval_value_node(src_table, *src_row, where_node.cols_names->operator[](idx).value.get(),
const_cast<ColDefNode *>(&rslt_tbl_col_defs[idx]), &rslt_row->operator[](idx));
ValueNode *col_value = evaluated_value.get();
rslt_row->setColumnValue((ColDefNode *) &rslt_tbl_col_defs[idx], col_value);
} else {
ColValue &col_value = src_row->operator[](src_table_col_idx);
rslt_row->setColumnValue((ColDefNode *) &rslt_tbl_col_defs[idx], col_value);
}
}
// add src_row to rslt_table
if (!is_aggregated) {
rslt_table->commit_row(*rslt_row);
}
}
}
bool USql::check_for_aggregate_only_functions(SelectFromTableNode &node, size_t result_cols_cnt) {
int aggregate_funcs = 0;
for (int i = 0; i < node.cols_names->size(); i++) {
SelectColNode * col_node = &node.cols_names->operator[](i);
@@ -99,7 +191,7 @@ bool USql::check_for_aggregate_only_functions(SelectFromTableNode &node, int res
return aggregate_funcs > 0;
}
void USql::expand_asterix_char(SelectFromTableNode &node, Table *table) const {
void USql::expand_asterix_char(SelectFromTableNode &node, Table *table) {
if (node.cols_names->size() == 1 && node.cols_names->operator[](0).name == "*") {
node.cols_names->clear();
node.cols_names->reserve(table->columns_count());
@@ -109,7 +201,7 @@ void USql::expand_asterix_char(SelectFromTableNode &node, Table *table) const {
}
}
void USql::setup_order_columns(std::vector<ColOrderNode> &node, Table *table) const {
void USql::setup_order_columns(std::vector<ColOrderNode> &node, Table *table) {
for (auto& order_node : node) {
if (!order_node.col_name.empty()) {
ColDefNode col_def = table->get_column_def(order_node.col_name);