dev
Bill Sun 3 years ago
parent 634ed382f5
commit 824db2a43b

@ -7,6 +7,8 @@ $(info $(OS_SUPPORT))
server.bin: server.bin:
g++ server/server.cpp $(OS_SUPPORT) --std=c++1z -O3 -march=native -o server.bin g++ server/server.cpp $(OS_SUPPORT) --std=c++1z -O3 -march=native -o server.bin
server.so:
g++ server/server.cpp -shared $(OS_SUPPORT) --std=c++1z -O3 -march=native -o server.so
snippet: snippet:
g++ -shared -fPIC --std=c++1z out.cpp -O3 -march=native -o dll.so g++ -shared -fPIC --std=c++1z out.cpp -O3 -march=native -o dll.so
clean: clean:

@ -41,4 +41,4 @@ Recent version of Linux, Windows or MacOS, with recent C++ compiler that has C++
- `exit`: quit the prompt - `exit`: quit the prompt
#### Example: #### Example:
`f moving_avg.a` <br> `f moving_avg.a` <br>
`exec` `exec`

@ -1,45 +1,45 @@
import mariadb import mariadb
class dbconn: class dbconn:
def __init__(self) -> None: def __init__(self) -> None:
self.db = None self.db = None
self.cur = None self.cur = None
def clear(self): def clear(self):
drop_all = f''' drop_all = f'''
SET FOREIGN_KEY_CHECKS = 0; SET FOREIGN_KEY_CHECKS = 0;
SET @tables = NULL; SET @tables = NULL;
SELECT GROUP_CONCAT('`', table_schema, '`.`', table_name, '`') INTO @tables SELECT GROUP_CONCAT('`', table_schema, '`.`', table_name, '`') INTO @tables
FROM information_schema.tables FROM information_schema.tables
WHERE table_schema = '{self.db.database}'; WHERE table_schema = '{self.db.database}';
SET @tables = CONCAT('DROP TABLE ', @tables); SET @tables = CONCAT('DROP TABLE ', @tables);
PREPARE stmt FROM @tables; PREPARE stmt FROM @tables;
EXECUTE stmt; EXECUTE stmt;
DEALLOCATE PREPARE stmt; DEALLOCATE PREPARE stmt;
SET FOREIGN_KEY_CHECKS = 1; SET FOREIGN_KEY_CHECKS = 1;
''' '''
if self.db: if self.db:
if not self.cur: if not self.cur:
self.cur = self.db.cursor() self.cur = self.db.cursor()
self.cur.execute(drop_all) self.cur.execute(drop_all)
def connect(self, ip, password = '0508', user = 'root', db = 'db', port = 3306): def connect(self, ip, password = '0508', user = 'root', db = 'db', port = 3306):
try: try:
self.db = mariadb.connect( self.db = mariadb.connect(
user = user, user = user,
password = password, password = password,
host = ip, host = ip,
port = port, port = port,
database = db database = db
) )
self.cur = self.db.cursor() self.cur = self.db.cursor()
except mariadb.Error as e: except mariadb.Error as e:
print(e) print(e)
self.db = None self.db = None
self.cur = None self.cur = None
def exec(self, sql, params = None): def exec(self, sql, params = None):
self.cur.execute(sql) self.cur.execute(sql)

