Compare commits

..

7 Commits

Author SHA1 Message Date
vaclavt
c16b062267 cron-like functionality wip 2022-02-17 20:46:20 +01:00
vaclavt
7d939a49dd exceptions related fixes 2022-02-17 20:45:33 +01:00
vaclavt
b7cbc64277 usestd::filesystem functions 2022-02-17 20:44:33 +01:00
vaclavt
5d0b36d0f0 .vscode dir updates 2022-02-17 20:43:28 +01:00
vaclavt
7ad26ba427 usql updated 2022-02-17 20:42:30 +01:00
vaclavt
765f2bc673 some TODOs solved 2022-02-17 20:41:47 +01:00
vaclavt
2d26c59df6 doc updates 2022-02-17 20:40:10 +01:00
19 changed files with 290 additions and 174 deletions

2
.gitignore vendored
View File

@@ -7,3 +7,5 @@ CMakeFiles
Testing Testing
.cache .cache
Makefile Makefile
cmake_install.cmake
CMakeCache.txt

View File

@@ -7,10 +7,6 @@
"${workspaceFolder}/clib" "${workspaceFolder}/clib"
], ],
"defines": [], "defines": [],
"macFrameworkPath": [
"/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/System/Library/Frameworks"
],
"compilerPath": "/usr/bin/clang",
"cStandard": "c17", "cStandard": "c17",
"intelliSenseMode": "macos-clang-x64", "intelliSenseMode": "macos-clang-x64",
"configurationProvider": "ms-vscode.cmake-tools" "configurationProvider": "ms-vscode.cmake-tools"

View File

