From 56996385209f71ce869dda85c5e1c183455f83f7 Mon Sep 17 00:00:00 2001 From: Bill Date: Tue, 9 Aug 2022 22:00:46 +0800 Subject: [PATCH] Multi-query support --- moving_avg.a | 4 +-- out.cpp | 60 +++++++++++++++++++++++++++++++--------- prompt.py | 11 ++++---- reconstruct/__init__.py | 2 +- reconstruct/ast.py | 46 +++++++++++++++++++++++------- reconstruct/storage.py | 36 ++++++++++++++++-------- server.exe | Bin 181760 -> 0 bytes server/server.cpp | 21 ++++++++++---- server/types.h | 7 +++-- server2.exp | Bin 815 -> 0 bytes server2.lib | Bin 2042 -> 0 bytes udf.hpp | 58 +++++++++++++++++++++++++++++++------- 12 files changed, 184 insertions(+), 61 deletions(-) delete mode 100644 server.exe delete mode 100644 server2.exp delete mode 100644 server2.lib diff --git a/moving_avg.a b/moving_avg.a index 1659cb7..0c87841 100644 --- a/moving_avg.a +++ b/moving_avg.a @@ -10,5 +10,5 @@ FROM sale INTO OUTFILE "moving_avg_output.csv" FIELDS TERMINATED BY ";" --- select Mont, mins(2,sales) from sale assuming desc Mont group by sales --- into outfile "flatten.csv" \ No newline at end of file +select Mont, mins(2,sales) from sale assuming desc Mont group by Mont +into outfile "flatten.csv" \ No newline at end of file diff --git a/out.cpp b/out.cpp index 28eb44b..1320768 100644 --- a/out.cpp +++ b/out.cpp @@ -1,19 +1,53 @@ #include "./server/libaquery.h" +#include #include "./server/monetdb_conn.h" +#include "./server/hasher.h" +#include "./server/aggregations.h" +__AQEXPORT__(int) dll_3V1c8v(Context* cxt) { + using namespace std; + using namespace types; + auto server = static_cast(cxt->alt_server); +auto len_5Bixfq = server->cnt; +auto mont_1Mz = ColRef(len_5Bixfq, server->getCol(0)); +auto sales_2DN = ColRef(len_5Bixfq, server->getCol(1)); +auto out_5Ffhnc = new TableInfo("out_5Ffhnc"); +out_5Ffhnc->get_col<0>().initfrom(mont_1Mz); +out_5Ffhnc->get_col<1>() = avgw(3, sales_2DN); +print(*out_5Ffhnc); +FILE* fp_57Mh6f = fopen("moving_avg_output.csv", "w"); +out_5Ffhnc->printall(";", "\n", nullptr, fp_57Mh6f); +fclose(fp_57Mh6f); +puts("done."); +return 0; +} +__AQEXPORT__(int) dll_frRsQ7(Context* cxt) { + using namespace std; + using namespace types; + auto server = static_cast(cxt->alt_server); +auto len_5JydG3 = server->cnt; +auto mont_34m = ColRef(len_5JydG3, server->getCol(0)); +auto sales_4wo = ColRef(len_5JydG3, server->getCol(1)); +auto out_4Fsh6O = new TableInfo>("out_4Fsh6O"); +decltype(auto) col_4A04Hh = out_4Fsh6O->get_col<0>(); +decltype(auto) col_1S5CS2 = out_4Fsh6O->get_col<1>(); +auto t4HUjxwQ = mont_34m; +typedef record> record_type5PGugsV; +unordered_map, transTypes> g6HIDqpq; +for (uint32_t ilq = 0; ilq < t4HUjxwQ.size; ++ilq){ +g6HIDqpq[forward_as_tuple(t4HUjxwQ[ilq])].emplace_back(ilq); +} +for (auto& i2M : g6HIDqpq) { +auto &key_5JcLJMV = i2M.first; +auto &val_yqDe0lt = i2M.second; +col_4A04Hh.emplace_back(get<0>(key_5JcLJMV)); + +col_1S5CS2.emplace_back(minw(2, sales_4wo[val_yqDe0lt])); - extern "C" int __DLLEXPORT__ dllmain(Context* cxt) { - using namespace std; - using namespace types; - auto server = static_cast(cxt->alt_server); - auto len_5sGusn = server->cnt; -auto sumc_5IN = ColRef<__int128_t>(len_5sGusn, server->getCol(0)); -auto b_79y = ColRef(len_5sGusn, server->getCol(1)); -auto d_4yS = ColRef(len_5sGusn, server->getCol(2)); -auto out_kio0QJ = new TableInfo<__int128_t,int,int>("out_kio0QJ"); -out_kio0QJ->get_col<0>().initfrom(sumc_5IN); -out_kio0QJ->get_col<1>().initfrom(b_79y); -out_kio0QJ->get_col<2>().initfrom(d_4yS); -print(*out_kio0QJ); +} +print(*out_4Fsh6O); +FILE* fp_6UC6Yg = fopen("flatten.csv", "w"); +out_4Fsh6O->printall(",", "\n", nullptr, fp_6UC6Yg); +fclose(fp_6UC6Yg); puts("done."); return 0; } \ No newline at end of file diff --git a/prompt.py b/prompt.py index e17c71f..8d7a03b 100644 --- a/prompt.py +++ b/prompt.py @@ -227,8 +227,8 @@ while test_parser: cxt = xengine.exec(stmts, cxt, keep) if server_mode == RunType.Threaded: # assignment to avoid auto gc - sqls = [s.strip() for s in cxt.sql.split(';')] - qs = [ctypes.c_char_p(bytes(q, 'utf-8')) for q in sqls if len(q)] + # sqls = [s.strip() for s in cxt.sql.split(';')] + qs = [ctypes.c_char_p(bytes(q, 'utf-8')) for q in cxt.queries if len(q)] sz = len(qs) payload = (ctypes.c_char_p*sz)(*qs) try: @@ -282,17 +282,18 @@ while test_parser: tm = time.gmtime() fname = f'{tm.tm_year}{tm.tm_mon}_{tm.tm_mday}_{tm.tm_hour}:{tm.tm_min}:{tm.tm_sec}' if cxt: - def savefile(attr:str, desc:str): + from typing import Optional + def savefile(attr:str, desc:str, ext:Optional[str] = None): if hasattr(cxt, attr): attr : str = getattr(cxt, attr) if attr: - ext = '.' + desc + ext = ext if ext else '.' + desc name = fname if fname.endswith(ext) else fname + ext with open('saves/' + name, 'wb') as cfile: cfile.write(attr.encode('utf-8')) print(f'saved {desc} code as {name}') savefile('ccode', 'cpp') - savefile('udf', 'udf') + savefile('udf', 'udf', '.hpp') savefile('sql', 'sql') continue diff --git a/reconstruct/__init__.py b/reconstruct/__init__.py index c3b1c2c..475e503 100644 --- a/reconstruct/__init__.py +++ b/reconstruct/__init__.py @@ -25,7 +25,7 @@ def exec(stmts, cxt = None, keep = False): generate(s, cxt) else: generate(stmts_stmts, cxt) - cxt.print(cxt.sql) + cxt.print(cxt.queries) return cxt __all__ = ["initialize", "generate", "exec", "saved_cxt"] diff --git a/reconstruct/ast.py b/reconstruct/ast.py index 5c04d14..5b248e6 100644 --- a/reconstruct/ast.py +++ b/reconstruct/ast.py @@ -35,7 +35,10 @@ class ast_node: name = 'null' def init(self, _): + if self.parent is None: + self.context.sql_begin() self.add(self.__class__.name.upper()) + def produce(self, _): pass def spawn(self, _): @@ -44,7 +47,7 @@ class ast_node: def consume(self, _): if self.parent is None: self.emit(self.sql+';\n') - + self.context.sql_end() from reconstruct.expr import expr, fastscan @@ -54,11 +57,17 @@ class projection(ast_node): first_order = 'select' def init(self, _): + # skip default init pass + def produce(self, node): p = node['select'] self.projections = p if type(p) is list else [p] self.add('SELECT') + if self.parent is None: + self.context.sql_begin() + self.postproc_fname = 'dll_' + base62uuid(6) + self.context.postproc_begin(self.postproc_fname) def spawn(self, node): self.datasource = None # datasource is Join instead of TableInfo @@ -245,6 +254,11 @@ class projection(ast_node): self.outfile.finalize() self.context.emitc(f'puts("done.");') + if self.parent is None: + self.context.sql_end() + self.context.postproc_end(self.postproc_fname) + + class orderby(ast_node): name = 'order by' def produce(self, node): @@ -314,15 +328,16 @@ class scan(ast_node): class groupby_c(ast_node): name = '_groupby' - def init(self, _): + def init(self, node : List[Tuple[expr, Set[ColRef]]]): self.proj : projection = self.parent - return super().init(_) + self.glist : List[Tuple[expr, Set[ColRef]]] = node + return super().init(node) def produce(self, node : List[Tuple[expr, Set[ColRef]]]): self.context.headers.add('"./server/hasher.h"') self.context.headers.add('unordered_map') self.group = 'g' + base62uuid(7) self.group_type = 'record_type' + base62uuid(7) - self.datasource = self.parent.datasource + self.datasource = self.proj.datasource self.scanner = None self.datasource.rec = set() @@ -330,7 +345,7 @@ class groupby_c(ast_node): g_contents_list = [] first_col = '' - for g in node: + for g in self.glist: e = expr(self, g[0].node, c_code=True) g_str = e.eval(c_code = True, y = lambda c: self.proj.pyname2cname[c]) # if v is compound expr, create tmp cols @@ -345,7 +360,7 @@ class groupby_c(ast_node): self.context.emitc(f'typedef record<{",".join(g_contents_decltype)}> {self.group_type};') self.context.emitc(f'unordered_map<{self.group_type}, vector_type, ' f'transTypes<{self.group_type}, hasher>> {self.group};') - self.n_grps = len(node) + self.n_grps = len(self.glist) self.scanner = scan(self, first_col + '.size') self.scanner.add(f'{self.group}[forward_as_tuple({g_contents}[{self.scanner.it_ver}])].emplace_back({self.scanner.it_ver});') @@ -372,9 +387,15 @@ class groupby_c(ast_node): if len_var is None: len_var = 'len_'+base62uuid(7) gscanner.add(f'auto &{len_var} = {val_var}.size;', position = 'front') - + + def get_key_idx (varname : str): + for i, g in enumerate(self.glist): + if varname == g[0].eval(): + return i + return var_table[varname] + def get_var_names (varname : str): - var = var_table[varname] + var = get_key_idx(varname) if type(var) is str: return f'{var}[{val_var}]' else: @@ -545,6 +566,8 @@ class create_table(ast_node): name = 'create_table' first_order = name def init(self, node): + if self.parent is None: + self.context.sql_begin() self.sql = 'CREATE TABLE ' def produce(self, node): @@ -558,10 +581,11 @@ class create_table(ast_node): self.sql += ')' if self.context.use_columnstore: self.sql += ' engine=ColumnStore' - + class insert(ast_node): name = 'insert' first_order = name + def produce(self, node): values = node['query']['select'] tbl = node['insert'] @@ -586,6 +610,8 @@ class load(ast_node): self.produce = self.produce_monetdb else: self.produce = self.produce_aq + if self.parent is None: + self.context.sql_begin() def produce_aq(self, node): node = node['load'] @@ -916,4 +942,4 @@ def include(objs): import sys -include(sys.modules[__name__]) \ No newline at end of file +include(sys.modules[__name__]) diff --git a/reconstruct/storage.py b/reconstruct/storage.py index dde8773..2c93f9e 100644 --- a/reconstruct/storage.py +++ b/reconstruct/storage.py @@ -87,7 +87,9 @@ class Context: self.finalized = False self.udf = None self.scans = [] - + self.procs = [] + self.queries = [] + def __init__(self): self.tables_byname = dict() self.col_byname = dict() @@ -101,11 +103,9 @@ class Context: self.has_dll = False self.dialect = 'MonetDB' self.have_hge = False + self.Error = lambda *args: print(*args) self.Info = lambda *_: None - self.Info = lambda *_: None - self.new() - def emit(self, sql:str): self.sql += sql + ' ' def emitc(self, c:str): @@ -118,17 +118,31 @@ class Context: self.emitc(str_scan) self.scans.remove(scan) - function_head = ''' - extern "C" int __DLLEXPORT__ dllmain(Context* cxt) { - using namespace std; - using namespace types; - auto server = static_cast(cxt->alt_server); - ''' + function_deco = '__AQEXPORT__(int) ' + function_head = ('(Context* cxt) {\n' + + '\tusing namespace std;\n' + + '\tusing namespace types;\n' + + '\tauto server = static_cast(cxt->alt_server);\n') + udf_head = ('#pragma once\n' '#include \"./server/libaquery.h\"\n' '#include \"./server/aggregations.h\"\n\n' ) + def sql_begin(self): + self.sql = '' + + def sql_end(self): + self.queries.append('Q' + self.sql) + self.sql = '' + def postproc_begin(self, proc_name: str): + self.ccode = self.function_deco + proc_name + self.function_head + + def postproc_end(self, proc_name: str): + self.procs.append(self.ccode + 'return 0;\n}') + self.ccode = '' + self.queries.append('P' + proc_name) + def finalize(self): if not self.finalized: headers = '' @@ -137,6 +151,6 @@ class Context: headers += '#include <' + h + '>\n' else: headers += '#include ' + h + '\n' - self.ccode = headers + self.function_head + self.ccode + 'return 0;\n}' + self.ccode = headers + '\n'.join(self.procs) self.headers = set() return self.ccode \ No newline at end of file diff --git a/server.exe b/server.exe deleted file mode 100644 index 8658fd983cbd8a2980f879e73433943bceb1e355..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 181760 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 if (cfg->new_query) { - + void *handle = 0; if (cfg->backend_type == BACKEND_MonetDB){ if (cxt->alt_server == 0) cxt->alt_server = new Server(cxt); Server* server = reinterpret_cast(cxt->alt_server); if(n_recv > 0){ + if (cfg->backend_type == BACKEND_AQuery || cfg->has_dll) { + handle = dlopen("./dll.so", RTLD_LAZY); + } for(int i = 0; i < n_recv; ++i) { - server->exec(n_recvd[i]); - printf("Exec Q%d: %s\n", i, n_recvd[i]); + if (n_recvd[i][0] == 'Q'){ + server->exec(n_recvd[i] + 1); + printf("Exec Q%d: %s\n", i, n_recvd[i]); + } + else if (n_recvd[i][0] == 'P' && handle) { + code_snippet c = reinterpret_cast(dlsym(handle, n_recvd[i]+1)); + c(cxt); + } } n_recv = 0; } @@ -108,12 +117,12 @@ int dll_main(int argc, char** argv, Context* cxt){ } // puts(cfg->has_dll ? "true" : "false"); - if (cfg->backend_type == BACKEND_AQuery || cfg->has_dll) { - void* handle = dlopen("./dll.so", RTLD_LAZY); + if (cfg->backend_type == BACKEND_AQuery) { + handle = dlopen("./dll.so", RTLD_LAZY); code_snippet c = reinterpret_cast(dlsym(handle, "dllmain")); c(cxt); - dlclose(handle); } + if (handle) dlclose(handle); cfg->new_query = 0; } std::this_thread::sleep_for(std::chrono::milliseconds(100)); diff --git a/server/types.h b/server/types.h index 5c55030..0f5bb97 100644 --- a/server/types.h +++ b/server/types.h @@ -220,12 +220,13 @@ constexpr size_t sum_type(size_t a[], size_t sz) { ret += a[i]; return ret; } -template constexpr size_t sum_type() { +template +constexpr size_t sum_type() { size_t t[] = {std::is_same_v ...}; return sum_type(t, sizeof...(T1)); } -template constexpr -size_t count_type(std::tuple* ts) { +template +constexpr size_t count_type(std::tuple* ts) { size_t t[] = {sum_type() ...}; return sum_type(t, sizeof...(Types)); } diff --git a/server2.exp b/server2.exp deleted file mode 100644 index d6bdad4751a5f0617cdae89c1b814665f03adec3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 815 zcmaJVv(?8gkJkc^4vqcyTg0w)A@DTozQlF4L zJa#Brw^8{trRf!*k;^KRJu2)n;%{Utyv0gAsRpzg2YUPn?l zhVmt6>&+U zZAAWiOZWc^^bG$@xgyf|gksdE3T+qX(DM&3Xj`T=dU_x_jN3{kvNI^HpKO#4emD2& zf_943z6&Yb@}tQAetav`eWgNTB$b}UR!qib{yioIi8zEUPlB2yIL(k zCc{kL5;M`s`@sDzN*)XIdNvon?E*1%5W-7F<((lsx>9dfAPwMvH$=8 diff --git a/server2.lib b/server2.lib deleted file mode 100644 index cd028f3384ed436dcb97752dfc98554a27d0c8c8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2042 zcmcIly>HV%6#vEff(W6IA^`)ED=Gm4A$6RJR0z3HB%-Eil%}l4P2AQ)KID{0bYbgM zG2|a$VdEb_Oc5|u3?P+_p#%Q_J8F4n-^I4l(4;CS-Mx={zW3hm-aAh}H0;{eqr`nV zIPT2`Wg%raGn=2|+=~Q&i-42@BJ)7B4a9ryjO_z##uYYoy|7$fsZ{mFr>jpYg>rSJ zqIXQYYuXBQy|h*=4jbS#w{Z8X&(=yy`r<-$fxfUBZQV9&rqwld!`|#5Ah`SMR@1Ow z=~i>21wZfZHVmr?XPGpACFA8EBLGqoFdqThQJ@zG_DQJ_C14POgeYQ&@HI@ap8<*C zgnUW3Yybd%x=xOP-I2I*ywjbQi^*w~pyri9CDeDrIC|6lkq7}7D04Q_b#wjY=FF-q z0U9xTLf}+G@^RX#8{5VVRf;>V68TE=&=nCTsv*@0cT&q%&2DvC8{6`o%3ZlwC@t~*0AapZ9BfjxJ6w`hx^&Wc zPAGy}tI?)V`#Yh~@v;94G6joGg2-3{oM^X%#>vg~!);V%Lmy#alk+r8FSCUYb~=#f z5+f2Sw4SNz&aF-qHSenv3AYYDe)-_U#v(kqPU`N~VD;5WRw!AWyb}VatWN&N{f~32 zHz|gZubHn9$LlWTLC%L-7*l(_-#^KNd&eiE_K)t$37}YavhMN^4VvgKRp^=Bfe<)l zcIS=mxX6wy$BB_uvm98N{lQp|)_32RtxwmSEF*!xg|D+G_LCJq3ZI|nneU(3yAh%{ h#Ce*14m@_e3Q^VJJbvAH`{z2HFVXpdSKm7ve*vrkkzN1* diff --git a/udf.hpp b/udf.hpp index a6d25af..271299d 100644 --- a/udf.hpp +++ b/udf.hpp @@ -2,17 +2,55 @@ #include "./server/libaquery.h" #include "./server/aggregations.h" -auto covariance = [](auto x, auto y) { - auto xmean = avg(x); - auto ymean = avg(y); - return avg(((x - xmean) * (y - ymean))); +auto covariances2 = [](auto x, auto y, auto w, uint32_t _builtin_len, auto& _builtin_ret) { + auto xmeans = 0.0; + auto ymeans = 0.0; + auto l = _builtin_len; + if((l > 0)) { + xmeans = x[0]; + ymeans = y[0]; + _builtin_ret[0] = 0.0; + } + if((w > l)) + w = l; + for(auto i = 1, j = 0; (i < w); i = (i + 1)) { + xmeans += x[i]; + ymeans += y[i]; + _builtin_ret[i] = avg(((x.subvec(0, i) - (xmeans / i)) * (y.subvec(0, i) - (ymeans / i)))); + } + xmeans /= w; + ymeans /= w; + for(auto i = w; (i < l); i += 1) { + xmeans += ((x[i] - x[(i - w)]) / w); + ymeans += ((y[i] - y[(i - w)]) / w); + _builtin_ret[i] = avg(((x.subvec((i - w), i) - xmeans) * (y.subvec((i - w), i) - ymeans))); + } + return ; }; -auto sd = [](auto x) { - return sqrt(covariance(x, x)); -}; - -auto paircorr = [](auto x, auto y) { - return (covariance(x, y) / (sd(x) * sd(y))); +auto covariances2_gettype = [](auto x, auto y, auto w) { + uint32_t _builtin_len = 0; + auto xmeans = 0.0; + auto ymeans = 0.0; + auto l = _builtin_len; + if((l > 0)) { + xmeans = x[0]; + ymeans = y[0]; + return 0.0; + } + if((w > l)) + w = l; + for(auto i = 1, j = 0; (i < w); i = (i + 1)) { + xmeans += x[i]; + ymeans += y[i]; + return avg(((x.subvec(0, i) - (xmeans / i)) * (y.subvec(0, i) - (ymeans / i)))); + } + xmeans /= w; + ymeans /= w; + for(auto i = w; (i < l); i += 1) { + xmeans += ((x[i] - x[(i - w)]) / w); + ymeans += ((y[i] - y[(i - w)]) / w); + return avg(((x.subvec((i - w), i) - xmeans) * (y.subvec((i - w), i) - ymeans))); + } };