@ -1,6 +1,6 @@
#include "./server/libaquery.h"
#include "./server/aggregations.h" #include "./server/aggregations.h"
#include "csv.h" #include "csv.h"
#include "./server/libaquery.h"
#include "./server/hasher.h" #include "./server/hasher.h"
#include <unordered_map> #include <unordered_map>
@ -18,40 +18,40 @@ test_a.init("a");
test_b.init("b"); test_b.init("b");
test_c.init("c"); test_c.init("c");
test_d.init("d"); test_d.init("d");
io::CSVReader<4> csv_reader_307VD4("test.csv"); io::CSVReader<4> csv_reader_1qh80y("test.csv");
csv_reader_307VD4.read_header(io::ignore_extra_column, "a","b","c","d"); csv_reader_1qh80y.read_header(io::ignore_extra_column, "a","b","c","d");
int tmp_3LXIYQmp; int tmp_6JfuovoZ;
int tmp_1m5NCKR4; int tmp_4B4ADRgW;
int tmp_10LZcLgy; int tmp_3JHd3elW;
int tmp_39pPZL8W; int tmp_1heR8kZw;
while(csv_reader_307VD4.read_row(tmp_3LXIYQmp,tmp_1m5NCKR4,tmp_10LZcLgy,tmp_39pPZL8W)) { while(csv_reader_1qh80y.read_row(tmp_6JfuovoZ,tmp_4B4ADRgW,tmp_3JHd3elW,tmp_1heR8kZw)) {
test_a.emplace_back(tmp_3LXIYQmp); test_a.emplace_back(tmp_6JfuovoZ);
test_b.emplace_back(tmp_1m5NCKR4); test_b.emplace_back(tmp_4B4ADRgW);
test_c.emplace_back(tmp_10LZcLgy); test_c.emplace_back(tmp_3JHd3elW);
test_d.emplace_back(tmp_39pPZL8W); test_d.emplace_back(tmp_1heR8kZw);
} }
typedef record<decltype(test_a[0]),decltype(test_b[0]),decltype(test_d[0])> record_type3OMslKw; typedef record<decltype(test_a[0]),decltype(test_b[0]),decltype(test_d[0])> record_type3he5qd1;
unordered_map<record_type3OMslKw, vector_type<uint32_t>, transTypes<record_type3OMslKw, hasher>> g7LNVAss; unordered_map<record_type3he5qd1, vector_type<uint32_t>, transTypes<record_type3he5qd1, hasher>> g59vWI2v;
for (uint32_t i1T = 0; i1T < test_a.size; ++i1T){ for (uint32_t i3P = 0; i3P < test_a.size; ++i3P){
g7LNVAss[forward_as_tuple(test_a[i1T],test_b[i1T],test_d[i1T])].emplace_back(i1T); g59vWI2v[forward_as_tuple(test_a[i3P],test_b[i3P],test_d[i3P])].emplace_back(i3P);
} }
auto out_HSfK = new TableInfo<decays<decltype(sum(test_c))>,value_type<decays<decltype(test_b)>>,value_type<decays<decltype(test_d)>>>("out_HSfK", 3); auto out_6JAp = new TableInfo<decays<decltype(sum(test_c))>,value_type<decays<decltype(test_b)>>,value_type<decays<decltype(test_d)>>>("out_6JAp", 3);
cxt->tables.insert({"out_HSfK", out_HSfK}); cxt->tables.insert({"out_6JAp", out_6JAp});
auto& out_HSfK_sumtestc = *(ColRef<decays<decltype(sum(test_c))>> *)(&out_HSfK->colrefs[0]); auto& out_6JAp_sumtestc = *(ColRef<decays<decltype(sum(test_c))>> *)(&out_6JAp->colrefs[0]);
auto& out_HSfK_b = *(ColRef<value_type<decays<decltype(test_b)>>> *)(&out_HSfK->colrefs[1]); auto& out_6JAp_b = *(ColRef<value_type<decays<decltype(test_b)>>> *)(&out_6JAp->colrefs[1]);
auto& out_HSfK_d = *(ColRef<value_type<decays<decltype(test_d)>>> *)(&out_HSfK->colrefs[2]); auto& out_6JAp_d = *(ColRef<value_type<decays<decltype(test_d)>>> *)(&out_6JAp->colrefs[2]);
out_HSfK_sumtestc.init("sumtestc"); out_6JAp_sumtestc.init("sumtestc");
out_HSfK_b.init("b"); out_6JAp_b.init("b");
out_HSfK_d.init("d"); out_6JAp_d.init("d");
for(auto& i18 : g7LNVAss) { for(auto& i2Y : g59vWI2v) {
auto &key_3s5slnK = i18.first; auto &key_1yBYhdd = i2Y.first;
auto &val_2nNLv0D = i18.second; auto &val_61QXy6G = i2Y.second;
out_HSfK_sumtestc.emplace_back(sum(test_c[val_2nNLv0D])); out_6JAp_sumtestc.emplace_back(sum(test_c[val_61QXy6G]));
out_HSfK_b.emplace_back(get<1>(key_3s5slnK)); out_6JAp_b.emplace_back(get<1>(key_1yBYhdd));
out_HSfK_d.emplace_back(get<2>(key_3s5slnK)); out_6JAp_d.emplace_back(get<2>(key_1yBYhdd));
} }
auto d5b7C95U = out_HSfK->order_by_view<-3,1>(); auto d1dyPtv0 = out_6JAp->order_by_view<-3,1>();
print(d5b7C95U); print(d1dyPtv0);
return 0; return 0;
} }