@@ -14,16 +14,20 @@ CsvParser::CsvParser(bool skip_hdr, char field_sep, char quote_ch, char line_sep
} }
MlValue CsvParser::parseCSV(const std::string &csvSource) { MlValue CsvParser::parseCSV(const std::string &csvSource) {
int linesRead = 0; constexpr size_t INITIAL_PARSED_ROWS_SIZE = 128;
constexpr size_t INITIAL_COLUMNS_SIZE = 32;
constexpr size_t ROWS_READ_FOR_SIZE_ESTIMATION = 16;
size_t linesRead = 0;
bool inQuote(false); bool inQuote(false);
bool newLine(false); bool newLine(false);
std::string field; std::string field;
std::vector<MlValue> parsed_data; std::vector<MlValue> parsed_rows;
parsed_data.reserve(128); // TODO introduce constant here parsed_rows.reserve(INITIAL_PARSED_ROWS_SIZE);
std::vector<MlValue> line; std::vector<MlValue> line;
line.reserve(32); // TODO introduce constant here line.reserve(INITIAL_COLUMNS_SIZE);
std::string::const_iterator aChar = csvSource.begin(); std::string::const_iterator aChar = csvSource.begin();
std::string::const_iterator aEnd = csvSource.end(); std::string::const_iterator aEnd = csvSource.end();
@@ -45,14 +49,14 @@ MlValue CsvParser::parseCSV(const std::string &csvSource) {
} else { } else {
if (!newLine) { if (!newLine) {
line.push_back(ivalualize(field)); line.push_back(ivalualize(field));
add_line(line, parsed_data); add_row(line, parsed_rows);
field.clear(); field.clear();
line.clear(); line.clear();
linesRead++; linesRead++;
if (linesRead == 16) { if (linesRead == ROWS_READ_FOR_SIZE_ESTIMATION) {
size_t linesEstimation = csvSource.size() / (std::distance(csvSource.begin(), aChar) / linesRead); size_t linesEstimation = csvSource.size() / (std::distance(csvSource.begin(), aChar) / linesRead);
if (linesEstimation > parsed_data.capacity()) if (linesEstimation > parsed_rows.capacity())
parsed_data.reserve(linesEstimation); parsed_rows.reserve(linesEstimation);
} }
newLine = true; newLine = true;
} }
@@ -68,18 +72,18 @@ MlValue CsvParser::parseCSV(const std::string &csvSource) {
if (!field.empty()) if (!field.empty())
line.push_back(ivalualize(field)); line.push_back(ivalualize(field));
add_line(line, parsed_data); add_row(line, parsed_rows);
return parsed_data; return parsed_rows;
} }
void CsvParser::add_line(const std::vector<MlValue> &line, std::vector<MlValue> &lines) { void CsvParser::add_row(const std::vector<MlValue> &columns, std::vector<MlValue> &rows) {
if (skip_header && !header_skiped) { if (skip_header && !header_skiped) {
header_skiped = true; header_skiped = true;
} else { } else {
if (!line.empty()) if (!columns.empty())
lines.emplace_back(line); rows.emplace_back(columns);
} }
} }

View File

@@ -26,7 +26,7 @@ public:
MlValue parseCSV(const std::string &csvSource); MlValue parseCSV(const std::string &csvSource);
private: private:
void add_line(const std::vector<MlValue> &line, std::vector<MlValue> &lines); void add_row(const std::vector<MlValue> &columns, std::vector<MlValue> &rows);
static MlValue ivalualize(const std::string &value) ; static MlValue ivalualize(const std::string &value) ;

View File

@@ -6,11 +6,11 @@
#include <vector> #include <vector>
std::string std::string mini_sprintf_format(bool left_align, bool sign, bool space_on_left, bool padding_by_zero,
mini_sprintf_format(bool left_align, bool sign, bool space_on_left, bool padding_by_zero, int width, int precision, int width, int precision,
int length, char specifier, const MlValue &value) { int length, char specifier, const MlValue &value) {
std::string s; std::string s;
std::ostringstream stream_str; // PERF simpler solution..without string stream std::ostringstream stream_str; // PERF string append should be faster
bool is_positive = false; bool is_positive = false;
if (specifier == 's') { if (specifier == 's') {
@@ -47,7 +47,7 @@ mini_sprintf_format(bool left_align, bool sign, bool space_on_left, bool padding
stream_str << std::setprecision(precision); stream_str << std::setprecision(precision);
stream_str << dval; stream_str << dval;
s = stream_str.str(); // TODO ?? s = stream_str.str();
} }
if (width > -1 && s.size() < width) { if (width > -1 && s.size() < width) {

View File

@@ -5,7 +5,6 @@
#include <netinet/in.h> #include <netinet/in.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <cstdio>
#include <iostream> #include <iostream>
#include <regex> #include <regex>
#include <sstream> #include <sstream>
@@ -16,8 +15,6 @@
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/GET // https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/GET
// TODO user streams instead of printf's
std::pair<int, std::string> HttpClient::doRequest(const std::string &method, const std::string &url, const std::map<std::string, std::string> &headers, const std::string &request_body) { std::pair<int, std::string> HttpClient::doRequest(const std::string &method, const std::string &url, const std::map<std::string, std::string> &headers, const std::string &request_body) {
// split url to parts // split url to parts
parseURL(url); parseURL(url);
@@ -39,7 +36,6 @@ std::pair<int, std::string> HttpClient::doRequest(const std::string &method, con
return std::make_pair(403, ""); return std::make_pair(403, "");
} }
// get headers // get headers
std::string::size_type position = ssl_read_packet.find("\r\n\r\n"); std::string::size_type position = ssl_read_packet.find("\r\n\r\n");
if (position == std::string::npos) if (position == std::string::npos)
@@ -198,7 +194,7 @@ int HttpClient::sslRequest(const std::string &server_name, const std::string &re
int s; int s;
s = socket(AF_INET, SOCK_STREAM, 0); s = socket(AF_INET, SOCK_STREAM, 0);
if (!s) { if (!s) {
printf("sslRequest, error creating socket.\n"); std::cerr << "HttpClient::sslRequest, error creating socket" << std::endl;
return -1; return -1;
} }
@@ -213,7 +209,7 @@ int HttpClient::sslRequest(const std::string &server_name, const std::string &re
// connect to server // connect to server
if (connect(s, (struct sockaddr *) &sa, socklen)) { if (connect(s, (struct sockaddr *) &sa, socklen)) {
printf("sslRequest, error connecting to server.\n"); std::cerr << "HttpClient::sslRequest, error connecting to server" << std::endl;
return -1; return -1;
} }
@@ -224,7 +220,7 @@ int HttpClient::sslRequest(const std::string &server_name, const std::string &re
SSL_CTX *ctx = SSL_CTX_new(meth); SSL_CTX *ctx = SSL_CTX_new(meth);
ssl = SSL_new(ctx); ssl = SSL_new(ctx);
if (!ssl) { if (!ssl) {
printf("sslRequest, error creating SSL.\n"); std::cerr << "HttpClient::sslRequest, error creating SSL" << std::endl;
logSSL(); logSSL();
return -1; return -1;
} }
@@ -235,23 +231,23 @@ int HttpClient::sslRequest(const std::string &server_name, const std::string &re
int err = SSL_connect(ssl); int err = SSL_connect(ssl);
if (err <= 0) { if (err <= 0) {
printf("sslRequest, error creating SSL connection. err=%x\n", err); std::cerr << "HttpClient::sslRequest, error creating SSL connection. " << err << std::endl;
logSSL(); logSSL();
fflush(stdout); fflush(stdout);
return -1; return -1;
} }
// log cipher // log cipher
// printf ("SSL connection using %s\n", SSL_get_cipher (ssl)); // std::cerr << "HttpClient::sslRequest, SSL connection using" << SSL_get_cipher (ssl) << std::endl;
// showCerts(ssl); // showCerts(ssl);
// send request // send request
// printf ("SSL sending request %s\n", request.c_str()); // std::cerr << "HttpClient::sslRequest, SSL sending request: " << request << std::endl;
int written_bytes = sslSendPacket(request); int written_bytes = sslSendPacket(request);
if (written_bytes != request.length()) { if (written_bytes != request.length()) {
printf("sslRequest, error sending request\n"); std::cerr << "HttpClient::sslRequest, error sending request" << std::endl;
return -1; return -1;
} }
@@ -275,15 +271,15 @@ void HttpClient::showCerts(SSL* ssl) {
cert = SSL_get_peer_certificate(ssl); /* get the server's certificate */ cert = SSL_get_peer_certificate(ssl); /* get the server's certificate */
if ( cert != NULL ) { if ( cert != NULL ) {
printf("Server certificates:\n"); std::cerr << "HttpClient::showCerts, Server certificates: " << std::endl;
line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0); line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
printf("Subject: %s\n", line); std::cerr << "HttpClient::showCerts, Subject: " << line << std::endl;
free(line); /* free the malloc'ed string */ free(line); /* free the malloc'ed string */
line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0); line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
printf("Issuer: %s\n", line); std::cerr << "HttpClient::showCerts, Issuer: " << line << std::endl;
free(line); /* free the malloc'ed string */ free(line); /* free the malloc'ed string */
X509_free(cert); /* free the malloc'ed certificate copy */ X509_free(cert); /* free the malloc'ed certificate copy */
} else { } else {
printf("No certificates.\n"); std::cerr << "HttpClient::showCerts, No certificates." << std::endl;
} }
} }

View File

@@ -9,7 +9,6 @@
class HttpClient { class HttpClient {
// TODO at this moment only https is implemented
private: private:
SSL *ssl; SSL *ssl;

View File

@@ -1,7 +1,5 @@
(include "/usr/local/var/mlisp/terminal.lsp") (include "/usr/local/var/mlisp/terminal.lsp")
; TODO better env formating
; TODO time parse function
(defn cron::sleep-to-next-minute () (defn cron::sleep-to-next-minute ()
@@ -9,9 +7,6 @@
(defn cron::eval-time-spec (val time_spec) (defn cron::eval-time-spec (val time_spec)
(do
;(print "DEBUG" "cron::eval-time-spec" val time_spec)
(def r
(cond (cond
((nil? time_spec) ((nil? time_spec)
#t) ; no time_spec -> it's true #t) ; no time_spec -> it's true
@@ -26,9 +21,6 @@
nil) ; TODO exception nil) ; TODO exception
) )
) )
(print "val:" val "time_spec:" time_spec "result" r)
r
))
(defn cron::add-job (name time_spec job) (defn cron::add-job (name time_spec job)
@@ -55,10 +47,17 @@
(set! bool (and bool (cron::eval-time-spec time_day (find-val-in-list time_spec "day")))) (set! bool (and bool (cron::eval-time-spec time_day (find-val-in-list time_spec "day"))))
(set! bool (and bool (cron::eval-time-spec time_month (find-val-in-list time_spec "month")))) (set! bool (and bool (cron::eval-time-spec time_month (find-val-in-list time_spec "month"))))
(set! bool (and bool (cron::eval-time-spec time_year (find-val-in-list time_spec "year")))) (set! bool (and bool (cron::eval-time-spec time_year (find-val-in-list time_spec "year"))))
(print "time-to-run test" bool) ; (print "time-to-run test" bool)
bool bool
)) ))
(defn cron::run-job (name code)
(do
;(print "running job:" name "->" code)
(def run_code (+ "(thread-create " (display code) ")"))
(eval (parse run_code))
)
)
(defn cron::start () (defn cron::start ()
(do (do
@@ -70,13 +69,13 @@
(for e cron::entries (for e cron::entries
(def job_name (first e)) (def job_name (first e))
(def time_spec (second e)) (def time_spec (second e))
(def job_code (third e))
; (print "DEBUG" "checking" job_name "time_spec" time_spec) ; (print "\n\n")
(if (cron::time-to-run now time_spec) (def is_for_run (cron::time-to-run now time_spec))
(do ; (print "DEBUG" job_name "checked" is_for_run)
;(print "running job:" job_name "code:" (third e)) (if is_for_run
(thread-create (eval (third e))) (cron::run-job job_name job_code)
)
; (print "not running" job_name) ; (print "not running" job_name)
) )
) )
@@ -99,19 +98,20 @@
(cron::add-job "every_min_print" (cron::add-job "every_min_print"
'(("minute" "*")) '(("minute" "*"))
'(print "code: every_min_print")) '(print "executing: every_min_print"))
; '(do (sleep 3) (print "executing: every_min_print")))
(cron::add-job "every_min_between_00_and_05" (cron::add-job "every_min_between_00_and_05"
'(("minute" "00-05")) '(("minute" "00-05"))
'(print "code: every_min_between_00_and_05")) '(print "executing: every_min_between_00_and_05"))
(cron::add-job "13:20_working_day" (cron::add-job "13:20_working_day"
'(("weekday" "1-5")("hour" "13")("minute" "20")) '(("weekday" "1-5")("hour" "13")("minute" "20"))
'(print "code: 13:20_working_day")) '(print "executing: 13:20_working_day"))
(cron::add-job "15:20_working_day" (cron::add-job "15:20_working_day"
'(("weekday" "1-5")("hour" "15")("minute" "20")) '(("weekday" "1-5")("hour" "15")("minute" "20"))
'(print "code: 15:20_working_day")) '(print "executing: 15:20_working_day"))
(cron::start) (cron::start)

View File

@@ -113,7 +113,7 @@
|`start-of-year datetime`|Returns epoch time of start of year|`>>> (start-of-year (str-to-date "2021-05-13 10:32:12" "%Y-%m-%d %H:%M:%S")) => 1609459200`|Date and time| |`start-of-year datetime`|Returns epoch time of start of year|`>>> (start-of-year (str-to-date "2021-05-13 10:32:12" "%Y-%m-%d %H:%M:%S")) => 1609459200`|Date and time|
|`end-of-year datetime`|Returns epoch time of end of year|`>>> (end-of-year (str-to-date "2021-05-13 10:32:12" "%Y-%m-%d %H:%M:%S")) => 1640995199`|Date and time| |`end-of-year datetime`|Returns epoch time of end of year|`>>> (end-of-year (str-to-date "2021-05-13 10:32:12" "%Y-%m-%d %H:%M:%S")) => 1640995199`|Date and time|
|`decode-universal-time time`|Returns the decoded time represented by the given universal time. Returns list with (second, minute, hour, day, month, year, day-of-the-week)|`>>> (decode-universal-time 0) => (0 0 0 1 1 1970 4)`|Date and time| |`decode-universal-time time`|Returns the decoded time represented by the given universal time. Returns list with (second, minute, hour, day, month, year, day-of-the-week)|`>>> (decode-universal-time 0) => (0 0 0 1 1 1970 4)`|Date and time|
|`(debug ..)`|TODO add me|TODO add me|IO| |`(debug ..)`|Returns string representation of passed params|`>>> (debug '(1 2 3)) => "(1 2 3)"`|IO|
|`(display ..)`|Displays passed parameters|`>>> (display '(1 2 3)) => "(1 2 3)"`|IO| |`(display ..)`|Displays passed parameters|`>>> (display '(1 2 3)) => "(1 2 3)"`|IO|
|`(string-replace source substr replacement)`|Replace a substring with a replacement string in a source string|`>>> (string-replace "abcdefg" "de" "DE") => "abcDEfg"`|String manipulation| |`(string-replace source substr replacement)`|Replace a substring with a replacement string in a source string|`>>> (string-replace "abcdefg" "de" "DE") => "abcDEfg"`|String manipulation|
|`(string-replace-re source substr replacement)`|Replace a substring regex with a replacement string in a source string|`>>> (string-replace-re "there is a subsequence in the string" "\\b(sub)([^ ]*)" "sub-$2") => "there is a sub-sequence in the string"`|String manipulation| |`(string-replace-re source substr replacement)`|Replace a substring regex with a replacement string in a source string|`>>> (string-replace-re "there is a subsequence in the string" "\\b(sub)([^ ]*)" "sub-$2") => "there is a sub-sequence in the string"`|String manipulation|
@@ -177,4 +177,4 @@
|`(thread-sleep milisecons)`|Sleeps thread for given amount of miliseconds||Threading| |`(thread-sleep milisecons)`|Sleeps thread for given amount of miliseconds||Threading|
|`(threads-join)`|Wait for all running threads to finish||Threading| |`(threads-join)`|Wait for all running threads to finish||Threading|
|`(try block catch_block [finally_block])`|Evaluates block and if an exception is thrown, evaluates catch_block.Eventually in both cases evals finally_block. Return evaluated last expression from block if no exception or last expression from catch_block, if exception is thrown from block. Variable ml-exception in catch block is available with astring describing exception||Exceptions| |`(try block catch_block [finally_block])`|Evaluates block and if an exception is thrown, evaluates catch_block.Eventually in both cases evals finally_block. Return evaluated last expression from block if no exception or last expression from catch_block, if exception is thrown from block. Variable ml-exception in catch block is available with astring describing exception||Exceptions|
|`(throw-exception exp_desc)`|Throws an exception with exp_desc describing what happened ||Exceptions| |`(throw exp_desc)`|Throws an exception with exp_desc describing what happened. exp_desc will be evaluated a returned as string|`>>> (throw (+ 1 2))\n3`|Exceptions|

18
ml.cpp
View File

@@ -1239,7 +1239,6 @@ MlValue read_url(std::vector<MlValue> args, MlEnvironment &env) {
MlValue parse_json(std::vector<MlValue> args, MlEnvironment &env) { MlValue parse_json(std::vector<MlValue> args, MlEnvironment &env) {
eval_args(args, env); eval_args(args, env);
// TODO add support for more params specifying options
if (args.size() != 1) if (args.size() != 1)
throw MlError(MlValue("parse-json", parse_json), env, args.size() > 1 ? TOO_MANY_ARGS : TOO_FEW_ARGS); throw MlError(MlValue("parse-json", parse_json), env, args.size() > 1 ? TOO_MANY_ARGS : TOO_FEW_ARGS);
@@ -1247,10 +1246,9 @@ MlValue parse_json(std::vector<MlValue> args, MlEnvironment &env) {
std::string err; std::string err;
auto json = json11::Json::parse(str, err); auto json = json11::Json::parse(str, err);
if (!err.empty()) { if (!err.empty())
// TODO handle error
return MlValue::string("ERROR json parsing: " + err); return MlValue::string("ERROR json parsing: " + err);
}
return json.ivalualize(); return json.ivalualize();
} }
@@ -1973,9 +1971,10 @@ MlValue thread_create(std::vector<MlValue> args, MlEnvironment &env) {
MlValue acc = arg.eval(env); MlValue acc = arg.eval(env);
} catch (const MlError &e) { } catch (const MlError &e) {
std::cerr << "thread_create exception: " << e.description() << std::endl; std::cerr << "thread_create exception: " << e.description() << std::endl;
throw;
} catch (const std::exception &e) { } catch (const std::exception &e) {
std::cerr << "thread_create exception: " << e.what() << std::endl; std::cerr << "thread_create exception: " << e.what() << std::endl;
throw e; throw;
} }
}; };
@@ -2058,10 +2057,12 @@ MlValue try_block(std::vector<MlValue> args, MlEnvironment &env) {
} }
MlValue throw_exception(std::vector<MlValue> args, MlEnvironment &env) { MlValue throw_exception(std::vector<MlValue> args, MlEnvironment &env) {
eval_args(args, env);
if (args.size() != 1) if (args.size() != 1)
throw MlError(MlValue("throw", throw_exception), env, args.size() > 1 ? TOO_MANY_ARGS : TOO_FEW_ARGS); throw MlError(MlValue("throw", throw_exception), env, args.size() > 1 ? TOO_MANY_ARGS : TOO_FEW_ARGS);
throw std::runtime_error(args[0].as_string()); throw std::runtime_error(args[0].cast_to_string().as_string());
} }
MlValue usql(std::vector<MlValue> args, MlEnvironment &env) { MlValue usql(std::vector<MlValue> args, MlEnvironment &env) {
@@ -2356,10 +2357,10 @@ int main(int argc, char *argv[]) {
run(read_file_contents(file), env); run(read_file_contents(file), env);
// sheebang // sheebang
} else if (cmdOptionExists(argv, argv + argc, "-run")) { } else if (cmdOptionExists(argv, argv + argc, "-run")) {
for (auto & file : getCmdOption(argv, argc, "-run")) { // TODO check only one file is specified ?? for (auto & file : getCmdOption(argv, argc, "-run")) {
std::string file_content = read_file_contents(file); std::string file_content = read_file_contents(file);
if (file_content.find("#!") == 0) // shebang ? if (file_content.find("#!") == 0) // shebang ?
file_content.erase(0, file_content.find('\n') + 1); // TODO mac osx newline?? file_content.erase(0, file_content.find('\n') + 1);
run(file_content, env); run(file_content, env);
} }
@@ -2376,7 +2377,6 @@ int main(int argc, char *argv[]) {
std::cerr << e.description() << std::endl; std::cerr << e.description() << std::endl;
} catch (const std::exception &e) { } catch (const std::exception &e) {
std::cerr << MlPerfMon::instance().callstack() << e.what() << std::endl; std::cerr << MlPerfMon::instance().callstack() << e.what() << std::endl;
MlPerfMon::instance().clear_callstack();
} }
return 1; return 1;

View File

@@ -3,6 +3,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <filesystem>
const std::vector<std::string> commands { const std::vector<std::string> commands {
"eval", "type", "parse", "do", "if", "for", "while", "scope", "quote", "defn", "eval", "type", "parse", "do", "if", "for", "while", "scope", "quote", "defn",
@@ -17,12 +18,11 @@ const std::vector<std::string> commands {
}; };
std::string get_history_file_dir() { std::string get_history_file_dir() {
// TODO not portable and in function std::string filename{".ml_history.txt"};
std::string file{"/.ml_history.txt"};
const char *t = std::getenv("HOME"); const char *t = std::getenv("HOME");
if (t == nullptr) return "/tmp/" + file; if (t == nullptr) return std::filesystem::temp_directory_path() / filename;
else return std::string{t} + "/" + file; else return std::filesystem::path(std::string{t}) /filename;
} }
MlEnvironment * repl_env = nullptr; MlEnvironment * repl_env = nullptr;
@@ -68,7 +68,7 @@ void completion(const char *buf, linenoiseCompletions *lc) {
std::string token = str.substr(pos+1); std::string token = str.substr(pos+1);
std::string begining = str.substr(0, pos+1); std::string begining = str.substr(0, pos+1);
// TODO optimize not to get all lambdas, but those beginning with token // PERF optimize not to get all lambdas, but those beginning with token
std::vector<std::string> lambdas = repl_env->get_lambdas_list(); std::vector<std::string> lambdas = repl_env->get_lambdas_list();
lambdas.insert(end(lambdas), begin(commands), end(commands)); lambdas.insert(end(lambdas), begin(commands), end(commands));

View File

@@ -83,7 +83,8 @@
; return 1 when list contains item otherwise nil ; return 1 when list contains item otherwise nil
(defn member (lst itm) (defn member (lst itm)
(do (do
; TODO check if is empty list (if (list? lst)
(do
(def found_index -1) (def found_index -1)
(def i 0) (def i 0)
(def lst_len (len lst)) (def lst_len (len lst))
@@ -97,6 +98,8 @@
(if (!= -1 found_index) (if (!= -1 found_index)
#t #t
nil) nil)
)
nil)
)) ))
(defn make-list-of (size val) (defn make-list-of (size val)

View File

@@ -5,6 +5,17 @@ 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: " + (int)type);
};
Parser::Parser() { Parser::Parser() {
m_lexer = Lexer{}; m_lexer = Lexer{};
} }
@@ -529,4 +540,3 @@ namespace usql {
} }
} // namespace } // namespace

View File

@@ -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,19 +119,76 @@ 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
enum class Type {
to_string,
to_date,
date_add,
pp,
lower,
upper,
min,
max,
count
};
static Type get_function(const std::string &str) {
if (str=="to_string") return Type::to_string;
if (str=="to_date") return Type::to_date;
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=="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_string) return "to_string";
if (type == Type::to_date) return "to_date";
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::min) return "min";
if (type == Type::max) return "max";
if (type == Type::count) return "count";
throw Exception("invalid function: " + (int)type);
};
Type function;
std::vector<std::unique_ptr<Node>> params; std::vector<std::unique_ptr<Node>> params;
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;
} }
}; };
@@ -325,7 +386,12 @@ 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;
} }
}; };
@@ -338,7 +404,17 @@ 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;
} }
}; };
@@ -354,8 +430,22 @@ struct SelectFromTableNode : Node {
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;
} }
}; };
@@ -384,8 +474,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 +529,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;
} }
}; };