@ -1,3 +1,4 @@
import enum
import re import re
import time import time
import dbconn import dbconn
@ -12,14 +13,26 @@ import sys
import os import os
from engine.utils import base62uuid from engine.utils import base62uuid
import atexit import atexit
import threading
import ctypes
class RunType(enum.Enum):
Threaded = 0
IPC = 1
server_mode = RunType.Threaded
server_bin = 'server.bin' if server_mode == RunType.IPC else 'server.so'
try: try:
os.remove('server.bin') os.remove(server_bin)
except Exception as e: except Exception as e:
print(type(e), e) print(type(e), e)
nullstream = open(os.devnull, 'w') nullstream = open(os.devnull, 'w')
subprocess.call(['make', 'server.bin'], stdout=nullstream) subprocess.call(['make', server_bin], stdout=nullstream)
cleanup = True cleanup = True
def rm(): def rm():
@ -44,10 +57,8 @@ def rm():
mm.close() mm.close()
cleanup = False cleanup = False
nullstream.close() nullstream.close()
atexit.register(rm)
def init(): def init_ipc():
global shm, server, basecmd, mm global shm, server, basecmd, mm
shm = base62uuid() shm = base62uuid()
if sys.platform != 'win32': if sys.platform != 'win32':
@ -70,6 +81,100 @@ def init():
mm.flush() mm.flush()
server = subprocess.Popen(["./server.bin", shm]) server = subprocess.Popen(["./server.bin", shm])
import numpy as np
c = lambda _ba: ctypes.cast((ctypes.c_char * len(_ba)).from_buffer(_ba), ctypes.c_char_p)
class Config:
def __init__(self, nq = 0, mode = server_mode, n_bufs = 0, bf_szs = []) -> None:
self.int_size = 4
self.n_attrib = 4
self.buf = bytearray((self.n_attrib + n_bufs) * self.int_size)
self.np_buf = np.ndarray(shape=(self.n_attrib), buffer=self.buf, dtype=np.int32)
self.new_query = nq
self.server_mode = mode.value
self.running = 1
self.n_buffers = n_bufs
@property
def running(self):
return self.np_buf[0]
@running.setter
def running(self, rn):
self.np_buf[0] = rn
@property
def new_query(self):
return self.np_buf[1]
@new_query.setter
def new_query(self, nq):
self.np_buf[1] = nq
@property
def server_mode(self):
return self.np_buf[2]
@server_mode.setter
def server_mode(self, mode):
self.np_buf[2] = mode
@property
def n_buffers(self):
return self.np_buf[3]
@n_buffers.setter
def n_buffers(self, n_bufs):
self.np_buf[3] = n_bufs
def set_bufszs(self, buf_szs):
for i in range(min(len(buf_szs), self.n_buffers)):
self.np_buf[i+self.n_attrib] = buf_szs[i]
@property
def c(self):
return c(self.buf)
cfg = Config()
th = None
def init_threaded():
if os.name == 'nt':
t = os.environ['PATH'].lower().split(';')
vars = re.compile('%.*%')
for e in t:
if(len(e) != 0):
if '%' in e:
try:
m_e = vars.findall(e)
for m in m_e:
e = e.replace(m, os.environ[m[1:-1]])
# print(m, e)
except Exception:
continue
os.add_dll_directory(e)
server_so = ctypes.CDLL('./'+server_bin)
global cfg, th
th = threading.Thread(target=server_so['main'], args=(-1, ctypes.POINTER(ctypes.c_char_p)(cfg.c)), daemon=True)
th.start()
if server_mode == RunType.IPC:
atexit.register(rm)
init = init_ipc
set_ready = lambda : mm.seek(0,os.SEEK_SET) or mm.write(b'\x01\x01')
def __get_ready():
mm.seek(0,os.SEEK_SET)
return mm.read(2)[1]
get_ready = __get_ready
server_status = lambda : server.poll() is not None
else:
init = init_threaded
rm = lambda: None
def __set_ready():
global cfg
cfg.new_query = 1
set_ready = __set_ready
get_ready = lambda:cfg.new_query
server_status = lambda : not th.is_alive()
init() init()
test_parser = True test_parser = True
@ -82,31 +187,16 @@ q = 'SELECT p.Name, v.Name FROM Production.Product p JOIN Purchasing.ProductVend
res = parser.parse(q) res = parser.parse(q)
# else:f
# if subprocess.call(['make', 'snippet']) == 0:
# mm.seek(0)
# mm.write(b'\x01\x01')
# time.sleep(.1)
# mm.seek(0)
# print(mm.read(2))
# mm.close()
# handle.close()
# os.remove(shm)
# exit()
keep = True keep = True
cxt = engine.initialize() cxt = engine.initialize()
cxt.Info(res) cxt.Info(res)
while test_parser: while test_parser:
try: try:
if server.poll() is not None: if server_status():
init() init()
print("> ", end="") while get_ready():
ready = 1
while ready == 1:
mm.seek(0,os.SEEK_SET)
ready = mm.read(2)[1]
time.sleep(.00001) time.sleep(.00001)
print("> ", end="")
q = input().lower() q = input().lower()
if q == 'exec': if q == 'exec':
if not keep or cxt is None: if not keep or cxt is None:
@ -123,8 +213,7 @@ while test_parser:
with open('out.cpp', 'wb') as outfile: with open('out.cpp', 'wb') as outfile:
outfile.write((cxt.finalize()).encode('utf-8')) outfile.write((cxt.finalize()).encode('utf-8'))
if subprocess.call(['make', 'snippet'], stdout = nullstream) == 0: if subprocess.call(['make', 'snippet'], stdout = nullstream) == 0:
mm.seek(0,os.SEEK_SET) set_ready()
mm.write(b'\x01\x01')
continue continue
if q == 'xexec': if q == 'xexec':
cxt = xengine.initialize() cxt = xengine.initialize()
@ -159,8 +248,10 @@ while test_parser:
break break
elif q == 'r': elif q == 'r':
if subprocess.call(['make', 'snippet']) == 0: if subprocess.call(['make', 'snippet']) == 0:
mm.seek(0,os.SEEK_SET) set_ready()
mm.write(b'\x01\x01') continue
elif q == 'rr':
set_ready()
continue continue
elif q.startswith('save'): elif q.startswith('save'):
filename = re.split(' |\t', q) filename = re.split(' |\t', q)

@ -1,11 +1,11 @@
from reconstruct.ast import Context, ast_node from reconstruct.ast import Context, ast_node
def initialize(): def initialize():
return Context() return Context()
def generate(ast, cxt): def generate(ast, cxt):
for k in ast.keys(): for k in ast.keys():
if k in ast_node.types.keys(): if k in ast_node.types.keys():
ast_node.types[k](None, ast, cxt) ast_node.types[k](None, ast, cxt)
__all__ = ["initialize", "generate"] __all__ = ["initialize", "generate"]

@ -1,303 +1,303 @@
from engine.utils import enlist, base62uuid, base62alp from engine.utils import enlist, base62uuid, base62alp
from reconstruct.storage import Context, TableInfo, ColRef from reconstruct.storage import Context, TableInfo, ColRef
class ast_node: class ast_node:
header = [] header = []
types = dict() types = dict()
first_order = False first_order = False
def __init__(self, parent:"ast_node", node, context:Context = None): def __init__(self, parent:"ast_node", node, context:Context = None):
self.context = parent.context if context is None else context self.context = parent.context if context is None else context
self.parent = parent self.parent = parent
self.sql = '' self.sql = ''
self.datasource = None self.datasource = None
self.init(node) self.init(node)
self.produce(node) self.produce(node)
self.spawn(node) self.spawn(node)
self.consume(node) self.consume(node)
def emit(self, code): def emit(self, code):
self.context.emit(code) self.context.emit(code)
def add(self, code): def add(self, code):
self.sql += code + ' ' self.sql += code + ' '
name = 'null' name = 'null'
def init(self, _): def init(self, _):
self.add(self.__class__.name.upper()) self.add(self.__class__.name.upper())
def produce(self, _): def produce(self, _):
pass pass
def spawn(self, _): def spawn(self, _):
pass pass
def consume(self, _): def consume(self, _):
if self.parent is None: if self.parent is None:
self.emit(self.sql+';\n') self.emit(self.sql+';\n')
from reconstruct.expr import expr from reconstruct.expr import expr
class projection(ast_node): class projection(ast_node):
name = 'projection' name = 'projection'
first_order = 'select' first_order = 'select'
def init(self, _): def init(self, _):
pass pass
def produce(self, node): def produce(self, node):
p = node['select'] p = node['select']
self.projections = p if type(p) is list else [p] self.projections = p if type(p) is list else [p]
self.add('SELECT') self.add('SELECT')
def spawn(self, node): def spawn(self, node):
self.datasource = None # datasource is Join instead of TableInfo self.datasource = None # datasource is Join instead of TableInfo
if 'from' in node: if 'from' in node:
from_clause = node['from'] from_clause = node['from']
self.datasource = join(self, from_clause) self.datasource = join(self, from_clause)
if 'assumptions' in from_clause: if 'assumptions' in from_clause:
self.assumptions = enlist(from_clause['assumptions']) self.assumptions = enlist(from_clause['assumptions'])
if self.datasource is not None: if self.datasource is not None:
self.datasource_changed = True self.datasource_changed = True
self.prev_datasource = self.context.datasource self.prev_datasource = self.context.datasource
self.context.datasource = self.datasource self.context.datasource = self.datasource
if 'where' in node: if 'where' in node:
self.where = filter(self, node['where']) self.where = filter(self, node['where'])
else: else:
self.where = None self.where = None
if 'groupby' in node: if 'groupby' in node:
self.group_node = groupby(self, node['groupby']) self.group_node = groupby(self, node['groupby'])
else: else:
self.group_node = None self.group_node = None
def consume(self, node): def consume(self, node):
# deal with projections # deal with projections
self.out_table = TableInfo('out_'+base62uuid(4), [], self.context) self.out_table = TableInfo('out_'+base62uuid(4), [], self.context)
cols = [] cols = []
col_exprs = [] col_exprs = []
for i, proj in enumerate(self.projections): for i, proj in enumerate(self.projections):
compound = False compound = False
self.datasource.rec = set() self.datasource.rec = set()
name = '' name = ''
if type(proj) is dict: if type(proj) is dict:
if 'value' in proj: if 'value' in proj:
e = proj['value'] e = proj['value']
name = expr(self, e).sql name = expr(self, e).sql
disp_name = ''.join([a if a in base62alp else '' for a in name]) disp_name = ''.join([a if a in base62alp else '' for a in name])
compound = True # compound column compound = True # compound column
if 'name' in proj: # renaming column by AS keyword if 'name' in proj: # renaming column by AS keyword
name += ' ' + proj['name'] name += ' ' + proj['name']
col_exprs.append(name) col_exprs.append(name)
elif type(proj) is str: elif type(proj) is str:
col = self.datasource.get_col(proj) col = self.datasource.get_col(proj)
name = col.name name = col.name
self.datasource.rec = None self.datasource.rec = None
# TODO: Type deduction in Python # TODO: Type deduction in Python
cols.append(ColRef('unknown', self.out_table, None, disp_name, i, compound=compound)) cols.append(ColRef('unknown', self.out_table, None, disp_name, i, compound=compound))
self.add(', '.join(col_exprs)) self.add(', '.join(col_exprs))
def finialize(astnode:ast_node): def finialize(astnode:ast_node):
if(astnode is not None): if(astnode is not None):
self.add(astnode.sql) self.add(astnode.sql)
self.add('FROM') self.add('FROM')
finialize(self.datasource) finialize(self.datasource)
finialize(self.where) finialize(self.where)
finialize(self.group_node) finialize(self.group_node)
if 'orderby' in node: if 'orderby' in node:
self.add(orderby(self, node['orderby']).sql) self.add(orderby(self, node['orderby']).sql)
if 'outfile' in node: if 'outfile' in node:
self.add(outfile(self, node['outfile']).sql) self.add(outfile(self, node['outfile']).sql)
if self.parent is None: if self.parent is None:
self.emit(self.sql+';\n') self.emit(self.sql+';\n')
else: else:
# TODO: subquery, name create tmp-table from subquery w/ alias as name # TODO: subquery, name create tmp-table from subquery w/ alias as name
pass pass
class orderby(ast_node): class orderby(ast_node):
name = 'order by' name = 'order by'
def produce(self, node): def produce(self, node):
if node is None: if node is None:
self.sql = '' self.sql = ''
return return
elif type(node) is not list: elif type(node) is not list:
node = [node] node = [node]
o_list = [] o_list = []
for o in node: for o in node:
o_str = expr(self, o['value']).sql o_str = expr(self, o['value']).sql
if 'sort' in o and f'{o["sort"]}'.lower() == 'desc': if 'sort' in o and f'{o["sort"]}'.lower() == 'desc':
o_str += ' ' + 'DESC' o_str += ' ' + 'DESC'
o_list.append(o_str) o_list.append(o_str)
self.add(', '.join(o_list)) self.add(', '.join(o_list))
class groupby(orderby): class groupby(orderby):
name = 'group by' name = 'group by'
class join(ast_node): class join(ast_node):
name = 'join' name = 'join'
def init(self, _): def init(self, _):
self.joins:list = [] self.joins:list = []
self.tables = [] self.tables = []
self.tables_dir = dict() self.tables_dir = dict()
# self.tmp_name = 'join_' + base62uuid(4) # self.tmp_name = 'join_' + base62uuid(4)
# self.datasource = TableInfo(self.tmp_name, [], self.context) # self.datasource = TableInfo(self.tmp_name, [], self.context)
def append(self, tbls, __alias = ''): def append(self, tbls, __alias = ''):
alias = lambda t : '(' + t + ') ' + __alias if len(__alias) else t alias = lambda t : '(' + t + ') ' + __alias if len(__alias) else t
if type(tbls) is join: if type(tbls) is join:
self.joins.append(alias(tbls.__str__())) self.joins.append(alias(tbls.__str__()))
self.tables += tbls.tables self.tables += tbls.tables
self.tables_dir = {**self.tables_dir, **tbls.tables_dir} self.tables_dir = {**self.tables_dir, **tbls.tables_dir}
elif type(tbls) is TableInfo: elif type(tbls) is TableInfo:
self.joins.append(alias(tbls.table_name)) self.joins.append(alias(tbls.table_name))
self.tables.append(tbls) self.tables.append(tbls)
self.tables_dir[tbls.table_name] = tbls self.tables_dir[tbls.table_name] = tbls
for a in tbls.alias: for a in tbls.alias:
self.tables_dir[a] = tbls self.tables_dir[a] = tbls
elif type(tbls) is projection: elif type(tbls) is projection:
self.joins.append(alias(tbls.finalize())) self.joins.append(alias(tbls.finalize()))
def produce(self, node): def produce(self, node):
if type(node) is list: if type(node) is list:
for d in node: for d in node:
self.append(join(self, d).__str__()) self.append(join(self, d).__str__())
elif type(node) is dict: elif type(node) is dict:
alias = '' alias = ''
if 'value' in node: if 'value' in node:
table_name = node['value'] table_name = node['value']
tbl = None tbl = None
if 'name' in node: if 'name' in node:
alias = node['name'] alias = node['name']
if type(table_name) is dict: if type(table_name) is dict:
if 'select' in table_name: if 'select' in table_name:
# TODO: subquery, create and register TableInfo in projection # TODO: subquery, create and register TableInfo in projection
tbl = projection(self, table_name).finalize() tbl = projection(self, table_name).finalize()
else: else:
tbl = self.context.tables_byname[table_name] tbl = self.context.tables_byname[table_name]
if 'name' in node: if 'name' in node:
tbl.add_alias(node['name']) tbl.add_alias(node['name'])
self.append(tbl, alias) self.append(tbl, alias)
else: else:
keys = node.keys() keys = node.keys()
if keys[0].lower().endswith('join'): if keys[0].lower().endswith('join'):
j = join(self, node[keys[0]]) j = join(self, node[keys[0]])
tablename = f' {keys[0]} {j}' tablename = f' {keys[0]} {j}'
if keys[1].lower() == 'on': if keys[1].lower() == 'on':
tablename += f' on {expr(self, node[keys[1]])}' tablename += f' on {expr(self, node[keys[1]])}'
self.joins.append(tablename) self.joins.append(tablename)
self.tables += j.tables self.tables += j.tables
self.tables_dir = {**self.tables_dir, **j.tables_dir} self.tables_dir = {**self.tables_dir, **j.tables_dir}
elif type(node) is str: elif type(node) is str:
self.append(self.context.tables_byname[node]) self.append(self.context.tables_byname[node])
def get_cols(self, colExpr: str) -> ColRef: def get_cols(self, colExpr: str) -> ColRef:
for t in self.tables: for t in self.tables:
if colExpr in t.columns_byname: if colExpr in t.columns_byname:
return t.columns_byname[colExpr] return t.columns_byname[colExpr]
def parse_col_names(self, colExpr:str) -> ColRef: def parse_col_names(self, colExpr:str) -> ColRef:
parsedColExpr = colExpr.split('.') parsedColExpr = colExpr.split('.')
if len(parsedColExpr) <= 1: if len(parsedColExpr) <= 1:
return self.get_cols(colExpr) return self.get_cols(colExpr)
else: else:
datasource = self.tables_dir[parsedColExpr[0]] datasource = self.tables_dir[parsedColExpr[0]]
if datasource is None: if datasource is None:
raise ValueError(f'Table name/alias not defined{parsedColExpr[0]}') raise ValueError(f'Table name/alias not defined{parsedColExpr[0]}')
else: else:
return datasource.parse_col_names(parsedColExpr[1]) return datasource.parse_col_names(parsedColExpr[1])
def consume(self, _): def consume(self, _):
self.sql = ', '.join(self.joins) self.sql = ', '.join(self.joins)
return super().consume(_) return super().consume(_)
def __str__(self): def __str__(self):
return ', '.join(self.joins) return ', '.join(self.joins)
def __repr__(self): def __repr__(self):
return self.__str__() return self.__str__()
class filter(ast_node): class filter(ast_node):
name = 'where' name = 'where'
def produce(self, node): def produce(self, node):
self.add(expr(self, node).sql) self.add(expr(self, node).sql)
class create_table(ast_node): class create_table(ast_node):
name = 'create_table' name = 'create_table'
first_order = name first_order = name
def init(self, node): def init(self, node):
self.sql = 'CREATE TABLE ' self.sql = 'CREATE TABLE '
def produce(self, node): def produce(self, node):
ct = node[self.name] ct = node[self.name]
tbl = self.context.add_table(ct['name'], ct['columns']) tbl = self.context.add_table(ct['name'], ct['columns'])
self.sql = f'CREATE TABLE {tbl.table_name}(' self.sql = f'CREATE TABLE {tbl.table_name}('
columns = [] columns = []
for c in tbl.columns: for c in tbl.columns:
columns.append(f'{c.name} {c.type.upper()}') columns.append(f'{c.name} {c.type.upper()}')
self.sql += ', '.join(columns) self.sql += ', '.join(columns)
self.sql += ')' self.sql += ')'
class insert(ast_node): class insert(ast_node):
name = 'insert' name = 'insert'
first_order = name first_order = name
def produce(self, node): def produce(self, node):
values = node['query']['select'] values = node['query']['select']
tbl = node['insert'] tbl = node['insert']
self.sql = f'INSERT INTO {tbl} VALUES(' self.sql = f'INSERT INTO {tbl} VALUES('
# if len(values) != table.n_cols: # if len(values) != table.n_cols:
# raise ValueError("Column Mismatch") # raise ValueError("Column Mismatch")
list_values = [] list_values = []
for i, s in enumerate(values): for i, s in enumerate(values):
if 'value' in s: if 'value' in s:
list_values.append(f"{s['value']}") list_values.append(f"{s['value']}")
else: else:
# subquery, dispatch to select astnode # subquery, dispatch to select astnode
pass pass
self.sql += ', '.join(list_values) + ')' self.sql += ', '.join(list_values) + ')'
class load(ast_node): class load(ast_node):
name="load" name="load"
first_order = name first_order = name
def produce(self, node): def produce(self, node):
node = node['load'] node = node['load']
s1 = 'LOAD DATA INFILE ' s1 = 'LOAD DATA INFILE '
s2 = 'INTO TABLE ' s2 = 'INTO TABLE '
s3 = 'FIELDS TERMINATED BY ' s3 = 'FIELDS TERMINATED BY '
self.sql = f'{s1} \"{node["file"]["literal"]}\" {s2} {node["table"]}' self.sql = f'{s1} \"{node["file"]["literal"]}\" {s2} {node["table"]}'
if 'term' in node: if 'term' in node:
self.sql += f' {s3} \"{node["term"]["literal"]}\"' self.sql += f' {s3} \"{node["term"]["literal"]}\"'
class outfile(ast_node): class outfile(ast_node):
name="_outfile" name="_outfile"
def produce(self, node): def produce(self, node):
filename = node['loc']['literal'] if 'loc' in node else node['literal'] filename = node['loc']['literal'] if 'loc' in node else node['literal']
self.sql = f'INTO OUTFILE "{filename}"' self.sql = f'INTO OUTFILE "{filename}"'
if 'term' in node: if 'term' in node:
self.sql += f' FIELDS TERMINATED BY \"{node["term"]["literal"]}\"' self.sql += f' FIELDS TERMINATED BY \"{node["term"]["literal"]}\"'
def include(objs): def include(objs):
import inspect import inspect
for _, cls in inspect.getmembers(objs): for _, cls in inspect.getmembers(objs):
if inspect.isclass(cls) and issubclass(cls, ast_node) and type(cls.first_order) is str: if inspect.isclass(cls) and issubclass(cls, ast_node) and type(cls.first_order) is str:
ast_node.types[cls.first_order] = cls ast_node.types[cls.first_order] = cls
import sys import sys
include(sys.modules[__name__]) include(sys.modules[__name__])