View File

@@ -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;

View File

@@ -8,6 +8,7 @@
#include <vector> #include <vector>
#include <mutex> #include <mutex>
namespace usql { namespace usql {
struct Table { struct Table {

View File

@@ -176,18 +176,17 @@ std::unique_ptr<ValueNode> USql::eval_function_value_node(Table *table, Row &row
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_string) return to_string_function(evaluatedPars);
if (fnc->function == "to_string") return to_string_function(evaluatedPars); if (fnc->function == FunctionNode::Type::date_add) return date_add_function(evaluatedPars);
if (fnc->function == "date_add") return date_add_function(evaluatedPars); if (fnc->function == FunctionNode::Type::pp) return pp_function(evaluatedPars);
if (fnc->function == "pp") return pp_function(evaluatedPars); if (fnc->function == FunctionNode::Type::count) return count_function(agg_func_value, evaluatedPars);
if (fnc->function == "count") return count_function(agg_func_value, evaluatedPars); if (fnc->function == FunctionNode::Type::max) return max_function(evaluatedPars, col_def_node, agg_func_value);
if (fnc->function == "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);
if (fnc->function == "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));
} }

View File

@@ -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());
if (func_node->function == "count" || func_node->function == "min" || func_node->function == "max")
aggregate_funcs++; 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;
@@ -229,20 +226,20 @@ 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_string) {
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_date) {
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::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::min || func_node->function == FunctionNode::Type::max) {
auto col_type= ColumnType::float_type; 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];
@@ -252,10 +249,10 @@ std::tuple<int, ColDefNode> USql::get_node_definition(Table *table, Node * node,
col_len = src_col_def.length; col_len = src_col_def.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");

View File

@@ -11,6 +11,7 @@ std::unique_ptr<ValueNode> USql::to_string_function(const std::vector<std::uniqu
long date = evaluatedPars[0]->getDateValue(); long date = evaluatedPars[0]->getDateValue();
std::string format = evaluatedPars[1]->getStringValue(); std::string format = evaluatedPars[1]->getStringValue();
std::string formatted_date = date_to_string(date, format); std::string formatted_date = date_to_string(date, format);
return std::make_unique<StringValueNode>(formatted_date); return std::make_unique<StringValueNode>(formatted_date);
} }
@@ -18,6 +19,7 @@ std::unique_ptr<ValueNode> USql::to_date_function(const std::vector<std::unique_
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,6 +29,7 @@ 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
} }
@@ -34,51 +37,57 @@ std::unique_ptr<ValueNode> USql::date_add_function(const std::vector<std::unique
std::unique_ptr<ValueNode> USql::upper_function(const std::vector<std::unique_ptr<ValueNode>> &evaluatedPars) { std::unique_ptr<ValueNode> USql::upper_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 toupper(c); }); std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) -> unsigned char { return toupper(c); });
return std::make_unique<StringValueNode>(str); 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::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());
} }