@ -1,128 +1,128 @@
from reconstruct.ast import ast_node from reconstruct.ast import ast_node
from reconstruct.storage import ColRef, TableInfo from reconstruct.storage import ColRef, TableInfo
class expr(ast_node): class expr(ast_node):
name='expr' name='expr'
builtin_func_maps = { builtin_func_maps = {
'max': 'MAX', 'max': 'MAX',
'min': 'MIN', 'min': 'MIN',
'avg': 'AVG', 'avg': 'AVG',
'sum': 'SUM', 'sum': 'SUM',
'count' : 'COUNT', 'count' : 'COUNT',
'mins': ['mins', 'minw'], 'mins': ['mins', 'minw'],
'maxs': ['maxs', 'maxw'], 'maxs': ['maxs', 'maxw'],
'avgs': ['avgs', 'avgw'], 'avgs': ['avgs', 'avgw'],
'sums': ['sums', 'sumw'], 'sums': ['sums', 'sumw'],
} }
binary_ops = { binary_ops = {
'sub':'-', 'sub':'-',
'add':'+', 'add':'+',
'mul':'*', 'mul':'*',
'div':'/', 'div':'/',
'mod':'%', 'mod':'%',
'and':' AND ', 'and':' AND ',
'or':' OR ', 'or':' OR ',
'xor' : ' XOR ', 'xor' : ' XOR ',
'gt':'>', 'gt':'>',
'lt':'<', 'lt':'<',
'le':'<=', 'le':'<=',
'gt':'>=' 'gt':'>='
} }
compound_ops = { compound_ops = {
} }
unary_ops = { unary_ops = {
'neg' : '-', 'neg' : '-',
'not' : ' NOT ' 'not' : ' NOT '
} }
coumpound_generating_ops = ['avgs', 'mins', 'maxs', 'sums'] + \ coumpound_generating_ops = ['avgs', 'mins', 'maxs', 'sums'] + \
list(binary_ops.keys()) + list(compound_ops.keys()) + list(unary_ops.keys() ) list(binary_ops.keys()) + list(compound_ops.keys()) + list(unary_ops.keys() )
def __init__(self, parent, node): def __init__(self, parent, node):
self.raw_col = None self.raw_col = None
self.inside_agg = False self.inside_agg = False
if(type(parent) is expr): if(type(parent) is expr):
self.inside_agg = parent.inside_agg self.inside_agg = parent.inside_agg
ast_node.__init__(self, parent, node, None) ast_node.__init__(self, parent, node, None)
def init(self, _): def init(self, _):
from engine.projection import projection from engine.projection import projection
parent = self.parent parent = self.parent
self.isvector = parent.isvector if type(parent) is expr else False self.isvector = parent.isvector if type(parent) is expr else False
self.is_compound = parent.is_compound if type(parent) is expr else False self.is_compound = parent.is_compound if type(parent) is expr else False
if type(parent) in [projection, expr]: if type(parent) in [projection, expr]:
self.datasource = parent.datasource self.datasource = parent.datasource
else: else:
self.datasource = self.context.datasource self.datasource = self.context.datasource
self.udf_map = parent.context.udf_map self.udf_map = parent.context.udf_map
self.func_maps = {**self.udf_map, **self.builtin_func_maps} self.func_maps = {**self.udf_map, **self.builtin_func_maps}
def produce(self, node): def produce(self, node):
if type(node) is dict: if type(node) is dict:
for key, val in node.items(): for key, val in node.items():
if key in self.func_maps: if key in self.func_maps:
# TODO: distinguish between UDF agg functions and other UDF functions. # TODO: distinguish between UDF agg functions and other UDF functions.
self.inside_agg = True self.inside_agg = True
if type(val) is list and len(val) > 1: if type(val) is list and len(val) > 1:
cfunc = self.func_maps[key] cfunc = self.func_maps[key]
cfunc = cfunc[len(val) - 1] if type(cfunc) is list else cfunc cfunc = cfunc[len(val) - 1] if type(cfunc) is list else cfunc
self.sql += f"{cfunc}(" self.sql += f"{cfunc}("
for i, p in enumerate(val): for i, p in enumerate(val):
self.sql += expr(self, p).sql + (',' if i < len(val) - 1 else '') self.sql += expr(self, p).sql + (',' if i < len(val) - 1 else '')
else: else:
funcname = self.func_maps[key] funcname = self.func_maps[key]
funcname = funcname[0] if type(funcname) is list else funcname funcname = funcname[0] if type(funcname) is list else funcname
self.sql += f"{funcname}(" self.sql += f"{funcname}("
self.sql += expr(self, val).sql self.sql += expr(self, val).sql
self.sql += ')' self.sql += ')'
self.inside_agg = False self.inside_agg = False
elif key in self.binary_ops: elif key in self.binary_ops:
l = expr(self, val[0]).sql l = expr(self, val[0]).sql
r = expr(self, val[1]).sql r = expr(self, val[1]).sql
self.sql += f'({l}{self.binary_ops[key]}{r})' self.sql += f'({l}{self.binary_ops[key]}{r})'
elif key in self.compound_ops: elif key in self.compound_ops:
x = [] x = []
if type(val) is list: if type(val) is list:
for v in val: for v in val:
x.append(expr(self, v).sql) x.append(expr(self, v).sql)
self.sql = self.compound_ops[key][1](x) self.sql = self.compound_ops[key][1](x)
elif key in self.unary_ops: elif key in self.unary_ops:
self.sql += f'{self.unary_ops[key]}({expr(self, val).sql})' self.sql += f'{self.unary_ops[key]}({expr(self, val).sql})'
else: else:
print(f'Undefined expr: {key}{val}') print(f'Undefined expr: {key}{val}')
if key in self.coumpound_generating_ops and not self.is_compound: if key in self.coumpound_generating_ops and not self.is_compound:
self.is_compound = True self.is_compound = True
p = self.parent p = self.parent
while type(p) is expr and not p.is_compound: while type(p) is expr and not p.is_compound:
p.is_compound = True p.is_compound = True
p = p.parent p = p.parent
elif type(node) is str: elif type(node) is str:
p = self.parent p = self.parent
while type(p) is expr and not p.isvector: while type(p) is expr and not p.isvector:
p.isvector = True p.isvector = True
p = p.parent p = p.parent
self.raw_col = self.datasource.parse_col_names(node) self.raw_col = self.datasource.parse_col_names(node)
self.raw_col = self.raw_col if type(self.raw_col) is ColRef else None self.raw_col = self.raw_col if type(self.raw_col) is ColRef else None
if self.raw_col is not None: if self.raw_col is not None:
self.sql = self.raw_col.name self.sql = self.raw_col.name
else: else:
self.sql = node self.sql = node
elif type(node) is bool: elif type(node) is bool:
self.sql = '1' if node else '0' self.sql = '1' if node else '0'
else: else:
self.sql = f'{node}' self.sql = f'{node}'
def __str__(self): def __str__(self):
return self.sql return self.sql
def __repr__(self): def __repr__(self):
return self.__str__() return self.__str__()

@ -1,89 +1,89 @@
class ColRef: class ColRef:
def __init__(self, _ty, cobj, table:'TableInfo', name, id, compound = False): def __init__(self, _ty, cobj, table:'TableInfo', name, id, compound = False):
self.type = _ty self.type = _ty
self.cobj = cobj self.cobj = cobj
self.table = table self.table = table
self.name = name self.name = name
self.alias = set() self.alias = set()
self.id = id # position in table self.id = id # position in table
self.compound = compound # compound field (list as a field) self.compound = compound # compound field (list as a field)
# e.g. order by, group by, filter by expressions # e.g. order by, group by, filter by expressions
self.__arr__ = (_ty, cobj, table, name, id) self.__arr__ = (_ty, cobj, table, name, id)
def __getitem__(self, key): def __getitem__(self, key):
if type(key) is str: if type(key) is str:
return getattr(self, key) return getattr(self, key)
else: else:
return self.__arr__[key] return self.__arr__[key]
def __setitem__(self, key, value): def __setitem__(self, key, value):
self.__arr__[key] = value self.__arr__[key] = value
class TableInfo: class TableInfo:
def __init__(self, table_name, cols, cxt:'Context'): def __init__(self, table_name, cols, cxt:'Context'):
# statics # statics
self.table_name = table_name self.table_name = table_name
self.alias = set([table_name]) self.alias = set([table_name])
self.columns_byname = dict() # column_name, type self.columns_byname = dict() # column_name, type
self.columns = [] self.columns = []
self.cxt = cxt self.cxt = cxt
# keep track of temp vars # keep track of temp vars
self.rec = None self.rec = None
self.add_cols(cols) self.add_cols(cols)
# runtime # runtime
self.order = [] # assumptions self.order = [] # assumptions
cxt.tables_byname[self.table_name] = self # construct reverse map cxt.tables_byname[self.table_name] = self # construct reverse map
def add_cols(self, cols, new = True): def add_cols(self, cols, new = True):
for i, c in enumerate(cols): for i, c in enumerate(cols):
self.add_col(c, new, i) self.add_col(c, new, i)
def add_col(self, c, new = True, i = 0): def add_col(self, c, new = True, i = 0):
_ty = c['type'] _ty = c['type']
if new: if new:
_ty = _ty if type(c) is ColRef else list(_ty.keys())[0] _ty = _ty if type(c) is ColRef else list(_ty.keys())[0]
col_object = ColRef(_ty, c, self, c['name'], len(self.columns)) col_object = ColRef(_ty, c, self, c['name'], len(self.columns))
else: else:
col_object = c col_object = c
c.table = self c.table = self
self.columns_byname[c['name']] = col_object self.columns_byname[c['name']] = col_object
self.columns.append(col_object) self.columns.append(col_object)
def add_alias(self, alias): def add_alias(self, alias):
if alias in self.cxt.tables_byname.keys(): if alias in self.cxt.tables_byname.keys():
print("Error: table alias already exists") print("Error: table alias already exists")
return return
self.cxt.tables_byname[alias] = self self.cxt.tables_byname[alias] = self
self.alias.add(alias) self.alias.add(alias)
def parse_col_names(self, colExpr) -> ColRef: def parse_col_names(self, colExpr) -> ColRef:
parsedColExpr = colExpr.split('.') parsedColExpr = colExpr.split('.')
if len(parsedColExpr) <= 1: if len(parsedColExpr) <= 1:
return self.columns_byname[colExpr] return self.columns_byname[colExpr]
else: else:
datasource = self.cxt.tables_byname[parsedColExpr[0]] datasource = self.cxt.tables_byname[parsedColExpr[0]]
if datasource is None: if datasource is None:
raise ValueError(f'Table name/alias not defined{parsedColExpr[0]}') raise ValueError(f'Table name/alias not defined{parsedColExpr[0]}')
else: else:
return datasource.parse_col_names(parsedColExpr[1]) return datasource.parse_col_names(parsedColExpr[1])
class Context: class Context:
def __init__(self): def __init__(self):
self.sql = '' self.sql = ''
self.tables_byname = dict() self.tables_byname = dict()
self.col_byname = dict() self.col_byname = dict()
self.tables = [] self.tables = []
self.cols = [] self.cols = []
self.datasource = None self.datasource = None
self.udf_map = dict() self.udf_map = dict()
def emit(self, sql:str): def emit(self, sql:str):
self.sql += sql + ' ' self.sql += sql + ' '
def add_table(self, table_name, cols): def add_table(self, table_name, cols):
tbl = TableInfo(table_name, cols, self) tbl = TableInfo(table_name, cols, self)
self.tables.append(tbl) self.tables.append(tbl)
return tbl return tbl

Binary file not shown.

@ -1,27 +0,0 @@
{
"BackgroundImageAbsolutePath": "c:\\users\\bill\\appdata\\local\\microsoft\\visualstudio\\17.0_03c65567\\extensions\\atkxhose.05t\\Images\\background.png",
"BackgroundImagesDirectoryAbsolutePath": "c:\\users\\bill\\appdata\\local\\microsoft\\visualstudio\\17.0_03c65567\\extensions\\atkxhose.05t\\Images",
"ExpandToIDE": false,
"Extensions": ".png, .jpg, .gif, .bmp",
"ImageBackgroundType": 0,
"ImageFadeAnimationInterval": "PT5S",
"ImageStretch": 0,
"IsLimitToMainlyEditorWindow": false,
"LoopSlideshow": true,
"MaxHeight": 0,
"MaxWidth": 0,
"Opacity": 0.35,
"PositionHorizon": 1,
"PositionVertical": 1,
"ShuffleSlideshow": false,
"SoftEdgeX": 0,
"SoftEdgeY": 0,
"TileMode": 0,
"UpdateImageInterval": "PT1M",
"ViewBoxPointX": 0,
"ViewBoxPointY": 0,
"ViewPortHeight": 1,
"ViewPortPointX": 0,
"ViewPortPointY": 0,
"ViewPortWidth": 1
}

@ -10,10 +10,21 @@ enum Log_level {
LOG_SILENT LOG_SILENT
}; };
struct Config{
int running, new_query, server_mode, n_buffers;
int buffer_sizes[];
};
struct Context{ struct Context{
typedef int (*printf_type) (const char *format, ...); typedef int (*printf_type) (const char *format, ...);
std::unordered_map<const char*, void*> tables; std::unordered_map<const char*, void*> tables;
std::unordered_map<const char*, uColRef *> cols; std::unordered_map<const char*, uColRef *> cols;
Config* cfg;
int n_buffers, *sz_bufs;
void **buffers;
Log_level log_level = LOG_SILENT; Log_level log_level = LOG_SILENT;
printf_type print = printf; printf_type print = printf;
template <class ...Types> template <class ...Types>
@ -28,8 +39,8 @@ struct Context{
} }
}; };
#ifdef _MSC_VER #ifdef _WIN32
#define __DLLEXPORT__ __declspec(dllexport) __stdcall #define __DLLEXPORT__ __declspec(dllexport) __stdcall
#else #else
#define __DLLEXPORT__ #define __DLLEXPORT__
#endif #endif

@ -36,13 +36,43 @@ void daemon(thread_context* c) {
#include "aggregations.h" #include "aggregations.h"
typedef int (*code_snippet)(void*); typedef int (*code_snippet)(void*);
int _main(); int _main();
int main(int argc, char** argv) {
int dll_main(int argc, char** argv, Context* cxt){
Config *cfg = reinterpret_cast<Config *>(argv[0]);
auto buf_szs = cfg->buffer_sizes;
void** buffers = (void**)malloc(sizeof(void*) * cfg->n_buffers);
for (int i = 0; i < cfg->n_buffers; i++)
buffers[i] = static_cast<void *>(argv[i + 1]);
cxt->buffers = buffers;
cxt->cfg = cfg;
cxt->n_buffers = cfg->n_buffers;
cxt->sz_bufs = buf_szs;
while(cfg->running){
if (cfg->new_query) {
void* handle = dlopen("d:/gg/Aquery++/dll.so", RTLD_LAZY);
code_snippet c = reinterpret_cast<code_snippet>(dlsym(handle, "dllmain"));
c(cxt);
dlclose(handle);
cfg->new_query = 0;
}
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
return 0;
}
extern "C" int __DLLEXPORT__ main(int argc, char** argv) {
Context* cxt = new Context(); Context* cxt = new Context();
cxt->log("%d %s\n", argc, argv[1]); cxt->log("%d %s\n", argc, argv[1]);
const char* shmname; const char* shmname;
if (argc <= 1) if (argc < 0)
return _main(); return dll_main(argc, argv, cxt);
else if (argc <= 1)
return test_main();
else else
shmname = argv[1]; shmname = argv[1];
SharedMemory shm = SharedMemory(shmname); SharedMemory shm = SharedMemory(shmname);
@ -68,7 +98,6 @@ int main(int argc, char** argv) {
cxt->log("inner\n"); cxt->log("inner\n");
cxt->err("return: %d\n", c(cxt)); cxt->err("return: %d\n", c(cxt));
} }
dlclose(handle);
} }
ready = false; ready = false;
} }
@ -77,7 +106,7 @@ int main(int argc, char** argv) {
return 0; return 0;
} }
#include "utils.h" #include "utils.h"
int _main() int test_main()
{ {
//vector_type<int> t; //vector_type<int> t;
//t = 1; //t = 1;

Loading…
Cancel
Save